From ea80fbfb56629ec6422498a7ace89d9b084fc1c1 Mon Sep 17 00:00:00 2001 From: Szymon Szyszkowski <69353402+project-defiant@users.noreply.github.com> Date: Thu, 25 Jul 2024 12:26:50 +0200 Subject: [PATCH 001/188] feat: expose summary statistics qc and locus breaker steps to hydra cli (#716) * feat: expose summary statistics qc to hydra cli * feat: expose locus breaker clumping step --------- Co-authored-by: Szymon Szyszkowski --- docs/python_api/steps/locus_breaker_clumping.md | 5 +++++ docs/python_api/steps/summary_statistics_qc.md | 5 +++++ src/gentropy/config.py | 4 ++++ 3 files changed, 14 insertions(+) create mode 100644 docs/python_api/steps/locus_breaker_clumping.md create mode 100644 docs/python_api/steps/summary_statistics_qc.md diff --git a/docs/python_api/steps/locus_breaker_clumping.md b/docs/python_api/steps/locus_breaker_clumping.md new file mode 100644 index 000000000..1e49234e3 --- /dev/null +++ b/docs/python_api/steps/locus_breaker_clumping.md @@ -0,0 +1,5 @@ +--- +title: locus_breaker_clumping +--- + +::: gentropy.locus_breaker_clumping.LocusBreakerClumpingStep diff --git a/docs/python_api/steps/summary_statistics_qc.md b/docs/python_api/steps/summary_statistics_qc.md new file mode 100644 index 000000000..a9fea12b9 --- /dev/null +++ b/docs/python_api/steps/summary_statistics_qc.md @@ -0,0 +1,5 @@ +--- +title: summary_statistics_qc +--- + +::: gentropy.sumstat_qc_step.SummaryStatisticsQCStep diff --git a/src/gentropy/config.py b/src/gentropy/config.py index a6f92669e..90160e962 100644 --- a/src/gentropy/config.py +++ b/src/gentropy/config.py @@ -532,3 +532,7 @@ def register_config() -> None: group="step", name="window_based_clumping", node=WindowBasedClumpingStepConfig ) cs.store(group="step", name="susie_finemapping", node=FinemapperConfig) + cs.store(group="step", name="summary_statistics_qc", node=GWASQCStep) + cs.store( + group="step", name="locus_breaker_clumping", node=LocusBreakerClumpingConfig + ) From a5c96b975dada005a1424ec241bbd80149f7a469 Mon Sep 17 00:00:00 2001 From: Szymon Szyszkowski <69353402+project-defiant@users.noreply.github.com> Date: Mon, 29 Jul 2024 11:31:10 +0200 Subject: [PATCH 002/188] fix: change config params to match new name (#721) Co-authored-by: Szymon Szyszkowski --- config/step/ot_gwas_catalog_ingestion.yaml | 2 +- config/step/ot_gwas_catalog_study_inclusion.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config/step/ot_gwas_catalog_ingestion.yaml b/config/step/ot_gwas_catalog_ingestion.yaml index fc82b82c2..8acc07d62 100644 --- a/config/step/ot_gwas_catalog_ingestion.yaml +++ b/config/step/ot_gwas_catalog_ingestion.yaml @@ -5,7 +5,7 @@ catalog_study_files: ${datasets.gwas_catalog_studies} catalog_ancestry_files: ${datasets.gwas_catalog_ancestries} catalog_associations_file: ${datasets.gwas_catalog_associations} catalog_sumstats_lut: ${datasets.gwas_catalog_sumstats_lut} -variant_annotation_path: ${datasets.variant_annotation} +variant_annotation_path: ${datasets.gnomad_variants} catalog_studies_out: ${datasets.gwas_catalog_study_index} catalog_associations_out: ${datasets.gwas_catalog_study_locus_folder}/gwas_catalog_curated_associations gwas_catalog_study_curation_file: ${datasets.gwas_catalog_study_curation} diff --git a/config/step/ot_gwas_catalog_study_inclusion.yaml b/config/step/ot_gwas_catalog_study_inclusion.yaml index 7f3bf80b3..41590333c 100644 --- a/config/step/ot_gwas_catalog_study_inclusion.yaml +++ b/config/step/ot_gwas_catalog_study_inclusion.yaml @@ -4,7 +4,7 @@ defaults: catalog_study_files: ${datasets.gwas_catalog_studies} catalog_ancestry_files: ${datasets.gwas_catalog_ancestries} catalog_associations_file: ${datasets.gwas_catalog_associations} -variant_annotation_path: ${datasets.variant_annotation} +variant_annotation_path: ${datasets.gnomad_variants} gwas_catalog_study_curation_file: ${datasets.gwas_catalog_study_curation} harmonised_study_file: ${datasets.gwas_catalog_summary_stats_list} criteria: ??? From 897ae12f2e71b100e8bc223b9b0c7525a5cadac9 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 30 Jul 2024 09:33:48 +0100 Subject: [PATCH 003/188] chore: pre-commit autoupdate (#715) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.5.2 → v0.5.5](https://github.com/astral-sh/ruff-pre-commit/compare/v0.5.2...v0.5.5) - [github.com/pre-commit/mirrors-mypy: v1.10.1 → v1.11.0](https://github.com/pre-commit/mirrors-mypy/compare/v1.10.1...v1.11.0) - [github.com/jsh9/pydoclint: 0.5.4 → 0.5.6](https://github.com/jsh9/pydoclint/compare/0.5.4...0.5.6) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index cd9808f07..a68850464 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -6,7 +6,7 @@ ci: skip: [poetry-lock] repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.5.2 + rev: v0.5.5 hooks: - id: ruff args: @@ -65,7 +65,7 @@ repos: stages: [commit-msg] - repo: https://github.com/pre-commit/mirrors-mypy - rev: "v1.10.1" + rev: "v1.11.0" hooks: - id: mypy args: @@ -98,7 +98,7 @@ repos: - id: beautysh - repo: https://github.com/jsh9/pydoclint - rev: 0.5.4 + rev: 0.5.6 hooks: - id: pydoclint From 397f1e99f1c12c48ae0c91887e10640115fa492e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 31 Jul 2024 16:09:08 +0100 Subject: [PATCH 004/188] build(deps-dev): bump pymdown-extensions from 10.8.1 to 10.9 (#720) Bumps [pymdown-extensions](https://github.com/facelessuser/pymdown-extensions) from 10.8.1 to 10.9. - [Release notes](https://github.com/facelessuser/pymdown-extensions/releases) - [Commits](https://github.com/facelessuser/pymdown-extensions/compare/10.8.1...10.9) --- updated-dependencies: - dependency-name: pymdown-extensions dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Szymon Szyszkowski <69353402+project-defiant@users.noreply.github.com> --- poetry.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/poetry.lock b/poetry.lock index beba69366..8f8fa90bf 100644 --- a/poetry.lock +++ b/poetry.lock @@ -6601,13 +6601,13 @@ files = [ [[package]] name = "pymdown-extensions" -version = "10.8.1" +version = "10.9" description = "Extension pack for Python Markdown." optional = false python-versions = ">=3.8" files = [ - {file = "pymdown_extensions-10.8.1-py3-none-any.whl", hash = "sha256:f938326115884f48c6059c67377c46cf631c733ef3629b6eed1349989d1b30cb"}, - {file = "pymdown_extensions-10.8.1.tar.gz", hash = "sha256:3ab1db5c9e21728dabf75192d71471f8e50f216627e9a1fa9535ecb0231b9940"}, + {file = "pymdown_extensions-10.9-py3-none-any.whl", hash = "sha256:d323f7e90d83c86113ee78f3fe62fc9dee5f56b54d912660703ea1816fed5626"}, + {file = "pymdown_extensions-10.9.tar.gz", hash = "sha256:6ff740bcd99ec4172a938970d42b96128bdc9d4b9bcad72494f29921dc69b753"}, ] [package.dependencies] From 0b9af70b711a7e1141e321fc2ed2bdbeb0a6f493 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 8 Aug 2024 09:47:30 +0100 Subject: [PATCH 005/188] build(deps-dev): bump deptry from 0.17.0 to 0.18.0 (#723) Bumps [deptry](https://github.com/fpgmaas/deptry) from 0.17.0 to 0.18.0. - [Release notes](https://github.com/fpgmaas/deptry/releases) - [Changelog](https://github.com/fpgmaas/deptry/blob/main/CHANGELOG.md) - [Commits](https://github.com/fpgmaas/deptry/compare/0.17.0...0.18.0) --- updated-dependencies: - dependency-name: deptry dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- poetry.lock | 26 +++++++++++++------------- pyproject.toml | 2 +- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/poetry.lock b/poetry.lock index 8f8fa90bf..64a192984 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1667,22 +1667,22 @@ dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "sphinx (<2)", "tox"] [[package]] name = "deptry" -version = "0.17.0" +version = "0.18.0" description = "A command line utility to check for unused, missing and transitive dependencies in a Python project." optional = false python-versions = ">=3.8" files = [ - {file = "deptry-0.17.0-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:ddd05503cbae9cce608003bc50691cb2a6d714a9da30bc16a99116eedad5a0c2"}, - {file = "deptry-0.17.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:31af1dd2f83bddb6cf5abc9f37a86f8ca4b8572fda971a4e7eb0d552a727f454"}, - {file = "deptry-0.17.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0588827e36f4822517fc66308a85428780e15bbce819e2216d0a5d010edd1998"}, - {file = "deptry-0.17.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce0eb1408aae315fa757fc9877101079ea6b2ebcae18b261e5d3e0141ba517b2"}, - {file = "deptry-0.17.0-cp38-abi3-win_amd64.whl", hash = "sha256:d102754cd1f4ba2ed599fccaec54acb6be56bd00e8d03384d0a2bcb8ba8141e1"}, - {file = "deptry-0.17.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:1753b8807c3da82637beb6a0b32df85fea73bcc33a31bcda2087487bd92c336e"}, - {file = "deptry-0.17.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:f34309d3c2f28c459f2e55d93b67c81950cb863e1b210788f3491ab973e42f53"}, - {file = "deptry-0.17.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac6b569c9623e41f1a18f722ddf8422ca7b0d5f718f9d6c71bc9dfcd9e28cf5d"}, - {file = "deptry-0.17.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7de2feebecb256ccee69b0f8144c678763d7842704959239fa7e7f3fc60f8a1"}, - {file = "deptry-0.17.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:e4724e014c0787452962833cc3030170d267fbd3ac34f6c09b8449d8e8147f39"}, - {file = "deptry-0.17.0.tar.gz", hash = "sha256:f48a71bab8f46a896fe507c8be5f2b50bb9bab0c44e4dfad00afe87e9a08c14b"}, + {file = "deptry-0.18.0-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:aac16b9825c67887f84795d3fe3c5a676376cd6cc8555f6f7b57bfd45603e421"}, + {file = "deptry-0.18.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:b1440d2fab960e224b542726e6fcb0d3065635cfa8233c14f6c578faa2766e02"}, + {file = "deptry-0.18.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5764d6b484d488ce0f7085dc1767d99069b476383857aafd3bbc912128892dd"}, + {file = "deptry-0.18.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee0a916d78ba8db092a9454d5bc20fccbadb6ed0e8fb81fc020ba7e0df3578ed"}, + {file = "deptry-0.18.0-cp38-abi3-win_amd64.whl", hash = "sha256:7d1b561a4477ab130e1cb277b3d3aa25743b3005e1bb60076031ec3926b47541"}, + {file = "deptry-0.18.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:e73d5c2676a1f49a954baa59c248b56bc940ab87d6070cb164f1394c24e07cf3"}, + {file = "deptry-0.18.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:7343bb4948ad625ac1b3109279665004e6790ce01c8dc6a8a2ef1e4424c29773"}, + {file = "deptry-0.18.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdf6da66e31ef8bdace3bb34a86c4f066b5c5296776dd61b76802c72b0b3f5f4"}, + {file = "deptry-0.18.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c7590966832f5222d2277612e07e67285d92123ad96cf7713cda579d420d63d1"}, + {file = "deptry-0.18.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:57e09ca29e98c4782197dc959849498941b5c4fc53178e9fe1fa30025e608bfd"}, + {file = "deptry-0.18.0.tar.gz", hash = "sha256:9cf8e398ea394f90ccfa8e11d7dcfba8ed485f6a33270ee2b024475b72a00d11"}, ] [package.dependencies] @@ -8691,4 +8691,4 @@ test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", [metadata] lock-version = "2.0" python-versions = "^3.10, <3.11" -content-hash = "b33fe69038e16c3ff9272ff76a563c5d91a833b568eb2a46acba8f411bf16eef" +content-hash = "5ebbf7ab3f609d1206d56ff465af3a648b945cb79e8415be61798530943a5911" diff --git a/pyproject.toml b/pyproject.toml index 962799dd8..3a206f4ef 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -75,7 +75,7 @@ apache-airflow = "^2.8.0" apache-airflow-providers-google = "^10.13.1" pydoclint = ">=0.3.8,<0.6.0" prettier = "^0.0.7" -deptry = ">=0.12,<0.18" +deptry = ">=0.12,<0.19" yamllint = "^1.33.0" [tool.semantic_release] From ae734a8f2eae6c4b777c2684c532e52daef7fe78 Mon Sep 17 00:00:00 2001 From: Daniel-Considine <113430683+Daniel-Considine@users.noreply.github.com> Date: Thu, 8 Aug 2024 14:51:39 +0100 Subject: [PATCH 006/188] feat: notebook for locus breaker and susie finemapping benchmark (#717) * feat: notebook for locus breaker and susie finemapping benchmark * fix: won't pass tests with matplotlib imported * feat: ukb_ppp_fm benchmark notebook * fix: check for nulls as well as nans * fix: removing matplotlib * fix: update notebooks * chore: re-run ukb ppp notebook * chore: rerun notebook --- notebooks/gwas_cat_benchmark.ipynb | 1507 ++++++++++++++++++++++++++++ notebooks/ukb_ppp_benchmark.ipynb | 1468 +++++++++++++++++++++++++++ 2 files changed, 2975 insertions(+) create mode 100644 notebooks/gwas_cat_benchmark.ipynb create mode 100644 notebooks/ukb_ppp_benchmark.ipynb diff --git a/notebooks/gwas_cat_benchmark.ipynb b/notebooks/gwas_cat_benchmark.ipynb new file mode 100644 index 000000000..cce01a050 --- /dev/null +++ b/notebooks/gwas_cat_benchmark.ipynb @@ -0,0 +1,1507 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + " \n", + "
\n", + " \n", + " Loading BokehJS ...\n", + "
\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/javascript": "'use strict';\n(function(root) {\n function now() {\n return new Date();\n }\n\n const force = true;\n\n if (typeof root._bokeh_onload_callbacks === \"undefined\" || force === true) {\n root._bokeh_onload_callbacks = [];\n root._bokeh_is_loading = undefined;\n }\n\nconst JS_MIME_TYPE = 'application/javascript';\n const HTML_MIME_TYPE = 'text/html';\n const EXEC_MIME_TYPE = 'application/vnd.bokehjs_exec.v0+json';\n const CLASS_NAME = 'output_bokeh rendered_html';\n\n /**\n * Render data to the DOM node\n */\n function render(props, node) {\n const script = document.createElement(\"script\");\n node.appendChild(script);\n }\n\n /**\n * Handle when an output is cleared or removed\n */\n function handleClearOutput(event, handle) {\n function drop(id) {\n const view = Bokeh.index.get_by_id(id)\n if (view != null) {\n view.model.document.clear()\n Bokeh.index.delete(view)\n }\n }\n\n const cell = handle.cell;\n\n const id = cell.output_area._bokeh_element_id;\n const server_id = cell.output_area._bokeh_server_id;\n\n // Clean up Bokeh references\n if (id != null) {\n drop(id)\n }\n\n if (server_id !== undefined) {\n // Clean up Bokeh references\n const cmd_clean = \"from bokeh.io.state import curstate; print(curstate().uuid_to_server['\" + server_id + \"'].get_sessions()[0].document.roots[0]._id)\";\n cell.notebook.kernel.execute(cmd_clean, {\n iopub: {\n output: function(msg) {\n const id = msg.content.text.trim()\n drop(id)\n }\n }\n });\n // Destroy server and session\n const cmd_destroy = \"import bokeh.io.notebook as ion; ion.destroy_server('\" + server_id + \"')\";\n cell.notebook.kernel.execute(cmd_destroy);\n }\n }\n\n /**\n * Handle when a new output is added\n */\n function handleAddOutput(event, handle) {\n const output_area = handle.output_area;\n const output = handle.output;\n\n // limit handleAddOutput to display_data with EXEC_MIME_TYPE content only\n if ((output.output_type != \"display_data\") || (!Object.prototype.hasOwnProperty.call(output.data, EXEC_MIME_TYPE))) {\n return\n }\n\n const toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n\n if (output.metadata[EXEC_MIME_TYPE][\"id\"] !== undefined) {\n toinsert[toinsert.length - 1].firstChild.textContent = output.data[JS_MIME_TYPE];\n // store reference to embed id on output_area\n output_area._bokeh_element_id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n }\n if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n const bk_div = document.createElement(\"div\");\n bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n const script_attrs = bk_div.children[0].attributes;\n for (let i = 0; i < script_attrs.length; i++) {\n toinsert[toinsert.length - 1].firstChild.setAttribute(script_attrs[i].name, script_attrs[i].value);\n toinsert[toinsert.length - 1].firstChild.textContent = bk_div.children[0].textContent\n }\n // store reference to server id on output_area\n output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n }\n }\n\n function register_renderer(events, OutputArea) {\n\n function append_mime(data, metadata, element) {\n // create a DOM node to render to\n const toinsert = this.create_output_subarea(\n metadata,\n CLASS_NAME,\n EXEC_MIME_TYPE\n );\n this.keyboard_manager.register_events(toinsert);\n // Render to node\n const props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n render(props, toinsert[toinsert.length - 1]);\n element.append(toinsert);\n return toinsert\n }\n\n /* Handle when an output is cleared or removed */\n events.on('clear_output.CodeCell', handleClearOutput);\n events.on('delete.Cell', handleClearOutput);\n\n /* Handle when a new output is added */\n events.on('output_added.OutputArea', handleAddOutput);\n\n /**\n * Register the mime type and append_mime function with output_area\n */\n OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n /* Is output safe? */\n safe: true,\n /* Index of renderer in `output_area.display_order` */\n index: 0\n });\n }\n\n // register the mime type if in Jupyter Notebook environment and previously unregistered\n if (root.Jupyter !== undefined) {\n const events = require('base/js/events');\n const OutputArea = require('notebook/js/outputarea').OutputArea;\n\n if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n register_renderer(events, OutputArea);\n }\n }\n if (typeof (root._bokeh_timeout) === \"undefined\" || force === true) {\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_failed_load = false;\n }\n\n const NB_LOAD_WARNING = {'data': {'text/html':\n \"
\\n\"+\n \"

\\n\"+\n \"BokehJS does not appear to have successfully loaded. If loading BokehJS from CDN, this \\n\"+\n \"may be due to a slow or bad network connection. Possible fixes:\\n\"+\n \"

\\n\"+\n \"
    \\n\"+\n \"
  • re-rerun `output_notebook()` to attempt to load from CDN again, or
  • \\n\"+\n \"
  • use INLINE resources instead, as so:
  • \\n\"+\n \"
\\n\"+\n \"\\n\"+\n \"from bokeh.resources import INLINE\\n\"+\n \"output_notebook(resources=INLINE)\\n\"+\n \"\\n\"+\n \"
\"}};\n\n function display_loaded(error = null) {\n const el = document.getElementById(\"aa16b16c-6126-4fc3-bc14-75eb4b44b50e\");\n if (el != null) {\n const html = (() => {\n if (typeof root.Bokeh === \"undefined\") {\n if (error == null) {\n return \"BokehJS is loading ...\";\n } else {\n return \"BokehJS failed to load.\";\n }\n } else {\n const prefix = `BokehJS ${root.Bokeh.version}`;\n if (error == null) {\n return `${prefix} successfully loaded.`;\n } else {\n return `${prefix} encountered errors while loading and may not function as expected.`;\n }\n }\n })();\n el.innerHTML = html;\n\n if (error != null) {\n const wrapper = document.createElement(\"div\");\n wrapper.style.overflow = \"auto\";\n wrapper.style.height = \"5em\";\n wrapper.style.resize = \"vertical\";\n const content = document.createElement(\"div\");\n content.style.fontFamily = \"monospace\";\n content.style.whiteSpace = \"pre-wrap\";\n content.style.backgroundColor = \"rgb(255, 221, 221)\";\n content.textContent = error.stack ?? error.toString();\n wrapper.append(content);\n el.append(wrapper);\n }\n } else if (Date.now() < root._bokeh_timeout) {\n setTimeout(() => display_loaded(error), 100);\n }\n }\n\n function run_callbacks() {\n try {\n root._bokeh_onload_callbacks.forEach(function(callback) {\n if (callback != null)\n callback();\n });\n } finally {\n delete root._bokeh_onload_callbacks\n }\n console.debug(\"Bokeh: all callbacks have finished\");\n }\n\n function load_libs(css_urls, js_urls, callback) {\n if (css_urls == null) css_urls = [];\n if (js_urls == null) js_urls = [];\n\n root._bokeh_onload_callbacks.push(callback);\n if (root._bokeh_is_loading > 0) {\n console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n return null;\n }\n if (js_urls == null || js_urls.length === 0) {\n run_callbacks();\n return null;\n }\n console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n root._bokeh_is_loading = css_urls.length + js_urls.length;\n\n function on_load() {\n root._bokeh_is_loading--;\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n run_callbacks()\n }\n }\n\n function on_error(url) {\n console.error(\"failed to load \" + url);\n }\n\n for (let i = 0; i < css_urls.length; i++) {\n const url = css_urls[i];\n const element = document.createElement(\"link\");\n element.onload = on_load;\n element.onerror = on_error.bind(null, url);\n element.rel = \"stylesheet\";\n element.type = \"text/css\";\n element.href = url;\n console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n document.body.appendChild(element);\n }\n\n for (let i = 0; i < js_urls.length; i++) {\n const url = js_urls[i];\n const element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error.bind(null, url);\n element.async = false;\n element.src = url;\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n };\n\n function inject_raw_css(css) {\n const element = document.createElement(\"style\");\n element.appendChild(document.createTextNode(css));\n document.body.appendChild(element);\n }\n\n const js_urls = [\"https://cdn.bokeh.org/bokeh/release/bokeh-3.4.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.4.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.4.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.4.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-mathjax-3.4.1.min.js\"];\n const css_urls = [];\n\n const inline_js = [ function(Bokeh) {\n Bokeh.set_log_level(\"info\");\n },\nfunction(Bokeh) {\n }\n ];\n\n function run_inline_js() {\n if (root.Bokeh !== undefined || force === true) {\n try {\n for (let i = 0; i < inline_js.length; i++) {\n inline_js[i].call(root, root.Bokeh);\n }\n\n } catch (error) {display_loaded(error);throw error;\n }if (force === true) {\n display_loaded();\n }} else if (Date.now() < root._bokeh_timeout) {\n setTimeout(run_inline_js, 100);\n } else if (!root._bokeh_failed_load) {\n console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n root._bokeh_failed_load = true;\n } else if (force !== true) {\n const cell = $(document.getElementById(\"aa16b16c-6126-4fc3-bc14-75eb4b44b50e\")).parents('.cell').data().cell;\n cell.output_area.append_execute_result(NB_LOAD_WARNING)\n }\n }\n\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: BokehJS loaded, going straight to plotting\");\n run_inline_js();\n } else {\n load_libs(css_urls, js_urls, function() {\n console.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n run_inline_js();\n });\n }\n}(window));", + "application/vnd.bokehjs_load.v0+json": "" + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# import matplotlib.pyplot as plt\n", + "import pyspark.sql.functions as f\n", + "from gentropy.common.session import Session\n", + "from gentropy.common.spark_helpers import order_array_of_structs_by_field\n", + "from gentropy.dataset.ld_index import LDIndex\n", + "from gentropy.dataset.study_index import StudyIndex\n", + "from gentropy.dataset.study_locus import StudyLocus\n", + "from gentropy.method.susie_inf import SUSIE_inf\n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Setting default log level to \"WARN\".\n", + "To adjust logging level use sc.setLogLevel(newLevel). For SparkR, use setLogLevel(newLevel).\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "24/08/07 13:43:18 WARN NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable\n", + "24/08/07 13:43:20 WARN Utils: Service 'SparkUI' could not bind on port 4040. Attempting port 4041.\n", + "24/08/07 13:43:20 WARN Utils: Service 'SparkUI' could not bind on port 4041. Attempting port 4042.\n" + ] + } + ], + "source": [ + "session = Session(\n", + " extended_spark_conf={\n", + " \"spark.driver.memory\": \"10g\",\n", + " \"spark.executor.memory\": \"10g\",\n", + " },\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Context\n", + "\n", + "Gwas catalog studies with summary statistics were filtered using QC white-list \n", + "Locus breaker clumping was performed on the resulting studies\n", + "\n", + "Parameters: \n", + " lbc_baseline_pvalue: 1e-5, \n", + " lbc_distance_cutoff: 250_000, \n", + " lbc_pvalue_threshold: 1e-8, \n", + " lbc_flanking_distance: 100_000, \n", + " large_loci_size: 1_500_000, \n", + " wbc_clump_distance: 500_000, \n", + " wbc_pvalue_threshold: 1e-8, \n", + " collect_locus: bool = True, \n", + " remove_mhc: bool = True,\n", + "\n", + "Loci with less than 100 variants, or more than 15,000, were filtered out and fine-mapped with PICS.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "24/08/07 13:45:02 WARN SharedInMemoryCache: Evicting cached table partition metadata from memory due to size constraints (spark.sql.hive.filesourcePartitionFileCacheSize = 262144000 bytes). This may impact query planning performance.\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + } + ], + "source": [ + "study_index = StudyIndex.from_parquet(\n", + " session, \"/Users/dc16/data/study_index/gwas_catalog/\"\n", + ")\n", + "ld_index = LDIndex.from_parquet(session, \"/Users/dc16/data/ld_index\")\n", + "susie_loci = StudyLocus(\n", + " session.spark.read.parquet(\"/Users/dc16/output/gwas_catalog/clean_loci.parquet\"),\n", + " StudyLocus.get_schema(),\n", + ")\n", + "pics_loci = StudyLocus(\n", + " session.spark.read.parquet(\"/Users/dc16/output/gwas_catalog/filtered_loci.parquet\"),\n", + " StudyLocus.get_schema(),\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Susie fine mapping\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Calculate the total number of unique studyIds\n" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[Stage 7:==============> (1542 + 8) / 5556]\r" + ] + } + ], + "source": [ + "susie_loci.df.select(\"studyId\").distinct().count()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Calculate the total number of loci for finemapping:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "data": { + "text/plain": [ + "176096" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "susie_loci.df.count()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "df = susie_loci.df.withColumns(\n", + " {\n", + " \"locusSize\": f.size(\"locus\"),\n", + " \"locusLength\": f.col(\"locusEnd\") - f.col(\"locusStart\"),\n", + " }\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "-RECORD 0------------------------------\n", + " meanLocusLength | 682633.2350024986 \n", + " q1LocusLength | 327752 \n", + " medianLocusLength | 517819 \n", + " q3LocusLength | 934946 \n", + "\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[Stage 21:> (0 + 1) / 1]\r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "-RECORD 0-----------------------------\n", + " meanLocusSize | 3517.7594266763585 \n", + " minLocusSize | 100 \n", + " q1LocusSize | 1383 \n", + " medianLocusSize | 2565 \n", + " q3LocusSize | 4859 \n", + " maxLocusSize | 15000 \n", + "\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + } + ], + "source": [ + "length = df.select(\n", + " f.mean(\"locusLength\").alias(\"meanLocusLength\"),\n", + " f.percentile_approx(\"locusLength\", 0.25).alias(\"q1LocusLength\"),\n", + " f.percentile_approx(\"locusLength\", 0.5).alias(\"medianLocusLength\"),\n", + " f.percentile_approx(\"locusLength\", 0.75).alias(\"q3LocusLength\"),\n", + ")\n", + "size = df.select(\n", + " f.mean(\"locusSize\").alias(\"meanLocusSize\"),\n", + " f.min(\"locusSize\").alias(\"minLocusSize\"),\n", + " f.percentile_approx(\"locusSize\", 0.25).alias(\"q1LocusSize\"),\n", + " f.percentile_approx(\"locusSize\", 0.5).alias(\"medianLocusSize\"),\n", + " f.percentile_approx(\"locusSize\", 0.75).alias(\"q3LocusSize\"),\n", + " f.max(\"locusSize\").alias(\"maxLocusSize\"),\n", + ")\n", + "length.show(vertical=True)\n", + "size.show(vertical=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABKUAAAJOCAYAAABm7rQwAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/TGe4hAAAACXBIWXMAAA9hAAAPYQGoP6dpAAB0HUlEQVR4nO3de3zP9f//8fsOdnDY5rTNMrOcz4S0HEqWYZ+ifCqHhCYdprBCSoikVKKITyWr74eKPqVCWI7JcliWQ8hhkhgKG3KY7fn7o99evG3EbK/39t7term8L3m/Xo/36/14vrx77+m+18HNGGMEAAAAAAAA2Mjd2Q0AAAAAAACg+CGUAgAAAAAAgO0IpQAAAAAAAGA7QikAAAAAAADYjlAKAAAAAAAAtiOUAgAAAAAAgO0IpQAAAAAAAGA7QikAAAAAAADYjlAKAAAAAAAAtiOUAoqgqlWrqk+fPs5uw+W99tpruvHGG+Xh4aHGjRs7ux1chRUrVsjNzU2fffaZs1sBABRxzLfswXzrn8XHx8vNzU179+51ditAviOUApws+4fMhg0bcl1/++23q379+tf9PgsXLtTo0aOvezvFxZIlSzR06FC1bNlSM2fO1Msvv3zZ2j59+qh06dI2dlfwqlatqn/961/ObuOyZs+erUmTJjm7DQBAEcF8q3Aq7vOtc+fOafLkyWrSpIn8/PwUEBCgevXqqX///tq+fbuz2wNs4ensBgBcux07dsjd/doy5YULF2rq1KlMlK7SsmXL5O7urhkzZsjLy8vZ7eASs2fP1pYtWzRo0CBntwIAcFHMtwpecZ9vde3aVd988426d++uRx55RBkZGdq+fbvmz5+vW2+9VbVr15Yk9erVS926dZO3t7eTOwbyH6EUUAQVxR9Ip06dUqlSpZzdxlU7fPiwfH19i+UECQAAMN+yQ3Geb61fv17z58/XuHHj9NxzzzmsmzJlio4fP2499/DwkIeHh80dAvbg9D2gCLr0GgcZGRl68cUXVaNGDfn4+Kh8+fJq1aqVEhISJP19uPPUqVMlSW5ubtYj26lTp/T0008rNDRU3t7eqlWrll5//XUZYxze9/Tp03rqqadUoUIFlSlTRnfffbd+//13ubm5OfxGcPTo0XJzc9PPP/+sHj16qGzZsmrVqpUkadOmTerTp49uvPFG+fj4KDg4WA8//LD+/PNPh/fK3sYvv/yiBx98UP7+/qpYsaJeeOEFGWP022+/qXPnzvLz81NwcLDeeOONq9p358+f19ixY1WtWjV5e3uratWqeu6553T27Fmrxs3NTTNnztSpU6esfRUfH39V27+SuXPnqmnTpvL19VWFChX04IMP6vfff89Rt337dt1///2qWLGifH19VatWLT3//PPW+j59+qhq1ao5Xpe9zy6WkJCgVq1aKSAgQKVLl1atWrVyTHyux3//+19rTOXKlVO3bt3022+/OdRknxLx888/q23btipZsqRuuOEGTZgwIcf2fv31V919990qVaqUAgMDNXjwYC1evFhubm5asWKFtb0FCxbo119/tf5+Lt0fWVlZGjdunCpXriwfHx+1a9dOu3btyrdxAwBcH/Mt5lsFOd/avXu3JKlly5Y51nl4eKh8+fLW80uvKZXdQ26Piz+zWVlZmjRpkurVqycfHx8FBQXp0Ucf1bFjx67YG2AnjpQCCom0tDT98ccfOZZnZGT842tHjx6t8ePHq1+/frr55puVnp6uDRs26Mcff9Sdd96pRx99VAcOHFBCQoL+7//+z+G1xhjdfffdWr58uWJiYtS4cWMtXrxYQ4YM0e+//64333zTqu3Tp4/mzJmjXr166ZZbbtHKlSsVHR192b7uu+8+1ahRQy+//LI14UpISNCePXvUt29fBQcHa+vWrXr33Xe1detW/fDDDzl+yD/wwAOqU6eOXnnlFS1YsEAvvfSSypUrp//85z+644479Oqrr2rWrFl65pln1Lx5c7Vp0+aK+6pfv3768MMP9e9//1tPP/201q5dq/Hjx2vbtm364osvJEn/93//p3fffVfr1q3T+++/L0m69dZb//Hv4Uri4+PVt29fNW/eXOPHj9ehQ4c0efJkff/999q4caMCAgIk/T2JbN26tUqUKKH+/furatWq2r17t77++muNGzfumt5z69at+te//qWGDRtqzJgx8vb21q5du/T9999f11iyjRs3Ti+88ILuv/9+9evXT0eOHNHbb7+tNm3aOIxJko4dO6YOHTro3nvv1f3336/PPvtMw4YNU4MGDdSxY0dJf0/W77jjDh08eFADBw5UcHCwZs+ereXLlzu87/PPP6+0tDTt37/f+nxeeo2JV155Re7u7nrmmWeUlpamCRMmqGfPnlq7dm2+jB0AUDQx32K+JRWO+VZYWJgkadasWWrZsqU8Pa/+n+b33nuvqlev7rAsKSlJkyZNUmBgoLXs0UcftfbJU089pZSUFE2ZMkUbN27U999/rxIlSlzDSIECYgA41cyZM42kKz7q1avn8JqwsDDTu3dv63mjRo1MdHT0Fd8nNjbW5Pa//Lx584wk89JLLzks//e//23c3NzMrl27jDHGJCUlGUlm0KBBDnV9+vQxksyoUaOsZaNGjTKSTPfu3XO8319//ZVj2ccff2wkmVWrVuXYRv/+/a1l58+fN5UrVzZubm7mlVdesZYfO3bM+Pr6OuyT3CQnJxtJpl+/fg7Ln3nmGSPJLFu2zFrWu3dvU6pUqStu72prz507ZwIDA039+vXN6dOnreXz5883kszIkSOtZW3atDFlypQxv/76q8M2srKyHN4vLCwsx/tk77Nsb775ppFkjhw5clXjuFhYWNgVP1N79+41Hh4eZty4cQ7LN2/ebDw9PR2W33bbbUaS+eijj6xlZ8+eNcHBwaZr167WsjfeeMNIMvPmzbOWnT592tSuXdtIMsuXL7eWR0dH57oPli9fbiSZOnXqmLNnz1rLJ0+ebCSZzZs3X9X4AQCuhfkW863CNt/Kysqy5khBQUGme/fuZurUqTl6MubC5zclJSXXbR05csRUqVLFNGjQwJw8edIYY8x3331nJJlZs2Y51C5atCjX5YCzcPoeUEhMnTpVCQkJOR4NGzb8x9cGBARo69at2rlz5zW/78KFC+Xh4aGnnnrKYfnTTz8tY4y++eYbSdKiRYskSU888YRD3ZNPPnnZbT/22GM5lvn6+lp/PnPmjP744w/dcsstkqQff/wxR32/fv2sP3t4eKhZs2YyxigmJsZaHhAQoFq1amnPnj2X7UX6e6ySFBcX57D86aefliQtWLDgiq/Pqw0bNujw4cN64okn5OPjYy2Pjo5W7dq1rfc9cuSIVq1apYcfflhVqlRx2Malv9G8Gtm/Dfzyyy+VlZWV9wHk4vPPP1dWVpbuv/9+/fHHH9YjODhYNWrUyHF0U+nSpfXggw9az728vHTzzTc7/J0tWrRIN9xwg+6++25rmY+Pjx555JFr7q9v374O16do3bq1JP3jZwQA4NqYbzHfKizzLTc3Ny1evFgvvfSSypYtq48//lixsbEKCwvTAw884HBNqSvJzMxU9+7ddeLECX3xxRfWNcXmzp0rf39/3XnnnQ5ztaZNm6p06dI55mqAsxBKAYXEzTffrMjIyByPsmXL/uNrx4wZo+PHj6tmzZpq0KCBhgwZok2bNl3V+/76668KCQlRmTJlHJbXqVPHWp/9X3d3d4WHhzvUXXro8MUurZWko0ePauDAgQoKCpKvr68qVqxo1aWlpeWov3Sy4O/vLx8fH1WoUCHH8n86Pz57DJf2HBwcrICAAGus+S17u7Vq1cqxrnbt2tb67EleftySWvr7UPyWLVuqX79+CgoKUrdu3TRnzpx8Cah27twpY4xq1KihihUrOjy2bdumw4cPO9RXrlw5x0SvbNmyDn9nv/76q6pVq5aj7kqfscu59HOT/f8R11AAgOKN+RbzrcI03/L29tbzzz+vbdu26cCBA/r44491yy23aM6cORowYMBVvf+IESO0bNkyzZ49W9WqVbOW79y5U2lpaQoMDMwxVzt58mSOuRrgLFxTCnABbdq00e7du/Xll19qyZIlev/99/Xmm29q+vTpDr/5stvFv6XLdv/992vNmjUaMmSIGjdurNKlSysrK0sdOnTI9Yd3bncaudzdR8wlFwq9nLz8FqwwuVz/mZmZDs99fX21atUqLV++XAsWLNCiRYv06aef6o477tCSJUuu6y4uWVlZcnNz0zfffJPrdi69xtP1/p1dK7vfDwDg+phv/Y35VsHMtypVqqRu3bqpa9euqlevnubMmaP4+PgrXmtq3rx5evXVVzV27Fh16NDBYV1WVpYCAwM1a9asXF9bsWLFq+oLKGgcKQW4iHLlyqlv3776+OOP9dtvv6lhw4YOd2i53A/WsLAwHThwQCdOnHBYvn37dmt99n+zsrKUkpLiUHctdzQ7duyYli5dqmeffVYvvvii7rnnHt1555268cYbr3ob1yN7DJcedn/o0CEdP37cGmtBvK8k7dixI8e6HTt2WOuz98OWLVuuuL2yZcvmekh3br95dHd3V7t27TRx4kT9/PPPGjdunJYtW3bdh2xXq1ZNxhiFh4fn+hvn7FMErkVYWJh2796dY7Kb22esqE90AQBFE/Otf8Z86/rmWyVKlFDDhg2VkZGR60X5s/3yyy/q3bu3unTpkuud/qpVq6Y///xTLVu2zHWu1qhRo2vuDSgIhFKAC7j09r6lS5dW9erVHW67m31++aU/XDt16qTMzExNmTLFYfmbb74p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NpYsWaKff/5Z3377rYKCgtS4cWONHTtWw4YN0+jRo+Xl5aXp06crPDxcb7zxhiSpTp06Wr16td58801FRUVJkiZOnKhHHnlEffv2lSRNnz5dCxYs0AcffKBnn322IIYPAAAAAABQbBWqa0qlpaVJksqVK+ewfNasWapQoYLq16+v4cOH66+//rLWJSYmqkGDBgoKCrKWRUVFKT09XVu3brVqIiMjHbYZFRWlxMRESdK5c+eUlJTkUOPu7q7IyEir5lJnz55Venq6wwMAAAAAAABXx6lHSl0sKytLgwYNUsuWLVW/fn1reY8ePRQWFqaQkBBt2rRJw4YN044dO/T5559LklJTUx0CKUnW89TU1CvWpKen6/Tp0zp27JgyMzNzrdm+fXuu/Y4fP14vvvji9Q0aAAAAAACgmCo0oVRsbKy2bNmi1atXOyzv37+/9ecGDRqoUqVKateunXbv3q1q1arZ3aZl+PDhiouLs56np6crNDTUaf0AAAAAAAAUJYUilBowYIDmz5+vVatWqXLlylesbdGihSRp165dqlatmoKDg3PcJe/QoUOSZF2HKjg42Fp2cY2fn598fX3l4eEhDw+PXGsudy0rb29veXt7X/0gAQAAAAAAYHHqNaWMMRowYIC++OILLVu2TOHh4f/4muTkZElSpUqVJEkRERHavHmzw13yEhIS5Ofnp7p161o1S5cuddhOQkKCIiIiJEleXl5q2rSpQ01WVpaWLl1q1QAAAAAAACD/OPVIqdjYWM2ePVtffvmlypQpY10Dyt/fX76+vtq9e7dmz56tTp06qXz58tq0aZMGDx6sNm3aqGHDhpKk9u3bq27duurVq5cmTJig1NRUjRgxQrGxsdaRTI899pimTJmioUOH6uGHH9ayZcs0Z84cLViwwOolLi5OvXv3VrNmzXTzzTdr0qRJOnXqlHU3PgAAAAAAAOQfp4ZS06ZNkyTdfvvtDstnzpypPn36yMvLS99++60VEIWGhqpr164aMWKEVevh4aH58+fr8ccfV0REhEqVKqXevXtrzJgxVk14eLgWLFigwYMHa/LkyapcubLef/99RUVFWTUPPPCAjhw5opEjRyo1NVWNGzfWokWLclz8HAAAAAAAANfPqaGUMeaK60NDQ7Vy5cp/3E5YWJgWLlx4xZrbb79dGzduvGLNgAEDNGDAgH98PwAAAAAA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GBioIUOG6Pz58w41K1as0E033SRvb29Vr15d8fHxdgwPAAAAAACg2CrUoZQk1atXTwcPHrQeq1evttYNHjxYX3/9tebOnauVK1fqwIEDuvfee631mZmZio6O1rlz57RmzRp9+OGHio+P18iRI62alJQURUdHq23btkpOTtagQYPUr18/LV682NZxAgAAAAAAFCeezm7gn3h6eio4ODjH8rS0NM2YMUOzZ8/WHXfcIUmaOXOm6tSpox9++EG33HKLlixZop9//lnffvutgoKC1LhxY40dO1bDhg3T6NGj5eXlpenTpys8PFxvvPGGJKlOnTpavXq13nzzTUVFRdk6VsCZYuLX5/m1M/o0z8dOAAAAAADFQaE/Umrnzp0KCQnRjTfeqJ49e2rfvn2SpKSkJGVkZCgyMtKqrV27tqpUqaLExERJUmJioho0aKCgoCCrJioqSunp6dq6datVc/E2smuyt3E5Z8+eVXp6usMDAAAAAAAAV6dQh1ItWrRQfHy8Fi1apGnTpiklJUWtW7fWiRMnlJqaKi8vLwUEBDi8JigoSKmpqZKk1NRUh0Aqe332uivVpKen6/Tp05ftbfz48fL397ceoaGh1ztcAAAAAACAYqNQn77XsWNH688NGzZUixYtFBYWpjlz5sjX19eJnUnDhw9XXFyc9Tw9PZ1gCgAAAAAA4CoV6lDqUgEBAapZs6Z27dqlO++8U+fOndPx48cdjpY6dOiQdQ2q4OBgrVu3zmEb2Xfnu7jm0jv2HTp0SH5+flcMvry9veXt7Z0fwwKKPK5HBQAAAAC4VoX69L1LnTx5Urt371alSpXUtGlTlShRQkuXLrXW79ixQ/v27VNERIQkKSIiQps3b9bhw4etmoSEBPn5+alu3bpWzcXbyK7J3gYAAAAAAADyX6EOpZ555hmtXLlSe/fu1Zo1a3TPPffIw8ND3bt3l7+/v2JiYhQXF6fly5crKSlJffv2VUREhG655RZJUvv27VW3bl316tVLP/30kxYvXqwRI0YoNjbWOsrpscce0549ezR06FBt375d77zzjubMmaPBgwc7c+gAAAAAAAAurVCfvrd//351795df/75pypWrKhWrVrphx9+UMWKFSVJb775ptzd3dW1a1edPXtWUVFReuedd6zXe3h4aP78+Xr88ccVERGhUqVKqXfv3hozZoxVEx4ergULFmjw4MGaPHmyKleurPfff19RUVG2jxcAAAAAAKC4KNSh1CeffHLF9T4+Ppo6daqmTp162ZqwsDAtXLjwitu5/fbbtXHjxjz1CAAAAAAAgGtXqE/fAwAAAAAAgGsilAIAAAAAAIDtCKUAAAAAAABgO0IpAAAAAAAA2I5QCgAAAAAAALYr1HffA+D6YuLXX9frZ/Rpnk+dAAAAAADsxJFSAAAAAAAAsB2hFAAAAAAAAGxHKAUAAAAAAADbEUoBAAAAAADAdoRSAAAAAAAAsB2hFAAAAAAAAGxHKAUAAAAAAADbeTq7AQC4HjHx6/P82hl9mudjJwAAAACAa8GRUgAAAAAAALAdoRQAAAAAAABsRygFAAAAAAAA2xFKAQAAAAAAwHaEUgAAAAAAALAdoRQAAAAAAABs5+nsBgAAAAAARUdM/Po8v3ZGn+b52AmAoo5QCkCxxYQKAAAAAJyH0/cAAAAAAABgO0IpAAAAAAAA2I5QCgAAAAAAALYjlAIAAAAAAIDtCKUAAAAAAABgO0IpAAAAAAAA2M7T2Q0AAAAAAFCQYuLXX9frZ/Rpnk+dALgYoRQA5AETGwAAAAC4Ppy+BwAAAAAAANtxpBQAAAAAwBbXc7Q5R5oDrocjpQAAAAAAAGA7QikAAAAAAADYjtP3AMAJOHQdAAAAQHHHkVIAAAAAAACwHaEUAAAAAAAAbMfpewAAAACAQu96Ln8AoHDiSCkAAAAAAADYjiOlAKCI4SLpAAAAAFwBR0oBAAAAAADAdoRSAAAAAAAAsB2n7wEAAAAAcAVcPgEoGBwpBQAAAAAAANsRSgEAAAAAAMB2nL4HAMUIh54DAAAAKCwIpQAAV+V6Ai2JUAsAAACAI07fAwAAAAAAgO0IpQAAAAAAAGA7Tt8DANiC61kBAAAAuBhHSgEAAAAAAMB2HCkFAAAAAEAB4Whx4PI4UgoAAAAAAAC240gpAAAAAAAKoes5ykriSCsUfhwpBQAAAAAAANsRSgEAAAAAAMB2nL4HACj0uEAoAAAA4Ho4UgoAAAAAAAC240gpAIBL4wKhAACguOJocxR2HCkFAAAAAAAA2xFKAQAAAAAAwHacvgcAwBVw2DsAAABQMAilAAAoIARaAACgqGIeAzsQSgEAUAgxEQQAAEUV8xhcLUIpAAAAAABQKHDn5OKFUAoAADjgt5sAAACwA6EUAAAu5np/wwgAAADYgVAKAAAAAAAUexwtbj9CKQAAAAAA4BKK6hHjxTUQI5QCAAD5pqhOBAEAAK4Hc6C8IZQCAAAAAAAoooryUVbuTn13AAAAAAAAFEuEUgAAAAAAALAdoRQAAAAAAABsRygFAAAAAAAA2xFKXWLq1KmqWrWqfHx81KJFC61bt87ZLQEAABRqzJ8AAEBeEEpd5NNPP1VcXJxGjRqlH3/8UY0aNVJUVJQOHz7s7NYAAAAKJeZPAAAgrwilLjJx4kQ98sgj6tu3r+rWravp06erZMmS+uCDD5zdGgAAQKHE/AkAAOQVodT/d+7cOSUlJSkyMtJa5u7ursjISCUmJjqxMwAAgMKJ+RMAALgens5uoLD4448/lJmZqaCgIIflQUFB2r59e476s2fP6uzZs9bztLQ0SVJ6enqB9Hfu9MkC2S4AAK6ioH4GZ2/XGFMg2y/KrnX+JDGHAgCgMHH2/IlQKo/Gjx+vF198Mcfy0NBQJ3QDAAD++0TBbv/EiRPy9/cv2DcpBphDAQBQeDh7/kQo9f9VqFBBHh4eOnTokMPyQ4cOKTg4OEf98OHDFRcXZz3PysrS0aNHVb58ebm5ueVrb+np6QoNDdVvv/0mPz+/fN12Uce+yR375fLYN7ljv1we+yZ3xWm/GGN04sQJhYSEOLuVQuda509Swc+hitNnM1txHLNUPMddHMcsFc9xF8cxS8Vz3K465qudPxFK/X9eXl5q2rSpli5dqi5dukj6e5K0dOlSDRgwIEe9t7e3vL29HZYFBAQUaI9+fn4u9SHNT+yb3LFfLo99kzv2y+Wxb3JXXPYLR0jl7lrnT5J9c6ji8tm8WHEcs1Q8x10cxywVz3EXxzFLxXPcrjjmq5k/EUpdJC4uTr1791azZs108803a9KkSTp16pT69u3r7NYAAAAKJeZPAAAgrwilLvLAAw/oyJEjGjlypFJTU9W4cWMtWrQox8U7AQAA8DfmTwAAIK8IpS4xYMCAyx5u7ize3t4aNWpUjkPdwb65HPbL5bFvcsd+uTz2Te7YL7hYYZo/FcfPZnEcs1Q8x10cxywVz3EXxzFLxXPcxXHMF3Mz3N8YAAAAAAAANnN3dgMAAAAAAAAofgilAAAAAAAAYDtCKQAAAAAAANiOUKqQmDp1qqpWrSofHx+1aNFC69atu2zte++9p9atW6ts2bIqW7asIiMjr1hf1F3LvrnYJ598Ijc3N3Xp0qVgG3SSa90vx48fV2xsrCpVqiRvb2/VrFlTCxcutKlbe13rvpk0aZJq1aolX19fhYaGavDgwTpz5oxN3dpj1apVuuuuuxQSEiI3NzfNmzfvH1+zYsUK3XTTTfL29lb16tUVHx9f4H3a7Vr3y+eff64777xTFStWlJ+fnyIiIrR48WJ7mrVZXj4z2b7//nt5enqqcePGBdYfkJu8zhkKg/Hjx6t58+YqU6aMAgMD1aVLF+3YscOh5syZM4qNjVX58uVVunRpde3aVYcOHXKo2bdvn6Kjo1WyZEkFBgZqyJAhOn/+vENNYf1+f+WVV+Tm5qZBgwZZy1x1zL///rsefPBBlS9fXr6+vmrQoIE2bNhgrTfGaOTIkapUqZJ8fX0VGRmpnTt3Omzj6NGj6tmzp/z8/BQQEKCYmBidPHnSoWbTpk1q3bq1fHx8FBoaqgkTJtgyvktlZmbqhRdeUHh4uHx9fVWtWjWNHTtWF1/e2BXG/E8/O+0c49y5c1W7dm35+PioQYMGBTbvv9KYMzIyNGzYMDVo0EClSpVSSEiIHnroIR04cKBIj1m6tnnSY489Jjc3N02aNMlheVEcd4EwcLpPPvnEeHl5mQ8++MBs3brVPPLIIyYgIMAcOnQo1/oePXqYqVOnmo0bN5pt27aZPn36GH9/f7N//36bOy9417pvsqWkpJgbbrjBtG7d2nTu3NmeZm10rfvl7NmzplmzZqZTp05m9erVJiUlxaxYscIkJyfb3HnBu9Z9M2vWLOPt7W1mzZplUlJSzOLFi02lSpXM4MGDbe68YC1cuNA8//zz5vPPPzeSzBdffHHF+j179piSJUuauLg48/PPP5u3337beHh4mEWLFtnTsE2udb8MHDjQvPrqq2bdunXml19+McOHDzclSpQwP/74oz0N2+ha9022Y8eOmRtvvNG0b9/eNGrUqEB7BC6W1zlDYREVFWVmzpxptmzZYpKTk02nTp1MlSpVzMmTJ62axx57zISGhpqlS5eaDRs2mFtuucXceuut1vrz58+b+vXrm8jISLNx40azcOFCU6FCBTN8+HCrprB+v69bt85UrVrVNGzY0AwcONBa7opjPnr0qAkLCzN9+vQxa9euNXv27DGLFy82u3btsmpeeeUV4+/vb+bNm2d++uknc/fdd5vw8HBz+vRpq6ZDhw6mUaNG5ocffjDfffedqV69uunevbu1Pi0tzQQFBZmePXuaLVu2mI8//tj4+vqa//znP7aO1xhjxo0bZ8qXL2/mz59vUlJSzNy5c03p0qXN5MmTrRpXGPM//ey0a4zff/+98fDwMBMmTDA///yzGTFihClRooTZvHmzrWM+fvy4iYyMNJ9++qnZvn27SUxMNDfffLNp2rSpwzaK2pj/adwX+/zzz02jRo1MSEiIefPNNx3WFcVxFwRCqULg5ptvNrGxsdbzzMxMExISYsaPH39Vrz9//rwpU6aM+fDDDwuqRafJy745f/68ufXWW837779vevfu7ZKh1LXul2nTppkbb7zRnDt3zq4WneZa901sbKy54447HJbFxcWZli1bFmifznQ1AcPQoUNNvXr1HJY98MADJioqqgA7c65rCV4uVrduXfPiiy/mf0OFyLXsmwceeMCMGDHCjBo1ilAKtrre+VRhc/jwYSPJrFy50hjz9z/uSpQoYebOnWvVbNu2zUgyiYmJxpi//5Hk7u5uUlNTrZpp06YZPz8/c/bsWWNM4fx+P3HihKlRo4ZJSEgwt912mxVKueqYhw0bZlq1anXZ9VlZWSY4ONi89tpr1rLjx48bb29v8/HHHxtjjPn555+NJLN+/Xqr5ptvvjFubm7m999/N8YY884775iyZcta+yH7vWvVqpXfQ/pH0dHR5uGHH3ZYdu+995qePXsaY1xzzJf+7LRzjPfff7+Jjo526KdFixbm0UcfzdcxXupq5gvr1q0zksyvv/5qjCn6Yzbm8uPev3+/ueGGG8yWLVtMWFiYQyjlCuPOL5y+52Tnzp1TUlKSIiMjrWXu7u6KjIxUYmLiVW3jr7/+UkZGhsqVK1dQbTpFXvfNmDFjFBgYqJiYGDvatF1e9stXX32liIgIxcbGKigoSPXr19fLL7+szMxMu9q2RV72za233qqkpCTrFI89e/Zo4cKF6tSpky09F1aJiYkO+1GSoqKirvp7qbjIysrSiRMnXO77N69mzpypPXv2aNSoUc5uBcVMfsynCpu0tDRJsr5fkpKSlJGR4TDG2rVrq0qVKtYYExMT1aBBAwUFBVk1UVFRSk9P19atW62awvb9Hhsbq+jo6Bx9ueqYv/rqKzVr1kz33XefAgMD1aRJE7333nvW+pSUFKWmpjr07O/vrxYtWjiMOyAgQM2aNbNqIiMj5e7urrVr11o1bdq0kZeXl1UTFRWlHTt26NixYwU9TAe33nqrli5dql9++UWS9NNPP2n16tXq2LGjJNcc86XsHGNh+8xfLC0tTW5ubgoICJDkumPOyspSr169NGTIENWrVy/Helcdd154OruB4u6PP/5QZmamww9SSQoKCtL27duvahvDhg1TSEhIjg9jUZeXfbN69WrNmDFDycnJNnToHHnZL3v27NGyZcvUs2dPLVy4ULt27dITTzyhjIwMl/rHY172TY8ePfTHH3+oVatWMsbo/Pnzeuyxx/Tcc8/Z0XKhlZqamut+TE9P1+nTp+Xr6+ukzgqX119/XSdPntT999/v7FacbufOnXr22Wf13XffydOT6QXslR/zqcIkKytLgwYNUsuWLVW/fn1Jf38ve3l5Wf+QyxYUFKTU1FSrJrd9kL3uSjXO+n7/5JNP9OOPP2r9+vU51rnqmPfs2aNp06YpLi5Ozz33nNavX6+nnnpKXl5e6t27t9V3bj1fPKbAwECH9Z6enipXrpxDTXh4eI5tZK8rW7ZsgYwvN88++6zS09NVu3ZteXh4KDMzU+PGjVPPnj2tfi7u7+J+i+qYL2XnGC/3mc/ehrOcOXNGw4YNU/fu3eXn5yfJdcf86quvytPTU0899VSu61113HnBrLGIe+WVV/TJJ59oxYoV8vHxcXY7TnXixAn16tVL7733nipUqODsdgqVrKwsBQYG6t1335WHh4eaNm2q33//Xa+99ppLhVJ5sWLFCr388st655131KJFC+3atUsDBw7U2LFj9cILLzi7PRRis2fP1osvvqgvv/wyx6SiuMnMzFSPHj304osvqmbNms5uByjyYmNjtWXLFq1evdrZrRSo3377TQMHDlRCQkKxmsdmZWWpWbNmevnllyVJTZo00ZYtWzR9+nT17t3byd0VjDlz5mjWrFmaPXu26tWrp+TkZA0aNEghISEuO2Y4ysjI0P333y9jjKZNm+bsdgpUUlKSJk+erB9//FFubm7ObqfQ4/Q9J6tQoYI8PDxy3EXk0KFDCg4OvuJrX3/9db3yyitasmSJGjZsWJBtOsW17pvdu3dr7969uuuuu+Tp6SlPT0999NFH+uqrr+Tp6andu3fb1XqBystnplKlSqpZs6Y8PDysZXXq1FFqaqrOnTtXoP3aKS/75oUXXlCvXr3Ur18/NWjQQPfcc49efvlljR8/XllZWXa0XSgFBwfnuh/9/Pw4Skp//2a/X79+mjNnjssdpZoXJ06c0IYNGzRgwADr+3fMmDH66aef5OnpqWXLljm7Rbi465lPFTYDBgzQ/PnztXz5clWuXNlaHhwcrHPnzun48eMO9ReP8XLf3dnrrlTjjO/3pKQkHT58WDfddJP13bFy5Uq99dZb8vT0VFBQkMuNWfp7Xla3bl2HZXXq1NG+ffskXej7Sp/n4OBgHT582GH9+fPndfTo0WvaN3YZMmSInn32WXXr1k0NGjRQr169NHjwYI0fP96hH1ca86XsHOPlapy1D7IDqV9//VUJCQnWUVKSa475u+++0+HDh1WlShXru+3XX3/V008/rapVq1r9utq484pQysm8vLzUtGlTLV261FqWlZWlpUuXKiIi4rKvmzBhgsaOHatFixY5nIfqSq5139SuXVubN29WcnKy9bj77rvVtm1bJScnKzQ01M72C0xePjMtW7bUrl27HEKWX375RZUqVXI4R7moy8u++euvv+Tu7vhVmB3emYtuU1zcREREOOxHSUpISLji91Jx8fHHH6tv3776+OOPFR0d7ex2CgU/P78c37+PPfaYatWqpeTkZLVo0cLZLcLF5XU+VZgYYzRgwAB98cUXWrZsWY5TNpo2baoSJUo4jHHHjh3at2+fNcaIiAht3rzZ4R862f8AzA5BCtP3e7t27XJ8dzRr1kw9e/a0/uxqY5b+npft2LHDYdkvv/yisLAwSVJ4eLiCg4Mdek5PT9fatWsdxn38+HElJSVZNcuWLVNWVpb1nRsREaFVq1YpIyPDqklISFCtWrVsP43tcvOt7LmpK475UnaOsTB95rMDqZ07d+rbb79V+fLlHda74ph79eqlTZs2OXy3hYSEaMiQIVq8eLHVr6uNO8+ce511GPP3LYy9vb1NfHy8+fnnn03//v1NQECAdReRXr16mWeffdaqf+WVV4yXl5f57LPPzMGDB63HiRMnnDWEAnOt++ZSrnr3vWvdL/v27TNlypQxAwYMMDt27DDz5883gYGB5qWXXnLWEArMte6bUaNGmTJlypiPP/7Y7NmzxyxZssRUq1bN3H///c4aQoE4ceKE2bhxo9m4caORZCZOnGg2btxo3fnk2WefNb169bLqs2+fPWTIELNt2zYzderUQnHL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c62KFSvK3d1dn332mTIzM69q+5MnT9bBgwetx8CBAxUYGKjatWtL+udfTgBwIgMATta7d2/TuXPnXNc999xzplatWiYrK8taNnXqVFO6dGmTmZlp0tPTjbe3t3nvvfdyff3y5cuNJHPs2DFr2caNG40kk5KSYowxpkGDBmb06NFX3e9tt91mBg4cmOu6mJgY079/f4dl3333nXF3dzenT582xhgTFhZmHnzwQWt9VlaWCQwMNNOmTTPGGDNt2jRTvnx5q94YY9577z0jyWzcuPGy48rurVWrVg7LmjdvboYNG3bV4wOKMknmiy++sJ7Pnz/fSDKlSpVyeHh6epr777/fGGPMI488YiSZHTt2WK9LSkoyksz27dvtHgIA5LuiNteaMmWKKVmypClTpoxp27atGTNmjNm9e7e1PiUlxWFedLH//e9/xsfHx6xevdoYY8yvv/5qPDw8zO+//+5Q165dOzN8+PCr7glAweCaUgAKtW3btikiIkJubm7WspYtW+rkyZPav3+/UlNTdfbsWbVr1y7P7/HUU0/p8ccf15IlSxQZGamuXbuqYcOGedrWTz/9pE2bNmnWrFnWMmOMsrKylJKSojp16kiSw/bd3NwUHBysw4cPS/r76KeGDRvKx8fHqrmWCy5f2nulSpWsbQPFzcmTJ+Xh4aGkpCR5eHg4rMv+LX2lSpXk6empmjVrWuuy/1/dt2+fdZ0pAHBFhXGuFRsbq4ceekgrVqzQDz/8oLlz5+rll1/WV199pTvvvPOyr9u4caN69eqlKVOmqGXLlpKkzZs3KzMz0+E7Xvr7lL7y5cvneUwA8gen7wEo0nx9fa+43t397685Y4y1LCMjw6GmX79+2rNnj3r16qXNmzerWbNmevvtt/PUz8mTJ/Xoo48qOTnZevz000/auXOnqlWrZtWVKFHC4XVubm7KysrK03teqiC3DRQ1TZo0UWZmpg4fPqzq1as7PLIvktuyZUudP39eu3fvtl73yy+/SJLCwsKc0jcAFBbOmmuVKVNGd911l8aNG6effvpJrVu3djil8FKpqam6++671a9fP8XExFjLL/7lxMXzs23btjlc/gCAcxBKASjU6tSpo8TERIeJzvfff68yZcqocuXKqlGjhnx9fbV06dJcX1+xYkVJ0sGDB61l2RfFvFhoaKgee+wxff7553r66af13nvv5anfm266ST///HOOf/xWr15dXl5eV7WNWrVqafPmzTp79qy1bP369Q412du62mstAK7s5MmT1j8ypL9vJZ6cnKx9+/apZs2a6tmzpx566CF9/vnnSklJ0bp16zR+/HgtWLBAkhQZGambbrpJDz/8sDZu3KikpCQ9+uijuvPOO3P8Zh0AXE1RmGu5ubmpdu3aDjeOudiZM2fUuXNn1a5dWxMnTnRYdzW/nADgPIRSAAqFtLQ0h99eJScn67ffftMTTzyh3377TU8++aS2b9+uL7/8UqNGjVJcXJzc3d3l4+OjYcOGaejQofroo4+0e/du/fDDD5oxY4YkqXr16goNDdXo0aO1c+dOLViwQG+88YbDew8aNEiLFy9WSkqKfvzxRy1fvtw6dedyjhw5kqPfQ4cOadiwYVqzZo0GDBig5ORk7dy5U19++WWOC51fSY8ePZSVlaX+/ftr27ZtWrx4sV5//XVJsg6tDwsLk5ubm+bPn68jR47o5MmT17K7AZeyYcMGNWnSRE2aNJEkxcXFqUmTJho5cqQkaebMmXrooYf09NNPq1atWurSpYvWr1+vKlWqSPr7t/xff/21KlSooDZt2ig6Olp16tTRJ5984rQxAUB+KypzreTkZHXu3FmfffaZfv75Z+3atUszZszQBx98oM6dO+f6mkcffVS//fab3nrrLR05ckSpqalKTU3VuXPnruqXEwCcyKlXtAIA8/fFNyXleMTExBhjjFmxYoVp3ry58fLyMsHBwWbYsGEmIyPDen1mZqZ56aWXTFhYmClRooSpUqWKefnll631q1evNg0aNDA+Pj6mdevWZu7cuQ4X3xwwYICpVq2a8fb2NhUrVjS9evUyf/zxx2X7ve2223Ltd+zYscYYY9atW2fuvPNOU7p0aVOqVCnTsGFDM27cOOv1YWFh5s0333TYZqNGjcyoUaOs599//71p2LCh8fLyMk2bNjWzZ8/OcdHlMWPGmODgYOPm5mZ69+5t9XbpRdg7d+5srQcAAMVPUZprHTlyxDz11FOmfv36pnTp0qZMmTKmQYMG5vXXXzeZmZnGmJwXOg8LC8t1fMuXLzfGGHPu3DkzcuRIU7VqVVOiRAlTqVIlc88995hNmzbl854GcK3cjLnoOE0AQKE0a9Ys9e3bV2lpaf94bQcAAAAAKAq4+x4AFEIfffSRbrzxRt1www366aefNGzYMN1///0EUgAAAABcBqEUABRCqampGjlypFJTU1WpUiXdd999GjdunLPbAgAAAIB8w+l7AAAAAAAAsB133wMAAAAAAIDtCKUAAAAAAABgO0IpAAAAAAAA2I5QCgAAAAAAALYjlAIAAAAAAIDtCKUAAAAAAABgO0IpAAAAAAAA2I5QCgAAAAAAALYjlAIAAAAAAIDt/h+6l1M7S3yh3QAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "panda_df = df.select(\"locusSize\", \"locusLength\").toPandas()\n", + "\n", + "plt.figure(figsize=(12, 6))\n", + "\n", + "# Histogram for locusLength\n", + "plt.subplot(1, 2, 1) # 1 row, 2 columns, 1st subplot\n", + "plt.hist(panda_df[\"locusLength\"], bins=30, alpha=0.7)\n", + "plt.xlabel(\"Locus Length\")\n", + "plt.ylabel(\"Frequency\")\n", + "plt.title(\"Histogram of Locus Length\")\n", + "\n", + "# Histogram for locusSize\n", + "plt.subplot(1, 2, 2) # 1 row, 2 columns, 2nd subplot\n", + "plt.hist(panda_df[\"locusSize\"], bins=30, alpha=0.7)\n", + "plt.xlabel(\"Locus Size\")\n", + "plt.ylabel(\"Frequency\")\n", + "plt.title(\"Histogram of Locus Size\")\n", + "\n", + "plt.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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k07in//5n/nYxz7GmjVrWLdu3VHv51SeeuopLr74YgqFAn/1V3+FaZr80z/9E5deeik///nPeelLXwpAtVrl4osv5umnn+bGG2/knHPOYXR0lB/84AccPHiwtY+LwfM8rrzySlzX5X3vex9Lly5lYGCAO+64g2KxSFtb25zf6+3tJZ1O88Mf/pD3ve99dHZ2Lnqdp5xyCrfddtu014rFIh/84AenOVy33XYb1113HVdeeSWf/OQnqdfrfPGLX+TlL385jz766Cwnq8l5553H2rVr+bd/+7eWc9vk9ttvp6OjgyuvvBKAd7/73fz7v/87733vezn11FMZGxvjvvvu4+mnn+acc85Z9D7NxQvp91wsR3sfeMtb3sKaNWv4xCc+wSOPPMKXv/xlent7+eQnP9n6zPXXX8+//du/8Ud/9EdccMEF/PznP+fqq6+etpzFXMf33Xcf3/nOd7jpppvI5/P83d/9HW984xvZv3//Ee8jCQkJzzIyISEh4TiwefNmqeu61HVdvuxlL5N/9Vd/Je+66y7ped60z+3YsUNqmiZf//rXyzAMp70XRVHr73q9Pmsd//W//leZyWSk4zit166++mq5atWqWZ996KGHJCC/8pWvzFrHhg0b5JVXXjlrfWvWrJFXXHFF67WPfvSjEpBvf/vbF3UM7r33XgnIf/mXf5EjIyNycHBQ/uhHP5KrV6+WQgj50EMPSSml3LNnz6xtO+uss2Rvb68cGxtrvfb4449LTdPku971rtZrn/70pyUg9+zZs+D2eJ4ne3t75emnny4bjUbr9TvuuEMC8iMf+Ujrta985SsSaG3jkVjMZ6+55hppWZbctWtX67XBwUGZz+flK17xitZrH/nIRyQgv/Od78xaRvP3aa5v5j43j/e9994rpZTy0UcflYD89re/veA+zKS5HdlsVl511VXy4x//uPztb38763Nz/XYzt/kP//APZS6Xk0899ZSUUspKpSLb29vln/7pn0777OHDh2VbW9us12fyoQ99SJqmKcfHx1uvua4r29vb5Y033th6ra2tTb7nPe9Z7C63+H38Pa+77jqZzWbnff9Y7gNTj7WUUr7+9a+XXV1drf//7W9/KwH5F3/xF9M+d/3110tAfvSjH229dqTrGJCWZcmdO3e2Xnv88cclIL/whS8suO8JCQnPHkmpXkJCwnHhiiuu4Fe/+hWve93rePzxx/nUpz7FlVdeybJly/jBD37Q+tz3vvc9oijiIx/5CJo2/RYkhGj9nU6nW39XKhVGR0e5+OKLqdfrbNu27Zi387HHHmPHjh1ce+21jI2NMTo6yujoKLVajVe96lX84he/IIqiad9597vffVTruPHGG+np6aG/v5+rr76aWq3G1772Nc4777w5P3/o0CEee+wxrr/++mnZjjPOOIMrrriC//zP/zz6HUWVeQ0PD3PTTTdN68u5+uqrOfnkk/nRj350TMtdiDAM2bx5M9dccw1r165tvd7X18e1117LfffdR7lcBuA//uM/OPPMM3n9618/azlTz4fF0MxA3HXXXbNKqBbilltu4Rvf+AZnn302d911Fx/+8Ic599xzOeecc6aVSy7Erbfeyh133MFXv/pVTj31VADuvvtuisUib3/721vn2+joKLqu89KXvpR77733iMt861vfiu/7fOc732m9tnnzZorFIm9961tbr7W3t/Pggw8eFxGSqbwQf8+FOB73gYsvvpixsbHWvjdL6W666aZpn3vf+9531Nt3+eWXT8v6nnHGGRQKheOmzpmQkHBsvKgdp1/84he89rWvpb+/HyEE3/ve9456GVJKPvOZz7Bx40Zs22bZsmV8/OMfP/4bm5DwAuD888/nO9/5DhMTE/zmN7/hQx/6EJVKhTe96U1s3boVUGVrmqa1jMr5eOqpp3j9619PW1sbhUKBnp4e3vnOdwL8Tv0NO3bsAOC6666jp6dn2r8vf/nLuK47a/lr1qw5qnV85CMf4e677+aee+7hiSeeYHBw8IgqbPv27QPgpJNOmvXeKaec0jLojpYjLffkk09uvX+8GRkZoV6vz7s/URRx4MABQJ0PC5V2LpY1a9bwwQ9+kC9/+ct0d3dz5ZVX8g//8A+LPl/e/va388tf/pKJiQk2b97Mtddey6OPPsprX/taHMdZ8Ps//vGPueWWW/jQhz7EG9/4xtbrzXPusssum3XObd68eUHxlDPPPJOTTz6Z22+/vfXa7bffTnd3d6t/DuBTn/oUW7ZsYcWKFbzkJS/h5ptvPi6G9gv19zwSx3IfWLly5bT/7+joAGBiYgJQ15umabPuF+vXrz/q7Zu5rub6mutKSEg4Mbyoe5xqtRpnnnkmN954I294wxuOaRl//ud/zubNm/nMZz7Dpk2bGB8fZ3x8/DhvaULCCwvLsjj//PM5//zz2bhxIzfccAPf/va3+ehHP7qo7xeLRS655BIKhQIf+9jHWLduHalUikceeYT/8T/+x6xI8NHQ/O6nP/1pzjrrrDk/M3P+y9Ts12LYtGkTl19++TFtX8Js5stUTBUKafLZz36W66+/nu9///ts3ryZ97///XziE5/g17/+NcuXL1/U+gqFAldccQVXXHEFpmnyta99jQcffJBLLrlk3u/s2bOHd7zjHVxxxRX89V//9bT3mufcbbfdxtKlS2d91zAWfhS/9a1v5eMf/zijo6Pk83l+8IMf8Pa3v33ad9/ylrdw8cUX893vfpfNmzfz6U9/mk9+8pN85zvf4aqrrlrUvj8XPNe/51wcy31A1/U5PyePoe9xIZ7LdSUkJCyeF7XjdNVVVx3xYeK6Lh/+8If55je/SbFY5PTTT+eTn/wkl156KQBPP/00X/ziF9myZUsrEne0kemEhN93muVphw4dAmDdunVEUcTWrVvnNVh+9rOfMTY2xne+8x1e8YpXtF6fS5VuPiNsvteb5S+FQuF549ysWrUKgGeeeWbWe9u2baO7u7slgX405U5Tlzs1M9F8rfn+8aanp4dMJjPv/miaxooVKwD1e2zZsuWIy2tG9mfOvJkvY7Zp0yY2bdrE//v//r888MADXHTRRXzpS1+a5dAshvPOO4+vfe1rrfN3LhqNBm94wxtob2/nm9/85qwS1OY519vbe8zn3Fvf+lZuueUW/uM//oMlS5ZQLpd529veNutzfX193HTTTdx0000MDw9zzjnn8PGPf/x3cpx+n37PJs/GfWDVqlVEUcSePXvYsGFD6/WdO3fO+uzRli0mJCQ8P3hRl+otxHvf+15+9atf8a1vfYsnnniCN7/5zbzmNa9ppfh/+MMfsnbtWu644w7WrFnD6tWr+ZM/+ZMk45TwouTee++dMxra7M9pBheuueYaNE3jYx/72KzMUfP7zWjr1OV5nsc//uM/zlp+Npuds3Sn6WjMNM7OPfdc1q1bx2c+8xmq1eqs742MjMy7j88WfX19nHXWWXzta1+btr1btmxh8+bN/MEf/EHrtfn2ay7OO+88ent7+dKXvoTruq3X77zzTp5++ulZal/HC13XefWrX833v//9aRLLQ0NDfOMb3+DlL385hUIBgDe+8Y08/vjjfPe73521nObv3zRyf/GLX7TeC8OQf/7nf572+XK5TBAE017btGkTmqZN2/+Z1Ot1fvWrX8353p133gnMXe7Y5N3vfjfbt2/nu9/9bsspmMqVV15JoVDgb/7mb/B9f9b7iznnTjnlFDZt2sTtt9/O7bffTl9f37SgQhiGs66D3t5e+vv7j7jvi+GF9nsuhmfjPtBUN5x5n/rCF74w67NHcx0nJCQ8f3hRZ5yOxP79+/nKV77C/v376e/vB+C///f/zo9//GO+8pWv8Dd/8zfs3r2bffv28e1vf5t//dd/JQxDPvCBD/CmN72Je+655wTvQULCc8v73vc+6vU6r3/96zn55JPxPI8HHniA22+/ndWrV3PDDTcAqt7/wx/+MLfeeisXX3wxb3jDG7Btm4ceeoj+/n4+8YlPcOGFF9LR0cF1113H+9//foQQ3HbbbXM6Zueeey633347H/zgBzn//PPJ5XK89rWvZd26dbS3t/OlL32JfD5PNpvlpS99KWvWrOHLX/4yV111Faeddho33HADy5YtY2BggHvvvZdCocAPf/jD5/rw8elPf5qrrrqKl73sZfzxH/9xS468ra2tNf+lub+gpNjf9ra3YZomr33ta+ccymuaJp/85Ce54YYbuOSSS3j729/ekiNfvXo1H/jAB36nbf6Xf/mXOWfL/Pmf/zl//dd/zd13383LX/5ybrrpJgzD4J/+6Z9wXZdPfepTrc/+5V/+Jf/+7//Om9/8Zm688UbOPfdcxsfH+cEPfsCXvvQlzjzzTE477TQuuOACPvShDzE+Pk5nZyff+ta3ZhnV99xzD+9973t585vfzMaNGwmCgNtuuw1d16f1HM2kXq9z4YUXcsEFF/Ca17yGFStWUCwW+d73vscvf/lLrrnmGs4+++w5v/ujH/2If/3Xf+WNb3wjTzzxBE888UTrvVwuxzXXXEOhUOCLX/wif/RHf8Q555zD2972Nnp6eti/fz8/+tGPuOiii/j7v//7BY/3W9/6Vj7ykY+QSqX44z/+42mZrUqlwvLly3nTm97EmWeeSS6X4yc/+QkPPfQQn/3sZxdcNvz+/J5NfN+fMyvV2dnJTTfddNzvA+eeey5vfOMb+fznP8/Y2FhLjnz79u3A9CzT0VzHCQkJzyNOmJ7f8wxAfve73239f1OuN5vNTvtnGIZ8y1veIqWU8k//9E8lIJ955pnW95pypNu2bXuudyEh4YRy5513yhtvvFGefPLJMpfLScuy5Pr16+X73vc+OTQ0NOvz//Iv/yLPPvtsadu27OjokJdccom8++67W+/ff//98oILLpDpdFr29/e35M2ZIlcspZTValVee+21sr29XQLTpMm///3vy1NPPVUahjFLQvrRRx+Vb3jDG2RXV5e0bVuuWrVKvuUtb5E//elPW59pyhCPjIws6hg05ZQXkk+eT9L6Jz/5ibzoootkOp2WhUJBvva1r5Vbt26d9f1bb71VLlu2TGqatihp8ttvv711rDs7O+U73vEOefDgwWmfORY58vn+HThwQEop5SOPPCKvvPJKmcvlZCaTka985SvlAw88MGt5Y2Nj8r3vfa9ctmyZtCxLLl++XF533XVydHS09Zldu3bJyy+/XNq2LZcsWSL/5//8n/Luu++edj7s3r1b3njjjXLdunUylUrJzs5O+cpXvlL+5Cc/OeL++L4v/8//+T/ymmuukatWrZK2bctMJiPPPvts+elPf1q6rtv67Mzf7kjHYqZM/r333iuvvPJK2dbWJlOplFy3bp28/vrr5cMPP7zgMZdSSfk3l33fffdNe891XfmXf/mX8swzz5T5fF5ms1l55plnyn/8x39ccLm/b7+nlEqOfL79WbduXetzv8t9YC5Z9VqtJt/znvfIzs5Omcvl5DXXXCOfeeYZCcj//b//97Tvz3cdA3PKyq9atUped911C+57QkLCs4eQMuk0BBUJ+u53v8s111wDKMWid7zjHTz11FOzmjRzuRxLly7lox/96KzSi0ajQSaTYfPmzVxxxRXP5S4kJCQkJCQkPM947LHHOPvss/n617/OO97xjhO9OQkJCb8DSanePJx99tmEYcjw8DAXX3zxnJ+56KKLCIKAXbt2tWq2myn5Z6vpOiEhISEhIeH5SaPRmKXC+fnPfx5N06b1pCUkJLwweVE7TtVqdZrazZ49e3jsscfo7Oxk48aNvOMd7+Bd73oXn/3sZzn77LMZGRnhpz/9KWeccQZXX301l19+Oeeccw433ngjn//854miiPe85z1cccUVbNy48QTuWUJCQkJCQsJzzac+9Sl++9vf8spXvhLDMLjzzju58847+bM/+7OW8mBCQsILlxd1qd7PfvYzXvnKV856/brrruOrX/1qq7H0X//1XxkYGKC7u5sLLriAW265hU2bNgEwODjI+973PjZv3kw2m+Wqq67is5/9LJ2dnc/17iQkJCQkJCScQO6++25uueUWtm7dSrVaZeXKlfzRH/0RH/7whxc1ryshIeH5zYvacUpISEhISEhISEhISFgMyRynhISEhISEhISEhISEBUgcp4SEhISEhISEhISEhAV40RXcRlHE4OAg+Xx+2jC6hISEhISEhISEhIQXF1JKKpUK/f390waLz8WLznEaHBxMlG0SEhISEhISEhISElocOHCA5cuXH/EzLzrHKZ/PA+rgFAqF53Tdvu+zefNmXv3qV2Oa5nO67hczyXE/cSTH/sSQHPcTR3LsTxzJsT8xJMf9xJEc++NDuVxmxYoVLR/hSLzoHKdmeV6hUDghjlMmk6FQKCQn+HNIctxPHMmxPzEkx/3EkRz7E0dy7E8MyXE/cSTH/viymBaeRBwiISEhISEhISEhISFhARLHKSEhISEhISEhISEhYQESxykhISEhISEhISEhIWEBEscpISEhISEhISEhISFhARLHKSEhISEhISEhISEhYQESxykhISEhISEhISEhIWEBEscpISEhISEhISEhISFhARLHKSEhISEhISEhISEhYQESxykhISEhISEhISEhIWEBEscpISEhISEhISEhISFhARLHKSEhISEhISEhISEhYQESxykhISEhISEhISEhIWEBEscpISEhISEhISEhISFhAYwTvQEvZqo1j8/e8wwHxx2W5G0i3+fxw3Uc32dgtIEHWDqcvyLDWSt7uG/nOIcqLoWUwaXrOqhH8OjBMqOlBg0voO6r5VoadOY0TNPC9wMiKcinDDoyJkXHZduQO207cjo0QgiP474ZQHAcl/e7YOuST70ETr/5LtxQnOjNeVGRHPsTQ3LcTxzJsT9xJMf+2acZbY+mvPZsHXedxdslBiBE/B0JEvUvAgSQMqCvzeakJVkGiw7bh+v4gbJTxIz9OVbaTGjL6ISRjucHlJwIb8Zn0gKkACHVf50pK9aBgg2mbtDwAyr+7H1s7o8W759+jMdeBzpSYBk6NU9thOdJGjM+J+L1HM1ydaH+RRICqZbRnRWs7S2g6xp1JyBtGXTmba46YymnLm1nRUcGTXthXLOJ43SCeO83HuHOJw8RLnBGOiH8cm+dX+7d13rtcMVj+0h93u8EEdTLEeBMvljxYdYloageT4+puQ3Hf5EJ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y7Vj3vCGN6iXvexl6re//a369a9/rVauXKne8Y531O4fHR1Vra2t6uqrr1abN29WP/jBD1QikVDf/va35/T9LhRf/OIXVWNjo/rxj3+sdu3apX74wx+qdDqtbr311toxsu7Hx09/+lP1l3/5l+rOO+9UgPqP//iPSffP1To/+OCDyjAM9eUvf1k988wz6q/+6q+UZVnq6aefPuFrMF+OtPYjIyNqw4YN6l/+5V/Uc889px566CF18cUXqwsvvHDSc8jaH72Z/s1PuPPOO9XLXvYy1d7erv7X//pfk+6TdZ9fEjjNgYsvvlhdd911ta/DMFTt7e3qpptumsezOrn19fUpQN1///1KqfgHvWVZ6oc//GHtmGeffVYB6qGHHlJKxT+wdF1XPT09tWO++c1vqmw2q6rVqlJKqU984hPq7LPPnvRab3/729WVV155ot/SgpbP59WqVavUPffco171qlfVAidZ9xPnxhtvVK94xSsOe38URaqtrU39z//5P2u3jYyMKMdx1A9+8AOllFLPPPOMAtTvfve72jE/+9nPlKZpat++fUoppf7+7/9e5XK52vdi4rXPOOOM4/2WTgpXXXWV+tM//dNJt/3X//pf1dVXX62UknU/UQ69iJzLdX7b296mrrrqqknnc8kll6j3v//9x/U9LlRHuoCf8MgjjyhAvfDCC0opWfvj4XDr/uKLL6qOjg61efNmtWTJkkmBk6z7/JNSvRPM8zwee+wxNmzYULtN13U2bNjAQw89NI9ndnIbHR0FoKGhAYDHHnsM3/cnrfOaNWvo6uqqrfNDDz3E2rVraW1trR1z5ZVXMjY2xpYtW2rHHPwcE8ec7t+r6667jquuumrK2si6nzj/9//+X9atW8cf/dEf0dLSwvnnn893vvOd2v27du2ip6dn0rrV1dVxySWXTFr7+vp61q1bVztmw4YN6LrOww8/XDvmla98JbZt14658sor2bp1K8PDwyf6bS44l112GRs3buT5558H4Mknn+SBBx7gjW98IyDrPlfmcp3l58/MRkdH0TSN+vp6QNb+RImiiGuuuYaPf/zjnH322VPul3WffxI4nWADAwOEYTjpohGgtbWVnp6eeTqrk1sURXzkIx9h/fr1nHPOOQD09PRg23bth/qEg9e5p6dn2u/DxH1HOmZsbIxyuXwi3s6Cd8cdd/D4449z0003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HKlUirPPPpuf/vSn057Lli1b2LFjB3//93/Py1/+cpYsWcL69ev5whe+wMtf/nJgaqneu9/9bjRNm/Jx3333AVCtVvnYxz5GR0cHqVSKSy65pHafEEKIhUsCJyGEEAvGvn37eNOb3sRFF13Ek08+yTe/+U3+8R//kS984Qu1Yz71qU9x88038+lPf5pnnnmG22+/ndbW1lm/xnXXXUe1WuVXv/oVTz/9NF/60pdIp9PTHtvc3Iyu6/zbv/0bYRjO6vlvvfVWuru7ax8f/vCHaWlpYc2aNQBcf/31PPTQQ9xxxx089dRT/NEf/RFveMMb2LZt26zfgxBCiLknpXpCCCEWjL//+7+ns7OTr3/962iaxpo1a9i/fz833ngjn/nMZygWi9x66618/etf59prrwVgxYoVvOIVr5j1a+zZs4c/+IM/YO3atQAsX778sMd2dHTw1a9+lU984hN8/vOfZ926dbzmNa/h6quvPuzj6urqqKurA+DOO+/k29/+Nr/4xS9oa2tjz5493HbbbezZs4f29nYAPvaxj3HXXXdx22238Td/8zezfh9CCCHmlmSchBBCLBjPPvssl156KZqm1W5bv349hUKBF198kWeffZZqtcoVV1zxkl/jQx/6EF/4whdYv349n/3sZ3nqqaeOePx1111HT08P3//+97n00kv54Q9/yNlnn80999xzxMc98cQTXHPNNXz9619n/fr1ADz99NOEYcjq1atJp9O1j/vvv58dO3a85PckhBDixJPASQghxEkjkUgc8X5dj3+tKaVqt/m+P+mYP/uzP2Pnzp1cc801PP3006xbt46vfe1rR3zeTCbDm9/8Zr74xS/y5JNPcvnll08qHzxUT08Pb3nLW/izP/sz3vve99ZuLxQKGIbBY489xqZNm2ofzz77LLfeeusRz0EIIcT8ksBJCCHEgnHmmWfy0EMPTQp8HnzwQTKZDIsXL2bVqlUkEgk2btw47eObm5sB6O7urt023Xylzs5OPvCBD3DnnXfy0Y9+lO985zuzPseJEsJisTjt/ZVKhd/7vd9jzZo1fOUrX5l03/nnn08YhvT19bFy5cpJH9KZTwghFjbZ4ySEEGLOjY6OTgloGhsb+eAHP8gtt9zCf//v/53rr7+erVu38tnPfpYbbrgBXddxXZcbb7yRT3ziE9i2zfr16+nv72fLli28973vZeXKlXR2dvK5z32OL37xizz//PP83d/93aTX+chHPsIb3/hGVq9ezfDwMPfeey9nnnnmtOe5adMmPvvZz3LNNddw1llnYds2999/P9/97ne58cYbp33M+9//fvbu3cvGjRvp7++v3d7Q0MDq1au5+uqrede73sXf/d3fcf7559Pf38/GjRs599xzueqqq45tYYUQQpw4SgghhJhD1157rQKmfLz3ve9VSil13333qYsuukjZtq3a2trUjTfeqHzfrz0+DEP1hS98QS1ZskRZlqW6urrU3/zN39Tuf+CBB9TatWuV67rq8ssvVz/84Q8VoHbt2qWUUur6669XK1asUI7jqObmZnXNNdeogYGBac+1v79ffehDH1LnnHOOSqfTKpPJqLVr16q//du/VWEYKqWU2rVrlwLUE088oZRSasmSJdO+v3vvvVcppZTneeozn/mMWrp0qbIsSy1atEj9/u//vnrqqaeO80oLIYQ4njSlDqqHEEIIIYQQQggxhexxEkIIIYQQQogZSOAkhBBCCCGEEDOQwEkIIYQQQgghZiCBkxBCCCGEEELMQAInIYQQQgghhJiBBE5CCCGEEEIIMQMJnIQQQgghhBBiBhI4CSGEEEIIIcQMJHASQgghhBBCiBlI4CSEEEIIIYQQM5DASQghhBBCCCFm8P8DNg0hygqUBHMAAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plt.figure(figsize=(10, 6))\n", + "plt.scatter(panda_df[\"locusSize\"], panda_df[\"locusLength\"], alpha=0.5)\n", + "plt.title(\"Scatter Plot of Locus Size vs Locus Length\")\n", + "plt.xlabel(\"Locus Size\")\n", + "plt.ylabel(\"Locus Length\")\n", + "plt.grid(True)\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "susie_fm = StudyLocus.from_parquet(session, \"/Users/dc16/output/gwas_cat_fm\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Total credible sets:\n" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "data": { + "text/plain": [ + "632123" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "susie_fm.df.count()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "It seems a very small fraction of loci have NaN assigned to values for their credible sets\n" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Number of credible sets with 'not a number' as the logBF: 39\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[Stage 14:====================================================> (175 + 6) / 181]\r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Number of credible sets with 'null' as the logBF: 0\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + } + ], + "source": [ + "nan = susie_fm.df.filter(f.isnan(\"credibleSetlog10BF\"))\n", + "null = susie_fm.df.filter(f.isnull(\"credibleSetlog10BF\"))\n", + "print(\"Number of credible sets with 'not a number' as the logBF: \", nan.count())\n", + "print(\"Number of credible sets with 'null' as the logBF: \", null.count())" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "-RECORD 0--------------------------\n", + " meanTopPP | 0.7341557442854078 \n", + " minTopPP | 5.30020287265377E-4 \n", + " q1TopPP | 0.43393218153901475 \n", + " medianTopPP | 0.9841312727728387 \n", + " q3TopPP | 0.9999999999927383 \n", + " maxTopPP | 1.0 \n", + "\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "-RECORD 0------------------------------\n", + " meanCredSetSize | 64.33602495870802 \n", + " minCredSetSize | 1 \n", + " q1CredSetSize | 1 \n", + " medianCredSetSize | 2 \n", + " q3CredSetSize | 13 \n", + " maxCredSetSize | 10710 \n", + "\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "-RECORD 0---------------------------------\n", + " meanPurityMeanR2 | 0.6459716225861719 \n", + " minPurityMeanR2 | 0.00469889394266767 \n", + " q1PurityMeanR2 | 0.23746586177412243 \n", + " medianPurityMeanR2 | 0.8203905763487525 \n", + " q3PurityMeanR2 | 1.0 \n", + " maxPurityMeanR2 | 1.0 \n", + "\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[Stage 28:> (0 + 1) / 1]\r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "-RECORD 0---------------------------------\n", + " meanPurityMinR2 | 0.48250211427144807 \n", + " minPurityMinR2 | 0.0 \n", + " q1PurityMinR2 | 6.409217073028031... \n", + " medianPurityMinR2 | 0.46903358691552954 \n", + " q3PurityMinR2 | 1.0 \n", + " maxPurityMinR2 | 1.0 \n", + "\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + } + ], + "source": [ + "susie_results = (\n", + " susie_fm.df.withColumn(\"credSetSize\", f.size(\"locus\"))\n", + " .withColumn(\n", + " \"locus\",\n", + " f.slice(order_array_of_structs_by_field(\"locus\", \"posteriorProbability\"), 1, 1)[\n", + " 0\n", + " ],\n", + " )\n", + " .withColumn(\"topPP\", f.col(\"locus\").getField(\"posteriorProbability\"))\n", + " .filter(~f.isnan(\"topPP\"))\n", + ")\n", + "(\n", + " susie_results.select(\n", + " f.mean(\"topPP\").alias(\"meanTopPP\"),\n", + " f.min(\"topPP\").alias(\"minTopPP\"),\n", + " f.percentile_approx(\"topPP\", 0.25).alias(\"q1TopPP\"),\n", + " f.percentile_approx(\"topPP\", 0.5).alias(\"medianTopPP\"),\n", + " f.percentile_approx(\"topPP\", 0.75).alias(\"q3TopPP\"),\n", + " f.max(\"topPP\").alias(\"maxTopPP\"),\n", + " ).show(vertical=True)\n", + ")\n", + "(\n", + " susie_results.select(\n", + " f.mean(\"credSetSize\").alias(\"meanCredSetSize\"),\n", + " f.min(\"credSetSize\").alias(\"minCredSetSize\"),\n", + " f.percentile_approx(\"credSetSize\", 0.25).alias(\"q1CredSetSize\"),\n", + " f.percentile_approx(\"credSetSize\", 0.5).alias(\"medianCredSetSize\"),\n", + " f.percentile_approx(\"credSetSize\", 0.75).alias(\"q3CredSetSize\"),\n", + " f.max(\"credSetSize\").alias(\"maxCredSetSize\"),\n", + " ).show(vertical=True)\n", + ")\n", + "(\n", + " susie_results.select(\n", + " f.mean(\"purityMeanR2\").alias(\"meanPurityMeanR2\"),\n", + " f.min(\"purityMeanR2\").alias(\"minPurityMeanR2\"),\n", + " f.percentile_approx(\"purityMeanR2\", 0.25).alias(\"q1PurityMeanR2\"),\n", + " f.percentile_approx(\"purityMeanR2\", 0.5).alias(\"medianPurityMeanR2\"),\n", + " f.percentile_approx(\"purityMeanR2\", 0.75).alias(\"q3PurityMeanR2\"),\n", + " f.max(\"purityMeanR2\").alias(\"maxPurityMeanR2\"),\n", + " ).show(vertical=True)\n", + ")\n", + "(\n", + " susie_results.select(\n", + " f.mean(\"purityMinR2\").alias(\"meanPurityMinR2\"),\n", + " f.min(\"purityMinR2\").alias(\"minPurityMinR2\"),\n", + " f.percentile_approx(\"purityMinR2\", 0.25).alias(\"q1PurityMinR2\"),\n", + " f.percentile_approx(\"purityMinR2\", 0.5).alias(\"medianPurityMinR2\"),\n", + " f.percentile_approx(\"purityMinR2\", 0.75).alias(\"q3PurityMinR2\"),\n", + " f.max(\"purityMinR2\").alias(\"maxPurityMinR2\"),\n", + " ).show(vertical=True)\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABKUAAASlCAYAAAB5vWpLAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/TGe4hAAAACXBIWXMAAA9hAAAPYQGoP6dpAADu20lEQVR4nOzdeVhVBf7H8c8FZXEB3AAZSXHJfZnUkFLTJFFpMXXGLQPFpYJSKS3L1NLJstxKk3FK0UZzacwmNZRw+5moiZK7pWnWKC6poJiAcH5/9HD0CioiHhbfr+e5z8w953vP+d4DxbfPPfccm2EYhgAAAAAAAAALORR2AwAAAAAAALj3EEoBAAAAAADAcoRSAAAAAAAAsByhFAAAAAAAACxHKAUAAAAAAADLEUoBAAAAAADAcoRSAAAAAAAAsByhFAAAAAAAACxHKAUAAAAAAADLEUoBJVSNGjUUGhpa2G2UeO+//75q1qwpR0dHNWvWrLDbMbVr107t2rUr7DYkSdHR0bLZbDp69GhhtwIAADOSRZiRAOQFoRRQDGT/R/327dtzXd+uXTs1atTojvezatUqjRs37o63c69Ys2aNRo4cqYcfflhz587VO++8U9gt3dDx48c1btw4JSYm5nsb7dq1k81mU506dXJdHxsbK5vNJpvNpi+++CLf+7nW+vXrzW3abDY5OjrK09NTPXr00P79+3PUL1u2TD179lTNmjVVpkwZ1a1bVy+//LLOnz9fIP0AAIoWZqSiiRnJ3t2Yke7UuHHj7Gas0qVLq0aNGnrppZdyzE2XLl3SzJkz1bFjR1WtWlXly5fXX//6V82aNUuZmZmF8wZQYpQq7AYA3B0HDx6Ug8Pt5c6rVq3SzJkzGbryaO3atXJwcNCnn34qJyenwm7Hzpo1a+yeHz9+XG+99ZZq1KhxR59Wuri46NChQ9q2bZsefPBBu3ULFiyQi4uLLl++bLe8X79+6tWrl5ydnfO935deekktW7ZURkaGdu3apaioKK1fv1579uyRt7e3WTd48GD5+PjomWee0X333afdu3drxowZWrVqlXbs2CFXV9d89wAAKBmYke4+ZqS8zUhFwaxZs1SuXDmlpqYqLi5OH330kXbs2KFNmzaZNT///LNefPFFdejQQZGRkXJzc9Pq1av1wgsvaMuWLZo3b14hvgMUd4RSQAl1JwFAYUlNTVXZsmULu408O3XqlFxdXYvUsHXp0iWVKVPmrvVUq1YtXblyRZ9//rndwHX58mV9+eWXCg4O1n/+8x+71zg6OsrR0fGO9tumTRv16NHDfF63bl09//zzmj9/vkaOHGku/+KLL3Kckt+8eXOFhIRowYIFGjhw4B31AQAo/piR7j5mpLzNSEVBjx49VLlyZUnSkCFD1KtXLy1evNguXPP29tbu3bvVsGFD83VDhgzRgAEDNHfuXL355puqXbt2ofSP4o+v7wEl1PXXS8jIyNBbb72lOnXqyMXFRZUqVVLr1q0VGxsrSQoNDdXMmTMlye5U3mypqal6+eWX5evrK2dnZ9WtW1cffPCBDMOw2+8ff/yhl156SZUrV1b58uX15JNP6n//+59sNpvdp4vZpwzv27dPffr0UYUKFdS6dWtJ0q5duxQaGqqaNWvKxcVF3t7eGjBggH7//Xe7fWVv48cff9Qzzzwjd3d3ValSRW+++aYMw9Cvv/6qp556Sm5ubvL29tbkyZPzdOyuXLmi8ePHq1atWnJ2dlaNGjX0+uuvKy0tzayx2WyaO3euUlNTzWMVHR19w21mf30gISFBDz30kFxdXeXn56eoqCi7uhtdfyn7a2zr16/PdZtt27ZVmTJl9Prrr5vrssOZ9evXq2XLlpKk/v372/U7duxYlS5dWqdPn87R8+DBg+Xh4ZHjU73evXtr8eLFysrKMpd9/fXXunTpkv7+97/n2E5u76lGjRp6/PHHtWnTJj344INycXFRzZo1NX/+/Bsew2u1adNGknT48GG75bldI+Lpp5+WpFy/7gcAuPcwIzEjFZUZSZL+97//acCAAfLy8pKzs7MaNmyoOXPm2NWkp6drzJgxat68udzd3VW2bFm1adNG69ats6s7evSobDabPvjgA82ePdv8ObVs2VLff/99rvu/Xm4zVuXKle0CqWzMWCgIhFJAMZKcnKwzZ87keGRkZNzytePGjdNbb72l9u3ba8aMGXrjjTd03333aceOHZL+/LTjsccekyR99tln5kOSDMPQk08+qalTp6pTp06aMmWK6tatqxEjRigyMtJuP6Ghofroo4/UpUsXvffee3J1dVVwcPAN+/rb3/6mS5cu6Z133tGgQYMk/fm9+59//ln9+/fXRx99pF69emnRokXq0qVLjgFPknr27KmsrCy9++678vf314QJ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bNmyxVz3yCOPGCEhIXb1S5YsMe6//37DycnJaNiwobFy5UqLOy6ebuc4V69e3ZCU4zF27FjrGy+Gbvd3+loMVnl3u8d58+bNhr+/v+Hs7GzUrFnT+Mc//mFcuXLF4q6Ln9s5zhkZGca4ceOMWrVqGS4uLoavr6/xwgsvGOfOnbO+8WJk3bp1uf47N/vYhoSEGI888kiO1zRr1sxwcnIyatasacydO9fyvlF4mJ2swexkHWYnazA7WYf56e4rDvOTzTA41w0AAAAAAADW4ppSAAAAAAAAsByhFAAAAAAAACxHKAUAAAAAAADLEUoBAAAAAADAcoRSAAAAAAAAsByhFAAAAAAAACxHKAUAAAAAAADLEUoBAAAAAADAcoRSAO5p0dHR8vDwsHy/7dq107BhwyzfLwAAQF4V1pwE4N5BKAXgntazZ0/9+OOP5vNx48apWbNmt72d0NBQ2Ww2PffccznWhYeHy2azKTQ01Fy2bNkyjR8//rb2YbPZzIebm5tatmypr776yq5m2bJleuyxx1SlShW5ubkpICBAq1evvu33AwAAUFhzklXatWtnzlYuLi66//77NXHiRBmGYdb88MMP6t27t3x9feXq6qr69etr+vTplvcKlFSEUgDuWRkZGXJ1dZWnp2eBbM/X11eLFi3SH3/8YS67fPmyFi5cqPvuu8+utmLFiipfvvxt72Pu3Lk6ceKEtm/frocfflg9evTQ7t27zfUbN27UY489plWrVikhIUHt27fXE088oZ07d+b/jQEAgHtOYc5JVho0aJBOnDihgwcPatSoURozZoyioqLM9QkJCfL09NS///1v7d27V2+88YZGjRqlGTNmFFrPQElCKAWgWGjXrp0iIiIUEREhd3d3Va5cWW+++ab5SZbNZtPy5cvtXuPh4aHo6GhJ0tGjR2Wz2bR48WI98sgjcnFx0YIFC+xOS4+OjtZbb72lH374wfzULDo6WgMGDNDjjz9ut+2MjAx5enrq008/NZc98MAD8vX11bJly8xly5Yt03333ae//vWvOd7PtV/fq1Gjht555x0NGDBA5cuX13333afZs2fnOA4eHh7y9vbW/fffr/Hjx+vKlStat26duX7atGkaOXKkWrZsqTp16uidd95RnTp19PXXX+f5WAMAgOKlpM1JWVlZmjhxovz8/OTq6qqmTZvqiy++MNdnZmYqLCzMXF+3bt0cZy+Fhoaqa9eu+uCDD1S1alVVqlRJ4eHhysjIsKsrU6aMvL29Vb16dfXv319NmjRRbGysuX7AgAGaPn26HnnkEdWsWVPPPPOM+vfvb/c+AOQfoRSAYmPevHkqVaqUtm3bpunTp2vKlCn65JNPbmsbr732moYOHar9+/crKCjIbl3Pnj318ssvq2HDhjpx4oROnDihnj17auDAgYqJidGJEyfM2hUrVujSpUvq2bOn3TYGDBiguXPnms/nzJmj/v3756m3yZMnq0WLFtq5c6deeOEFPf/88zp48GCutVeuXDEHPScnpxtuMysrSxcuXFDFihXz1AMAACieStKcNHHiRM2fP19RUVHau3evhg8frmeeeUYbNmyQ9Od8U61aNS1dulT79u3TmDFj9Prrr2vJkiV221m3bp0OHz6sdevWad68eYqOjjaDuOsZhqH/+7//04EDB246W0lScnIysxVQQEoVdgMAkFe+vr6aOnWqbDab6tatq927d2vq1KkaNGhQnrcxbNgwdevWLdd1rq6uKleunEqVKiVvb29z+UMPPaS6devqs88+08iRIyX9+TW6v/3tbypXrpzdNp555hmNGjVKv/zyiyTpu+++06JFi7R+/fpb9talSxe98MILkqRXX31VU6dO1bp161S3bl2zpnfv3nJ0dNQff/yhrKws1ahRQ3//+99vuM0PPvhAFy9evGkNAAAo/krKnJSWlqZ33nlH3377rQICAiRJNWvW1KZNm/TPf/5TjzzyiEqXLq233nrLfI2fn5/i4+O1ZMkSu5mnQoUKmjFjhhwdHVWvXj0FBwcrLi7O7ph8/PHH+uSTT5Senq6MjAy5uLjopZdeuuEx2rx5sxYvXqyVK1fe6nACyAPOlAJQbLRq1Uo2m818HhAQoJ9++kmZmZl53kaLFi3yte+BAwean+ydPHlS33zzjQYMGJCjrkqVKgoODlZ0dLTmzp2r4OBgVa5cOU/7aNKkifn/bTabvL29derUKbuaqVOnKjExUd98840aNGigTz755Iaf1C1cuFBvvfWWlixZUmDXgwAAAEVTSZmTDh06pEuXLumxxx5TuXLlzMf8+fN1+PBhs27mzJlq3ry5qlSponLlymn27Nk6duyY3bYaNmwoR0dH83nVqlVzzFZ9+/ZVYmKivvvuO3Xu3FlvvPGGHnrooVzf5549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Lqov/q3S5ZZJuujipZdSlmsDVFV9+/a9aPJakkv9gwAAgKqMuc1Pqvrcxs/P76JfdhUVFSkoKEgrVqwocZtLhTGl5ePjo86dO6tz586KiopSv379tGLFCkVHR1vj/c9//lMhISEXbVueO+W1atVK9913n+68805dddVVWrFixWVDqYULF+q1117Tv/71L3Xt2tVjXVFRkTp37qxnn322xG3DwsLK3CNQFoRSAK6Ixo0ba9SoURo1apROnTqlvn37as6cOdbE7VKTleILR548edLjN4oHDhyw1hf/t6ioSIcOHfL4jdYXX3xR6h5/+OEHpaam6rHHHtOsWbOs5eU5Nb88il/DwYMHrd+WSlJWVpays7NLvKNLafzc2H7yyScqKirymLBdOLbFShqHzz//3ONufgAA1BbMbS7vSsxtis++3rdv30UX7S7t9u+884569+5dYoh3fu/ST2N11VVXWcuPHz9+0V36LqX4F29Hjx716D0oKOiyvZc1yGvUqJGuvvrqy94Z+b333tPDDz+sSZMmWXcjPN/VV1+tjz/+WLfcckuN+EUpqh++MwGgwl14aneDBg3Upk0bj++8169fX5KUnZ3tUTtw4EAVFhZq0aJFHsufe+45eXl56dZbb5UkxcTESJKWLFniUfe3v/2t1H0W/xbwwt/6LViwoNT7+CUGDhxY4vGKf1P1c3fb+Tn169cv8fT8gQMHyuVyafXq1daygoIC/e1vf1ODBg100003edSvW7dO//3vf63nO3fu1I4dO6y/AwAAagvmNqVzJeY23bp1U3h4uBYsWHDR2JbmzK3f//73Kiws1OOPP37RuoKCAmuf0dHRqlu3rv72t7957LeksXvvvfdKvGtj8TW12rVrJ+mnv1OHw6Enn3yyxPrjx49bf77U++fjjz8u8eul33zzjT799FPrWCU5evSofv/736tPnz56+umnS6z5/e9/r//+978e18Iqdvr0aeXm5l5y/0BF4EwpABWuY8eOuvnmmxUREaHGjRtr9+7d+r//+z+NHz/eqomIiJAkPfjgg4qJiZGPj4+GDh2q22+/Xf369dOjjz6qr7/+Wtddd53efvtt/ec//9GkSZOs3zhFRERo8ODBWrBggf73v/9Zt03+/PPPJZXut00Oh0N9+/bV/PnzdfbsWf3qV7/S22+/rUOHDl2BUbnYddddp7i4OL34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ANsRSgEAAAAAAMB2hFIAAAAAAACwHaEUAAAAAAAAbEcoBQAAAAAAANsRSgEAAAAAAMB2hFIAAAAAAACwHaEUAAAAAAAAbEcoBQAAAAAAANsRSgEAAAAAAMB2hFIAAAAAAACwHaEUAAAAAAAAbEcoBQAAAAAAANsRSgEAAAAAAMB2hFIAAAAAAACwHaEUAABANTJnzhx5eXl5PNq3b2+tP3PmjBISEtSkSRM1aNBAgwcPVlZWlsc+Dh8+rNjYWNWrV09BQUGaMmWKCgoKPGq2bNmibt26yc/PT23atFFSUtJFvSxevFitW7eWv7+/IiMjtXPnTo/1pekFAADUXoRSAAAA1cy1116ro0ePWo/333/fWjd58mS9+eabWrt2rbZu3aojR47orrvustYXFhYqNjZW+fn52r59u5YvX66kpCTNmjXLqjl06JBiY2PVr18/ZWRkaNKkSbr//vu1adMmq2b16tVKTEzU7Nmz9dFHH+m6665TTEyMjh07VupeAABA7UYoBQAAUM3UqVNHISEh1qNp06aSpJycHL3yyit69tln9etf/1oRERF69dVXtX37dn344YeSpLfffluffvqp/vWvf6lr16669dZb9fjjj2vx4sXKz8+XJC1btkzh4eF65pln1KFDB40fP1533323nnvuOauHZ599VqNHj9aoUaPUsWNHLVu2TPXq1dPf//73UvcCAABqN0IpAACAaubgwYMKDQ3VVVddpeHDh+vw4cOSpPT0dJ09e1bR0dFWbfv27dWyZUulpaVJktLS0tS5c2cFBwdbNTExMXK73dq/f79Vc/4+imuK95Gfn6/09HSPGm9vb0VHR1s1pemlJHl5eXK73R4PAABQMxFKAQAAVCORkZFKSkpScnKyli5dqkOHDunGG2/UyZMn5XK55Ovrq8DAQI9tgoOD5XK5JEkul8sjkCpeX7zu52rcbrdOnz6t77//XoWFhSXWnL+Py/VSknnz5snpdFqPsLCw0g0MAACodupUdgMAAAAovVtvvdX6c5cuXRQZGalWrVppzZo1CggIqMTOKsaMGTOUmJhoPXe73QRTAADUUJwpBQAAUI0FBgbqmmuu0RdffKGQkBDl5+crOzvboyYrK0shISGSpJCQkIvugFf8/HI1DodDAQEBatq0qXx8fEqsOX8fl+ulJH5+fnI4HB4PAABQMxFKAQAAVGOnTp3Sl19+qebNmysiIkJ169ZVamqqtT4zM1OHDx9WVFSUJCkqKkp79+71uEteSkqKHA6HOnbsaNWcv4/imuJ9+Pr6KiIiwqOmqKhIqampVk1pegEAALUbX98DAACoRh5++GHdfvvtatWqlY4cOaLZs2fLx8dHw4YNk9PpVHx8vBITE9W4cWM5HA5NmDBBUVFR6tWrlySpf//+6tixo0aMGKH58+fL5XJp5syZSkhIkJ+fnyRp7NixWrRokaZOnar77rtPmzdv1po1a7Rhwwarj8TERMXFxal79+7q2bOnFixYoNzcXI0aNUqSStULAACo3QilAAAAqpHvvvtOw4YN0//+9z81a9ZMffr00YcffqhmzZpJkp577jl5e3tr8ODBysvLU0xMjJYsWWJt7+Pjo/Xr12vcuHGKiopS/fr1FRcXp7lz51o14eHh2rBhgyZPnqyFCxeqRYsWevnllxUTE2PVDBkyRMePH9esWbPkcrnUtWtXJScne1z8/HK9AACA2s3LGGMqu4nawu12y+l0Kicnh+sjAABQgvikXeXe9pWRPSqwk3P4/K5cV3r8q+J7DgCA6q60n99cUwoAAAAAAAC2I5QCAAAAAACA7QilAAAAAAAAYDtCKQAAAAAAANiOUAoAAAAAAAC2I5QCAAAAAACA7QilAAAAAAAAYDtCKQAAAAAAANiOUAoAAAAAAAC2I5QCAAAAAACA7QilAAAAAAAAYDtCKQAAAAAAANiOUAoAAAAAAAC2I5QCAAAAAACA7QilAAAAAAAAYDtCKQAAAAAAANiOUAoAAAAAAAC2I5QCAAAAAACA7QilAAAAAAAAYDtCKQAAAAAAANiOUAoAAAAAAAC2I5QCAAAAAACA7QilAAAAAAAAYDtCKQAAAAAAANiOUAoAAAAAAAC2I5QCAAAAAACA7So1lJo3b5569Oihhg0bKigoSIMGDVJmZqZHzc033ywvLy+Px9ixYz1qDh8+rNjYWNWrV09BQUGaMmWKCgoKPGq2bNmibt26yc/PT23atFFSUtJF/SxevFitW7eWv7+/IiMjtXPnTo/1Z86cUUJCgpo0aaIGDRpo8ODBysrKqpjBAAAAAAAAqEUqNZTaunWrEhIS9OGHHyolJUVnz55V//79lZub61E3evRoHT161HrMnz/fWldYWKjY2Fjl5+dr+/btWr58uZKSkjRr1iyr5tChQ4qNjVW/fv2UkZGhSZMm6f7779emTZusmtWrVysxMVGzZ8/WRx99pOuuu04xMTE6duyYVTN58mS9+eabWrt2rbZu3aojR47orrvuuoIjBAAAAAAAUDN5GWNMZTdR7Pjx4woKCtLWrVvVt29fST+dKdW1a1ctWLCgxG02btyo2267TUeOHFFwcLAkadmyZZo2bZqOHz8uX19fTZs2TRs2bNC+ffus7YYOHars7GwlJydLkiIjI9WjRw8tWrRIklRUVKSwsDBNmDBB06dPV05Ojpo1a6aVK1fq7rvvliQdOHBAHTp0UFpamnr16nVRb3l5ecrLy7Oeu91uhYWFKScnRw6H45cPGAAANUx80q5yb/vKyB4V2Mk5brdbTqeTz+9KcqXHvyq+5wAAqO5K+/ldpa4plZOTI0lq3Lixx/IVK1aoadOm6tSpk2bMmKEff/zRWpeWlqbOnTtbgZQkxcTEyO12a//+/VZNdHS0xz5jYmKUlpYmScrPz1d6erpHjbe3t6Kjo62a9PR0nT171qOmffv2atmypVVzoXnz5snpdFqPsLCwMo8JAAAAAABATVSnshsoVlRUpEmTJql3797q1KmTtfyee+5Rq1atFBoaqk8++UTTpk1TZmam/v3vf0uSXC6XRyAlyXrucrl+tsbtduv06dP64YcfVFhYWGLNgQMHrH34+voqMDDwopri41xoxowZSkxMtJ4XnykFAAAAAABQ21WZUCohIUH79u3T+++/77F8zJgx1p87d+6s5s2b65ZbbtGXX36pq6++2u42y8TPz09+fn6V3QYAAAAAAECVUyW+vjd+/HitX79e7777rlq0aPGztZGRkZKkL774QpIUEhJy0R3wip+HhIT8bI3D4VBAQICaNm0qHx+fEmvO30d+fr6ys7MvWQMAAAAAAIDSqdRQyhij8ePH6/XXX9fmzZsVHh5+2W0yMjIkSc2bN5ckRUVFae/evR53yUtJSZHD4VDHjh2tmtTUVI/9pKSkKCoqSpLk6+uriIgIj5qioiKlpqZaNREREapbt65HTWZmpg4fPmzVAAAAAAAAoHQq9et7CQkJWrlypf7zn/+oYcOG1rWZnE6nAgIC9OWXX2rlypUaOHCgmjRpok8++USTJ09W37591aVLF0lS//791bFjR40YMULz58+Xy+XSzJkzlZCQYH11buzYsVq0aJGm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kyerbt26Onz4sOrVq2ctHzJkiJKTk8uzSwAAgBqPORQAAMA55fr63ttvv61NmzapRYsWHsvbtm2rb775pkIaAwAAqGmYQwEAAJxTrjOlcnNzPX67V+zEiRPcwhcAAOASmEMBAACcU65Q6sYbb9Q//vEP67mXl5eKioo0f/589evXr8KaAwAAqEmYQwEAAJxTrq/vzZ8/X7fccot2796t/Px8TZ06Vfv379eJEyf0wQcfVHSPAAAANQJzKAAAgHPKdaZUp06d9Pnnn6tPnz664447lJubq7vuukt79uzR1VdfXdE9AgAA1AjMoQAAAM4p85lSZ8+e1YABA7Rs2TI9+uijV6InAACAGoc5FAAAgKcynylVt25dffLJJ1eiFwAAgBqLORQAAICncn197w9/+INeeeWViu4FAACgRmMOBQAAcE65LnReUFCgv//973rnnXcUERGh+vXre6x/9tlnK6Q5AACAmoQ5FAAAwDllCqW++uortW7dWvv27VO3bt0kSZ9//rlHjZeXV8V1BwAAUAMwhwIAALhYmb6+17ZtW33//fd699139e677yooKEirVq2ynr/77rvavHlzqfe3bds23X777QoNDZWXl5fWrVvnsX7kyJHy8vLyeAwYMMCj5sSJExo+fLgcDocCAwMVHx+vU6dOedR88sknuvHGG+Xv76+wsDDNnz//ol7Wrl2r9u3by9/fX507d9Zbb73lsd4Yo1mzZql58+YKCAhQdHS0Dh48WOrXCgAAaq+KnkMBAADUBGUKpYwxHs83btyo3Nzcch88NzdX1113nRYvXnzJmgEDBujo0aPW47XXXvNYP3z4cO3fv18pKSlav369tm3bpjFjxljr3W63+vfvr1atWik9PV1PP/205syZoxdffNGq2b59u4YNG6b4+Hjt2bNHgwYN0qBBg7Rv3z6rZv78+Xr++ee1bNky7dixQ/Xr11dMTIzOnDlT7tcPAABqh4qeQwEAANQE5bqmVLELJ1hldeutt+rWW2/92Ro/Pz+FhISUuO6zzz5TcnKydu3ape7du0uS/va3v2ngwIH661//qtDQUK1YsUL5+fn6+9//Ll9fX1177bXKyMjQs88+a4VXCxcu1IABAzRlyhRJ0uOPP66UlBQtWrRIy5YtkzFGCxYs0MyZM3XHHXdIkv7xj38oODhY69at09ChQ3/ROAAAgNrl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wMBAj9rz55qX+vkrXvdzNTXtZ3TVqlX66KOPtGvXrovWMZZl99VXX2np0qVKTEzUI488ol27dunBBx+Ur6+v4uLirDH5uX8LuVwuBQUFeayvU6eOGjdu7FETHh5+0T6K1zVq1OiKvD67TZ8+XW63W+3bt5ePj48KCwv15z//WcOHD5ckxvMXsHPsqvu//wmlgArw1FNPadWqVdqyZYv8/f0ru50a4+TJkxoxYoReeuklNW3atLLbqfGKiooUFBSkF198UT4+PoqIiNB///tfPf3004RSFWjLli168skntWTJEkVGRuqLL77QxIkT9fjjj+tPf/pTZbcHAJaEhATt27dP77//fmW3Ui19++23mjhxolJSUpgfVpCioiJ1795dTz75pCTp+uuv1759+7Rs2TLFxcVVcnfVz5o1a7RixQqtXLlS1157rTIyMjRp0iSFhoYynrANoVQV17RpU/n4+Fx0F46srCyFhISUuE1ISEiZ6lG+cS7217/+VU899ZTeeecddenS5Uq2We2VdZy//PJLff3117r99tutZUVFRZJ++i1CZmamrr766ivbdDVVnvd08+bNVbduXfn4+FjLOnToIJfLpfz8fI/ThvGT8ozzn/70J40YMUL333+/JKlz587Kzc3VmDFj9Oijj8rbm2/WV4RLfRY6HI4addYAyu6XfObXJuPHj9f69eu1bds2tWjRwloeEhKi/Px8ZWdne5zhc/74hYSEXHQ3w+LxPr+mpv+Mpqen69ixY+rWrZu1rLCwUNu2bdOiRYu0adMmxrKMmjdvro4dO3os69Chg/7f//t/ks6NSVZWlpo3b27VZGVlqWvXrlbNsWPHPPZRUFCgEydOXHZMzz9GTTBlyhRNnz5dQ4cOlfTTnOSbb77RvHnzFBcXx3j+AnaOXXX/9z8z3yrO19dXERERSk1NtZYVFRUpNTVVUVFRJW4TFRXlUS9JKSkpl6xH+cZZkubPn6/HH39cycnJHt8FRsnKOs7t27fX3r17lZGRYT1++9vfql+/fsrIyFBYWJid7Vcr5XlP9+7dW1988YUV/EnS559/rubNmxNIXUJ5xvnHH3+8KHgqDgLNebdgxi/DZyEupbyf+bWFMUbjx4/X66+/rs2bN1/0tZGIiAjVrVvXY/wyMzN1+PBha/yioqK0d+9ej39spaSkyOFwWIFCbfgZveWWWy6ax3Tv3l3Dhw+3/sxYlk3v3r2VmZnpsezzzz9Xq1atJEnh4eEKCQnxGA+3260dO3Z4jGl2drbS09Otms2bN6uoqEiRkZFWzbZt23T27FmrJiUlRe3atatRXzW71JykeC7IeJafnWNX7f8fUMkXWkcprFq1yvj5+ZmkpCTz6aefmjFjxpjAwEDrLhwjRoww06dPt+o/+OADU6dOHfPXv/7VfPbZZ2b27NnV6paQlaWs4/zUU08ZX19f83//93/m6NGj1uPkyZOV9RKqhbKO84W4+17plXWsDx8+bBo2bGjGjx9vMjMzzfr1601QUJB54oknKuslVAtlHefZs2ebhg0bmtdee8189dVX5u233zZXX321+f3vf19ZL6FaOHnypNmzZ4/Zs2ePkWSeffZZs2fPHvPNN98YY4yZPn26GTFihFVffIv0KVOmmM8++8wsXry4xt4iHWV3uZ/b2mzcuHHG6XSaLVu2eMxvfvzxR6tm7NixpmXLlmbz5s1m9+7dJioqykRFRVnrCwoKTKdOnUz//v1NRkaGSU5ONs2aNTMzZsywamrrz+j5d98zhrEsq507d5o6deqYP//5z+bgwYNmxYoVpl69euZf//qXVfPUU0+ZwMBA85///Md88skn5o477jDh4eHm9OnTVs2AAQPM9ddfb3bs2GHef/9907ZtWzNs2DBrfXZ2tgkODjYjRoww+/btM6tWrTL16tUzL7zwgq2v90qLi4szv/rVr8z69evNoUOHzL///W/TtGlTM3XqVKuG8by0y81N7Bq76v7vf0KpauJvf/ubadmypfH19TU9e/Y0H374obXupptuMnFxcR71a9asMddcc43x9fU11157rdmwYYPNHVdPZRnnVq1aGUkXPWbPnm1/49VMWd/P5yOUKpuyjvX27dtNZGSk8fPzM1dddZX585//bAoKCmzuuvopyzifPXvWzJkzx1x99dXG39/fhIWFmQceeMD88MMP9jdejbz77rsl/j+3eGzj4uLMTTfddNE2Xbt2Nb6+vuaqq64yr776qu19o+r6uZ/b2qyknzNJHj8/p0+fNg888IBp1KiRqVevnrnzzjvN0aNHPfbz9ddfm1tvvdUEBASYpk2bmoceesicPXvWo6Y2/oxeGEoxlmX35ptvmk6dOhk/Pz/Tvn178+KLL3qsLyoqMn/6059McHCw8fPzM7fccovJ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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "pdf = susie_results.select(\"purityMinR2\", \"purityMeanR2\", \"topPP\", \"credSetSize\").toPandas()\n", + "plt.figure(figsize=(12, 12))\n", + "\n", + "# Histogram for purityMinR2\n", + "plt.subplot(2, 2, 1)\n", + "plt.hist(pdf[\"purityMinR2\"], bins=30, alpha=0.7)\n", + "plt.title(\"Histogram of purityMinR2\")\n", + "plt.xlabel(\"purityMinR2\")\n", + "plt.ylabel(\"Frequency\")\n", + "\n", + "# Histogram for purityMeanR2\n", + "plt.subplot(2, 2, 2)\n", + "plt.hist(pdf[\"purityMeanR2\"], bins=30, alpha=0.7)\n", + "plt.title(\"Histogram of purityMeanR2\")\n", + "plt.xlabel(\"purityMeanR2\")\n", + "plt.ylabel(\"Frequency\")\n", + "\n", + "# Histogram for topPP\n", + "plt.subplot(2, 2, 3)\n", + "plt.hist(pdf[\"topPP\"], bins=30, alpha=0.7)\n", + "plt.title(\"Histogram of topPP\")\n", + "plt.xlabel(\"topPP\")\n", + "plt.ylabel(\"Frequency\")\n", + "\n", + "# Histogram for credSetSize\n", + "plt.subplot(2, 2, 4)\n", + "plt.hist(pdf[\"credSetSize\"], bins=30, alpha=0.7)\n", + "plt.title(\"Histogram of credSetSize\")\n", + "plt.xlabel(\"credSetSize\")\n", + "plt.ylabel(\"Frequency\")\n", + "\n", + "# Adjust layout to prevent overlap\n", + "plt.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Repeating the same steps, but filtering for only the first credible set" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Total number of primary credible sets and number of unique studyIds:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Number of primary credible sets: 175991\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[Stage 46:====================================================> (176 + 5) / 181]\r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Number of unique studyIds in primary credible sets: 5328\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + } + ], + "source": [ + "first_credset = susie_results.filter(f.col(\"credibleSetIndex\") == 1)\n", + "print(\"Number of primary credible sets: \", first_credset.count())\n", + "print(\"Number of unique studyIds in primary credible sets: \", first_credset.select(\"studyId\").distinct().count())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "-RECORD 0--------------------------\n", + " meanTopPP | 0.6268846688460689 \n", + " minTopPP | 5.30020287265377E-4 \n", + " q1TopPP | 0.22323522754002711 \n", + " medianTopPP | 0.7547370350843897 \n", + " q3TopPP | 0.9999999999979536 \n", + " maxTopPP | 1.0 \n", + "\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "-RECORD 0------------------------------\n", + " meanCredSetSize | 50.48537709314681 \n", + " minCredSetSize | 1 \n", + " q1CredSetSize | 1 \n", + " medianCredSetSize | 3 \n", + " q3CredSetSize | 19 \n", + " maxCredSetSize | 10710 \n", + "\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "-RECORD 0---------------------------------\n", + " meanPurityMeanR2 | 0.674055454136671 \n", + " minPurityMeanR2 | 0.00469889394266767 \n", + " q1PurityMeanR2 | 0.3980306136489271 \n", + " medianPurityMeanR2 | 0.8336824740390751 \n", + " q3PurityMeanR2 | 0.9776068324678869 \n", + " maxPurityMeanR2 | 1.0 \n", + "\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[Stage 61:=====================================================>(178 + 3) / 181]\r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "-RECORD 0---------------------------------\n", + " meanPurityMinR2 | 0.48629879351056204 \n", + " minPurityMinR2 | 0.0 \n", + " q1PurityMinR2 | 3.997840337231423E-6 \n", + " medianPurityMinR2 | 0.5018138600363721 \n", + " q3PurityMinR2 | 0.9490123559383069 \n", + " maxPurityMinR2 | 1.0 \n", + "\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + } + ], + "source": [ + "(\n", + " first_credset.select(\n", + " f.mean(\"topPP\").alias(\"meanTopPP\"),\n", + " f.min(\"topPP\").alias(\"minTopPP\"),\n", + " f.percentile_approx(\"topPP\", 0.25).alias(\"q1TopPP\"),\n", + " f.percentile_approx(\"topPP\", 0.5).alias(\"medianTopPP\"),\n", + " f.percentile_approx(\"topPP\", 0.75).alias(\"q3TopPP\"),\n", + " f.max(\"topPP\").alias(\"maxTopPP\"),\n", + " ).show(vertical=True)\n", + ")\n", + "(\n", + " first_credset.select(\n", + " f.mean(\"credSetSize\").alias(\"meanCredSetSize\"),\n", + " f.min(\"credSetSize\").alias(\"minCredSetSize\"),\n", + " f.percentile_approx(\"credSetSize\", 0.25).alias(\"q1CredSetSize\"),\n", + " f.percentile_approx(\"credSetSize\", 0.5).alias(\"medianCredSetSize\"),\n", + " f.percentile_approx(\"credSetSize\", 0.75).alias(\"q3CredSetSize\"),\n", + " f.max(\"credSetSize\").alias(\"maxCredSetSize\"),\n", + " ).show(vertical=True)\n", + ")\n", + "(\n", + " first_credset.select(\n", + " f.mean(\"purityMeanR2\").alias(\"meanPurityMeanR2\"),\n", + " f.min(\"purityMeanR2\").alias(\"minPurityMeanR2\"),\n", + " f.percentile_approx(\"purityMeanR2\", 0.25).alias(\"q1PurityMeanR2\"),\n", + " f.percentile_approx(\"purityMeanR2\", 0.5).alias(\"medianPurityMeanR2\"),\n", + " f.percentile_approx(\"purityMeanR2\", 0.75).alias(\"q3PurityMeanR2\"),\n", + " f.max(\"purityMeanR2\").alias(\"maxPurityMeanR2\"),\n", + " ).show(vertical=True)\n", + ")\n", + "(\n", + " first_credset.select(\n", + " f.mean(\"purityMinR2\").alias(\"meanPurityMinR2\"),\n", + " f.min(\"purityMinR2\").alias(\"minPurityMinR2\"),\n", + " f.percentile_approx(\"purityMinR2\", 0.25).alias(\"q1PurityMinR2\"),\n", + " f.percentile_approx(\"purityMinR2\", 0.5).alias(\"medianPurityMinR2\"),\n", + " f.percentile_approx(\"purityMinR2\", 0.75).alias(\"q3PurityMinR2\"),\n", + " f.max(\"purityMinR2\").alias(\"maxPurityMinR2\"),\n", + " ).show(vertical=True)\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "data": { + "image/png": "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X/6irVu3Fvgk8WZp166dwsPD9eabb+rcuXO68847tWfPHq1YsUJ9+/Yt9PbBRVW/fn298sor+umnn3TrrbdqzZo1Sk5O1ptvvqkqVapIklq1aqUuXbpoypQp+u2331SrVi2tXr1aOTk5N/S+brnlFnl5eSk2NlY1atRQtWrVFBQUZF53okqVKho0aJAWL14sJycnPfzww9fdpqenp82nxlabOHGi1q5dq4ULF+rll1+WJPXq1Us//vijJk2apE8//VSffvqpWe/j42PewhsAgKthZioaZqbSn5lefvll7dixQ0FBQXr00UcVEBCg3377Tfv27dN//vMf/fbbb5Kke++9V+vXr9eDDz6osLAwHTt2TLGxsQoICNCFCxdu6P1fqUqVKho3bpwmTpyozZs3q1evXvr55591//33y8HBQQMGDNC6detsXtO2bdsi3VQAuC673PMPQAH5t7zdu3dvoesvv+1svitvb/zCCy8YnTt3Nry8vAx3d3ejRYsWxosvvmjeVtcw/ry97NixY426desaDg4ONrc6Pn/+vDFhwgSjfv36RpUqVYxmzZoZc+fONfLy8mz2m5GRYURGRhq1atUyqlevbvTt29c4evSoIcnmdsP5t509c+ZMgffzyy+/GA8++KDh5eVleHp6Gg899JBx8uTJq94i+cptXO22w4Udp8JkZ2cbzz//vOHv729UqVLF8PPzM6ZMmWJcunSpSPspTP6+v/zySyM4ONhwc3MzGjVqZCxevLhA7Q8//GCEhIQYrq6uho+Pj/Hss88aCQkJ17zdcGH7u/z2xobx5+1/AwICDGdn50Jvdbxnzx5DktGzZ89rvodrKez2xoXdsrlRo0aF3m77yr4L297lunfvbnh4eBjnzp0zDMO45i3ArzweAICKh5mJmak8z0yGYRipqalGZGSk4efnZ1SpUsXw9fU17r77buPNN980a/Ly8oyXXnrJaNSokeHq6mr89a9/NTZs2GCEh4cbjRo1MuuOHTtmSDLmzp1bYP9F/TtiGIaRlpZmeHp6mscpv/erPS7fLnAjHAyjiFe3A4BrSE5O1l//+le9++67GjJkiL3bsYvu3bvr7NmzhZ6OXVZ89dVXat++vd555x0NHTrU3u0AAFDpMDMxMwH4P3wpFECxXbx4scCyhQsXytHRUXfccYcdOkJRvfXWW6pevbr69etn71YA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WrRI8+fP19KlS4u1jWeeeUbjxo3TN998o9DQUJt1AwcO1FNPPaVWrVrp1KlTOnXqlAYOHKhRo0Zp8+bNOnXqlFm7YcMG/fHHHxo4cKDNNkaOHKnly5ebz99++22NGDGiSL3NmzdPHTt21P79+/XEE09ozJgxOnr0aKG1OTk55lDn4uJy1W3m5eXp/PnzqlWrVpF6AAAAFUdFmp1mz56td955R7GxsTp06JAmTJigRx55RLt27ZL058zToEEDrVu3TocPH9a0adP07LPPau3atTbb2bFjh3744Qft2LFDK1asUFxcnBnEXckwDP33v//VkSNHrjlvSVJaWhrzFlDKnO3dAABczs/PTwsWLJCDg4OaN2+uAwcOaMGCBXr00UeLvI3x48erX79+ha5zd3dX9erV5ezsLF9fX3P5bbfdpubNm+uf//ynJk2aJOnPr9E99NBDql69us02HnnkEU2ZMkU///yzJOmzzz7T6tWrtXPnzuv21qdPHz3xxBOSpMmTJ2vBggXasWOHmjdvbtY8/PDDcnJy0sWLF5WXl6fGjRvrb3/721W3+eqrr+rChQvXrAEAABVTRZmdMjMz9dJLL+k///mPgoODJUlNmjTRp59+qn/84x+68847VaVKFT3//PPma/z9/ZWYmKi1a9fazEE1a9bU4sWL5eTkpBYtWigsLEzbtm2zOSZLlizR0qVLlZWVpezsbLm5uenJJ5+86jHavXu31qxZo/j4+OsdTgDFwJlSAMqULl26yMHBwXweHBys7777Trm5uUXeRseOHUu071GjRpmf4qWmpmrTpk0aOXJkgbq6desqLCxMcXFxWr58ucLCwlSnTp0i7aNt27bmnx0cHOTr66vTp0/b1CxYsEDJycnatGmTAgICtHTp0qt+Krdq1So9//zzWrt2bald+wEAAJQfFWV2+v777/XHH3/onnvuUfXq1c3HO++8ox9++MGsi4mJUWBgoOrWravq1avrzTff1PHjx2221apVKzk5OZnP69WrV2DeGjJkiJKTk/XZZ5+pd+/eeu6553TbbbcV+j4PHjyoBx54QNOnT1fPnj2Ld5AAXBNnSgEoNxwcHGzuiiKpwPUBJKlatWol2v6wYcP0zDPPKDExUbt375a/v7+6detWaO3IkSMVFRUl6c/hqKiqVKli89zBwUF5eXk2y3x9fdW0aVM1bdpUy5cvV58+fXT48OECodPq1as1atQorVu3TiEhIUXuAQAAVA7laXa6cOGCJCk+Pl5/+ctfbNa5urpK+nP2efrppzVv3jwFBwerRo0amjt3rr744gub+qLMW56enmratKkkae3atWratKm6dOlSYKY6fPiw7r77bj322GOaOnXqNY8HgOIjlAJQplw5VHz++edq1qyZnJycVLduXZvrFnz33Xf6448/ir0PFxeXQj89rF27tvr27avly5crMTHxmteJ6tWrl7KysuTg4FDg2gulqXPnzgoMDNSLL75ocyHP9957TyNHjtTq1asVFhZ20/YPAADKtooyOwUEBMjV1VXHjx/XnXfeWeg2PvvsM912223mpRAk2ZxFVVLVq1fXuHHj9PTTT2v//v3mmWeHDh3SXXfdpfDwcL344os3vB8ABRFKAShTjh8/rujoaD3++OPat2+fXn/9dc2bN0+SdNddd2nx4sUKDg5Wbm6uJk+eXOCTsKJo3Lixjh07puTkZDVo0EA1atQwP4EbNWqU7r33XuXm5io8PPyq23ByctI333xj/vlmGj9+vB588EFNmjRJf/nLX7Rq1SqFh4dr0aJFCgoKUkpKiqQ/r/ng6el5U3sBAABlS0WZnWrUqKGnn35aEyZMUF5enrp27aq0tDR99tln8vDwUHh4uJo1a6Z33nlHW7Zskb+/v/75z39q79698vf3L/Z7utLjjz+uWbNm6V//+pcGDBiggwcP6q677lJoaKiio6PNeSs/7ANQOrimFIAyZdiwYbp48aI6d+6syMhIjRs3To899pikP+9c5+fnp27dumnw4MF6+umnVbVq1WLvo3///urVq5d69OihunXr6r333jPXhYSEqF69egoNDVX9+vWvuR0PDw95eHgUe//F1atXL/n7+5uf0L355pvKyclRZGSk6tWrZz7GjRt303sBAABlS0WanWbNmqW///3vmj17tlq2bKlevXopPj7eDJ0ef/xx9evXTwMHDlRQUJB+/fVXm7OmbkStWrU0bNgwzZgxQ3l5eXr//fd15swZvfvuuzbzVqdOnUplfwD+5GBc+SVjALCT7t27q3379lq4cKHderhw4YL+8pe/aPny5Ve9Cw0AAEBZwOwEoLzj63sAICkvL09nz57VvHnz5OXlpfvvv9/eLQEAAJRZzE4ASgOhFADoz+sx+Pv7q0GDBoqLi5OzM//3CAAAcDXMTgBKA1/fAwAAAAAAgOW40DkAAAAAAAAsRygFAAAAAAAAyxFKAQAAAAAAwHKEUgAAAAAAALAcoRQAAAAAAAAsRygFAAAAAAAAyxFKAQAAAAAAwHKEUgAAAAAAALAcoRQAAAAAAAAsRygFAAAAAAAAyxFKAQAAAAAAwHKEUgAAAAAAALAcoRQAAAAAAAAsRygFoEgaN26s4cOH27uNCm/u3Llq0qSJnJyc1L59e3u3AwBApcK8Y43yMu+Ul78PM2bMkIODg73bAEqEUAqohOLi4uTg4KAvv/yy0PXdu3dX69atb3g/Gzdu1IwZM254O5XF1q1bNWnSJN1+++1avny5XnrppavWrlq1SgsXLrSkr/xBJ/9RtWpVBQQEaOrUqUpPTzfr8v9e5T/c3Nx06623KioqSqmpqZb0CgBAPuadsqk4805Z9NNPP2nEiBG65ZZb5ObmJl9fX91xxx2aPn16ibZ3rb8/Fy5c0PTp09W6dWtVq1ZNtWvXVvv27TVu3DidPHnyBt4FUHY427sBAOXD0aNH5ehYvBx748aNiomJYVArou3bt8vR0VHLli2Ti4vLNWtXrVqlgwcPavz48dY0J+mNN95Q9erVdeHCBW3dulUvvviitm/frs8++8zm07mZM2fK399fly5d0qeffqo33nhDGzdu1MGDB1W1alXL+gUAoLiYd26+4sw7Zc3333+vTp06yd3dXSNHjlTjxo116tQp7du3T6+88oqef/75Ym/zan9/srOzdccdd+jIkSMKDw/X2LFjdeHCBR06dEirVq3Sgw8+qPr160uSpk6dqmeeeaY03iJgOUIpAEXi6upq7xaKLSMjQ9WqVbN3G0V2+vRpubu7l9kBbcCAAapTp44kafTo0erfv7/Wr1+vzz//XMHBwWZd79691bFjR0nSqFGjVLt2bc2fP18fffSRHn74Ybv0DgBAUTDv3HxWzDs365gsWLBAFy5cUHJysho1amSz7vTp06W6rw8//FD79+/XypUrNXjwYJt1ly5dUlZWlvnc2dlZzs78pz3KJ76+B6BIrvxOfXZ2tp5//nk1a9ZMbm5uql27trp27aqEhARJ0vDhwxUTEyNJNl/pypeRkaGnnnpKfn5+cnV1VfPmzfXqq6/KMAyb/V68eFFPPvmk6tSpoxo1auj+++/X//73Pzk4ONh8opT/FbPDhw9r8ODBqlmzprp27SpJ+vrrrzV8+HA1adLEPM165MiR+vXXX232lb+Nb7/9Vo888og8PT1Vt25d/f3vf5dhGDpx4oQeeOABeXh4yNfXV/PmzSvSscvJydGsWbN0yy23yNXVVY0bN9azzz6rzMxMs8bBwUHLly9XRkaGeazi4uIK3V737t0VHx+vn3/+2axt3Lixuf706dOKiIiQj4+P3Nzc1K5dO61YscJmGz/99JMcHBz06quvasGCBWrUqJHc3d1155136uDBg0V6X3fddZck6dixY6VSBwCAvTHvlJ15J98XX3yhPn36qGbNmqpWrZratm2rRYsWmeuHDx+u6tWr64cfflCfPn1Uo0YNDRkyRJL0/9i7+7io6rz/429u5MabGbwD5BKVTfMmSRMNMbW1WKekNspaLbfUSLNFU0lNy9DKjdI1b9Iky8JKN3OvzS1NlLC0krxBLbU0KzYtG7RLmQlKQDi/P/pxcoIUCQ83vp6Pxzy2OedzzvnMl6n57nvOnFNaWqr58+frsssuU0BAgEJCQnTvvffq5MmTHscwDEOzZs1S69at1bBhQw0YMED79+8v18uXX36p1q1blwukJCk4OLjcsvXr16tfv35q1KiRmjRpori4OI/9nu398+WXX0qSrrrqqnL7DQgIkM1mM5//+ppSI0aM8NjfmY8z30+FhYWaMWOG2rdvL39/f4WHh2vKlCkefzPgQiNOBS5iLpdL33//fbnlxcXF59x25syZSklJ0T333KMrr7xSbrdbO3fu1K5du/SnP/1J9957r44ePaqMjAy98sorHtsahqE///nPevfdd5WQkKDu3btrw4YNmjx5sr799lvNmzfPrB0xYoRef/113Xnnnerdu7c2b96suLi43+zrtttuU4cOHfTEE0+YE76MjAx99dVXGjlypEJDQ7V//34tXbpU+/fv10cffVTuwpBDhgxR586d9eSTT2rdunWaNWuWmjVrpueee07XXHONnnrqKa1YsUKTJk1Sr1691L9//7OO1T333KPly5fr1ltv1QMPPKBt27YpJSVFn332md544w1J0iuvvKKlS5dq+/bteuGFFyRJffr0qXB/Dz/8sFwul7755htzrBo3bizp50ntH//4R33xxRcaO3asIiIitHr1ao0YMUJ5eXkaP368x75efvll/fDDD0pMTNSpU6e0YMECXXPNNdq7d69CQkLO+rrKJkvNmzevljoAAC4E5jt1c75T9ppuuOEGtWrVSuPHj1doaKg+++wzrV271mNOc/r0aTkcDvXt21f/+Mc/zMsF3HvvvUpLS9PIkSN1//33KycnR4sWLdLu3bv14YcfqkGDBpKk5ORkzZo1S4MGDdKgQYO0a9cuDRw40ONsJElq27at3nnnHW3atMn80u23vPLKKxo+fLgcDoeeeuop/fjjj1qyZIn69u2r3bt3q127dmd9/5QFXy+//LKmT59+Xhcyv/feexUbG+uxLD09XStWrDDDs9LSUv35z3/WBx98oNGjR6tz587au3ev5s2bp88//1xr1qyp9PGA38UAcNF56aWXDElnfVx22WUe27Rt29YYPny4+bxbt25GXFzcWY+TmJhoVPSfmTVr1hiSjFmzZnksv/XWWw0vLy/jiy++MAzDMLKzsw1JxoQJEzzqRowYYUgyZsyYYS6bMWOGIcm4/fbbyx3vxx9/LLfsn//8pyHJ2LJlS7l9jB492lx2+vRpo3Xr1oaXl5fx5JNPmstPnjxpBAYGeoxJRfbs2WNIMu655x6P5ZMmTTIkGZs2bTKXDR8+3GjUqNFZ91cmLi7OaNu2bbnl8+fPNyQZr776qrmsqKjIiImJMRo3bmy43W7DMAwjJyfHkGQEBgYa33zzjVm7bds2Q5IxceJEc1nZuBw8eNA4fvy4kZOTYzz33HOGv7+/ERISYhQUFBiG8cv76p133jGOHz9uHDlyxHjttdeM5s2blzsOAAAXGvOduj3fOX36tBEREWG0bdvWOHnypMe60tJSj/1JMqZOnepR8/777xuSjBUrVngsT09P91h+7Ngxw8/Pz4iLi/PY70MPPWRI8njt+/btMwIDAw1JRvfu3Y3x48cba9asMedCZX744QcjKCjIGDVqlMdyp9Np2O12j+W/9f758ccfjY4dOxqSjLZt2xojRowwli1bZuTm5parLfub/pZDhw4Zdrvd+NOf/mScPn3aMAzDeOWVVwxvb2/j/fff96hNTU01JBkffvjhb+4PqE78fA+4iC1evFgZGRnlHpdffvk5tw0KCtL+/ft16NCh8z7u22+/LR8fH91///0eyx944AEZhqH169dL+vkbHUn629/+5lE3bty439z3mDFjyi0LDAw0//nUqVP6/vvv1bt3b0nSrl27ytXfc8895j/7+PioZ8+eMgxDCQkJ5vKgoCB17NhRX3311W/2Iv38WiUpKSnJY/kDDzwgSVq3bt1Ztz9fb7/9tkJDQz2u3dSgQQPdf//9ys/P1+bNmz3q4+Pj9T//8z/m8yuvvFLR0dFm32fq2LGjWrZsqYiICN17771q37691q1bV+7i5bGxsWrZsqXCw8M1dOhQNW7cWG+88YbHcQAAsArznbo539m9e7dycnI0YcIEBQUFeayr6Kyh++67z+P56tWrZbfb9ac//Unff/+9+YiKilLjxo317rvvSpLeeecdFRUVady4cR77rehmMpdddpn27Nmjv/71r/rvf/+rBQsWKD4+XiEhIXr++efNuoyMDOXl5en222/3OLaPj4+io6PNY59NYGCgtm3bpsmTJ0v6+W6SCQkJatWqlcaNG1fpn9gVFBTo5ptvVtOmTfXPf/5TPj4+5vh07txZnTp18uix7AywyvQIVAd+vgdcxK688krzgtRnatq0aYWnuZ/pscce00033aRLL71UXbt21XXXXac777yzUhO8r7/+WmFhYWrSpInH8s6dO5vry/7X29tbERERHnXt27f/zX3/ulaSTpw4oUcffVSvvfZauYtQulyucvVt2rTxeG632xUQEGBe5PvM5b++TsOvlb2GX/ccGhqqoKAg87VWl6+//lodOnQod+egX49tmQ4dOpTbx6WXXqrXX3+93PL//d//lc1mU4MGDdS6dWtdcsklFfawePFiXXrppfL19VVISIg6dux43ncyAgCgujDfqZvznbKf/3ft2vWctb6+vmrdurXHskOHDsnlclV4rSfplwuTl/X26zlRy5Yt1bRp03LbXXrppXrllVdUUlKiTz/9VGvXrtXs2bM1evRoRUREKDY21gwxf+snfmdeD+ps7Ha7Zs+erdmzZ+vrr79WZmam/vGPf2jRokWy2+2aNWvWOfcxatQoffnll9q6davHpRQOHTqkzz77TC1btqxwu+q+cDvwWwilAFRJ//799eWXX+o///mPNm7cqBdeeEHz5s1TamqqxzdvVjvzW8Iyf/nLX7R161ZNnjxZ3bt3V+PGjVVaWqrrrrtOpaWl5erLvkE61zJJ5S5U+lvO5zoAtVX//v3LTVQr8luTfwAA6hrmOz+r7fMdf3//cl+AlZaWKjg4WCtWrKhwm98KYyrLx8dHkZGRioyMVExMjAYMGKAVK1YoNjbWHO9XXnlFoaGh5batyp3y2rZtq7vvvls333yz/vCHP2jFihXnDKUWLFigf/7zn3r11VfVvXt3j3WlpaWKjIzU008/XeG24eHh590jUBWEUgCqrFmzZho5cqRGjhyp/Px89e/fXzNnzjQnab81MSm7SOQPP/zg8e3hgQMHzPVl/1taWqqcnByPb6+++OKLSvd48uRJZWZm6tFHH1VycrK5vCqn4VdF2Ws4dOiQ+c2oJOXm5iovL6/Cu7dUxtnG9pNPPlFpaanH5OzXY1umonH4/PPPPe7mBwDAxYz5zrldiPlO2RnZ+/btK3fR7spu/8477+iqq66qMMQ7s3fp57H6wx/+YC4/fvx4ubv0/ZayL+O+++47j96Dg4PP2fv5BnlNmzbVJZdccs67Jb///vuaNGmSJkyYYN6N8EyXXHKJPv74Y1177bX14stT1F38ngJAlfz6NO7GjRurffv2Hr9vb9SokSQpLy/Po3bQoEEqKSnRokWLPJbPmzdPXl5euv766yVJDodDkvTss8961D3zzDOV7rPsG79ff8M3f/78Su/j9xg0aFCFxyv7Vupsd9Y5m0aNGlV4Kv6gQYPkdDq1atUqc9np06f1zDPPqHHjxrr66qs96tesWaNvv/3WfL59+3Zt27bN/BsAAHAxY75TORdivtOjRw9FRERo/vz55ca2Mmdu/eUvf1FJSYkef/zxcutOnz5t7jM2NlYNGjTQM88847Hfisbu/fffr/CujWXX1OrYsaOkn/+mNptNTzzxRIX1x48fN//5t94/H3/8cYU/L/3666/16aefmseqyHfffae//OUv6tu3r+bMmVNhzV/+8hd9++23HtfCKvPTTz+poKDgN/cPVCfOlAJQJV26dNEf//hHRUVFqVmzZtq5c6f+9a9/aezYsWZNVFSUJOn++++Xw+GQj4+Phg4dqhtvvFEDBgzQww8/rP/+97/q1q2bNm7cqP/85z+aMGGC+e1SVFSUBg8erPnz5+v//u//zFskf/7555Iq982SzWZT//79NXv2bBUXF+t//ud/tHHjRuXk5FyAUSmvW7duGj58uJYuXaq8vDxdffXV2r59u5YvX674+HgNGDCgSvuNiorSqlWrlJSUpF69eqlx48a68cYbNXr0aD333HMaMWKEsrOz1a5dO/3rX//Shx9+qPnz55e7rkX79u3Vt29f3XfffSosLNT8+fPVvHlzTZkypTpePgAAdRrzncq5EPMdb29vLVmyRDfeeKO6d++ukSNHqlWrVjpw4ID279+vDRs2nHX7q6++Wvfee69SUlK0Z88eDRw4UA0aNNChQ4e0evVqLViwQLfeeqtatmypSZMmKSUlRTfccIMGDRqk3bt3a/369eUuW/DUU08pOztbt9xyi3ldsV27dunll19Ws2bNzIuj22w2LVmyRHfeead69OihoUOHqmXLljp8+LDWrVunq666ygwrf+v9k5GRoRkzZujPf/6zevfurcaNG+urr77Siy++qMLCQs2cOfM3X/v999+v48ePa8qUKXrttdc81l1++eW6/PLLdeedd+r111/XmDFj9O677+qqq65SSUmJDhw4oNdff10bNmzgcgywRk3d9g9AzSm7RfKOHTsqXH/11Vef8xbJs2bNMq688kojKCjICAwMNDp16mT8/e9/N4qKisya06dPG+PGjTNatmxpeHl5edyq9ocffjAmTpxohIWFGQ0aNDA6dOhgzJkzx+NWvIZhGAUFBUZiYqLRrFkzo3HjxkZ8fLxx8OBBQ5LHLYvLboV7/Pjxcq/nm2++MW6++WYjKCjIsNvtxm233WYcPXr0N2+z/Ot9/Natiysap4oUFxcbjz76qBEREWE0aNDACA8PN6ZNm2acOnWqUsepSH5+vnHHHXcYQUFB5q2Cy+Tm5hojR440WrRoYfj5+RmRkZHGSy+95LF9Tk6OIcmYM2eOMXfuXCM8PNzw9/c3+vXrZ3z88ccetWcb2zOd630FAICVmO/U/fmOYRjGBx98YPzpT38ymjRpYjRq1Mi4/PLLjWeeeabS+1u6dKkRFRVlBAYGGk2aNDEiIyONKVOmGEePHjVrSkpKjEcffdRo1aqVERgYaPzxj3809u3bV+798OGHHxqJiYlG165dDbvdbjRo0MBo06aNMWLECOPLL78sd+x3333XcDgcht1uNwICAoxLLrnEGDFihLFz506z5rfeP1999ZWRnJxs9O7d2wgODjZ8fX2Nli1bGnFxccamTZs8jlP2Ny1z9dVXG5IqfJz5XigqKjKeeuop47LLLjP8/f2Npk2bGlFRUcajjz5quFyuc/9xgGrgZRiVvGodANQSe/bs0RVXXKFXX321wt/I49z++9//KiIiQnPmzNGkSZNquh0AAPArzHcAXAy4phSAWu2nn34qt2z+/Pny9vZW//79a6AjAACA6sV8B8DFimtKAajVZs+erezsbA0YMEC+vr5av3691q9fr9GjR3OrWgAAUC8w3wFwsSKUAlCr9enTRxkZGXr88ceVn5+vNm3aaObMmXr44YdrujUAAIBqwXwHwMWKa0oBAAAAAADAclxTCgAAAAAAAJYjlAIAAAAAAIDluKZUNSktLdXRo0fVpEkTeXl51XQ7AACgCgzD0A8//KCwsDB5e/PdXU1gTgUAQN1X2TkVoVQ1OXr0KHfGAACgnjhy5Ihat25d021clJhTAQBQf5xrTkUoVU2aNGki6ecBt9lsNdwNAACoCrfbrfDwcPNzHdZjTgUAQN1X2TkVoVQ1KTu93GazMYECAKCO42djNYc5FQAA9ce55lRcLAEAAAAAAACWI5QCAAAAAACA5QilAAAAAAAAYDlCKQAAAAAAAFiOUAoAAAAAAACWI5QCAAAAAACA5QilAAAAAAAAYDlCKQAAAAAAAFiOUAoAAAAAAACWI5QCAAAAAACA5QilAAAAAAAAYDlCKQAAAAAAAFiOUAoAAAAAAACWI5QCAAAAAACA5QilAAAAAAAAYDlCKQAAAAAAAFiOUAoAAAAAAACWI5QCAAAAAACA5QilAAAAAAAAYDlCKQAAAAAAAFiOUAoAAAAAAACW863pBgAAwMUpIW1HlbddNqJXNXaCiwnvOwAAag/OlAIAAAAAAIDlCKUAAAAAAABgOUIpAAAAAAAAWI5QCgAAAAAAAJYjlAIAAAAAAIDlCKUAAAAAAABgOUIpAAAAAAAAWI5QCgAAAAAAAJYjlAIAAAAAAIDlCKUAAAAAAABgOUIpAAAAAAAAWI5QCgAAAAAAAJYjlAIAAAAAAIDlCKUAAAAAAABgOUIpAAAAAAAAWI5QCgAAAAAAAJYjlAIAAAAAAIDlCKUAAAAAAABgOUIpAAAAAAAAWI5QCgAAAAAAAJYjlAIAAAAAAIDlCKUAAAAAAABgOUIpAAAAAAAAWI5QCgAAAAAAAJYjlAIAAAAAAIDlCKUAAAAAAABgOUIpAAAAAAAAWK5GQ6l27drJy8ur3CMxMVGSdOrUKSUmJqp58+Zq3LixBg8erNzcXI99HD58WHFxcWrYsKGCg4M1efJknT592qPmvffeU48ePeTv76/27dsrLS2tXC+LFy9Wu3btFBAQoOjoaG3fvv2CvW4AAIDK2rJli2688UaFhYXJy8tLa9asKVfz2Wef6c9//rPsdrsaNWqkXr166fDhw+Z65lQAAKA2qtFQaseOHfruu+/MR0ZGhiTptttukyRNnDhRb731llavXq3Nmzfr6NGjuuWWW8ztS0pKFBcXp6KiIm3dulXLly9XWlqakpOTzZqcnBzFxcVpwIAB2rNnjyZMmKB77rlHGzZsMGtWrVqlpKQkzZgxQ7t27VK3bt3kcDh07Ngxi0YCAACgYgUFBerWrZsWL15c4fovv/xSffv2VadOnfTee+/pk08+0SOPPKKAgACzhjkVAACojbwMwzBquokyEyZM0Nq1a3Xo0CG53W61bNlSK1eu1K233ipJOnDggDp37qysrCz17t1b69ev1w033KCjR48qJCREkpSamqoHH3xQx48fl5+fnx588EGtW7dO+/btM48zdOhQ5eXlKT09XZIUHR2tXr16adGiRZKk0tJShYeHa9y4cZo6dWqFvRYWFqqwsNB87na7FR4eLpfLJZvNdkHGBwCA+iQhbUeVt102olc1dvILt9stu91eaz/Pvby89MYbbyg+Pt5cNnToUDVo0ECvvPJKhdu4XC7mVGeoje87AADqm8rOqWrNNaWKior06quv6u6775aXl5eys7NVXFys2NhYs6ZTp05q06aNsrKyJElZWVmKjIw0J0+S5HA45Ha7tX//frPmzH2U1ZTto6ioSNnZ2R413t7eio2NNWsqkpKSIrvdbj7Cw8N//yAAAACch9LSUq1bt06XXnqpHA6HgoODFR0d7fETP+ZUAACgtqo1odSaNWuUl5enESNGSJKcTqf8/PwUFBTkURcSEiKn02nWnDl5Kltftu5sNW63Wz/99JO+//57lZSUVFhTto+KTJs2TS6Xy3wcOXLkvF8zAADA73Hs2DHl5+frySef1HXXXaeNGzfq5ptv1i233KLNmzdLYk4FAABqL9+abqDMsmXLdP311yssLKymW6kUf39/+fv713QbAADgIlZaWipJuummmzRx4kRJUvfu3bV161alpqbq6quvrsn2KoU5FQAAF69acabU119/rXfeeUf33HOPuSw0NFRFRUXKy8vzqM3NzVVoaKhZ8+s7x5Q9P1eNzWZTYGCgWrRoIR8fnwpryvYBAABQG7Vo0UK+vr7q0qWLx/LOnTubd99jTgUAAGqr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aNAgffPNNwoLC9OSJUv08MMPy+l0ys/Pzzz2mjVrdODAAUnSkCFDVFBQoLVr15rH7927t7p3767U1NRKvZ4L/Teoje87AADqm8p+nnOmFAAAQB325ptvqmfPnrrtttsUHBysK664Qs8//7y5PicnR06nU7GxseYyu92u6OhoZWVlSZKysrIUFBRkBlKSFBsbK29vb23bts2s6d+/vxlISZLD4dDBgwd18uRJs+bM45TVlB2nIoWFhXK73R4PAABwcSCUAgAAqMO++uorLVmyRB06dNCGDRt033336f7779fy5cslSU6nU5IUEhLisV1ISIi5zul0Kjg42GO9r6+vmjVr5lFT0T7OPMZv1ZStr0hKSorsdrv5CA8PP6/XDwAA6i5CKQAAgDqstLRUPXr00BNPPKErrrhCo0eP1qhRoyr9c7maNm3aNLlcLvNx5MiRmm4JAABYhFAKAACgDmvVqpW6dOnisaxz5846fPiwJCk0NFSSlJub61GTm5trrgsNDdWxY8c81p8+fVonTpzwqKloH2ce47dqytZXxN/fXzabzeMBAAAuDoRSAAAAddhVV12lgwcPeiz7/PPP1bZtW0lSRESEQkNDlZmZaa53u93atm2bYmJiJEkxMTHKy8tTdna2WbNp0yaVlpYqOjrarNmyZYuKi4vNmoyMDHXs2NG8019MTIzHccpqyo4DAABwJkIpAACAOmzixIn66KOP9MQTT+iLL77QypUrtXTpUiUmJkqSvLy8NGHCBM2aNUtvvvmm9u7dq7vuukthYWGKj4+X9POZVdddd51GjRql7du368MPP9TYsWM1dOhQhYWFSZLuuOMO+fn5KSEhQfv379eqVau0YMECJSUlmb2MHz9e6enpmjt3rg4cOKCZM2dq586dGjt2rOXjAgAAaj/fmm4AAAAAVderVy+98cYbmjZtmh577DFFRERo/vz5GjZsmFkzZcoUFRQUaPTo0crLy1Pfvn2Vnp6ugIAAs2bFihUaO3asrr32Wnl7e2vw4MFauHChud5ut2vjxo1KTExUVFSUWrRooeTkZI0ePdqs6dOnj1auXKnp06froYceUocOHbRmzRp17drVmsEAAAB1ipdhGEZNN1EfuN1u2e12uVwuroUAAEAlJKTtqPK2y0b0qsZOfsHnec270H+D2vi+AwCgvqns5zk/3wMAAAAAAIDlCKUA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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "pdf = first_credset.select(\"purityMinR2\", \"purityMeanR2\", \"topPP\", \"credSetSize\").toPandas()\n", + "plt.figure(figsize=(12, 12))\n", + "\n", + "# Histogram for purityMinR2\n", + "plt.subplot(2, 2, 1)\n", + "plt.hist(pdf[\"purityMinR2\"], bins=30, alpha=0.7)\n", + "plt.title(\"Histogram of purityMinR2\")\n", + "plt.xlabel(\"purityMinR2\")\n", + "plt.ylabel(\"Frequency\")\n", + "\n", + "# Histogram for purityMeanR2\n", + "plt.subplot(2, 2, 2)\n", + "plt.hist(pdf[\"purityMeanR2\"], bins=30, alpha=0.7)\n", + "plt.title(\"Histogram of purityMeanR2\")\n", + "plt.xlabel(\"purityMeanR2\")\n", + "plt.ylabel(\"Frequency\")\n", + "\n", + "# Histogram for topPP\n", + "plt.subplot(2, 2, 3)\n", + "plt.hist(pdf[\"topPP\"], bins=30, alpha=0.7)\n", + "plt.title(\"Histogram of topPP\")\n", + "plt.xlabel(\"topPP\")\n", + "plt.ylabel(\"Frequency\")\n", + "\n", + "# Histogram for credSetSize\n", + "plt.subplot(2, 2, 4)\n", + "plt.hist(pdf[\"credSetSize\"], bins=30, alpha=0.7)\n", + "plt.title(\"Histogram of credSetSize\")\n", + "plt.xlabel(\"credSetSize\")\n", + "plt.ylabel(\"Frequency\")\n", + "\n", + "# Adjust layout to prevent overlap\n", + "plt.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Filtering credible sets with qc function" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "24/08/07 13:49:35 WARN package: Truncated the string representation of a plan since it was too large. This behavior can be adjusted by setting 'spark.sql.debug.maxToStringFields'.\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Number of high quality credible sets: 220670\n", + "Number of unique studyIds in high quality credible sets: 4862\n" + ] + } + ], + "source": [ + "qc_credsets = SUSIE_inf.credible_set_qc(\n", + " susie_fm, study_index, ld_index, 1e-5, 0.25, 0.8\n", + ").persist()\n", + "\n", + "qc_credsets = (\n", + " qc_credsets.df.withColumn(\"credSetSize\", f.size(\"locus\"))\n", + " .withColumn(\n", + " \"locus\",\n", + " f.slice(order_array_of_structs_by_field(\"locus\", \"posteriorProbability\"), 1, 1)[\n", + " 0\n", + " ],\n", + " )\n", + " .withColumn(\"topPP\", f.col(\"locus\").getField(\"posteriorProbability\"))\n", + " .filter(~f.isnan(\"topPP\"))\n", + ")\n", + "\n", + "print(\"Number of high quality credible sets: \", qc_credsets.count())\n", + "print(\n", + " \"Number of unique studyIds in high quality credible sets: \",\n", + " qc_credsets.select(\"studyId\").distinct().count(),\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "-RECORD 0---------------------------\n", + " meanTopPP | 0.7351960328222914 \n", + " minTopPP | 0.002487989359821... \n", + " q1TopPP | 0.4347870006604458 \n", + " medianTopPP | 0.9884991069860085 \n", + " q3TopPP | 0.9999999989221352 \n", + " maxTopPP | 1.0 \n", + "\n", + "-RECORD 0------------------------------\n", + " meanCredSetSize | 11.30863667991574 \n", + " minCredSetSize | 1 \n", + " q1CredSetSize | 1 \n", + " medianCredSetSize | 2 \n", + " q3CredSetSize | 8 \n", + " maxCredSetSize | 2681 \n", + "\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "-RECORD 0--------------------------------\n", + " meanPurityMeanR2 | 0.9362013839231683 \n", + " minPurityMeanR2 | 0.50525100583065 \n", + " q1PurityMeanR2 | 0.8961545002734692 \n", + " medianPurityMeanR2 | 0.991509701456222 \n", + " q3PurityMeanR2 | 1.0 \n", + " maxPurityMeanR2 | 1.0 \n", + "\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[Stage 192:==================================================> (191 + 8) / 200]\r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "-RECORD 0--------------------------------\n", + " meanPurityMinR2 | 0.8346683610862959 \n", + " minPurityMinR2 | 0.25001241379266637 \n", + " q1PurityMinR2 | 0.6919444964125268 \n", + " medianPurityMinR2 | 0.9832675585945014 \n", + " q3PurityMinR2 | 1.0 \n", + " maxPurityMinR2 | 1.0 \n", + "\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + } + ], + "source": [ + "(\n", + " qc_credsets.select(\n", + " f.mean(\"topPP\").alias(\"meanTopPP\"),\n", + " f.min(\"topPP\").alias(\"minTopPP\"),\n", + " f.percentile_approx(\"topPP\", 0.25).alias(\"q1TopPP\"),\n", + " f.percentile_approx(\"topPP\", 0.5).alias(\"medianTopPP\"),\n", + " f.percentile_approx(\"topPP\", 0.75).alias(\"q3TopPP\"),\n", + " f.max(\"topPP\").alias(\"maxTopPP\"),\n", + " ).show(vertical=True)\n", + ")\n", + "(\n", + " qc_credsets.select(\n", + " f.mean(\"credSetSize\").alias(\"meanCredSetSize\"),\n", + " f.min(\"credSetSize\").alias(\"minCredSetSize\"),\n", + " f.percentile_approx(\"credSetSize\", 0.25).alias(\"q1CredSetSize\"),\n", + " f.percentile_approx(\"credSetSize\", 0.5).alias(\"medianCredSetSize\"),\n", + " f.percentile_approx(\"credSetSize\", 0.75).alias(\"q3CredSetSize\"),\n", + " f.max(\"credSetSize\").alias(\"maxCredSetSize\"),\n", + " ).show(vertical=True)\n", + ")\n", + "(\n", + " qc_credsets.select(\n", + " f.mean(\"purityMeanR2\").alias(\"meanPurityMeanR2\"),\n", + " f.min(\"purityMeanR2\").alias(\"minPurityMeanR2\"),\n", + " f.percentile_approx(\"purityMeanR2\", 0.25).alias(\"q1PurityMeanR2\"),\n", + " f.percentile_approx(\"purityMeanR2\", 0.5).alias(\"medianPurityMeanR2\"),\n", + " f.percentile_approx(\"purityMeanR2\", 0.75).alias(\"q3PurityMeanR2\"),\n", + " f.max(\"purityMeanR2\").alias(\"maxPurityMeanR2\"),\n", + " ).show(vertical=True)\n", + ")\n", + "(\n", + " qc_credsets.select(\n", + " f.mean(\"purityMinR2\").alias(\"meanPurityMinR2\"),\n", + " f.min(\"purityMinR2\").alias(\"minPurityMinR2\"),\n", + " f.percentile_approx(\"purityMinR2\", 0.25).alias(\"q1PurityMinR2\"),\n", + " f.percentile_approx(\"purityMinR2\", 0.5).alias(\"medianPurityMinR2\"),\n", + " f.percentile_approx(\"purityMinR2\", 0.75).alias(\"q3PurityMinR2\"),\n", + " f.max(\"purityMinR2\").alias(\"maxPurityMinR2\"),\n", + " ).show(vertical=True)\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABKUAAASlCAYAAAB5vWpLAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/TGe4hAAAACXBIWXMAAA9hAAAPYQGoP6dpAADrOUlEQVR4nOzde3yP9f/H8ednYwfs4LhZFnPIOSvHyTHLRAeiHzm0MYe+mQj5knKILORUZCmZikhJfZEshxRyGHIKJUWxUdgymdmu3x/ddvGxYZu5Pjs87rfb5/btc13vz3W9ruuzvp9Xz8/1eV82wzAMAQAAAAAAABZycnQBAAAAAAAAKHwIpQAAAAAAAGA5QikAAAAAAABYjlAKAAAAAAAAliOUAgAAAAAAgOUIpQAAAAAAAGA5QikAAAAAAABYjlAKAAAAAAAAliOUAgAAAAAAgOUIpYACqlKlSgoLC3N0GQXe1KlTVblyZTk7OyswMNDR5ZhatWqlVq1aOboMSVJ0dLRsNpt+/fVXR5cCAAA9kkXokQBkBaEUkA+k/0f9zp07M13fqlUr1alT57b3s3r1ao0bN+62t1NYrF27ViNGjNADDzygBQsWaNKkSY4u6YZOnjypcePGac+ePTneRqtWrWSz2VStWrVM18fExMhms8lms+mTTz7J8X6utXHjRnObNptNzs7OKleunLp06aIff/wxw/jly5era9euqly5sooVK6bq1atr2LBhOn/+fK7UAwDIW+iR8iZ6JHt3oke6XePGjbPrsYoWLapKlSrpueeey9A3Xbx4UXPmzFHbtm1Vvnx5eXh46L777tPcuXOVmprqmANAgVHE0QUAuDMOHz4sJ6fs5c6rV6/WnDlzaLqyaP369XJyctL8+fPl4uLi6HLsrF271u75yZMnNX78eFWqVOm2vq10c3PTzz//rO3bt6tRo0Z26xYtWiQ3NzddunTJbnmvXr3UrVs3ubq65ni/zz33nBo2bKiUlBTt3btXUVFR2rhxo/bv3y9fX19zXP/+/eXn56eePXvq7rvv1r59+zR79mytXr1au3btkru7e45rAAAUDPRIdx49UtZ6pLxg7ty5KlGihJKSkrRu3Tq9+eab2rVrl7777jtzzC+//KJBgwapTZs2Gjp0qDw9PfXVV1/p2Wef1ffff6+FCxc68AiQ3xFKAQXU7QQAjpKUlKTixYs7uowsO336tNzd3fNUs3Xx4kUVK1bsjtVUpUoVXblyRR999JFdw3Xp0iV99tln6tChgz799FO71zg7O8vZ2fm29tu8eXN16dLFfF69enX95z//0fvvv68RI0aYyz/55JMMl+TXr19foaGhWrRokfr27XtbdQAA8j96pDuPHilrPVJe0KVLF5UpU0aSNGDAAHXr1k1Lly61C9d8fX21b98+1a5d23zdgAED1KdPHy1YsEAvv/yyqlat6pD6kf/x8z2ggLp+voSUlBSNHz9e1apVk5ubm0qXLq1mzZopJiZGkhQWFqY5c+ZIkt2lvOmSkpI0bNgw+fv7y9XVVdWrV9frr78uwzDs9vvPP//oueeeU5kyZeTh4aHHHntMf/zxh2w2m923i+mXDB88eFDdu3dXyZIl1axZM0nS3r17FRYWpsqVK8vNzU2+vr7q06eP/vrrL7t9pW/jyJEj6tmzp7y8vFS2bFm9/PLLMgxDJ06c0OOPPy5PT0/5+vpq2rRpWTp3V65c0YQJE1SlShW5urqqUqVKevHFF5WcnGyOsdlsWrBggZKSksxzFR0dfcNtpv98IDY2Vk2bNpW7u7sCAgIUFRVlN+5G8y+l/4xt48aNmW6zRYsWKlasmF588UVzXXo4s3HjRjVs2FCS1Lt3b7t6x44dq6JFi+rMmTMZau7fv7+8vb0zfKv31FNPaenSpUpLSzOX/e9//9PFixf1f//3fxm2k9kxVapUSY888oi+++47NWrUSG5ubqpcubLef//9G57DazVv3lySdPToUbvlmc0R0alTJ0nK9Od+AIDChx6JHimv9EiS9Mcff6hPnz7y8fGRq6urateurffee89uzOXLlzVmzBjVr19fXl5eKl68uJo3b64NGzbYjfv1119ls9n0+uuva968eeb71LBhQ+3YsSPT/V8vsx6rTJkydoFUOnos5AZCKSAfSUhI0J9//pnhkZKScsvXjhs3TuPHj1fr1q01e/ZsjR49Wnfffbd27dol6d9vOx566CFJ0gcffGA+JMkwDD322GOaMWOG2rVrp+nTp6t69ep64YUXNHToULv9hIWF6c0331T79u01efJkubu7q0OHDjes68knn9TFixc1adIk9evXT9K/v7v/5Zdf1Lt3b7355pvq1q2blixZovbt22do8CSpa9euSktL02uvvabGjRtr4sSJmjlzph566CHdddddmjx5sqpWrarhw4dr06ZNtzxXffv21ZgxY3T//fdrxowZatmypSIjI9WtWzdzzAcffKDmzZvL1dXVPFctWrS46XbPnTun9u3bq379+poyZYoqVKig//znPxkaj+z466+/9PDDDyswMFAzZ85U69atM4ypWbOmXnnlFUn/NlHX1turVy9duXJFS5cutXvN5cuX9cknn6hz585yc3OzW9e9e3edOnXKrvlbvHix2rRpo3LlymW59p9//lldunTRQw89pGnTpqlkyZIKCwvTgQMHbvna9Ia0ZMmStxwbFxcnSea3gACAgoceiR7pevmhR4qPj1eTJk309ddfKyIiQrNmzVLVqlUVHh6umTNnmuMSExP17rvvqlWrVpo8ebLGjRunM2fOKCQkJNO5sBYvXqypU6dqwIABmjhxon799Vc98cQTWfr3gR4LljMA5HkLFiwwJN30Ubt2bbvXVKxY0QgNDTWf16tXz+jQocNN9zNw4EAjs/9bWLFihSHJmDhxot3yLl26GDabzfj5558NwzCM2NhYQ5IxZMgQu3FhYWGGJGPs2LHmsrFjxxqSjKeeeirD/i5evJhh2UcffWRIMjZt2pRhG/379zeXXblyxahQoYJhs9mM1157zVx+7tw5w93d3e6cZGbPnj2GJKNv3752y4cPH25IMtavX28uCw0NNYoXL37T7aVr2bKlIcmYNm2auSw5OdkIDAw0ypUrZ1y+fNkwjKvv9bFjx+xev2HDBkOSsWHDhgzbjIqKynR/LVu2NJ/v2LHDkGQsWLAgw9igoCCjcePGdsuWL1+e6f7S/84aNGhghIeHG4bx77l1cXExFi5caNa5bNky83WZHVPFihUzvJ+nT582XF1djWHDhmU47vfee884c+aMcfLkSWPNmjVG1apVDZvNZmzfvj3D8VwvPDzccHZ2No4cOXLLsQCA/IUeiR4pP/dI4eHhRvny5Y0///zTbh/dunUzvLy8zPf7ypUrRnJyst2Yc+fOGT4+PkafPn3MZceOHTMkGaVLlzbOnj1rLv/8888NScb//vc/c1n638jhw4eNM2fOGL/++qvx3nvvGe7u7kbZsmWNpKSkDOfjWsnJyUatWrWMgIAAIyUl5aZjgZvhSikgH5kzZ45iYmIyPO69995bvtbb21sHDhzQTz/9lO39rl69Ws7Oznruuefslg8b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AABAYZSjOaW++OILu+eGYejUqVOaPXu2HnjggVwpDAAAoKChhwIAALgqR6FUx44d7Z7bbDaVLVtWDz74oKZNm5YbdQEAABQ49FAAAABX5SiUSktLy+06AAAACjx6KAAAgKtydU4pAAAAAAAAICtydKXU0KFDszx2+vTpOdkFAABAgUMPBQAAcFWOQqndu3dr9+7dSklJUfXq1SVJR44ckbOzs+6//35znM1my50qAQAACgB6KAAAgKtyFEo9+uij8vDw0MKFC1WyZElJ0rlz59S7d281b95cw4YNy9UiAQAACgJ6KAAAgKtyNKfUtGnTFBkZaTZTklSyZElNnDiRO8cAAADcAD0UAADAVTkKpRITE3XmzJkMy8+cOaO///77tosCAAAoiOihAAAArspRKNWpUyf17t1by5cv1++//67ff/9dn376qcLDw/XEE0/kdo0AAAAFAj0UAADAVTmaUyoqKkrDhw9X9+7dlZKS8u+GihRReHi4pk6dmqsFAgAAFBT0UAAAAFflKJQqVqyY3nrrLU2dOlVHjx6VJFWpUkXFixfP1eIAAAAKEnooAACAq3L08710p06d0qlTp1StWjUVL15chmHkVl0AAAAFFj0UAABADkOpv/76S23atNE999yj9u3b69SpU5Kk8PBwbmUMAABwA/RQAAAAV+UolHr++edVtGhRHT9+XMWKFTOXd+3aVWvWrMm14gAAAAoSeigAAICrcjSn1Nq1a/XVV1+pQoUKdsurVaum3377LVcKAwAAKGjooQAAAK7K0ZVSSUlJdt/upTt79qxcXV1vuygAAICCiB4KAADgqhyFUs2bN9f7779vPrfZbEpLS9OUKVPUunXrXCsOAACgIKGHAgAAuCpHP9+bMmWK2rRpo507d+ry5csaMWKEDhw4oLNnz2rz5s25XSMAAECBQA8FAABwVY6ulKpTp46OHDmiZs2a6fHHH1dSUpKeeOIJ7d69W1WqVMntGgEAAAoEeigAAICrsn2lVEpKitq1a6eoqCiNHj36TtQEAABQ4NBDAQAA2Mv2lVJFixbV3r1770QtAAAABRY9FAAAgL0c/XyvZ8+emj9/fm7XAgAAUKDRQwEAAFyVo4nOr1y5ovfee09ff/216tevr+LFi9utnz59eq4UBwAAUJDQQwEAAFyVrVDql19+UaVKlbR//37df//9kqQjR47Y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HR2tPn366JFHHrHbdkpKisqVK6f58+eby+6//375+/tr+fLl5rLly5fr7rvv1n333ZfheK79+V6lSpU0adIk9enTRx4eHrr77rs1b968DOfB29tbvr6+uueeezRhwgRduXJFGzZsMNfPnDlTI0aMUMOGDVWtWjVNmjRJ1apV0//+978sn2sAAJC/FLQ+KS0tTZGRkQoICJC7u7vq1aunTz75xFyfmpqq8PBwc3316tUzXL0UFhamjh076vXXX1f58uVVunRpDRw4UCkpKXbjihUrJl9fX1WsWFG9e/fWvffeq5iYGHN9nz59NGvWLLVs2VKVK1dWz5491bt3b7vjAJBzhFIA8o2FCxeqSJEi2r59u2bNmqXp06fr3XffzdY2Ro4cqcGDB+vHH39USEiI3bquXbtq2LBhql27tk6dOqVTp06pa9eu6tu3r9asWaNTp06ZY1euXKmLFy+qa9eudtvo06ePFixYYD5/77331Lt37yzVNm3aNDVo0EC7d+/Ws88+q//85z86fPhwpmOvXLliNnouLi433GZaWpr+/vtvlSpVKks1AACA/Kkg9UmRkZF6//33FRUVpQMHDuj5559Xz5499c0330j6t7+pUKGCli1bpoMHD2rMmDF68cUX9fHHH9ttZ8OGDTp69Kg2bNighQsXKjo62gzirmcYhr799lsdOnTopr2VJCUkJNBbAbmkiKMLAICs8vf314wZM2Sz2VS9enXt27dPM2bMUL9+/bK8jSFDhuiJJ57IdJ27u7tKlCihIkWKyNfX11zetGlTVa9eXR988IFGjBgh6d+f0T355JMqUaKE3TZ69uypUaNG6bfffpMkbd68WUuWLNHGjRtvWVv79u317LPPSpL++9//asaMGdqwYYOqV69ujnnqqafk7Oysf/75R2lpaapUqZL+7//+74bbfP3113XhwoWbjgEAAPlfQemTkpOTNWnSJH399dcKCgqSJFWuXFnfffed3n77bbVs2VJFixbV+PHjzdcEBARo69at+vjjj+16npIlS2r27NlydnZWjRo11KFDB61bt87unLz11lt69913dfnyZaWkpMjNzU3PPffcDc/Rli1btHTpUq1atepWpxNAFnClFIB8o0mTJrLZbObzoKAg/fTTT0pNTc3yNho0aJCjffft29f8Zi8+Pl5ffvml+vTpk2Fc2bJl1aFDB0VH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kydr0aJFGj58uBo2bKgWLVrc9Fz17dtXCxcuVJcuXTRs2DBt27ZNkZGR+vHHH/XZZ59Jkj744APNmzdP27dv17vvvitJatq0aabbGz16tBISEvT777+b56pEiRKS/m10W7VqpZ9//lkREREKCAjQsmXLFBYWpvPnz2vw4MF223r//ff1999/a+DAgbp06ZJmzZqlBx98UPv27ZOPj89Njyu9gSpdunSujAMA4HbR2+TP3ib9mB555BGVL19egwcPlq+vr3788UetXLnSrn+5cuWKQkJC1KxZM73++uvm1AADBgxQdHS0evfureeee07Hjh3T7NmztXv3bm3evFlFixaVJI0ZM0YTJ05U+/bt1b59e+3atUtt27a1uxpJkipWrKivv/5a69evN79gu5EPPvhAoaGhCgkJ0eTJk3Xx4kXNnTtXzZo10+7du1WpUqWb/v2kB1/vv/++XnrppWxNZD5gwAAFBwfbLVuzZo0WLVpkhmdpaWl67LHH9N1336l///6qWbOm9u3bpxkzZujIkSNasWJFlvcH5IgBANdYsGCBIemmj9q1a9u9pmLFikZoaKj5vF69ekaHDh1uup+BAwcamf1f0IoVKwxJxsSJE+2Wd+nSxbDZbMbPP/9sGIZhxMbGGpKMIUOG2I0LCwszJBljx441l40dO9aQZDz11FMZ9nfx4sUMyz766CNDkrFp06YM2+jfv7+57MqVK0aFChUMm81mvPbaa+byc+fOGe7u7nbnJDN79uwxJBl9+/a1Wz58+HBDkrF+/XpzWWhoqFG8ePGbbi9dhw4djIoVK2ZYPnPmTEOS8eGHH5rLLl++bAQFBRklSpQwEhMTDcMwjGPHjhmSDHd3d+P33383x27bts2QZDz//PPmsvTzcvjwYePMmTPGsWPHjLfffttwdXU1fHx8jKSkJMMwrv5dff3118aZM2eMEydOGEuWLDFKly6dYT8AAOQmepv83dtcuXLFCAgIMCpWrGicO3fObl1aWprd9iQZI0eOtBvz7bffGpKMRYsW2S1fs2aN3fLTp08bLi4uRocOHey2++KLLxqS7I59//79hru7uyHJCAwMNAYPHmysWLHC7HvS/f3334a3t7fRr18/u+VxcXGGl5eX3fIb/f1cvHjRqF69uiHJqFixohEWFmbMnz/fiI+PzzA2/T29kZ9++snw8vIyHnroIePKlSuGYRjGBx98YDg5ORnffvut3dioqChDkrF58+Ybbg/IDfx8D0Cm5syZo5iYmAyPe++995av9fb21oEDB/TTTz9le7+rV6+Ws7OznnvuObvlw4YNk2EY+vLLLyX9+y2PJD377LN24wYNGnTDbT/zzDMZlrm7u5v/fOnSJf35559q0qSJJGnXrl0Zxvft29f8Z2dnZzVo0ECGYSg8PNxc7u3trerVq+uXX365YS3Sv8cqSUOHDrVbPmzYMEnSqlWrbvr67Fq9erV8fX3t5m4qWrSonnvuOV24cEHffPON3fiOHTvqrrvuMp83atRIjRs3Nuu+VvXq1VW2bFkFBARowIABqlq1qlatWpVh8vLg4GCVLVtW/v7+6tatm0qUKKHPPvvMbj8AANwJ9Db5s7fZvXu3jh07piFDhsjb29tuXWZXDf3nP/+xe75s2TJ5eXnpoYce0p9//mk+6tevrxIlSmjDhg2SpK+//lqXL1/WoEGD7Lab2Y1jateurT179qhnz5769ddfNWvWLHXs2FE+Pj565513zHExMTE6f/68nnrqKbt9Ozs7q3Hjxua+b8bd3V3btm3TCy+8IOnfu0mGh4erfPnyGjRoUJZ/YpeUlKROnTqpZMmS+uijj+Ts7Gyen5o1a6pGjRp2NaZfAZaVGoHbwc/3AGSqUaNG5oTU1ypZsmSml75f65VXXtHjjz+ue+65R3Xq1FG7du3Uq1evLDV9v/32m/z8/OTh4WG3vGbNmub69P91cnL6//buPK6Kev/j+BtUFheOK9sVldxN3NCQ3K/8xCXLspualRpJC5RKpVmGW6Xh1bQ0bTGxm16Xe8tKjSRMrSQXlFxSUqOsq6ilcpIUEeb3Rw9Gj2AiwbC9no/HeeSZ+cycz/l2cL6+mTMjf39/h7omTZpcc99X10rS6dOnNXXqVK1YsSLPhSnT09Pz1Ddo0MDhuc1mk5ubm3mR7yuXX33thqvlvoere/b29lbNmjXN91pUfvzxRzVt2jTP3YSuHttcTZs2zbOPZs2aadWqVXmW//e//5WHh4eqVKmi+vXrq3Hjxvn2sGDBAjVr1kyVK1eWl5eXmjdvfsN3NwIAoDCY25TNuU3uV/1bt2593drKlSurfv36DssOHTqk9PT0fK/1JF2+MHlub1fPf+rVq6datWrl2a5Zs2b617/+pezsbH377bdau3atYmJiFB4eLn9/f4WEhJgh5rW+4nfl9aD+jM1mU0xMjGJiYvTjjz8qISFB//znPzV//nzZbDa98MIL193H6NGjdeTIEW3dutXhsgmHDh3SgQMHVK9evXy3K+oLtwNXI5QCUOS6d++uI0eO6MMPP9SGDRv09ttv65VXXtGiRYscfhtntSt/c5jrnnvu0datW/X000+rXbt2ql69unJyctS3b1/l5OTkqc/9rdL1lknKc/HSa7mRawOUVt27d88zec3Ptf5BAABAacbc5g+lfW7j6uqa55ddOTk58vT01LJly/Ld5lphTEFVqlRJAQEBCggIUHBwsHr16qVly5YpJCTEHO9//etf8vb2zrNtYe6U17BhQz344IO68847ddNNN2nZsmXXDaXmzZunf//733rvvffUrl07h3U5OTkKCAjQnDlz8t3Wz8/vhnsEbgShFIBiUbt2bY0aNUqjRo3SuXPn1L17d02ZMsWcuF1rspJ74cjffvvN4TeKBw8eNNfn/jcnJ0epqakOv9E6fPhwgXs8c+aMEhISNHXqVEVHR5vLC3NqfmHkvodDhw6Zvy2VpBMnTujs2bP53tGlIP5sbPfs2aOcnByHCdvVY5srv3H47rvvHO7mBwBARcHc5vqKY26Te/b1vn378ly0u6Dbf/bZZ+rSpUu+Id6VvUt/jNVNN91kLj916lSeu/RdS+4v3o4fP+7Qu6en53V7v9Egr1atWmrcuPF174z8xRdf6KmnntLYsWPNuxFeqXHjxvrmm2/Uu3fvcvGLUpQ9fGcCQJG7+tTu6tWrq0mTJg7fea9WrZok6ezZsw61/fv3V3Z2tubPn++w/JVXXpGTk5P69esnSQoNDZUkvf766w51r732WoH7zP0t4NW/9Zs7d26B9/FX9O/fP9/Xy/1N1Z/dbefPVKtWLd/T8/v376+0tDStXLnSXHbp0iW99tprql69unr06OFQv2bNGv3vf/8zn2/fvl3btm0z/x8AAFBRMLcpmOKY23To0EH+/v6aO3dunrEtyJlb99xzj7KzszV9+vQ86y5dumTuMyQkRFWqVNFrr73msN/8xu6LL77I966NudfUat68uaQ//p96eHjopZdeyrf+1KlT5p+v9fn55ptv8v166Y8//qhvv/3WfK38HD9+XPfcc4+6du2qWbNm5Vtzzz336H//+5/DtbBynT9/XhkZGdfcP1AUOFMKQJFr1aqVevbsqcDAQNWuXVs7d+7Uf/7zH0VGRpo1gYGBkqQnnnhCoaGhqlSpkoYOHaqBAweqV69eeu655/TDDz+obdu22rBhgz788EONHTvW/I1TYGCgBg8erLlz5+rXX381b5v83XffSSrYb5s8PDzUvXt3xcTEKCsrS3/729+0YcMGpaamFsOo5NW2bVuNGDFCb775ps6ePasePXpo+/btWrp0qQYNGqRevXoVar+BgYFauXKloqKi1KlTJ1WvXl0DBw5UeHi43njjDY0cOVJJSUlq1KiR/vOf/+irr77S3Llz81zrokmTJurataseffRRZWZmau7cuapTp47Gjx9fFG8fAIAyg7lNwRTH3MbZ2VkLFy7UwIED1a5dO40aNUo+Pj46ePCg9u/fr08//fRPt+/Ro4cefvhhzZgxQ8nJyerTp4+qVKmiQ4cOafXq1Zo3b57uvvtu1atXT0899ZRmzJih2267Tf3799fu3bv1ySef5LlEwcsvv6ykpCTddddd5nXFdu3apXfffVe1a9c2L47u4eGhhQsX6v7771eHDh00dOhQ1atXT0ePHtW6devUpUsXM6y81ucnPj5ekydP1u23367OnTurevXq+v777/XOO+8oMzNTU6ZMueZ7f+KJJ3Tq1CmNHz9eK1ascFjXpk0btWnTRvfff79WrVqlRx55RJ9//rm6dOmi7OxsHTx4UKtWrdKnn37KpRdQvErqtn8ASqfc2ybv2LEj3/U9evS47m2TX3jhBeOWW24xatasabi7uxstWrQwXnzxRePixYtmzaVLl4zHH3/cqFevnuHk5ORw+9rffvvNGDdunOHr62tUqVLFaNq0qTFr1iyH2/MahmFkZGQYERERRu3atY3q1asbgwYNMlJSUgxJDrcxzr097qlTp/K8n59//tm48847jZo1axo2m834xz/+YRw7duyat16+eh/Xup1xfuOUn6ysLGPq1KmGv7+/UaVKFcPPz8+YOHGiceHChQK9Tn7OnTtn3HvvvUbNmjXN2wfnOnHihDFq1Cijbt26houLixEQEGAsWbLEYfvU1FRDkjFr1ixj9uzZhp+fn+Hq6mp069bN+Oabbxxq/2xsr3S9zxUAAMWFuU3Zn9sYhmF8+eWXxv/93/8ZNWrUMKpVq2a0adPGeO211wq8vzfffNMIDAw03N3djRo1ahgBAQHG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lJaWZl7M85lnntGaNWt08OBBSdKQIUOUkZGhtWvXmr107txZ7dq106JFiwr0fux2u2w2m9LT0+Xh4VEkYwQAQHkSFruj0NsuHtmpCDu5rDQev8+dO2ee9dS+fXvNmTNHvXr1Uu3atVW7dm1NnTpVgwcPlre3t44cOaLx48frt99+0969e82vxvXr108nTpzQokWLlJWVpVGjRqljx45avny5pD/mVM2bN1efPn00YcIE7du3Tw8++KBeeeUV85d7W7duVY8ePTRz5kwNGDBAK1as0EsvvaRdu3apdevWkv74JePMmTO1dOlS+fv76/nnn9eePXv07bffys3N7brvtbjHvzR+5gAAKOsKevwu1WdK3XrrrUpISNB3330nSfrmm2/05ZdfmrdALsgdXay6u0x+MjMzZbfbHR4AAAB/1c6dO9W+fXu1b99ekhQVFaX27dsrOjpalSpV0p49e3T77berWbNmCgsLU2BgoL744guHazUtW7ZMLVq0UO/evdW/f3917drV4Sxxm82mDRs2KDU1VYGBgXryyScVHR3tcLb5rbfequXLl+vNN99U27Zt9Z///Edr1qwxAylJGj9+vB5//HGFh4erU6dOOnfunOLi4goUSAEAgPKtVF/o/JlnnpHdbleLFi1UqVIlZWdn68UXX9Tw4cMlFeyOLgW9u4y/v3+efeSuq1Wr1nXvLpOfGTNmaOrUqTf6tgEAAP5Uz5499Wcnu3/66afX3Uft2rXNs6KupU2bNvriiy/+tOYf//iH/vGPf1xzvZOTk6ZNm6Zp06ZdtycAAFCxlOozpVatWqVly5Zp+fLl2rVrl5YuXap//vOfWrp0aUm3ViDc0hgAAAAAACB/pfpMqaefflrPPPOMeVvjgIAA/fjjj5oxY4ZGjBjhcEeX3At35j5v166dJOvuLpMfbmkMAAAAAACQv1J9ptTvv/8uZ2fHFitVqqScnBxJBbuji1V3lwEAAAAAAEDBlepQauDAgXrxxRe1bt06/fDDD/rggw80Z84c3XnnnZL+uEbB2LFj9cILL+ijjz7S3r179cADD8jX11eDBg2SJLVs2VJ9+/bV6NGjtX37dn311VeKjIzU0KFD5evrK0m699575eLiorCwMO3fv18rV67UvHnzFBUVZfYyZswYxcXFafbs2Tp48KCmTJminTt3KjIy0vJxAQAAAAAAKOtK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51BpaWmSJC8vL4flXl5e5rq0tDR5eno6rK9cubJq167tUJPfPq58jWvVXLn+er1cbeLEiUpPTzcfP/30UwHeNQAAKIsKFUr9+uuv6t27t5o1a6b+/fvr+PHjkqSwsDBuZQwAAHANzKGuz9XVVR4eHg4PAABQPhUqlBo3bpyqVKmio0ePqmrVqubyIUOGKC4ursiaAwAAKE+smEN5e3tLkk6cOOGw/MSJE+Y6b29vnTx50mH9pUuXdPr0aYea/PZx5Wtcq+bK9dfrBQAAVFyFCqU2bNigl19+WfXr13dY3rRpU/34449F0hgAAEB5Y8Ucyt/fX97e3kpISDCX2e12bdu2TcHBwZKk4OBgnT17VklJSWbNxo0blZOTo6CgILNmy5Yt5gXZJSk+Pl7NmzdXrVq1zJorXye3Jvd1CtILAACouAoVSmVkZDj8di/X6dOn5erq+pebAgAAKI+Kag517tw5JScnKzk5WdIfFxRPTk7W0aNH5eTkpLFjx+qFF17QRx99pL179+qBBx6Qr6+veYe+li1bqm/fvho9erS2b9+ur776SpGRkRo6dKh8fX0lSffee69cXFwUFham/fv3a+XKlZo3b56ioqLMPsaMGaO4uDjNnj1bBw8e1JQpU7Rz505FRkZKUoF6AQAAFVehQqlu3brp3XffNZ87OTkpJydHMTEx6tWrV5E1BwAAUJ4U1Rxq586dat++vdq3by9JioqKUvv27RUdHS1JGj9+vB5//HGFh4erU6dOOnfunOLi4uTm5mbuY9myZWrRooV69+6t/v37q2vXrnrzzTfN9TabTRs2bFBqaqoCAwP15JNPKjo6WuHh4WbNrbfequXLl+vNN99U27Zt9Z///Edr1qxR69atzZqC9AIAAComJ6MQt3vZt2+fevfurQ4dOmjjxo26/fbbtX//fp0+fVpfffWVGjduXBy9lnl2u102m03p6elctBMAgHyExe4o9LaLR3Yqwk4uK8rjN3OoG1fc86fS+JkDAKCsK+jxu1BnSrVu3VrfffedunbtqjvuuEMZGRm66667tHv3biZTAAAA18AcCgAA4LLKN7pBVlaW+vbtq0WLFum5554rjp4AAADKHeZQAAAAjm74TKkqVapoz549xdELAABAucUcCgAAwFGhvr533333afHixUXdCwAAQLnGHAoAAOCyG/76niRdunRJ77zz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v/3NmDlzplVv0VJ/Np6///670adPH6NevXpGlSpVjIYNGxqjR4/OEzYznn/IbxwlORwri+rnu6Icj683pkePHjW6d+9u1K5d23B1dTWaNGliPP3000Z6errDfiramDoZBt8VAAAAAAAAgLW4phQAAAAAAAAsRygFAAAAAAAAyxFKAQAAAAAAwHKEUgAAAAAAALAcoRQAAAAAAAAsRygFAAAAAAAAyxFKAQAAAAAAwHKEUgAAAAAAALAcoRQAAAAA4C/54Ycf5OTkpOTk5JJuRZLUs2dPjR07tqTbAHAdhFIAKrTimrD07NlTTk5OcnJykpubm1q1aqXXX3/dXB8bG2uud3Z2Vv369TVq1CidPHmyyHsBAAAoCR988IE6d+4sm82mGjVq6Oabb77heZeTk5PWrFnjsCw7O1szZ85UixYt5O7urtq1aysoKEhvv/22WfP+++9r+vTpRfAuABSnyiXdAACUV6NHj9a0adP0+++/691331VERIRq1aqlYcOGSZI8PDyUkpKinJwcffPNNxo1apSOHTumTz/9tIQ7BwAAFVVWVpaqVKnyl/eTkJCgIUOG6MUXX9Ttt98uJycnffvtt4qPj//L+546dareeOMNzZ8/Xx07dpTdbtfOnTt15swZs6Z27dp/+XUAFD/OlAJQYY0cOVKbN2/WvHnzzLOWfvjhB23evFm33HKLXF1d5ePjo2eeeUaXLl0yt+vZs6ciIyMVGRkpm82munXr6vnnn5dhGA77r1q1qry9vXXTTTdpypQpatq0qT766CNzvZOTk7y9veXr66t+/frpiSee0Geffabz589bNgYAAKD8y8nJUUxMjJo0aSJXV1c1aNBAL774ovmVu5UrV6pHjx5yc3PTsmXLJElvv/22WrZsKTc3N7Vo0cLhjG9J2r59u9q3by83Nzd17NhRu3fvdlj/8ccfq0uXLnr66afVvHlzNWvWTIMGDdKCBQsc6j788EN16NBBbm5uuummmzR16lRz3tWoUSNJ0p133iknJyfz+UcffaTHHntM//jHP+Tv76+2bdsqLCxMTz31lLnfK8+G37RpkznXu/IxcuTIAvUBoPhwphSACmvevHn67rvv1Lp1a02bNk3SH6eD9+/fXyNHjtS7776rgwcPavTo0XJzc9OUKVPMbZcuXaqwsDBt375dO3fuVHh4uBo0aKDRo0df8/Xc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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "pdf = qc_credsets.select(\"purityMinR2\", \"purityMeanR2\", \"topPP\", \"credSetSize\").toPandas()\n", + "plt.figure(figsize=(12, 12))\n", + "\n", + "# Histogram for purityMinR2\n", + "plt.subplot(2, 2, 1)\n", + "plt.hist(pdf[\"purityMinR2\"], bins=30, alpha=0.7)\n", + "plt.title(\"Histogram of purityMinR2\")\n", + "plt.xlabel(\"purityMinR2\")\n", + "plt.ylabel(\"Frequency\")\n", + "\n", + "# Histogram for purityMeanR2\n", + "plt.subplot(2, 2, 2)\n", + "plt.hist(pdf[\"purityMeanR2\"], bins=30, alpha=0.7)\n", + "plt.title(\"Histogram of purityMeanR2\")\n", + "plt.xlabel(\"purityMeanR2\")\n", + "plt.ylabel(\"Frequency\")\n", + "\n", + "# Histogram for topPP\n", + "plt.subplot(2, 2, 3)\n", + "plt.hist(pdf[\"topPP\"], bins=30, alpha=0.7)\n", + "plt.title(\"Histogram of topPP\")\n", + "plt.xlabel(\"topPP\")\n", + "plt.ylabel(\"Frequency\")\n", + "\n", + "# Histogram for credSetSize\n", + "plt.subplot(2, 2, 4)\n", + "plt.hist(pdf[\"credSetSize\"], bins=30, alpha=0.7)\n", + "plt.title(\"Histogram of credSetSize\")\n", + "plt.xlabel(\"credSetSize\")\n", + "plt.ylabel(\"Frequency\")\n", + "\n", + "# Adjust layout to prevent overlap\n", + "plt.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# WIP" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Clumped loci filtered for usage with PICS\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Number of unique studyIds\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "data": { + "text/plain": [ + "231" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pics_loci.df.select(\"studyId\").distinct().count()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Number of loci to fine map with PICS\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "data": { + "text/plain": [ + "9990" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pics_loci.df.count()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "df = pics_loci.df.withColumns(\n", + " {\n", + " \"locusSize\": f.size(\"locus\"),\n", + " \"locusLength\": f.col(\"locusEnd\") - f.col(\"locusStart\"),\n", + " }\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "How many loci with less than 100 variants from summary statistics?\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "data": { + "text/plain": [ + "985" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.filter(f.col(\"locusSize\") < 100).count()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "How many loci with more than 15,000 variants from summary statistics?\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "data": { + "text/plain": [ + "9005" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.filter(f.col(\"locusSize\") > 15_000).count()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "-RECORD 0------------------------------\n", + " meanLocusLength | 1294768.356956957 \n", + " q1LocusLength | 1231357 \n", + " medianLocusLength | 1500000 \n", + " q3LocusLength | 1500000 \n", + "\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[Stage 102:===================================================> (334 + 8) / 346]\r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "-RECORD 0-----------------------------\n", + " meanLocusSize | 18537.992992992993 \n", + " minLocusSize | 1 \n", + " q1LocusSize | 16779 \n", + " medianLocusSize | 19456 \n", + " q3LocusSize | 22436 \n", + " maxLocusSize | 39972 \n", + "\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + } + ], + "source": [ + "length = df.select(\n", + " f.mean(\"locusLength\").alias(\"meanLocusLength\"),\n", + " f.percentile_approx(\"locusLength\", 0.25).alias(\"q1LocusLength\"),\n", + " f.percentile_approx(\"locusLength\", 0.5).alias(\"medianLocusLength\"),\n", + " f.percentile_approx(\"locusLength\", 0.75).alias(\"q3LocusLength\"),\n", + ")\n", + "size = df.select(\n", + " f.mean(\"locusSize\").alias(\"meanLocusSize\"),\n", + " f.min(\"locusSize\").alias(\"minLocusSize\"),\n", + " f.percentile_approx(\"locusSize\", 0.25).alias(\"q1LocusSize\"),\n", + " f.percentile_approx(\"locusSize\", 0.5).alias(\"medianLocusSize\"),\n", + " f.percentile_approx(\"locusSize\", 0.75).alias(\"q3LocusSize\"),\n", + " f.max(\"locusSize\").alias(\"maxLocusSize\"),\n", + ")\n", + "length.show(vertical=True)\n", + "size.show(vertical=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABKMAAAJOCAYAAABr8MR3AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/TGe4hAAAACXBIWXMAAA9hAAAPYQGoP6dpAAB1ZklEQVR4nO3dd3gU1f7H8U8KKZQktDQJMdI7UoRciiCRALkKyr2KIgIGsSRKUUGuilRBRJoiWBDwJ1jwWkGBSBUNLRK6kaZBIcErJCEIISTn94dPBpcAQkhmU96v59lHd86Zme+ZXZbDZ2dnXIwxRgAAAAAAAIANXJ1dAAAAAAAAAMoOwigAAAAAAADYhjAKAAAAAAAAtiGMAgAAAAAAgG0IowAAAAAAAGAbwigAAAAAAADYhjAKAAAAAAAAtiGMAgAAAAAAgG0IowAAAAAAAGAbwiigmLv++us1YMAAZ5dR6r300ku64YYb5ObmpubNmzu7HFyBtWvXysXFRR999JGzSwEAlFDMs+zBPOvvLViwQC4uLvrpp5+cXQpgC8IowEZ5f8ls3br1ou2dOnVS48aNr3k/X375pcaMGXPN2ykrVq5cqREjRqhdu3aaP3++XnjhhUv2HTBggCpWrGhjdUXv+uuv1z//+U9nl3FJixcv1owZM5xdBgCgmGOeVTyV9XnW2bNnNXPmTN14443y8fGRn5+fGjVqpMGDB+uHH35wdnmA07g7uwAAl5eUlCRX16vLjb/88kvNnj2bidIVWr16tVxdXTVv3jx5eHg4uxxcYPHixdq1a5eGDh3q7FIAAKUM86yiV9bnWb1799ZXX32le+65Rw8++KCys7P1ww8/aOnSpfrHP/6h+vXrS5L69eunPn36yNPT08kVA/YgjAKKuZL4F9KpU6dUoUIFZ5dxxY4dOyZvb+8yOUECAKAsY55V9MryPGvLli1aunSpJk6cqP/85z8Oba+++qrS0tKs525ubnJzc7O5QsB5+JkeUMxdeC2D7OxsjR07VnXq1JGXl5eqVq2q9u3bKy4uTtKfpzfPnj1bkuTi4mI98pw6dUpPPPGEQkJC5OnpqXr16mnq1Kkyxjjs9/Tp03r88cdVrVo1VapUSbfffrt+/fVXubi4OHwTOGbMGLm4uGjPnj269957VblyZbVv316StGPHDg0YMEA33HCDvLy8FBgYqAceeEC///67w77ytvHjjz/qvvvuk6+vr6pXr67nnntOxhgdPnxYPXv2lI+PjwIDA/Xyyy9f0bE7d+6cxo8fr1q1asnT01PXX3+9/vOf/ygrK8vq4+Liovnz5+vUqVPWsVqwYMEVbf9ylixZopYtW8rb21vVqlXTfffdp19//TVfvx9++EF33XWXqlevLm9vb9WrV0/PPPOM1T5gwABdf/31+dbLO2Z/FRcXp/bt28vPz08VK1ZUvXr18k18rsW7775rjalKlSrq06ePDh8+7NAn7ycQe/bsUefOnVW+fHldd911mjJlSr7t/fzzz7r99ttVoUIF+fv7a9iwYVqxYoVcXFy0du1aa3vLli3Tzz//bL0+Fx6P3NxcTZw4UTVq1JCXl5e6dOmi/fv3F9q4AQClF/Ms5llFOc86cOCAJKldu3b52tzc3FS1alXr+YXXjMqr4WKPv75nc3NzNWPGDDVq1EheXl4KCAjQQw89pBMnTly2NsDZODMKcIL09HT973//y7c8Ozv7b9cdM2aMJk2apEGDBummm25SRkaGtm7dqu+//1633nqrHnroIR05ckRxcXH6v//7P4d1jTG6/fbbtWbNGkVHR6t58+ZasWKFnnrqKf3666+aPn261XfAgAH68MMP1a9fP7Vt21br1q1TVFTUJev697//rTp16uiFF16wJlxxcXE6ePCgBg4cqMDAQO3evVtvvPGGdu/erY0bN+b7S/7uu+9WgwYNNHnyZC1btkwTJkxQlSpV9Prrr+uWW27Riy++qEWLFunJJ59U69at1bFjx8seq0GDBmnhwoX617/+pSeeeEKbNm3SpEmTtHfvXn3yySeSpP/7v//TG2+8oc2bN+utt96SJP3jH//429fhchYsWKCBAweqdevWmjRpklJTUzVz5kx9++232rZtm/z8/CT9OYns0KGDypUrp8GDB+v666/XgQMH9MUXX2jixIlXtc/du3frn//8p5o2bapx48bJ09NT+/fv17fffntNY8kzceJEPffcc7rrrrs0aNAg/fbbb3rllVfUsWNHhzFJ0okTJ9StWzfdeeeduuuuu/TRRx9p5MiRatKkibp37y7pz8n6LbfcoqNHj2rIkCEKDAzU4sWLtWbNGof9PvPMM0pPT9cvv/xivT8vvJbE5MmT5erqqieffFLp6emaMmWK+vbtq02bNhXK2AEAJQvzLOZZUvGYZ4WGhkqSFi1apHbt2snd/cr/+X3nnXeqdu3aDssSEhI0Y8YM+fv7W8seeugh65g8/vjjOnTokF599VVt27ZN3377rcqVK3cVIwVsZADYZv78+UbSZR+NGjVyWCc0NNT079/fet6sWTMTFRV12f3ExMSYi/3x/vTTT40kM2HCBIfl//rXv4yLi4vZv3+/McaYhIQEI8kMHTrUod+AAQOMJPP8889by55//nkjydxzzz359vfHH3/kW/bee+8ZSWb9+vX5tjF48GBr2blz50yNGjWMi4uLmTx5srX8xIkTxtvb2+GYXExiYqKRZAYNGuSw/MknnzSSzOrVq61l/fv3NxUqVLjs9q6079mzZ42/v79p3LixOX36tLV86dKlRpIZPXq0taxjx46mUqVK5ueff3bYRm5ursP+QkND8+0n75jlmT59upFkfvvttysax1+FhoZe9j31008/GTc3NzNx4kSH5Tt37jTu7u4Oy2+++WYjybzzzjvWsqysLBMYGGh69+5tLXv55ZeNJPPpp59ay06fPm3q169vJJk1a9ZYy6Oioi56DNasWWMkmQYNGpisrCxr+cyZM40ks3PnzisaPwCgdGCexTyruM2zcnNzrblRQECAueeee8zs2bPz1WTM+ffvoUOHLrqt3377zdSsWdM0adLEZGZmGmOM+eabb4wks2jRIoe+y5cvv+hyoDjhZ3qAE8yePVtxcXH5Hk2bNv3bdf38/LR7927t27fvqvf75Zdfys3NTY8//rjD8ieeeELGGH311VeSpOXLl0uSHn30UYd+jz322CW3/fDDD+db5u3tbf3/mTNn9L///U9t27aVJH3//ff5+g8aNMj6fzc3N7Vq1UrGGEVHR1vL/fz8VK9ePR08ePCStUh/jlWShg8f7rD8iSeekCQtW7bssusX1NatW3Xs2DE9+uij8vLyspZHRUWpfv361n5/++03rV+/Xg888IBq1qzpsI0Lv8m8EnnfAn722WfKzc0t+AAu4uOPP1Zubq7uuusu/e9//7MegYGBqlOnTr6zmSpWrKj77rvPeu7h4aGbbrrJ4TVbvny5rrvuOt1+++3WMi8vLz344INXXd/AgQMdrkPRoUMHSfrb9wgAoHRinsU8q7jMs1xcXLRixQpNmDBBlStX1nvvvaeYmBiFhobq7rvvdrhm1OXk5OTonnvu0cmTJ/XJJ59Y1wxbsmSJfH19deuttzrM0Vq2bKmKFSvmm6MBxQlhFOAEN910kyIiIvI9Kleu/Lfrjhs3Tmlpaapbt66aNGmip556Sjt27Lii/f78888KDg5WpUqVHJY3aNDAas/7r6urq8LCwhz6XXiq8F9d2FeSjh8/riFDhiggIEDe3t6qXr261S89PT1f/wsnC76+vvLy8lK1atXyLf+738HnjeHCmgMDA+Xn52eNtbDlbbdevXr52urXr2+1503yCuMW09Kfp963a9dOgwYNUkBAgPr06aMPP/ywUIKpffv2yRijOnXqqHr16g6PvXv36tixYw79a9SokW+iV7lyZYfX7Oeff1atWrXy9bvce+xSLnzf5P054loJAFA2Mc9inlWc5lmenp565plntHfvXh05ckTvvfee2rZtqw8//FCxsbFXtP9nn31Wq1ev1uLFi1WrVi1r+b59+5Seni5/f/98c7TMzMx8czSgOOGaUUAJ07FjRx04cECfffaZVq5cqbfeekvTp0/X3LlzHb7xsttfv53Lc9ddd+m7777TU089pebNm6tixYrKzc1Vt27dLvqX98XuIHKpu4qYCy4EeikF+farOLlU/Tk5OQ7Pvb29tX79eq1Zs0bLli3T8uXL9cEHH+iWW27RypUrr+nuLLm5uXJxcdFXX3110e1ceA2na33Nrpbd+wMAlF7Ms/7EPKto5llBQUHq06ePevfurUaNGunDDz/UggULLnstqU8//VQvvviixo8fr27dujm05ebmyt/fX4sWLbroutWrV7+iugBn4MwooASqUqWKBg4cqPfee0+HDx9W06ZNHe68cqm/WENDQ3XkyBGdPHnSYfkPP/xgtef9Nzc3V4cOHXLodzV3KDtx4oRWrVqlp59+WmPHjtUdd9yhW2+9VTfccMMVb+Na5I3hwtPsU1NTlZaWZo21KPYrSUlJSfnakpKSrPa847Br167Lbq9y5coXPYX7Yt84urq6qkuXLpo2bZr27NmjiRMnavXq1dd8inatWrVkjFFYWNhFv2nO+0nA1QgNDdWBAwfyTXYv9h4r6RNdAEDJwjzr7zHPurZ5Vrly5dS0aVNlZ2df9GL7eX788Uf1799fvXr1uuid+2rVqqXff/9d7dq1u+gcrVmzZlddG2AXwiighLnwdr0VK1ZU7dq1HW6jm/c78gv/cu3Ro4dycnL06quv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B7R69Wp9+OGHWrZsmb0DBgAAAAAAQMHOjDp48GBh13FR06dP1z//+U/17t1bHTt2VGBgoD7++GOr3c3NTUuXLpWbm5vCw8N133336f7779e4ceOsPmFhYVq2bJni4uLUrFkzvfzyy3rrrbcUGRlpyxgAAADsmjsBAACUBAU6M6p27dq6+eabFR0drX/961+FdgHytWvXOjz38vLS7NmzNXv27EuuExoaqi+//PKy2+3UqZO2bdtWGCUCAABctaKaOwEAAJREBToz6vvvv1fTpk01fPhwBQYG6qGHHtLmzZsLuzYAAIBSgbkTAADAeQUKo5o3b66ZM2fqyJEjevvtt3X06FG1b99ejRs31rRp0/Tbb78Vdp0AAAAlFnMnAACA867pbnru7u668847tWTJEr344ovav3+/nnzySYWEhOj+++/X0aNHC6tOAACAEo+5EwAAwDWGUVu3btWjjz6qoKAgTZs2TU8++aQOHDiguLg4HTlyRD179iysOgEAAEo85k4AAAAFvID5tGnTNH/+fCUlJalHjx5655131KNHD7m6/plthYWFacGCBbr++usLs1YAAIASibkTAADAeQUKo+bMmaMHHnhAAwYMUFBQ0EX7+Pv7a968eddUHAAAQGnA3AkAAOC8AoVR+/bt+9s+Hh4e6t+/f0E2DwAAUKowdwIAADivQNeMmj9/vpYsWZJv+ZIlS7Rw4cJrLgoAAKA0Ye4EAABwXoHCqEmTJqlatWr5lvv7++uFF1645qIAAABKE+ZOAAAA5xUojEpOTlZYWFi+5aGhoUpOTr7mogAAAEoT5k4AAADnFSiM8vf3144dO/It3759u6pWrXrNRQEAAJQmzJ0AAADOK1AYdc899+jxxx/XmjVrlJOTo5ycHK1evVpDhgxRnz59CrtGAACAEo25EwAAwHkFupve+PHj9dNPP6lLly5yd/9zE7m5ubr//vu57gEAAMAFmDsBAACcV6AwysPDQx988IHGjx+v7du3y9vbW02aNFFoaGhh1wcAAFDiMXcCAAA4r0BhVJ66deuqbt26hVULAABAqcbcCQAAoIBhVE5OjhYsWKBVq1bp2LFjys3NdWhfvXp1oRQHAABQGjB3AgAAOK9AYdSQIUO0YMECRUVFqXHjxnJxcSnsugAAAEoN5k4AAADnFSiMev/99/Xhhx+qR48ehV0PAABAqcPc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jz/+2Egyn3zyyWX7Hzx40JQvX94MHz7c7Nmzx7zyyivGzc3NLF++3J6CbXa1x2fIkCHmxRdfNJs3bzY//vijGTVqlClXrpz5/vvv7SnYZld7fPKcOHHC3HDDDaZr166mWbNmRVojyq6Czhuc5fnnnzeNGjUyR48etR6//fab1f7www+bkJAQs2rVKrN161bTtm1b849//MNqP3funGncuLGJiIgw27ZtM19++aWpVq2aGTVqlNXHWZ/hf/dZMXnyZOPr62s+/fRTs337dnP77bebsLAwc/r0aatPt27dTLNmzczGjRvNN998Y2rXrm3uueceqz09Pd0EBASYvn37ml27dpn33nvPeHt7m9dff93q8+233xo3NzczZcoUs2fPHvPss8+acuXKmZ07d9oyzv79+5tu3bo5vMbHjx936FMSxhkZGWnmz59vdu3aZRITE02PHj1MzZo1TWZmptXHrvdrUf45v5Jx3nzzzebBBx90eE3T09NL1Dg///xzs2zZMvPjjz+apKQk85///MeUK1fO7Nq1yxhTOl7LKxlnaXgtL7R582Zz/fXXm6ZNm5ohQ4ZYy0via0oYZYObbrrJxMTEWM9zcnJMcHCwmTRp0hWtf+7cOVOpUiWzcOHCoirRaQpybM6dO2f+8Y9/mLfeesv079+/VIdRV3t85syZY2644QZz9uxZu0p0mqs9NjExMeaWW25xWDZ8+HDTrl27Iq3T2a4kTBgxYoRp1KiRw7K7777bREZGFmFlxcPVhC1/1bBhQzN27NjCL6iYuZrjc/fdd5tnn33WPP/884RRKDLXOqey2+X+PKSlpZly5cqZJUuWWMv27t1rJJn4+HhjzJ9BiKurq0lJSbH6zJkzx/j4+JisrCxjTPH4DL/wsyI3N9cEBgaal156yVqWlpZmPD09zXvvvWeMMWbPnj1GktmyZYvV56uvvjIuLi7m119/NcYY89prr5nKlStbYzXGmJEjR5p69epZz++66y4TFRXlUE+bNm3MQw89VKhjNObin4l/NxctieM0xphjx44ZSWbdunXGGHvfr3b+Ob9wnMb8GWD89R/5FyqJ4zTGmMqVK5u33nqr1L6WefLGaUzpey1Pnjxp6tSpY+Li4hzGVlJfU36mV8TOnj2rhIQERUREWMtcXV0VERGh+Pj4K9rGH3/8oezsbFWpUqWoynSKgh6bcePG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uzzIX1/T4j7Oi8nNzVVWVlapeS3/bpwXU1Jfyy5duuSbb7Vq1Up9+/a1/r9EvqZXfclzXLX333/feHp6mgULFpg9e/aYwYMHGz8/P+tK9v369TNPP/201X/y5MnGw8PDfPTRRw63oTx58qSzhlBkrvbYXKi0303vao9PcnKyqVSpkomNjTVJSUlm6dKlxt/f30yYMMFZQygyV3tsnn/+eVOpUiXz3nvvmYMHD5qVK1eaWrVqmbvuustZQygyJ0+eNNu2bTPbtm0zksy0adPMtm3bzM8//2yMMebpp582/fr1s/rn3cb1qaeeMnv37jWzZ8+25bbgznK1x2fRokXG3d3dzJ492+EzOS0tzVlDKFJXe3wuxN30UJT+7rO/uHniiSfM2rVrzaFDh8y3335rIiIiTLVq1cyxY8eMMX/eirtmzZpm9erVZuvWrSY8PNyEh4db6+fdirtr164mMTHRLF++3FSvXv2it+K2+zP87z4rJk+ebPz8/Mxnn31mduzYYXr27GnCwsLM6dOnrW1069bN3HjjjWbTpk1mw4YNpk6dOuaee+6x2tPS0kxAQIDp16+f2bVrl3n//fdN+fLlzeuvv271+fbbb427u7uZOnWq2bt3r3n++edNuXLlzM6dO4t8nCdPnjRPPvmkiY+PN4cOHTJff/21adGihalTp445c+ZMiRrnI488Ynx9fc3atWsd/q77448/rD52vV+L8s/5341z//79Zty4cWbr1q3m0KFD5rPPPjM33HCD6dixY4ka59NPP23WrVtnDh06ZHbs2GGefvpp4+LiYlauXGmMKR2v5d+Ns7S8lpdy4Z0CS+JrShhlk1deecXUrFnTeHh4mJtuusls3LjRarv55ptN//79reehoaFGUr7H888/b3/hNriaY3Oh0h5GGXP1x+e7774zbdq0MZ6enuaGG24wEydONOfOnbO5antczbHJzs42Y8aMMbVq1TJeXl4mJCTEPProo+bEiRP2F17E1qxZc9HPkLzj0b9/f3PzzTfnW6d58+bGw8PD3HDDDWb+/Pm2122Xqz0+N99882X7lzYFef/8FWEUitrlPvuLm7vvvtsEBQUZDw8Pc91115m7777b7N+/32o/ffq0efTRR03lypVN+fLlzR133GGOHj3qsI2ffvrJdO/e3Xh7e5tq1aqZJ554wmRnZzv0ccZn+N99VuTm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888/16233nrJ9bZt26Z+/frp1VdfVbt27SRJO3fuVE5OjsPnufTnT/eqVq1a4DEBKDr8TA9AieHt7X3ZdlfXPz/SjDHWsuzsbIc+gwYN0sGDB9WvXz/t3LlTrVq10iuvvFKgejIzM/XQQw8pMTHRemzfvl379u1TrVq1rH7lypVzWM/FxUW5ubkF2ueFinLbQEl24403KicnR8eOHVPt2rUdHnkXxG3Xrp3OnTunAwcOWOv9+OOPkqTQ0FCn1A0AzuCsOValSpV02223aeLEidq+fbs6dOjg8NPBC6WkpOj222/XoEGDFB0dbS3/6xcQf52X7d271+HyBgCKD8IoAMVGgwYNFB8f7zDR+fbbb1WpUiXVqFFDderUkbe3t1atWnXR9atXry5JOnr0qLUs76KXfxUSEqKHH35YH3/8sZ544gm9+eabBaq3RYsW2rNnT75/6NauXVseHh5XtI169epp586dysrKspZt2bLFoU/etq70mgpAWZGZmWn9g0P68zbhiYmJSk5OVt26ddW3b1/df//9+vjjj3Xo0CFt3rxZkyZN0rJlyyRJERERatGihR544AFt27ZNCQkJeuihh3Trrbfm+3YdAEqykjDHcnFxUf369R1uBPNXZ86cUc+ePVW/fn1NmzbNoe1KvoAAULwQRgGwXXp6usO3VomJiTp8+LAeffRRHT58WI899ph++OEHffbZZ3r++ec1fPhwubq6ysvLSyNHjtSIESP0zjvv6MCBA9q4caPmzZsnSapdu7ZCQkI0ZswY7du3T8uWLdPLL7/ssO+hQ4dqxYoVOnTokL7//nutWbPG+lnOpfz222/56k1NTdXIkSP13XffKTY2VomJidq3b58+++yzfBcwv5x7771Xubm5Gjx4sPbu3asVK1Zo6tSpkmSdSh8aGioXFxctXbpUv/32mzIzM6/mcAOl1tatW3XjjTfqxhtvlCQNHz5cN954o0aPHi1Jmj9/vu6//3498cQTqlevnnr16qUtW7aoZs2akv78pv+LL75QtWrV1LFjR0VFRalBgwZ6//33nTYmALgWJWWOlZiYqJ49e+qjjz7Snj17tH//fs2bN09vv/22evbsedF1HnroIR0+fFizZs3Sb7/9ppSUFKWkpOjs2bNX9AUEgGLGqVesAlDm9O/f30jK94iOjjbGGLN27VrTunVr4+HhYQIDA83IkSNNdna2tX5OTo6ZMGGCCQ0NNeXKlTM1a9Y0L7zwgtW+YcMG06RJE+Pl5WU6dOhglixZ4nBxzdjYWFOrVi3j6elpqlevbvr162f+97//XbLem2+++aL1jh8/3hhjzObNm82tt95qKlasaCpUqGCaNm1qJk6caK0fGhpqpk+f7rDNZs2ameeff956/u2335qmTZsaDw8P07JlS7N48eJ8F1AeN26cCQwMNC4uLqZ///5WbRdeXL1nz55WOwAAKDtK0hzrt99+M48//rhp3LixqVixoqlUqZJp0qSJmTp1qsnJyTHG5L+AeWho6EXHt2bNGmOMMWfPnjWjR482119/vSlXrpwJCgoyd9xxh9mxY0chH2kAhcHFmL+cqwkAcLpFixZp4MCBSk9P/9trOAAAAABAScPd9ADAyd555x3dcMMNuu6667R9+3aNHDlSd911F0EUAAAAgFKJMAoAnCwlJUWjR49WSkqKgoKC9O9//1sTJ050dlkAAAAAUCT4mR4AAAAAAABsw930AAAAAAAAYBvCKAAAAAAAANiGMAoAAAAAAAC2IYwCAAAAAACAbQijAAAAAAAAYBvCKAAAAAAAANiGMAoAAAAAAAC2IYwCAAAAAACAbQijAAAAAAAAYJv/BzbRwx6A6/LbAAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "panda_df = df.select(\"locusSize\", \"locusLength\").toPandas()\n", + "\n", + "plt.figure(figsize=(12, 6))\n", + "\n", + "# Histogram for locusLength\n", + "plt.subplot(1, 2, 1) # 1 row, 2 columns, 1st subplot\n", + "plt.hist(panda_df[\"locusLength\"], bins=30, alpha=0.7)\n", + "plt.xlabel(\"Locus Length\")\n", + "plt.ylabel(\"Frequency\")\n", + "plt.title(\"Histogram of Locus Length\")\n", + "\n", + "# Histogram for locusSize\n", + "plt.subplot(1, 2, 2) # 1 row, 2 columns, 2nd subplot\n", + "plt.hist(panda_df[\"locusSize\"], bins=30, alpha=0.7)\n", + "plt.xlabel(\"Locus Size\")\n", + "plt.ylabel(\"Frequency\")\n", + "plt.title(\"Histogram of Locus Size\")\n", + "\n", + "plt.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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yy9n8eLFfO973+ts953vfAcpJR/84AexrJlfQUKIzt8zmUzn79VqlbGxMS655BIajQbr169/2uN85JFH2LhxI9dccw3j4+OMjY0xNjZGvV7nFa94BT//+c+RUs7Y513vetdhneOGG26gv7+fwcFBrrzySur1Ol/60pc4//zz59x+z549PPLII1x33XUzoh1nnnkml112Gf/5n/95+BeKTvMaGRnh3e9+94y6nCuvvJKTTz6ZH/7wh0/ruIcijmPWrl3LVVddxapVqzqvL1q0iGuuuYZf/vKXVCoVAP7jP/6Ds846i9e+9rWzjjP98zAf2hGIH/3oR7NSqA7FzTffzFe/+lXOOeccfvSjH/GBD3yA8847j3PPPXdGuuSh+MhHPsIPfvADbr31Vk499VQA7rrrLsrlMm95y1s6n7exsTFs2+aFL3wh99xzz0GP+aY3vYkwDPnWt77VeW3t2rWUy2Xe9KY3dV4rlUrcf//9R8SEZDrPxft5KI7E98All1zC+Ph459rbqXTvfve7Z2z33ve+97DH98pXvnJG1PfMM8+kWCweMXdOg8Hw9HheC6ef//znvOY1r2FwcBAhBN/5zncO+xhKKT71qU+xZs0aUqkUixcv5qMf/eiRH6zB8Bzgggsu4Fvf+haTk5P85je/4cYbb6RarfL617+eJ598EtBpa5ZldRaVB+KJJ57gta99LV1dXRSLRfr7+3nb294G8IzqGzZu3AjAtddeS39//4w/X/ziF/F9f9bxV65ceVjn+OAHP8hdd93F3XffzWOPPcbQ0NBBXdi2b98OwEknnTTrvVNOOaWzoDtcDnbck08+ufP+kWZ0dJRGo3HA65FSsnPnTkB/Hg6V2jlfVq5cyfvf/36++MUv0tfXx+WXX84///M/z/vz8pa3vIVf/OIXTE5OsnbtWq655hoefvhhXvOa19BqtQ65/5133snNN9/MjTfeyNVXX915vf2Ze/nLXz7rM7d27dpDmqecddZZnHzyydx+++2d126//Xb6+vo69XMAn/jEJ3j88cdZunQpL3jBC7jpppuOyEL7uXo/D8bT+R5YtmzZjJ+7u7sBmJycBPTvm2VZs74vTjjhhMMe3/7nap+vfS6DwXBseF7XONXrdc466yxuuOEGXve61z2tY/zFX/wFa9eu5VOf+hRnnHEGExMTTExMHOGRGgzPLTzP44ILLuCCCy5gzZo1XH/99XzjG9/gQx/60Lz2L5fLXHrppRSLRT784Q+zevVq0uk0Dz30EP/tv/23WU+CD4f2vp/85Cc5++yz59xm//4v06Nf8+GMM87gla985dMan2E2B4pUTDcKafPpT3+a6667ju9+97usXbuW973vfXzsYx/j17/+NUuWLJnX+YrFIpdddhmXXXYZruvypS99ifvvv59LL730gPts3bqVt771rVx22WX87d/+7Yz32p+52267jYULF87a13EO/U/xm970Jj760Y8yNjZGoVDge9/7Hm95y1tm7PvGN76RSy65hG9/+9usXbuWT37yk3z84x/nW9/6FldcccW8rv3Z4Nm+n3PxdL4HbNueczv1NOoeD8WzeS6DwTB/ntfC6YorrjjoPya+7/OBD3yAr33ta5TLZU4//XQ+/vGP89KXvhSAdevW8fnPf57HH3+88yTucJ9MGwy/77TT0/bs2QPA6tWrkVLy5JNPHnDB8tOf/pTx8XG+9a1v8ZKXvKTz+lyudAdahB3o9Xb6S7FYPG7EzfLlywF46qmnZr23fv16+vr6Ohboh5PuNP240yMT7dfa7x9p+vv7yWazB7wey7JYunQpoO/H448/ftDjtZ/s79/z5kARszPOOIMzzjiD//k//yf33XcfF198MV/4whdmCZr5cP755/OlL32p8/mdi2azyete9zpKpRJf+9rXZqWgtj9zAwMDT/sz96Y3vYmbb76Z//iP/2DBggVUKhXe/OY3z9pu0aJFvPvd7+bd7343IyMjnHvuuXz0ox99RsLp9+l+tjka3wPLly9HSsnWrVs58cQTO69v2rRp1raHm7ZoMBiOD57XqXqH4j3veQ+/+tWv+PrXv85jjz3GG97wBl796ld3Qvzf//73WbVqFT/4wQ9YuXIlK1as4I//+I9NxMnwvOSee+6Z82louz6n/XDhqquuwrIsPvzhD8+KHLX3bz9tnX68IAj43Oc+N+v4uVxuztSdttDYf3F23nnnsXr1aj71qU9Rq9Vm7Tc6OnrAazxaLFq0iLPPPpsvfelLM8b7+OOPs3btWv7gD/6g89qBrmsuzj//fAYGBvjCF76A7/ud1++44w7WrVs3y+3rSGHbNq961av47ne/O8NieXh4mK9+9au8+MUvplgsAnD11Vfz6KOP8u1vf3vWcdr3v73I/fnPf955L45j/vVf/3XG9pVKhSiKZrx2xhlnYFnWjOvfn0ajwa9+9as537vjjjuAudMd27zrXe9iw4YNfPvb3+6IgulcfvnlFItF/u7v/o4wDGe9P5/P3CmnnMIZZ5zB7bffzu23386iRYtmPFSI43jW78HAwACDg4MHvfb58Fy7n/PhaHwPtN0N9/+e+uxnPztr28P5PTYYDMcPz+uI08HYsWMHt9xyCzt27GBwcBCA//pf/yt33nknt9xyC3/3d3/Hli1b2L59O9/4xjf48pe/TBzH/NVf/RWvf/3rufvuu4/xFRgMzy7vfe97aTQavPa1r+Xkk08mCALuu+8+br/9dlasWMH1118P6Hz/D3zgA3zkIx/hkksu4XWvex2pVIoHHniAwcFBPvaxj3HRRRfR3d3Ntddey/ve9z6EENx2221zCrPzzjuP22+/nfe///1ccMEF5PN5XvOa17B69WpKpRJf+MIXKBQK5HI5XvjCF7Jy5Uq++MUvcsUVV3Daaadx/fXXs3jxYnbv3s0999xDsVjk+9///rM9fXzyk5/kiiuu4EUvehHvfOc7O3bkXV1dnf4v7esFbcX+5je/Gdd1ec1rXjNnU17Xdfn4xz/O9ddfz6WXXspb3vKWjh35ihUr+Ku/+qtnNOZ/+7d/m7O3zF/8xV/wt3/7t9x11128+MUv5t3vfjeO4/Av//Iv+L7PJz7xic62f/3Xf803v/lN3vCGN3DDDTdw3nnnMTExwfe+9z2+8IUvcNZZZ3Haaadx4YUXcuONNzIxMUFPTw9f//rXZy2q7777bt7znvfwhje8gTVr1hBFEbfddhu2bc+oOdqfRqPBRRddxIUXXsirX/1qli5dSrlc5jvf+Q6/+MUvuOqqqzjnnHPm3PeHP/whX/7yl7n66qt57LHHeOyxxzrv5fN5rrrqKorFIp///Od5+9vfzrnnnsub3/xm+vv72bFjBz/84Q+5+OKL+ad/+qdDzveb3vQmPvjBD5JOp3nnO985I7JVrVZZsmQJr3/96znrrLPI5/P8+Mc/5oEHHuDTn/70IY8Nvz/3s00YhnNGpXp6enj3u999xL8HzjvvPK6++mo+85nPMD4+3rEj37BhAzAzynQ4v8cGg+E44pj5+R1nAOrb3/525+e2XW8ul5vxx3Ec9cY3vlEppdSf/MmfKEA99dRTnf3adqTr169/ti/BYDim3HHHHeqGG25QJ598ssrn88rzPHXCCSeo9773vWp4eHjW9v/2b/+mzjnnHJVKpVR3d7e69NJL1V133dV5/95771UXXnihymQyanBwsGNvzjS7YqWUqtVq6pprrlGlUkkBM6zJv/vd76pTTz1VOY4zy0L64YcfVq973etUb2+vSqVSavny5eqNb3yj+slPftLZpm1DPDo6Oq85aNspH8o++UCW1j/+8Y/VxRdfrDKZjCoWi+o1r3mNevLJJ2ft/5GPfEQtXrxYWZY1L2vy22+/vTPXPT096q1vfavatWvXjG2ejh35gf7s3LlTKaXUQw89pC6//HKVz+dVNptVL3vZy9R9990363jj4+PqPe95j1q8eLHyPE8tWbJEXXvttWpsbKyzzebNm9UrX/lKlUql1IIFC9T/+B//Q911110zPg9btmxRN9xwg1q9erVKp9Oqp6dHvexlL1M//vGPD3o9YRiq//N//o+66qqr1PLly1UqlVLZbFadc8456pOf/KTyfb+z7f737mBzsb9N/j333KMuv/xy1dXVpdLptFq9erW67rrr1IMPPnjIOVdKW/m3j/3LX/5yxnu+76u//uu/VmeddZYqFAoql8ups846S33uc5875HF/3+6nUtqO/EDXs3r16s52z+R7YC5b9Xq9rv78z/9c9fT0qHw+r6666ir11FNPKUD97//9v2fsf6DfY2BOW/nly5era6+99pDXbjAYjh5CKVNpCPpJ0Le//W2uuuoqQDsWvfWtb+WJJ56YVaSZz+dZuHAhH/rQh2alXjSbTbLZLGvXruWyyy57Ni/BYDAYDAbDccYjjzzCOeecw1e+8hXe+ta3HuvhGAyGZ4BJ1TsA55xzDnEcMzIywiWXXDLnNhdffDFRFLF58+ZOznY7JH+0iq4NBoPBYDAcnzSbzVkunJ/5zGewLGtGTZrBYHhu8rwWTrVabYbbzdatW3nkkUfo6elhzZo1vPWtb+Ud73gHn/70pznnnHMYHR3lJz/5CWeeeSZXXnklr3zlKzn33HO54YYb+MxnPoOUkj//8z/nsssuY82aNcfwygwGg8FgMDzbfOITn+C3v/0tL3vZy3AchzvuuIM77riDP/3TP+04DxoMhucuz+tUvZ/+9Ke87GUvm/X6tddey6233topLP3yl7/M7t276evr48ILL+Tmm2/mjDPOAGBoaIj3vve9rF27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8tx2XRxCq9Vi5MiRZgs7NC/08MNb9x62YcMGvPnmmzh8+DCio6NtMdQOs2vRpHb3fXNq+/sSEREREZF67L6q3qJFi7Bz5078/e9/R3FxMebNm4c7d+5g1qxZAICXX37ZbPGIt99+GytXrsSuXbvQt29fVFRUoKKiAnV1dfY6hUd2Kd16QdSePkREREREZBt2L5ymTp2KjRs3YtWqVRg2bBiMRiMOHz4MPz8/AEBZWRnKy8uV/jt27MD9+/fxq1/9CgEBAcq2ceNGe53Cj3IpfRKe8Wm5P2k4iyYiIiIios6mUywOkZKSgpSUFIttBoPB7PtLly6pPyAb2ZaSgIMHD6JodQLvnyUiIiIi6sTs/o4TERERERFRZ8fCiYiIiIiIyAoWTkRERERERFawcCIiIiIiIrKChRMREREREZEVLJyIiIiIiIisYOFERERERERkBQsnIiIiIiIiK1g4ERERERERWcHCiYiIiIiIyAoWTkRERERERFawcCIiIiIiIrKChRMREREREZEVTvYegK2JCACgpqbGziMBTCYT6uvrUVNTA2dnZ3sPp0tixupivupivupivupivupivupivurrLBk31wTNNUJbul3hVFtbCwAICgqy80iIiIiIiKgzqK2thaenZ5t9NNKe8qoLaWpqwrVr19CjRw9oNBq7jqWmpgZBQUG4fPkyPDw87DqWrooZq4v5qov5qov5qov5qov5qov5qq+zZCwiqK2tRWBgIBwc2v4UU7d7x8nBwQF9+vSx9zDMeHh48JdSZcxYXcxXXcxXXcxXXcxXXcxXXcxXfZ0hY2vvNDXj4hBERERERERWsHAiIiIiIiKygoWTHel0OqSlpUGn09l7KF0WM1YX81UX81UX81UX81UX81UX81Xf45hxt1scgoiIiIiI6FHxHSciIiIiIiIrWDgRERERERFZwcKJiIiIiIjIChZOREREREREVrBwsqNt27ahb9++cHFxQUxMDE6dOmXvIXU6q1evhkajMdvCw8OV9nv37iE5ORlPPvkk3N3d8dJLL+H69etmxygrK8OkSZPg5uaGXr16YenSpXjw4IFZH4PBgBEjRkCn0yE0NBR79uyxxenZ3LFjxzB58mQEBgZCo9Hgk08+MWsXEaxatQoBAQFwdXVFfHw8zp8/b9bn1q1bSExMhIeHB7y8vDB79mzU1dWZ9SkoKMDY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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plt.figure(figsize=(10, 6))\n", + "plt.scatter(panda_df[\"locusSize\"], panda_df[\"locusLength\"], alpha=0.5)\n", + "plt.title(\"Scatter Plot of Locus Size vs Locus Length\")\n", + "plt.xlabel(\"Locus Size\")\n", + "plt.ylabel(\"Locus Length\")\n", + "plt.grid(True)\n", + "plt.show()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "gentropy-iQynFIia-py3.10", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.14" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/notebooks/ukb_ppp_benchmark.ipynb b/notebooks/ukb_ppp_benchmark.ipynb new file mode 100644 index 000000000..4a3e200db --- /dev/null +++ b/notebooks/ukb_ppp_benchmark.ipynb @@ -0,0 +1,1468 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + " \n", + "
\n", + " \n", + " Loading BokehJS ...\n", + "
\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/javascript": "'use strict';\n(function(root) {\n function now() {\n return new Date();\n }\n\n const force = true;\n\n if (typeof root._bokeh_onload_callbacks === \"undefined\" || force === true) {\n root._bokeh_onload_callbacks = [];\n root._bokeh_is_loading = undefined;\n }\n\nconst JS_MIME_TYPE = 'application/javascript';\n const HTML_MIME_TYPE = 'text/html';\n const EXEC_MIME_TYPE = 'application/vnd.bokehjs_exec.v0+json';\n const CLASS_NAME = 'output_bokeh rendered_html';\n\n /**\n * Render data to the DOM node\n */\n function render(props, node) {\n const script = document.createElement(\"script\");\n node.appendChild(script);\n }\n\n /**\n * Handle when an output is cleared or removed\n */\n function handleClearOutput(event, handle) {\n function drop(id) {\n const view = Bokeh.index.get_by_id(id)\n if (view != null) {\n view.model.document.clear()\n Bokeh.index.delete(view)\n }\n }\n\n const cell = handle.cell;\n\n const id = cell.output_area._bokeh_element_id;\n const server_id = cell.output_area._bokeh_server_id;\n\n // Clean up Bokeh references\n if (id != null) {\n drop(id)\n }\n\n if (server_id !== undefined) {\n // Clean up Bokeh references\n const cmd_clean = \"from bokeh.io.state import curstate; print(curstate().uuid_to_server['\" + server_id + \"'].get_sessions()[0].document.roots[0]._id)\";\n cell.notebook.kernel.execute(cmd_clean, {\n iopub: {\n output: function(msg) {\n const id = msg.content.text.trim()\n drop(id)\n }\n }\n });\n // Destroy server and session\n const cmd_destroy = \"import bokeh.io.notebook as ion; ion.destroy_server('\" + server_id + \"')\";\n cell.notebook.kernel.execute(cmd_destroy);\n }\n }\n\n /**\n * Handle when a new output is added\n */\n function handleAddOutput(event, handle) {\n const output_area = handle.output_area;\n const output = handle.output;\n\n // limit handleAddOutput to display_data with EXEC_MIME_TYPE content only\n if ((output.output_type != \"display_data\") || (!Object.prototype.hasOwnProperty.call(output.data, EXEC_MIME_TYPE))) {\n return\n }\n\n const toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n\n if (output.metadata[EXEC_MIME_TYPE][\"id\"] !== undefined) {\n toinsert[toinsert.length - 1].firstChild.textContent = output.data[JS_MIME_TYPE];\n // store reference to embed id on output_area\n output_area._bokeh_element_id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n }\n if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n const bk_div = document.createElement(\"div\");\n bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n const script_attrs = bk_div.children[0].attributes;\n for (let i = 0; i < script_attrs.length; i++) {\n toinsert[toinsert.length - 1].firstChild.setAttribute(script_attrs[i].name, script_attrs[i].value);\n toinsert[toinsert.length - 1].firstChild.textContent = bk_div.children[0].textContent\n }\n // store reference to server id on output_area\n output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n }\n }\n\n function register_renderer(events, OutputArea) {\n\n function append_mime(data, metadata, element) {\n // create a DOM node to render to\n const toinsert = this.create_output_subarea(\n metadata,\n CLASS_NAME,\n EXEC_MIME_TYPE\n );\n this.keyboard_manager.register_events(toinsert);\n // Render to node\n const props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n render(props, toinsert[toinsert.length - 1]);\n element.append(toinsert);\n return toinsert\n }\n\n /* Handle when an output is cleared or removed */\n events.on('clear_output.CodeCell', handleClearOutput);\n events.on('delete.Cell', handleClearOutput);\n\n /* Handle when a new output is added */\n events.on('output_added.OutputArea', handleAddOutput);\n\n /**\n * Register the mime type and append_mime function with output_area\n */\n OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n /* Is output safe? */\n safe: true,\n /* Index of renderer in `output_area.display_order` */\n index: 0\n });\n }\n\n // register the mime type if in Jupyter Notebook environment and previously unregistered\n if (root.Jupyter !== undefined) {\n const events = require('base/js/events');\n const OutputArea = require('notebook/js/outputarea').OutputArea;\n\n if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n register_renderer(events, OutputArea);\n }\n }\n if (typeof (root._bokeh_timeout) === \"undefined\" || force === true) {\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_failed_load = false;\n }\n\n const NB_LOAD_WARNING = {'data': {'text/html':\n \"
\\n\"+\n \"

\\n\"+\n \"BokehJS does not appear to have successfully loaded. If loading BokehJS from CDN, this \\n\"+\n \"may be due to a slow or bad network connection. Possible fixes:\\n\"+\n \"

\\n\"+\n \"
    \\n\"+\n \"
  • re-rerun `output_notebook()` to attempt to load from CDN again, or
  • \\n\"+\n \"
  • use INLINE resources instead, as so:
  • \\n\"+\n \"
\\n\"+\n \"\\n\"+\n \"from bokeh.resources import INLINE\\n\"+\n \"output_notebook(resources=INLINE)\\n\"+\n \"\\n\"+\n \"
\"}};\n\n function display_loaded(error = null) {\n const el = document.getElementById(\"d831fede-136f-40d0-a9cd-423fefca302f\");\n if (el != null) {\n const html = (() => {\n if (typeof root.Bokeh === \"undefined\") {\n if (error == null) {\n return \"BokehJS is loading ...\";\n } else {\n return \"BokehJS failed to load.\";\n }\n } else {\n const prefix = `BokehJS ${root.Bokeh.version}`;\n if (error == null) {\n return `${prefix} successfully loaded.`;\n } else {\n return `${prefix} encountered errors while loading and may not function as expected.`;\n }\n }\n })();\n el.innerHTML = html;\n\n if (error != null) {\n const wrapper = document.createElement(\"div\");\n wrapper.style.overflow = \"auto\";\n wrapper.style.height = \"5em\";\n wrapper.style.resize = \"vertical\";\n const content = document.createElement(\"div\");\n content.style.fontFamily = \"monospace\";\n content.style.whiteSpace = \"pre-wrap\";\n content.style.backgroundColor = \"rgb(255, 221, 221)\";\n content.textContent = error.stack ?? error.toString();\n wrapper.append(content);\n el.append(wrapper);\n }\n } else if (Date.now() < root._bokeh_timeout) {\n setTimeout(() => display_loaded(error), 100);\n }\n }\n\n function run_callbacks() {\n try {\n root._bokeh_onload_callbacks.forEach(function(callback) {\n if (callback != null)\n callback();\n });\n } finally {\n delete root._bokeh_onload_callbacks\n }\n console.debug(\"Bokeh: all callbacks have finished\");\n }\n\n function load_libs(css_urls, js_urls, callback) {\n if (css_urls == null) css_urls = [];\n if (js_urls == null) js_urls = [];\n\n root._bokeh_onload_callbacks.push(callback);\n if (root._bokeh_is_loading > 0) {\n console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n return null;\n }\n if (js_urls == null || js_urls.length === 0) {\n run_callbacks();\n return null;\n }\n console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n root._bokeh_is_loading = css_urls.length + js_urls.length;\n\n function on_load() {\n root._bokeh_is_loading--;\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n run_callbacks()\n }\n }\n\n function on_error(url) {\n console.error(\"failed to load \" + url);\n }\n\n for (let i = 0; i < css_urls.length; i++) {\n const url = css_urls[i];\n const element = document.createElement(\"link\");\n element.onload = on_load;\n element.onerror = on_error.bind(null, url);\n element.rel = \"stylesheet\";\n element.type = \"text/css\";\n element.href = url;\n console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n document.body.appendChild(element);\n }\n\n for (let i = 0; i < js_urls.length; i++) {\n const url = js_urls[i];\n const element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error.bind(null, url);\n element.async = false;\n element.src = url;\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n };\n\n function inject_raw_css(css) {\n const element = document.createElement(\"style\");\n element.appendChild(document.createTextNode(css));\n document.body.appendChild(element);\n }\n\n const js_urls = [\"https://cdn.bokeh.org/bokeh/release/bokeh-3.4.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.4.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.4.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.4.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-mathjax-3.4.1.min.js\"];\n const css_urls = [];\n\n const inline_js = [ function(Bokeh) {\n Bokeh.set_log_level(\"info\");\n },\nfunction(Bokeh) {\n }\n ];\n\n function run_inline_js() {\n if (root.Bokeh !== undefined || force === true) {\n try {\n for (let i = 0; i < inline_js.length; i++) {\n inline_js[i].call(root, root.Bokeh);\n }\n\n } catch (error) {display_loaded(error);throw error;\n }if (force === true) {\n display_loaded();\n }} else if (Date.now() < root._bokeh_timeout) {\n setTimeout(run_inline_js, 100);\n } else if (!root._bokeh_failed_load) {\n console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n root._bokeh_failed_load = true;\n } else if (force !== true) {\n const cell = $(document.getElementById(\"d831fede-136f-40d0-a9cd-423fefca302f\")).parents('.cell').data().cell;\n cell.output_area.append_execute_result(NB_LOAD_WARNING)\n }\n }\n\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: BokehJS loaded, going straight to plotting\");\n run_inline_js();\n } else {\n load_libs(css_urls, js_urls, function() {\n console.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n run_inline_js();\n });\n }\n}(window));", + "application/vnd.bokehjs_load.v0+json": "" + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# import matplotlib.pyplot as plt\n", + "import pyspark.sql.functions as f\n", + "from gentropy.common.session import Session\n", + "from gentropy.common.spark_helpers import order_array_of_structs_by_field\n", + "from gentropy.dataset.ld_index import LDIndex\n", + "from gentropy.dataset.study_index import StudyIndex\n", + "from gentropy.dataset.study_locus import StudyLocus\n", + "from gentropy.method.susie_inf import SUSIE_inf\n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Setting default log level to \"WARN\".\n", + "To adjust logging level use sc.setLogLevel(newLevel). For SparkR, use setLogLevel(newLevel).\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "24/08/07 09:34:15 WARN NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable\n" + ] + } + ], + "source": [ + "session = Session(\n", + " extended_spark_conf={\n", + " \"spark.driver.memory\": \"10g\",\n", + " \"spark.executor.memory\": \"10g\",\n", + " },\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Context\n", + "UKB-PPP summary statistics were ingested, a deduplication and sanity filter was run on harmonised summary statistics prior to clumping\n", + "Locus breaker clumping was performed on the resulting studies\n", + "\n", + "Parameters: \n", + " lbc_baseline_pvalue: 1e-5, \n", + " lbc_distance_cutoff: 250_000, \n", + " lbc_pvalue_threshold: 1e-8, \n", + " lbc_flanking_distance: 100_000, \n", + " large_loci_size: 1_500_000, \n", + " wbc_clump_distance: 500_000, \n", + " wbc_pvalue_threshold: 1e-8, \n", + " collect_locus: bool = True, \n", + " remove_mhc: bool = True,\n", + "\n", + "Loci with less than 100 variants, or more than 15,000, were filtered out and fine-mapped with PICS.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + } + ], + "source": [ + "study_index = StudyIndex.from_parquet(\n", + " session, \"/Users/dc16/data/study_index/ukb_ppp/\"\n", + ")\n", + "ld_index = LDIndex.from_parquet(session, \"/Users/dc16/data/ld_index\")\n", + "susie_loci = StudyLocus(\n", + " session.spark.read.parquet(\"/Users/dc16/output/ukb_ppp/clean_loci.parquet/\"),\n", + " StudyLocus.get_schema(),\n", + ")\n", + "pics_loci = StudyLocus(\n", + " session.spark.read.parquet(\"/Users/dc16/output/ukb_ppp/filtered_loci.parquet/\"),\n", + " StudyLocus.get_schema(),\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [], + "source": [ + "susie_loci.df = susie_loci.df.filter(f.col(\"pValueExponent\") < -11)\n", + "pics_loci.df = pics_loci.df.filter(f.col(\"pValueExponent\") < -11)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Susie fine mapping\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Calculate the total number of unique studyIds\n" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "data": { + "text/plain": [ + "2387" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "susie_loci.df.select(\"studyId\").distinct().count()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Calculate the total number of loci for finemapping:\n" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "data": { + "text/plain": [ + "17117" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "susie_loci.df.count()" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [], + "source": [ + "df = susie_loci.df.withColumns(\n", + " {\n", + " \"locusSize\": f.size(\"locus\"),\n", + " \"locusLength\": f.col(\"locusEnd\") - f.col(\"locusStart\"),\n", + " }\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "-RECORD 0------------------------------\n", + " meanLocusLength | 820240.6895484022 \n", + " q1LocusLength | 371912 \n", + " medianLocusLength | 651459 \n", + " q3LocusLength | 1500000 \n", + "\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[Stage 63:> (0 + 1) / 1]\r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "-RECORD 0-----------------------------\n", + " meanLocusSize | 4029.3360986154116 \n", + " minLocusSize | 116 \n", + " q1LocusSize | 1997 \n", + " medianLocusSize | 3348 \n", + " q3LocusSize | 5727 \n", + " maxLocusSize | 13348 \n", + "\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + } + ], + "source": [ + "length = df.select(\n", + " f.mean(\"locusLength\").alias(\"meanLocusLength\"),\n", + " f.percentile_approx(\"locusLength\", 0.25).alias(\"q1LocusLength\"),\n", + " f.percentile_approx(\"locusLength\", 0.5).alias(\"medianLocusLength\"),\n", + " f.percentile_approx(\"locusLength\", 0.75).alias(\"q3LocusLength\"),\n", + ")\n", + "size = df.select(\n", + " f.mean(\"locusSize\").alias(\"meanLocusSize\"),\n", + " f.min(\"locusSize\").alias(\"minLocusSize\"),\n", + " f.percentile_approx(\"locusSize\", 0.25).alias(\"q1LocusSize\"),\n", + " f.percentile_approx(\"locusSize\", 0.5).alias(\"medianLocusSize\"),\n", + " f.percentile_approx(\"locusSize\", 0.75).alias(\"q3LocusSize\"),\n", + " f.max(\"locusSize\").alias(\"maxLocusSize\"),\n", + ")\n", + "length.show(vertical=True)\n", + "size.show(vertical=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABKUAAAJOCAYAAABm7rQwAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/TGe4hAAAACXBIWXMAAA9hAAAPYQGoP6dpAABq3ElEQVR4nO3deVhV5f7//xeDDA6AqICkIjnPmppyHNI0UTmlacccMjXMBiyHUvNUag5pVg6V6alM7Jtm2mlUU8khG3AicZYccCgFLRXEo4hw//7ox/64BU22sDbI83Fd+6q91r3Xft+3uLl97bXu5WKMMQIAAAAAAAAs5OrsAgAAAAAAAFD8EEoBAAAAAADAcoRSAAAAAAAAsByhFAAAAAAAACxHKAUAAAAAAADLEUoBAAAAAADAcoRSAAAAAAAAsByhFAAAAAAAACxHKAUAAAAAAADLEUoBhUjVqlU1cOBAZ5dx23v99dd15513ys3NTY0bN3Z2ObgJGzZskIuLiz777DNnlwIAKISYQ1mDOdTfi46OlouLi44cOeLsUoAigVAKKCDZv5C2bduW6/527dqpfv36t/w+K1eu1IQJE275OMXFmjVrNHr0aLVq1UoLFizQq6++et22AwcOVOnSpS2sruBVrVpV//znP51dxnUtXrxYs2bNcnYZAAAnYg5VOBX3OdTly5c1e/ZsNWnSRD4+PvLz81O9evU0ZMgQ7d+/39nlAUWWu7MLAPB/EhIS5Oqat6x45cqVmjNnDpOqm7Ru3Tq5urpq/vz58vDwcHY5uMbixYu1e/duDR8+3NmlAACKEOZQBa+4z6F69uypb7/9Vn369NHjjz+ujIwM7d+/X8uXL9c//vEP1a5dW5LUv39/9e7dW56enk6uGCgaCKWAQqQo/vK6cOGCSpUq5ewybtqpU6fk7e1dLCdTAADcrphDFbziPIfaunWrli9frilTpujf//633b533nlH586dsz13c3OTm5ubxRUCRReX7wGFyLXrIWRkZOiVV15RjRo15OXlpXLlyql169aKiYmR9Nep0XPmzJEkubi42B7ZLly4oOeee06VK1eWp6enatWqpTfeeEPGGLv3vXjxop599lmVL19eZcqU0QMPPKDff/9dLi4udt8eTpgwQS4uLtq7d6/69u2rsmXLqnXr1pKknTt3auDAgbrzzjvl5eWloKAgPfbYY/rzzz/t3iv7GL/++qseeeQR+fr6qkKFCnr55ZdljNHx48fVrVs3+fj4KCgoSG+++eZNjd2VK1c0adIkVatWTZ6enqpatar+/e9/Kz093dbGxcVFCxYs0IULF2xjFR0dfVPHv5Fly5apadOm8vb2Vvny5fXII4/o999/z9Fu//796tWrlypUqCBvb2/VqlVLL774om3/wIEDVbVq1Ryvyx6zq8XExKh169by8/NT6dKlVatWrRyTpFvx8ccf2/rk7++v3r176/jx43Ztsi+f2Lt3r9q3b6+SJUvqjjvu0PTp03Mc7+jRo3rggQdUqlQpBQQEaMSIEVq9erVcXFy0YcMG2/FWrFiho0eP2v58rh2PrKwsTZkyRZUqVZKXl5c6dOiggwcP5lu/AQBFE3Mo5lAFOYc6dOiQJKlVq1Y59rm5ualcuXK259euKZVdQ26Pq39ms7KyNGvWLNWrV09eXl4KDAzUE088obNnz96wNqCo40wpoIClpKTojz/+yLE9IyPjb187YcIETZ06VYMHD9bdd9+t1NRUbdu2Tb/88ovuu+8+PfHEEzpx4oRiYmL0//7f/7N7rTFGDzzwgNavX6/IyEg1btxYq1ev1qhRo/T7779r5syZtrYDBw7U0qVL1b9/f7Vs2VLff/+9IiIirlvXv/71L9WoUUOvvvqqbXIWExOjw4cPa9CgQQoKCtKePXv03nvvac+ePdq0aVOOCcHDDz+sOnXqaNq0aVqxYoUmT54sf39//ec//9G9996r1157TYsWLdLzzz+v5s2bq23btjccq8GDB2vhwoV66KGH9Nxzz2nz5s2aOnWq9u3bpy+++EKS9P/+3//Te++9py1btuiDDz6QJP3jH//42z+HG4mOjtagQYPUvHlzTZ06VcnJyZo9e7Z++uknbd++XX5+fpL+mnC2adNGJUqU0JAhQ1S1alUdOnRI33zzjaZMmZKn99yzZ4/++c9/qmHDhpo4caI8PT118OBB/fTTT7fUl2xTpkzRyy+/rF69emnw4ME6ffq03n77bbVt29auT5J09uxZde7cWT169FCvXr302WefacyYMWrQoIG6dOki6a+J/b333quTJ09q2LBhCgoK0uLFi7V+/Xq7933xxReVkpKi3377zfbzee16FNOmTZOrq6uef/55paSkaPr06erXr582b96cL30HABQezKGYQ0mFYw4VEhIiSVq0aJFatWold/eb/2d0jx49VL16dbttcXFxmjVrlgICAmzbnnjiCduYPPvss0pMTNQ777yj7du366efflKJEiXy0FOgCDEACsSCBQuMpBs+6tWrZ/eakJAQM2DAANvzRo0amYiIiBu+T1RUlMntr/KXX35pJJnJkyfbbX/ooYeMi4uLOXjwoDHGmLi4OCPJDB8+3K7dwIEDjSQzfvx427bx48cbSaZPnz453u9///tfjm2ffPKJkWQ2btyY4xhDhgyxbbty5YqpVKmScXFxMdOmTbNtP3v2rPH29rYbk9zEx8cbSWbw4MF2259//nkjyaxbt862bcCAAaZUqVI3PN7Ntr18+bIJCAgw9evXNxcvXrRtX758uZFkxo0bZ9vWtm1bU6ZMGXP06FG7Y2RlZdm9X0hISI73yR6zbDNnzjSSzOnTp2+qH1cLCQm54c/UkSNHjJubm5kyZYrd9l27dhl3d3e77ffcc4+RZD766CPbtvT0dBMUFGR69uxp2/bmm28aSebLL7+0bbt48aKpXbu2kWTWr19v2x4REZHrGKxfv95IMnXq1DHp6em27bNnzzaSzK5du26q/wCAwo85FHOowjaHysrKss17AgMDTZ8+fcycOXNy1GTM//38JiYm5nqs06dPmypVqpgGDRqYtLQ0Y4wxP/zwg5FkFi1aZNd21apVuW4HbidcvgcUsDlz5igmJibHo2HDhn/7Wj8/P+3Zs0cHDhzI8/uuXLlSbm5uevbZZ+22P/fcczLG6Ntvv5UkrVq1SpL09NNP27V75plnrnvsJ598Msc2b29v2/9funRJf/zxh1q2bClJ+uWXX3K0Hzx4sO3/3dzc1KxZMxljFBkZadvu5+enWrVq6fDhw9etRfqrr5I0cuRIu+3PPfecJGnFihU3fL2jtm3bplOnTunpp5+Wl5eXbXtERIRq165te9/Tp09r48aNeuyxx1SlShW7Y1z77efNyP7m8KuvvlJWVpbjHcjF559/rqysLPXq1Ut//PGH7REUFKQaNWrkOLupdOnSeuSRR2zPPTw8dPfdd9v9ma1atUp33HGHHnjgAds2Ly8vPf7443mub9CgQXZrWbRp00aS/vZnBABQ9DCHYg5VWOZQLi4uWr16tSZPnqyyZcvqk08+UVRUlEJCQvTwww/brSl1I5mZmerTp4/Onz+vL774wram2LJly+Tr66v77rvPbv7VtGlTlS5dOsf8C7idEEoBBezuu+9Wx44dczzKli37t6+dOHGizp07p5o1a6pBgwYaNWqUdu7ceVPve/ToUQUHB6tMmTJ22+vUqWPbn/1fV1dXhYaG2rW79jTjq13bVpLOnDmjYcOGKTAwUN7e3qpQoYKtXUpKSo72104sfH195eXlpfLly+fY/nfX0mf34dqag4KC5OfnZ+trfss+bq1atXLsq127tm1/9oQwP25fLf112n6rVq00ePBgBQYGqnfv3lq6dGm+BFQHDhyQMUY1atRQhQoV7B779u3TqVOn7NpXqlQpx6SwbNmydn9mR48eVbVq1XK0u9HP2PVc+3OT/feI9RYA4PbDHIo5VGGaQ3l6eurFF1/Uvn37dOLECX3yySdq2bKlli5dqqFDh97U+7/00ktat26dFi9erGrVqtm2HzhwQCkpKQoICMgx/0pLS8sx/wJuJ6wpBRRibdu21aFDh/TVV19pzZo1+uCDDzRz5kzNmzfP7lsyq139jV62Xr166eeff9aoUaPUuHFjlS5dWllZWercuXOuv+hzuyvJ9e5UYq5ZVPR6HPnGrDC5Xv2ZmZl2z729vbVx40atX79eK1as0KpVq/Tpp5/q3nvv1Zo1a27pji9ZWVlycXHRt99+m+txrl3j6Vb/zPLK6vcDABRNzKH+whyqYOZQFStWVO/evdWzZ0/Vq1dPS5cuVXR09A3Xmvryyy/12muvadKkSercubPdvqysLAUEBGjRokW5vrZChQo3VRdQFHGmFFDI+fv7a9CgQfrkk090/PhxNWzY0O5uLtf7JRwSEqITJ07o/Pnzdtv3799v25/936ysLCUmJtq1y8sdzc6ePau1a9fqhRde0CuvvKIHH3xQ9913n+68886bPsatyO7DtafoJycn69y5c7a+FsT7SlJCQkKOfQkJCbb92eOwe/fuGx6vbNmyuZ7+ndu3lK6ururQoYNmzJihvXv3asqUKVq3bt0tn95drVo1GWMUGhqa67fT2ZcT5EVISIgOHTqUY2Kc289YUZ8UAwAKD+ZQf4851K3NoUqUKKGGDRsqIyMj10X5s/36668aMGCAunfvnuud/qpVq6Y///xTrVq1ynX+1ahRozzXBhQVhFJAIXbtrYBLly6t6tWr292iN/ta9Gt/EXft2lWZmZl655137LbPnDlTLi4utjujhYeHS5Leffddu3Zvv/32TdeZ/a3StaHDrFmzbvoYt6Jr1665vt+MGTMk6YZ3wbkVzZo1U0BAgObNm2f3Z/Ltt99q3759tvetUKGC2rZtqw8//FDHjh2zO8bVY1atWjWlpKTYXV5w8uRJ251vsp05cyZHLY0bN5Ykuzoc0aNHD7m5uemVV17J8edpjMnxM3kzwsPD9fvvv+vrr7+2bbt06ZLef//9HG1LlSqV66UKAADkBXOom8Mc6ubmUAcOHMjx/tJfPzuxsbEqW7bsdc9mSktL04MPPqg77rhDCxcuzDUM7dWrlzIzMzVp0qQc+65cuXLTa1YBRRGX7wGFWN26ddWuXTs1bdpU/v7+2rZtmz777DO769abNm0qSXr22WcVHh4uNzc39e7dW/fff7/at2+vF198UUeOHFGjRo20Zs0affXVVxo+fLjtOvamTZuqZ8+emjVrlv7880/b7Yx//fVXSTd35oqPj4/atm2r6dOnKyMjQ3fccYfWrFmT45vDgtKoUSMNGDBA7733ns6dO6d77rlHW7Zs0cKFC9W9e3e1b9/e4WNnZGRo8uTJObb7+/vr6aef1muvvaZBgwbpnnvuUZ8+fWy3M65atapGjBhha//WW2+pdevWuuuuuzRkyBCFhobqyJEjWrFiheLj4yVJvXv31pgxY/Tggw/q2Wef1f/+9z/NnTtXNWvWtFvodOLEidq4caMiIiIUEhKiU6dO6d1331WlSpXUunXrv+3TwYMHc+1TkyZNFBERocmTJ2vs2LE6cuSIunfvrjJlyigxMVFffPGFhgwZoueffz5PY/jEE0/onXfeUZ8+fTRs2DBVrFhRixYtsi1sevXPWNOmTfXpp59q5MiRat68uUqXLq37778/T+8HAABzqJvDHOrm5lA7duxQ37591aVLF7Vp00b+/v76/ffftXDhQp04cUKzZs267qV/r7zyivbu3auXXnpJX331ld2+atWqKSwsTPfcc4+eeOIJTZ06VfHx8erUqZNKlCihAwcOaNmyZZo9e7YeeuihvAw/UHRYfr8/oJjIvh3s1q1bc91/zz33/O3tjCdPnmzuvvtu4+fnZ7y9vU3t2rXNlClTzOXLl21trly5Yp555hlToUIF4+LiYnfb2/Pnz5sRI0aY4OBgU6JECVOjRg3z+uuv291C1xhjLly4YKKiooy/v78pXbq06d69u0lISDCS7G4vnH1b3dxuo/vbb7+ZBx980Pj5+RlfX1/zr3/9y5w4ceK6t0S+9hjXu3VwbuOUm4yMDPPKK6+Y0NBQU6JECVO5cmUzduxYc+nSpZt6n9wMGDDgureirlatmq3dp59+apo0aWI8PT2Nv7+/6devn/ntt99yHG/37t22MfLy8jK1atUyL7/8sl2bNWvWmPr16xsPDw9Tq1Yt8/HHH+e4nfHatWtNt27dTHBwsPHw8DDBwcGmT58+5tdff/3bPoWEhFy3T5GRkbZ2//3vf03r1q1NqVKlTKlSpUzt2rVNVFSUSUhIsLW53p9NbrdlPnz4sImIiDDe3t6mQoUK5rnnnjP//e9/jSSzadMmW7u0tDTTt29f4+fnZyTZjrN+/XojySxbtszuuImJiUaSWbBgwd/2HQBQNDCHYg51LWfPoZKTk820adPMPffcYypWrGjc3d1N2bJlzb333ms+++wzu7bZP7+JiYl/OxZX/8waY8x7771nmjZtary9vU2ZMmVMgwYNzOjRo82JEyduZtiBIsnFGFaHBZBTfHy8mjRpoo8//lj9+vVzdjm4Dc2aNUsjRozQb7/9pjvuuMPZ5QAAkC+YQwHAzWNNKQC6ePFijm2zZs2Sq6ur2rZt64SKcLu59mfs0qVL+s9//qMaNWoQSAEAiizmUABwa1hTCoCmT5+uuLg4tW/fXu7u7vr222/17bffasiQIapcubKzy8NtoEePHqpSpYoaN26slJQUffzxx9q/f/91b30MAEBRwBwKAG4Nl+8BUExMjG0RxrS0NFWpUkX9+/fXiy++KHd3smvculmzZumDDz7QkSNHlJmZqbp162r06NF6+OGHnV0aAAAOYw4FALeGUAoAAAAAAACWY00pAAAAAAAAWI5QCgAAAAAAAJbjQuebkJWVpRMnTqhMmTJycXFxdjkAAOAWGWN0/vx5BQcHy9WV7+jygnkRAAC3D2fPiQilbsKJEye4ewYAALeh48ePq1KlSs4uo0hhXgQAwO3HWXMiQqmbUKZMGUl//SH5+Pg4uRoAAHCrUlNTVblyZdvveNw85kUAANw+nD0nIpS6Cdmnpvv4+DD5AgDgNsLlZ3nHvAgAgNuPs+ZELKIAAAAAAAAAyxFKAQAAAAAAwHKEUgAAAAAAALAcoRQAAAAAAAAsRygFAAAAAAAAyxFKAQAAAAAAwHKEUgAAAAAAALAcoRQAAAAAAAAsRygFAAAAAAAAyxFKAQAAAAAAwHKEUgAAAAAAALAcoRQAAAAAAAAsRygFAAAAAAAAyxFKAQAAAAAAwHKEUgAAAAAAALAcoRQAAAAAAAAsRygFAAAAAAAAyxFKAQAAAAAAwHKEUgAAAAAAALAcoRQAAAAAAAAsRygFAAAAAAAAy7k7uwAAAHB7i4ze6vBr5w9sno+VAAWHn3MAAPKOM6UAAAAAAABgOUIpAAAAAAAAWI5QCgAAAAAAAJYjlAIAAAAAAIDlCKUAAAAAAABgOUIpAAAAAAAAWI5QCgAAAAAAAJYjlAIAAAAAAIDlCKUAAAAAAABgOUIpAAAAAAAAWI5QCgAAAAAAAJYjlAIAAAAAAIDlCKUAAAAAAABgOUIpAAAAAAAAWI5QCgAAAAAAAJYjlAIAAAAAAIDlCKUAAAAAAABgOUIpAAAAAAAAWI5QCgAAAAAAAJYjlAIAAAAAAIDlCKUAAAAAAABgOUIpAAAAAAAAWI5QCgAAAAAAAJYjlAIAAAAAAIDlCKUAAAAAAABgOUIpAAAAAAAAWI5QCgAAAAAAAJYjlAIAAAAAAIDlCKUAAAAAAABgOUIpAAAAAAAAWI5QCgAAAAAAAJYjlAIAAAAAAIDlCKUAAAAAAABgOUIpAAAAAAAAWI5QCgAAAAAAAJYjlAIAAAAAAIDlCKUAAAAAAABgOUIpAAAAJ5s6daqaN2+uMmXKKCAgQN27d1dCQoJdm0uXLikqKkrlypVT6dKl1bNnTyUnJ9u1OXbsmCIiIlSyZEkFBARo1KhRunLlil2bDRs26K677pKnp6eqV6+u6Ojogu4eAABArgilAAAAnOz7779XVFSUNm3apJiYGGVkZKhTp066cOGCrc2IESP0zTffaNmyZfr+++914sQJ9ejRw7Y/MzNTERERunz5sn7++WctXLhQ0dHRGjdunK1NYmKiIiIi1L59e8XHx2v48OEaPHiwVq9ebWl/AQAAJMnd2QUAAAAUd6tWrbJ7Hh0drYCAAMXFxalt27ZKSUnR/PnztXjxYt17772SpAULFqhOnTratGmTWrZsqTVr1mjv3r367rvvFBgYqMaNG2vSpEkaM2aMJkyYIA8PD82bN0+hoaF68803JUl16tTRjz/+qJkzZyo8PNzyfgMAgOKNM6UAAAAKmZSUFEmSv7+/JCkuLk4ZGRnq2LGjrU3t2rVVpUoVxcbGSpJiY2PVoEEDBQYG2tqEh4crNTVVe/bssbW5+hjZbbKPkZv09HSlpqbaPQAAAPIDoRQAAEAhkpWVpeHDh6tVq1aqX7++JCkpKUkeHh7y8/OzaxsYGKikpCRbm6sDqez92ftu1CY1NVUXL17MtZ6pU6fK19fX9qhcufIt9xEAAEAilAIAAChUoqKitHv3bi1ZssTZpUiSxo4dq5SUFNvj+PHjzi4JAADcJlhTCgAAoJAYOnSoli9fro0bN6pSpUq27UFBQbp8+bLOnTtnd7ZUcnKygoKCbG22bNlid7zsu/Nd3ebaO/YlJyfLx8dH3t7eudbk6ekpT0/PW+4bAADAtThTCgAAwMmMMRo6dKi++OILrVu3TqGhoXb7mzZtqhIlSmjt2rW2bQkJCTp27JjCwsIkSWFhYdq1a5dOnTplaxMTEyMfHx/VrVvX1ubqY2S3yT4GAACAlThTCgAAwMmioqK0ePFiffXVVypTpoxtDShfX195e3vL19dXkZGRGjlypPz9/eXj46NnnnlGYWFhatmypSSpU6dOqlu3rvr376/p06crKSlJL730kqKiomxnOj355JN65513NHr0aD322GNat26dli5dqhUrVjit7wAAoPjiTCkAAAAnmzt3rlJSUtSuXTtVrFjR9vj0009tbWbOnKl//vOf6tmzp9q2baugoCB9/vnntv1ubm5avny53NzcFBYWpkceeUSPPvqoJk6caGsTGhqqFStWKCYmRo0aNdKbb76pDz74QOHh4Zb2FwAAQOJMKQAAAKczxvxtGy8vL82ZM0dz5sy5bpuQkBCtXLnyhsdp166dtm/fnucaAQAA8htnSgEAAAAAAMByhFIAAAAAAACwHKEUAAAAAAAALEcoBQAAAAAAAMsRSgEAAAAAAMByhFIAAAAAAACwHKEUAAAAAAAALEcoBQAAAAAAAMsRSgEAAAAAAMByhFIAAAAAAACwHKEUAAAAAAAALEcoBQAAAAAAAMsRSgEAAAAAAMByhFIAAAAAAACwHKEUAAAAAAAALEcoBQAAAAAAAMsRSgEAAAAAAMByhFIAAAAAAACwHKEUAAAAAAAALEcoBQAAAAAAAMsRSgEAAAAAAMByhFIAAAAAAACwHKEUAAAAAAAALEcoBQAAAAAAAMsVmlBq2rRpcnFx0fDhw23bLl26pKioKJUrV06lS5dWz549lZycbPe6Y8eOKSIiQiVLllRAQIBGjRqlK1eu2LXZsGGD7rrrLnl6eqp69eqKjo62oEcAAAAAAAC4nkIRSm3dulX/+c9/1LBhQ7vtI0aM0DfffKNly5bp+++/14kTJ9SjRw/b/szMTEVEROjy5cv6+eeftXDhQkVHR2vcuHG2NomJiYqIiFD79u0VHx+v4cOHa/DgwVq9erVl/QMAAAAAAIA9p4dSaWlp6tevn95//32VLVvWtj0lJUXz58/XjBkzdO+996pp06ZasGCBfv75Z23atEmStGbNGu3du1cff/yxGjdurC5dumjSpEmaM2eOLl++LEmaN2+eQkND9eabb6pOnToaOnSoHnroIc2cOdMp/QUAAAAAAEAhCKWioqIUERGhjh072m2Pi4tTRkaG3fbatWurSpUqio2NlSTFxsaqQYMGCgwMtLUJDw9Xamqq9uzZY2tz7bHDw8Ntx8hNenq6UlNT7R4AAAAAAADIP+7OfPMlS5bol19+0datW3PsS0pKkoeHh/z8/Oy2BwYGKikpydbm6kAqe3/2vhu1SU1N1cWLF+Xt7Z3jvadOnapXXnnF4X4BAAAAAADgxpx2ptTx48c1bNgwLVq0SF5eXs4qI1djx45VSkqK7XH8+HFnlwQAAAAAAHBbcVooFRcXp1OnTumuu+6Su7u73N3d9f333+utt96Su7u7AgMDdfnyZZ07d87udcnJyQoKCpIkBQUF5bgbX/bzv2vj4+OT61lSkuTp6SkfHx+7BwAAAAAAAPKP00KpDh06aNeuXYqPj7c9mjVrpn79+tn+v0SJElq7dq3tNQkJCTp27JjCwsIkSWFhYdq1a5dOnTplaxMTEyMfHx/VrVvX1ubqY2S3yT4GAAAAAAAArOe0NaXKlCmj+vXr220rVaqUypUrZ9seGRmpkSNHyt/fXz4+PnrmmWcUFhamli1bSpI6deqkunXrqn///po+fbqSkpL00ksvKSoqSp6enpKkJ598Uu+8845Gjx6txx57TOvWrdPSpUu1YsUKazsMAAAAAAAAG6cudP53Zs6cKVdXV/Xs2VPp6ekKDw/Xu+++a9vv5uam5cuX66mnnlJYWJhKlSqlAQMGaOLEibY2oaGhWrFihUaMGKHZs2erUqVK+uCDDxQeHu6MLgEAAAB2IqNz3vTnZs0f2DwfKwEAwFqFKpTasGGD3XMvLy/NmTNHc+bMue5rQkJCtHLlyhset127dtq+fXt+lAgAAAAAAIB84LQ1pQAAAAAAAFB8EUoBAAAAAADAcoRSAAAAAAAAsByhFAAAAAAAACxHKAUAAAAAAADLEUoBAAAAAADAcoRSAAAAAAAAsByhFAAAAAAAACxHKAUAAAAAAADLEUoBAAAAAADAcoRSAAAAAAAAsByhFAAAAAAAACxHKAUAAAAAAADLEUoBAAAAAADAcoRSAAAAAAAAsByhFAAAAAAAACxHKAUAAAAAAADLEUoBAAAAAADAcoRSAAAAAAAAsByhFAAAAAAAACxHKAUAAAAAAADLEUoBAAAAAADAcoRSAAAAAAAAsByhFAAAAAAAACxHKAUAAAAAAADLEUoBAAAAAADAcoRSAAAAAAAAsByhFAAAAAAAACxHKAUAAAAAAADLEUoBAAAAAADAcoRSAAAAAAAAsByhFAAAAAAAACxHKAUAAAAAAADLEUoBAAAAAADAcoRSAAAAAAAAsByhFAAAAAAAACxHKAUAAAAAAADLEUoBAAAAAADAcoRSAAAAAAAAsByhFAAAAAAAACxHKAUAAAAAAADLEUoBAAAAAADAcoRSAAAAAAAAsByhFAAAAAAAACxHKAUAAAAAAADLEUoBAAAAAADAcoRSAAAAAAAAsByhFAAAAAAAACxHKAUAAAAAAADLEUoBAAAAAADAcoRSAAAAAAAAsByhFAAAAAAAACxHKAUAAAAAAADLEUoBAAAAAADAcoRSAAAAAAAAsByhFAAAAAAAACxHKAUAAAAAAADLEUoBAAAAAADAcu7OLgAAAACAYyKjtzr82vkDm+djJQAA5B1nSgEAAAAAAMByhFIAAAAAAACwHKEUAAAAAAAALEcoBQAAAAAAAMsRSgEAABQCGzdu1P3336/g4GC5uLjoyy+/tNs/cOBAubi42D06d+5s1+bMmTPq16+ffHx85Ofnp8jISKWlpdm12blzp9q0aSMvLy9VrlxZ06dPL+iuAQAA5IpQCgAAoBC4cOGCGjVqpDlz5ly3TefOnXXy5Enb45NPPrHb369fP+3Zs0cxMTFavny5Nm7cqCFDhtj2p6amqlOnTgoJCVFcXJxef/11TZgwQe+9916B9QsAAOB63J1dAAAAAKQuXbqoS5cuN2zj6empoKCgXPft27dPq1at0tatW9WsWTNJ0ttvv62uXbvqjTfeUHBwsBYtWqTLly/rww8/lIeHh+rVq6f4+HjNmDHDLrwCAACwAmdKAQAAFBEbNmxQQECAatWqpaeeekp//vmnbV9sbKz8/PxsgZQkdezYUa6urtq8ebOtTdu2beXh4WFrEx4eroSEBJ09e9a6jgAAAIgzpQAAAIqEzp07q0ePHgoNDdWhQ4f073//W126dFFsbKzc3NyUlJSkgIAAu9e4u7vL399fSUlJkqSkpCSFhobatQkMDLTtK1u2bI73TU9PV3p6uu15ampqfncNAAAUU4RSAAAARUDv3r1t/9+gQQM1bNhQ1apV04YNG9ShQ4cCe9+pU6fqlVdeKbDjAwCA4ovL9wAAAIqgO++8U+XLl9fBgwclSUFBQTp16pRdmytXrujMmTO2daiCgoKUnJxs1yb7+fXWqho7dqxSUlJsj+PHj+d3VwAAQDFFKAUAAFAE/fbbb/rzzz9VsWJFSVJYWJjOnTunuLg4W5t169YpKytLLVq0sLXZuHGjMjIybG1iYmJUq1atXC/dk/5aXN3Hx8fuAQAAkB8IpQAAAAqBtLQ0xcfHKz4+XpKUmJio+Ph4HTt2TGlpaRo1apQ2bdqkI0eOaO3aterWrZuqV6+u8PBwSVKdOnXUuXNnPf7449qyZYt++uknDR06VL1791ZwcLAkqW/fvvLw8FBkZKT27NmjTz/9VLNnz9bIkSOd1W0AAFCMEUoBAAAUAtu2bVOTJk3UpEkTSdLIkSPVpEkTjRs3Tm5ubtq5c6ceeOAB1axZU5GRkWratKl++OEHeXp62o6xaNEi1a5dWx06dFDXrl3VunVrvffee7b9vr6+WrNmjRITE9W0aVM999xzGjdunIYMGWJ5fwEAAFjoHAAAoBBo166djDHX3b969eq/PYa/v78WL158wzYNGzbUDz/8kOf6AAAA8htnSgEAAAAAAMByhFIAAAAAAACwHKEUAAAAAAAALEcoBQAAAAAAAMsRSgEAAAAAAMByhFIAAAAAAACwnLuzCwAAAACcLTJ6q7NLAACg2OFMKQAAAAAAAFiOUAoAAAAAAACWI5QCAAAAAACA5QilAAAAAAAAYDlCKQAAAAAAAFiOUAoAAAAAAACWI5QCAAAAAACA5QilAAAAAAAAYDmnhlJz585Vw4YN5ePjIx8fH4WFhenbb7+17b906ZKioqJUrlw5lS5dWj179lRycrLdMY4dO6aIiAiVLFlSAQEBGjVqlK5cuWLXZsOGDbrrrrvk6emp6tWrKzo62oruAQAAAAAA4DqcGkpVqlRJ06ZNU1xcnLZt26Z7771X3bp10549eyRJI0aM0DfffKNly5bp+++/14kTJ9SjRw/b6zMzMxUREaHLly/r559/1sKFCxUdHa1x48bZ2iQmJioiIkLt27dXfHy8hg8frsGDB2v16tWW9xcAAAAAAAB/cTHGGGcXcTV/f3+9/vrreuihh1ShQgUtXrxYDz30kCRp//79qlOnjmJjY9WyZUt9++23+uc//6kTJ04oMDBQkjRv3jyNGTNGp0+floeHh8aMGaMVK1Zo9+7dtvfo3bu3zp07p1WrVt1UTampqfL19VVKSop8fHzyv9MAANzGIqO3Ovza+QOb52Ml/4ff7Y67XcfuVn5Oi6qC+vsFACg6nP17vdCsKZWZmaklS5bowoULCgsLU1xcnDIyMtSxY0dbm9q1a6tKlSqKjY2VJMXGxqpBgwa2QEqSwsPDlZqaajvbKjY21u4Y2W2yjwEAAAAAAADruTu7gF27diksLEyXLl1S6dKl9cUXX6hu3bqKj4+Xh4eH/Pz87NoHBgYqKSlJkpSUlGQXSGXvz953ozapqam6ePGivL29c9SUnp6u9PR02/PU1NRb7icAAAAAAAD+j9PPlKpVq5bi4+O1efNmPfXUUxowYID27t3r1JqmTp0qX19f26Ny5cpOrQcAAAAAAOB24/RQysPDQ9WrV1fTpk01depUNWrUSLNnz1ZQUJAuX76sc+fO2bVPTk5WUFCQJCkoKCjH3fiyn/9dGx8fn1zPkpKksWPHKiUlxfY4fvx4fnQVAAAAAAAA/z+nh1LXysrKUnp6upo2baoSJUpo7dq1tn0JCQk6duyYwsLCJElhYWHatWuXTp06ZWsTExMjHx8f1a1b19bm6mNkt8k+Rm48PT3l4+Nj9wAAAAAAAED+ceqaUmPHjlWXLl1UpUoVnT9/XosXL9aGDRu0evVq+fr6KjIyUiNHjpS/v798fHz0zDPPKCwsTC1btpQkderUSXXr1lX//v01ffp0JSUl6aWXXlJUVJQ8PT0lSU8++aTeeecdjR49Wo899pjWrVunpUuXasWKFc7sOgAAAAAAQLHm1FDq1KlTevTRR3Xy5En5+vqqYcOGWr16te677z5J0syZM+Xq6qqePXsqPT1d4eHhevfdd22vd3Nz0/Lly/XUU08pLCxMpUqV0oABAzRx4kRbm9DQUK1YsUIjRozQ7NmzValSJX3wwQcKDw+3vL8AAAAAAAD4i1NDqfnz599wv5eXl+bMmaM5c+Zct01ISIhWrlx5w+O0a9dO27dvd6hGAAAAAAAA5L9Ct6YUAAAAAAAAbn+EUgAAAAAAALAcoRQAAAAAAAAsRygFAAAAAAAAyxFKAQAAAAAAwHKEUgAAAAAAALAcoRQAAAAAAAAsRygFAAAAAAAAyxFKAQAAAAAAwHKEUgAAAAAAALAcoRQAAAAAAAAs51Aodfjw4fyuAwAAoEhiXgQAAOAYh0Kp6tWrq3379vr444916dKl/K4JAACgyGBeBAAA4BiHQqlffvlFDRs21MiRIxUUFKQnnnhCW7Zsye/aAAAACj3mRQAAAI5xKJRq3LixZs+erRMnTujDDz/UyZMn1bp1a9WvX18zZszQ6dOn87tOAACAQol5EQAAgGNuaaFzd3d39ejRQ8uWLdNrr72mgwcP6vnnn1flypX16KOP6uTJk/lVJwAAQKHGvAgAACBvbimU2rZtm55++mlVrFhRM2bM0PPPP69Dhw4pJiZGJ06cULdu3fKrTgAAgEKNeREAAEDeuDvyohkzZmjBggVKSEhQ165d9dFHH6lr165ydf0r4woNDVV0dLSqVq2an7UCAAAUOsyLAAAAHONQKDV37lw99thjGjhwoCpWrJhrm4CAAM2fP/+WigMAACjsmBcBAAA4xqFQ6sCBA3/bxsPDQwMGDHDk8AAAAEUG8yIAAADHOLSm1IIFC7Rs2bIc25ctW6aFCxfeclEAAABFBfMiAAAAxzgUSk2dOlXly5fPsT0gIECvvvrqLRcFAABQVDAvAgAAcIxDodSxY8cUGhqaY3tISIiOHTt2y0UBAAAUFcyLAAAAHONQKBUQEKCdO3fm2L5jxw6VK1fulosCAAAoKpgXAQAAOMahUKpPnz569tlntX79emVmZiozM1Pr1q3TsGHD1Lt37/yuEQAAoNBiXgQAAOAYh+6+N2nSJB05ckQdOnSQu/tfh8jKytKjjz7K2gkAAKBYYV4EAADgGIdCKQ8PD3366aeaNGmSduzYIW9vbzVo0EAhISH5XR8AAEChxrwIAADAMQ6FUtlq1qypmjVr5lctAAAARRbzIgAAgLxxKJTKzMxUdHS01q5dq1OnTikrK8tu/7p16/KlOAAAgMKOeREAAIBjHAqlhg0bpujoaEVERKh+/fpycXHJ77oAAACKBOZFAAAAjnEolFqyZImWLl2qrl275nc9AAAARQrzIgAAAMe4OvIiDw8PVa9ePb9rAQAAKHKYFwEAADjGoVDqueee0+zZs2WMye96AAAAihTmRQAAAI5x6PK9H3/8UevXr9e3336revXqqUSJEnb7P//883wpDgAAoLBjXgQAAOAYh0IpPz8/Pfjgg/ldCwAAQJHDvAgAAMAxDoVSCxYsyO86AAAAiiTmRQAAAI5xaE0pSbpy5Yq+++47/ec//9H58+clSSdOnFBaWlq+FQcAAFAUMC8CAADIO4fOlDp69Kg6d+6sY8eOKT09Xffdd5/KlCmj1157Tenp6Zo3b15+1wkAAFAoMS8CAABwjENnSg0bNkzNmjXT2bNn5e3tbdv+4IMPau3atflWHAAAQGHHvAgAAMAxDp0p9cMPP+jnn3+Wh4eH3faqVavq999/z5fCAAAAigLmRQAAAI5x6EyprKwsZWZm5tj+22+/qUyZMrdcFAAAQFHBvAgAAMAxDoVSnTp10qxZs2zPXVxclJaWpvHjx6tr1675VRsAAEChx7wIAADAMQ5dvvfmm28qPDxcdevW1aVLl9S3b18dOHBA5cuX1yeffJLfNQIAABRazIsAAAAc41AoValSJe3YsUNLlizRzp07lZaWpsjISPXr189ugU8AAIDbHfMiAAAAxzgUSkmSu7u7HnnkkfysBQAAoEhiXgQAAJB3DoVSH3300Q33P/roow4VAwAAUNQwLwIAAHCMQ6HUsGHD7J5nZGTof//7nzw8PFSyZEkmXwAAoNhgXgQAAOAYh+6+d/bsWbtHWlqaEhIS1Lp1axb0BAAAxQrzIgAAAMc4FErlpkaNGpo2bVqObwsBAACKG+ZFAAAAfy/fQinpr0U+T5w4kZ+HBAAAKJKYFwEAANyYQ2tKff3113bPjTE6efKk3nnnHbVq1SpfCgMAACgKmBcBAAA4xqFQqnv37nbPXVxcVKFCBd177716880386MuAACAIoF5EQAAgGMcCqWysrLyuw4AAIAiiXkRAACAY/J1TSkAAAAAAADgZjh0ptTIkSNvuu2MGTMceQsAAIAigXkRAACAYxwKpbZv367t27crIyNDtWrVkiT9+uuvcnNz01133WVr5+Likj9VAgAAFFLMiwAAABzjUCh1//33q0yZMlq4cKHKli0rSTp79qwGDRqkNm3a6LnnnsvXIgEAAAor5kUAAACOcWhNqTfffFNTp061TbwkqWzZspo8eTJ3mQEAAMUK8yIAAADHOBRKpaam6vTp0zm2nz59WufPn7/logAAAIoK5kUAAACOcejyvQcffFCDBg3Sm2++qbvvvluStHnzZo0aNUo9evTI1wIBAAAKM+ZFKKoio7c6/Nr5A5vnYyUAgOLKoVBq3rx5ev7559W3b19lZGT8dSB3d0VGRur111/P1wIBAAAKM+ZFAAAAjnEolCpZsqTeffddvf766zp06JAkqVq1aipVqlS+FgcAAFDYMS8CAABwjENrSmU7efKkTp48qRo1aqhUqVIyxuRXXQAAAEUK8yIAAIC8cSiU+vPPP9WhQwfVrFlTXbt21cmTJyVJkZGR3PYYAAAUK8yLAAAAHONQKDVixAiVKFFCx44dU8mSJW3bH374Ya1atSrfigMAACjsmBcBAAA4xqE1pdasWaPVq1erUqVKdttr1Kiho0eP5kthAAAARQHzIgAAAMc4dKbUhQsX7L4JzHbmzBl5enreclEAAABFBfMiAAAAxzgUSrVp00YfffSR7bmLi4uysrI0ffp0tW/fPt+KAwAAKOyYFwEAADjGocv3pk+frg4dOmjbtm26fPmyRo8erT179ujMmTP66aef8rtGAACAQot5EQAAgGMcOlOqfv36+vXXX9W6dWt169ZNFy5cUI8ePbR9+3ZVq1Ytv2sEAAAotJgXAQAAOCbPZ0plZGSoc+fOmjdvnl588cWCqAkAAKBIYF4EAADguDyfKVWiRAnt3LmzIGoBAAAoUpgXAQAAOM6hy/ceeeQRzZ8/P79rAQAAKHKYFwEAADjGoYXOr1y5og8//FDfffedmjZtqlKlStntnzFjRr4UBwAAUNjl17xo48aNev311xUXF6eTJ0/qiy++UPfu3W37jTEaP3683n//fZ07d06tWrXS3LlzVaNGDVubM2fO6JlnntE333wjV1dX9ezZU7Nnz1bp0qVtbXbu3KmoqCht3bpVFSpU0DPPPKPRo0ff2iAAAAA4IE+h1OHDh1W1alXt3r1bd911lyTp119/tWvj4uKSf9UBAAAUUvk9L7pw4YIaNWqkxx57TD169Mixf/r06Xrrrbe0cOFChYaG6uWXX1Z4eLj27t0rLy8vSVK/fv108uRJxcTEKCMjQ4MGDdKQIUO0ePFiSVJqaqo6deqkjh07at68edq1a5cee+wx+fn5aciQIY4OBQAAgEPyFErVqFFDJ0+e1Pr16yVJDz/8sN566y0FBgYWSHEAAACFVX7Pi7p06aIuXbrkus8Yo1mzZumll15St27dJEkfffSRAgMD9eWXX6p3797at2+fVq1apa1bt6pZs2aSpLfffltdu3bVG2+8oeDgYC1atEiXL1/Whx9+KA8PD9WrV0/x8fGaMWMGoRQAALBcntaUMsbYPf/222914cKFfC0IAACgKLByXpSYmKikpCR17NjRts3X11ctWrRQbGysJCk2NlZ+fn62QEqSOnbsKFdXV23evNnWpm3btvLw8LC1CQ8PV0JCgs6ePZvre6enpys1NdXuAQAAkB8cWug827WTMQAAgOKqIOdFSUlJkpTjLKzAwEDbvqSkJAUEBNjtd3d3l7+/v12b3I5x9Xtca+rUqfL19bU9KleufOsdAgAAUB5DKRcXlxxrI7CGFAAAKI6Ky7xo7NixSklJsT2OHz/u7JIAAMBtIk9rShljNHDgQHl6ekqSLl26pCeffDLHXWY+//zz/KsQAACgELJyXhQUFCRJSk5OVsWKFW3bk5OT1bhxY1ubU6dO2b3uypUrOnPmjO31QUFBSk5OtmuT/Ty7zbU8PT1tfQQAAMhPeQqlBgwYYPf8kUceyddiAAAAigor50WhoaEKCgrS2rVrbSFUamqqNm/erKeeekqSFBYWpnPnzikuLk5NmzaVJK1bt05ZWVlq0aKFrc2LL76ojIwMlShRQpIUExOjWrVqqWzZsgVWPwAAQG7yFEotWLCgoOoAAAAoUvJ7XpSWlqaDBw/anicmJio+Pl7+/v6qUqWKhg8frsmTJ6tGjRoKDQ3Vyy+/rODgYHXv3l2SVKdOHXXu3FmPP/645s2bp4yMDA0dOlS9e/dWcHCwJKlv37565ZVXFBkZqTFjxmj37t2aPXu2Zs6cma99AQAAuBl5CqUAAABQMLZt26b27dvbno8cOVLSX2dkRUdHa/To0bpw4YKGDBmic+fOqXXr1lq1apW8vLxsr1m0aJGGDh2qDh06yNXVVT179tRbb71l2+/r66s1a9YoKipKTZs2Vfny5TVu3DgNGTLEuo4CAAD8/wilAAAACoF27drd8A5+Li4umjhxoiZOnHjdNv7+/lq8ePEN36dhw4b64YcfHK4TAAAgv+Tp7nsAAAAAAABAfiCUAgAAAAAAgOUIpQAAAAAAAGA5QikAAAAAAABYjlAKAAAAAAAAliOUAgAAAAAAgOWcGkpNnTpVzZs3V5kyZRQQEKDu3bsrISHBrs2lS5cUFRWlcuXKqXTp0urZs6eSk5Pt2hw7dkwREREqWbKkAgICNGrUKF25csWuzYYNG3TXXXfJ09NT1atXV3R0dEF3DwAAAAAAANfh1FDq+++/V1RUlDZt2qSYmBhlZGSoU6dOunDhgq3NiBEj9M0332jZsmX6/vvvdeLECfXo0cO2PzMzUxEREbp8+bJ+/vlnLVy4UNHR0Ro3bpytTWJioiIiItS+fXvFx8dr+PDhGjx4sFavXm1pfwEAAAAAAPAXd2e++apVq+yeR0dHKyAgQHFxcWrbtq1SUlI0f/58LV68WPfee68kacGCBapTp442bdqkli1bas2aNdq7d6++++47BQYGqnHjxpo0aZLGjBmjCRMmyMPDQ/PmzVNoaKjefPNNSVKdOnX0448/aubMmQoPD7e83wAAAAAAAMVdoVpTKiUlRZLk7+8vSYqLi1NGRoY6duxoa1O7dm1VqVJFsbGxkqTY2Fg1aNBAgYGBtjbh4eFKTU3Vnj17bG2uPkZ2m+xjAAAAAAAAwFpOPVPqallZWRo+fLhatWql+vXrS5KSkpLk4eEhPz8/u7aBgYFKSkqytbk6kMren73vRm1SU1N18eJFeXt72+1LT09Xenq67XlqauqtdxAAAAAAAAA2heZMqaioKO3evVtLlixxdimaOnWqfH19bY/KlSs7uyQAAAAAAIDbSqEIpYYOHarly5dr/fr1qlSpkm17UFCQLl++rHPnztm1T05OVlBQkK3NtXfjy37+d218fHxynCUlSWPHjlVKSortcfz48VvuIwAAAAAAAP6PU0MpY4yGDh2qL774QuvWrVNoaKjd/qZNm6pEiRJau3atbVtCQoKOHTumsLAwSVJYWJh27dqlU6dO2drExMTIx8dHdevWtbW5+hjZbbKPcS1PT0/5+PjYPQAAAAAAAJB/nLqmVFRUlBYvXqyvvvpKZcqUsa0B5evrK29vb/n6+ioyMlIjR46Uv7+/fHx89MwzzygsLEwtW7aUJHXq1El169ZV//79NX36dCUlJemll15SVFSUPD09JUlPPvmk3nnnHY0ePVqPPfaY1q1bp6VLl2rFihVO6zsAAAAAAEBx5tRQau7cuZKkdu3a2W1fsGCBBg4cKEmaOXOmXF1d1bNnT6Wnpys8PFzvvvuura2bm5uWL1+up556SmFhYSpVqpQGDBigiRMn2tqEhoZqxYoVGjFihGbPnq1KlSrpgw8+UHh4eIH3EQAAALjdREZvvaXXzx/YPJ8qAQAUZU4NpYwxf9vGy8tLc+bM0Zw5c67bJiQkRCtXrrzhcdq1a6ft27fnuUYAAAAAAADkv0Kx0DkAAAAAAACKF0IpAAAAAAAAWI5QCgAAAAAAAJYjlAIAAAAAAIDlCKUAAAAAAABgOUIpAAAAAAAAWI5QCgAAAAAAAJYjlAIAAAAAAIDlCKUAAAAAAABgOXdnFwAAAAAAVoiM3urwa+cPbJ6PlQAAJM6UAgAAAAAAgBMQSgEAAAAAAMByXL4HAAAAwFJcRgcAkDhTCgAAAAAAAE5AKAUAAAAAAADLEUoBAAAAAADAcoRSAAAAAAAAsByhFAAAAAAAACxHKAUAAAAAAADLEUoBAAAAAADAcoRSAAAAAAAAsByhFAAAAAAAACxHKAUAAAAAAADLEUoBAAAAAADAcu7OLgAAAAAAblZk9FZnlwAAyCecKQUAAAAAAADLEUoBAAAAAADAcoRSAAAAAAAAsByhFAAAAAAAACxHKAUAAAAAAADLEUoBAAAAAADAcoRSAAAAAAAAsByhFAAAAAAAACxHKAUAAAAAAADLEUoBAAAAAADAcoRSAAAAAAAAsByhFAAAAAAAACxHKAUAAAAAAADLEUoBAAAAAADAcoRSAAAAAAAAsByhFAAAAAAAACxHKAUAAAAAAADLEUoBAAAAAADAcu7OLgAAAAAAbneR0Vsdfu38gc3zsRIAKDwIpYq4W/nlJvELDgAAAAAAOAeX7wEAAAAAAMBynCkFAAAAAH/jVq9QAADkxJlSAAAAAAAAsByhFAAAAAAAACxHKAUAAAAAAADLEUoBAAAAAADAcoRSAAAAAAAAsByhFAAAAAAAACxHKAUAAAAAAADLEUoBAAAAAADAcoRSAAAAAAAAsByhFAAAAAAAACxHKAUAAAAAAADLEUoBAAAAAADAcoRSAAAAAAAAsByhFAAAAAAAACxHKAUAAAAAAADLEUoBAAAAAADAcu7OLgAAAAAAUPhERm91+LXzBzbPx0oA3K44UwoAAAAAAACWI5QCAAAAAACA5QilAAAAAAAAYDlCKQAAAAAAAFiOUAoAAAAAAACWI5QCAAAAAACA5dydXQCci9u8AgAAAAAAZ+BMKQAAAAAAAFiOUAoAAAAAAACW4/I9AAAAALhN3cpyHQBQ0AilAAAAAAD56lbDMNavBYoHQikAAAAAQKHCDZmA4oE1pQAAAAAAAGA5QikAAAAAAABYjlAKAAAAAAAAliOUAgAAAAAAgOUIpQAAAAAAAGA57r4HAAAAAIXYrdyJDgAKM86UAgAAKAImTJggFxcXu0ft2rVt+y9duqSoqCiVK1dOpUuXVs+ePZWcnGx3jGPHjikiIkIlS5ZUQECARo0apStXrljdFQAAAEmcKQUAAFBk1KtXT999953tubv7/03lRowYoRUrVmjZsmXy9fXV0KFD1aNHD/3000+SpMzMTEVERCgoKEg///yzTp48qUcffVQlSpTQq6++anlfAAAACKUAAACKCHd3dwUFBeXYnpKSovnz52vx4sW69957JUkLFixQnTp1tGnTJrVs2VJr1qzR3r179d133ykwMFCNGzfWpEmTNGbMGE2YMEEeHh5WdwcACsStXO44f2DzfKwEwN/h8j0AAIAi4sCBAwoODtadd96pfv366dixY5KkuLg4ZWRkqGPHjra2tWvXVpUqVRQbGytJio2NVYMGDRQYGGhrEx4ertTUVO3Zs+e675menq7U1FS7BwAAQH4glAIAACgCWrRooejoaK1atUpz585VYmKi2rRpo/PnzyspKUkeHh7y8/Oze01gYKCSkpIkSUlJSXaBVPb+7H3XM3XqVPn6+toelStXzt+OAQCAYovL9wAAAIqALl262P6/YcOGatGihUJCQrR06VJ5e3sX2PuOHTtWI0eOtD1PTU0lmAIAAPmCM6UAAACKID8/P9WsWVMHDx5UUFCQLl++rHPnztm1SU5Otq1BFRQUlONufNnPc1unKpunp6d8fHzsHgAAAPmBUAoAAKAISktL06FDh1SxYkU1bdpUJUqU0Nq1a237ExISdOzYMYWFhUmSwsLCtGvXLp06dcrWJiYmRj4+Pqpbt67l9QMAADg1lNq4caPuv/9+BQcHy8XFRV9++aXdfmOMxo0bp4oVK8rb21sdO3bUgQMH7NqcOXNG/fr1k4+Pj/z8/BQZGam0tDS7Njt37lSbNm3k5eWlypUra/r06QXdNQAAgHz1/PPP6/vvv9eRI0f0888/68EHH5Sbm5v69OkjX19fRUZGauTIkVq/fr3i4uI0aNAghYWFqWXLlpKkTp06qW7duurfv7927Nih1atX66WXXlJUVJQ8PT2d3DsAAFAcOTWUunDhgho1aqQ5c+bkun/69Ol66623NG/ePG3evFmlSpVSeHi4Ll26ZGvTr18/7dmzRzExMVq+fLk2btyoIUOG2PanpqaqU6dOCgkJUVxcnF5//XVNmDBB7733XoH3DwAAIL/89ttv6tOnj2rVqqVevXqpXLly2rRpkypUqCBJmjlzpv75z3+qZ8+eatu2rYKCgvT555/bXu/m5qbly5fLzc1NYWFheuSRR/Too49q4sSJzuoSAAAo5py60HmXLl3sFu28mjFGs2bN0ksvvaRu3bpJkj766CMFBgbqyy+/VO/evbVv3z6tWrVKW7duVbNmzSRJb7/9trp27ao33nhDwcHBWrRokS5fvqwPP/xQHh4eqlevnuLj4zVjxgy78AoAAKAwW7JkyQ33e3l5ac6cOdf9sk+SQkJCtHLlyvwuDQAAwCGFdk2pxMREJSUlqWPHjrZtvr6+atGihWJjYyVJsbGx8vPzswVSktSxY0e5urpq8+bNtjZt27aVh4eHrU14eLgSEhJ09uxZi3oDAAAAAACAqzn1TKkbSUpKkiQFBgbabQ8MDLTtS0pKUkBAgN1+d3d3+fv727UJDQ3NcYzsfWXLls3x3unp6UpPT7c9T01NvcXeAAAAAAAA4GqF9kwpZ5o6dap8fX1tj8qVKzu7JAAAAAAAgNtKoQ2lgoKCJEnJycl225OTk237goKC7G5rLElXrlzRmTNn7Nrkdoyr3+NaY8eOVUpKiu1x/PjxW+8QAAAAAAAAbAptKBUaGqqgoCCtXbvWti01NVWbN29WWFiYJCksLEznzp1TXFycrc26deuUlZWlFi1a2Nps3LhRGRkZtjYxMTGqVatWrpfuSZKnp6d8fHzsHgAAAAAAAMg/Tg2l0tLSFB8fr/j4eEl/LW4eHx+vY8eOycXFRcOHD9fkyZP19ddfa9euXXr00UcVHBys7t27S5Lq1Kmjzp076/HHH9eWLVv0008/aejQoerdu7eCg4MlSX379pWHh4ciIyO1Z88effrpp5o9e7ZGjhzppF4DAAAAAADAqQudb9u2Te3bt7c9zw6KBgwYoOjoaI0ePVoXLlzQkCFDdO7cObVu3VqrVq2Sl5eX7TWLFi3S0KFD1aFDB7m6uqpnz5566623bPt9fX21Zs0aRUVFqWnTpipfvrzGjRunIUOGWNdRAAAAAAAA2HFqKNWuXTsZY66738XFRRMnTtTEiROv28bf31+LFy++4fs0bNhQP/zwg8N1AgAAAAAAIH8V2jWlAAAAAAAAcPsilAIAAAAAAIDlCKUAAAAAAABgOUIpAAAAAAAAWM6pC50DjoiM3npLr58/sHk+VQIAAAAAABzFmVIAAAAAAACwHKEUAAAAAAAALEcoBQAAAAAAAMuxphQcditrO7GuEwAAAAAAxRtnSgEAAAAAAMByhFIAAAAAAACwHKEUAAAAAAAALEcoBQAAAAAAAMsRSgEAAAAAAMByhFIAAAAAAACwnLuzC0DxFBm91dklAAAAAAAAJ+JMKQAAAAAAAFiOUAoAAAAAAACWI5QCAAAAAACA5VhTCsXOraxnNX9g83ysBAAAAACA4oszpQAAAAAAAGA5QikAAAAAAABYjlAKAAAAAAAAlmNNqULgVtY4AgAAAAAAKIo4UwoAAAAAAACW40wpAAAAAADEnboBq3GmFAAAAAAAACxHKAUAAAAAAADLcfkekAeczgsAAAAAQP7gTCkAAAAAAABYjlAKAAAAAAAAliOUAgAAAAAAgOUIpQAAAAAAAGA5QikAAAAAAABYjlAKAAAAAAAAliOUAgAAAAAAgOUIpQAAAAAAAGA5QikAAAAAAABYjlAKAAAAAAAAliOUAgAAAAAAgOUIpQAAAAAAAGA5QikAAAAAAABYjlAKAAAAAAAAliOUAgAAAAAAgOXcnV0AUFxERm91+LXzBzbPx0oAAAAAAHA+zpQCAAAAAACA5QilAAAAAAAAYDlCKQAAAAAAAFiOUAoAAAAAAACWI5QCAAAAAACA5bj7HlAE3Mqd+24Vd/4DAAAAABQEQikABeZWwjTCMAAAAAC4vXH5HgAAAAAAACxHKAUAAAAAAADLEUoBAAAAAADAcoRSAAAAAAAAsBwLnQO4IWfe+Q8AAAAAcPviTCkAAAAAAABYjjOlAAAAAAC4Rbd6hcH8gc3zqRKg6OBMKQAAAAAAAFiOUAoAAAAAAACWI5QCAAAAAACA5VhTCkChdCvX5HM9PgAAAAAUfpwpBQAAAAAAAMtxphQA5CPO8AIA57nVO18BgDMxj0RxRCgFANfgHzUAAAAAUPC4fA8AAAAAAACWI5QCAAAAAACA5QilAAAAAAAAYDlCKQAAAAAAAFiOUAoAAAAAAACW4+57AG473D0PAAAAAAo/zpQCAAAAAACA5QilAAAAAAAAYDlCKQAAAAAAAFiONaUAoJi71TW45g9snk+VAAAAAChOCKUAoJC4lXCIYAgAAABAUUMoBQC3Ae44CAAAAKCoYU0pAAAAAAAAWI4zpQAATsMliwAAAEDxRSgFALglXDoIAAAAwBFcvgcAAAAAAADLcaYUAKBI4tK/vGG8AAC4ffF7HkUVoRQAAHnExA8AAAC4dVy+BwAAAAAAAMtxphQAoNhhcXYAAADA+QilAACwEIEYAAAoTFiWAM5EKAUAAG6IIA0AAAAFgVAKAAAAhQYhKAAAxQehFAAAAAAAyDNnfpHApYO3h2IVSs2ZM0evv/66kpKS1KhRI7399tu6++67nV0WAACApZgTAQCKOtbCuj24OrsAq3z66acaOXKkxo8fr19++UWNGjVSeHi4Tp065ezSAAAALMOcCAAAFBbFJpSaMWOGHn/8cQ0aNEh169bVvHnzVLJkSX344YfOLg0AAMAyzIkAAEBhUSxCqcuXLysuLk4dO3a0bXN1dVXHjh0VGxvrxMoAAACsw5wIAAAUJsViTak//vhDmZmZCgwMtNseGBio/fv352ifnp6u9PR02/OUlBRJUmpqaoHUd/liWoEcFwCAoq6gfvdmH9cYUyDHL6zyOieSmBcBAG4//eeud3YJDpnTr2m+H9PZc6JiEUrl1dSpU/XKK6/k2F65cmUnVAMAQPH18dMFe/zz58/L19e3YN+kiGNeBABA4VCQ86I///zTKXOiYhFKlS9fXm5ubkpOTrbbnpycrKCgoBztx44dq5EjR9qeZ2Vl6cyZMypXrpxcXFzytbbU1FRVrlxZx48fl4+PT74euyhjXK6Psckd45I7xiV3jMv1FZexMcbo/PnzCg4OdnYplsrrnEgq2HlRcfl5ywvGJCfGJCfGJCfGJCfGJCfGJKeUlBRVqVJF/v7+Tnn/YhFKeXh4qGnTplq7dq26d+8u6a8J1dq1azV06NAc7T09PeXp6Wm3zc/Pr0Br9PHx4S9FLhiX62Nscse45I5xyR3jcn3FYWyK4xlSeZ0TSdbMi4rDz1teMSY5MSY5MSY5MSY5MSY5MSY5ubo6Z8nxYhFKSdLIkSM1YMAANWvWTHfffbdmzZqlCxcuaNCgQc4uDQAAwDLMiQAAQGFRbEKphx9+WKdPn9a4ceOUlJSkxo0ba9WqVTkW+gQAALidMScCAACFRbEJpSRp6NCh1z013Vk8PT01fvz4HKfFF3eMy/UxNrljXHLHuOSOcbk+xqZ4KCxzIn7ecmJMcmJMcmJMcmJMcmJMcmJMcnL2mLiY4nYvZAAAAAAAADidc1ayAgAAAAAAQLFGKAUAAAAAAADLEUoBAAAAAADAcoRSFpgzZ46qVq0qLy8vtWjRQlu2bLlu2/fff19t2rRR2bJlVbZsWXXs2PGG7YuyvIzL1ZYsWSIXFxd17969YAt0oryOzblz5xQVFaWKFSvK09NTNWvW1MqVKy2q1jp5HZdZs2apVq1a8vb2VuXKlTVixAhdunTJomqtsXHjRt1///0KDg6Wi4uLvvzyy799zYYNG3TXXXfJ09NT1atXV3R0dIHXabW8jsvnn3+u++67TxUqVJCPj4/CwsK0evVqa4q1kCM/L9l++uknubu7q3HjxgVWH4oXR+cBhd3UqVPVvHlzlSlTRgEBAerevbsSEhLs2ly6dElRUVEqV66cSpcurZ49eyo5OdmuzbFjxxQREaGSJUsqICBAo0aN0pUrV+zaFNXP82nTpsnFxUXDhw+3bSuOY/L777/rkUceUbly5eTt7a0GDRpo27Zttv3GGI0bN04VK1aUt7e3OnbsqAMHDtgd48yZM+rXr598fHzk5+enyMhIpaWl2bXZuXOn2rRpIy8vL1WuXFnTp0+3pH95lZmZqZdfflmhoaHy9vZWtWrVNGnSJF29BHJxGJO/+11t5RgsW7ZMtWvXlpeXlxo0aOC0f1/caEwyMjI0ZswYNWjQQKVKlVJwcLAeffRRnThxwu4YxWlMrvXkk0/KxcVFs2bNstteaMbEoEAtWbLEeHh4mA8//NDs2bPHPP7448bPz88kJyfn2r5v375mzpw5Zvv27Wbfvn1m4MCBxtfX1/z2228WV16w8jou2RITE80dd9xh2rRpY7p162ZNsRbL69ikp6ebZs2ama5du5off/zRJCYmmg0bNpj4+HiLKy9YeR2XRYsWGU9PT7No0SKTmJhoVq9ebSpWrGhGjBhhceUFa+XKlebFF180n3/+uZFkvvjiixu2P3z4sClZsqQZOXKk2bt3r3n77beNm5ubWbVqlTUFWySv4zJs2DDz2muvmS1btphff/3VjB071pQoUcL88ssv1hRskbyOS7azZ8+aO++803Tq1Mk0atSoQGtE8eDoPKAoCA8PNwsWLDC7d+828fHxpmvXrqZKlSomLS3N1ubJJ580lStXNmvXrjXbtm0zLVu2NP/4xz9s+69cuWLq169vOnbsaLZv325Wrlxpypcvb8aOHWtrU1Q/z7ds2WKqVq1qGjZsaIYNG2bbXtzG5MyZMyYkJMQMHDjQbN682Rw+fNisXr3aHDx40NZm2rRpxtfX13z55Zdmx44d5oEHHjChoaHm4sWLtjadO3c2jRo1Mps2bTI//PCDqV69uunTp49tf0pKigkMDDT9+vUzu3fvNp988onx9vY2//nPfyzt782YMmWKKVeunFm+fLlJTEw0y5YtM6VLlzazZ8+2tSkOY/J3v6utGoOffvrJuLm5menTp5u9e/eal156yZQoUcLs2rWrwMfgWjcak3PnzpmOHTuaTz/91Ozfv9/Exsaau+++2zRt2tTuGMVpTK72+eefm0aNGpng4GAzc+ZMu32FZUwIpQrY3XffbaKiomzPMzMzTXBwsJk6depNvf7KlSumTJkyZuHChQVVolM4Mi5Xrlwx//jHP8wHH3xgBgwYcNuGUnkdm7lz55o777zTXL582aoSnSKv4xIVFWXuvfdeu20jR440rVq1KtA6nelmQobRo0ebevXq2W17+OGHTXh4eAFW5lx5CV+uVrduXfPKK6/kf0GFRF7G5eGHHzYvvfSSGT9+PKEU8sWtzo+KklOnThlJ5vvvvzfG/PUPqBIlSphly5bZ2uzbt89IMrGxscaYv/6x4erqapKSkmxt5s6da3x8fEx6eroxpmh+np8/f97UqFHDxMTEmHvuuccWShXHMRkzZoxp3br1dfdnZWWZoKAg8/rrr9u2nTt3znh6eppPPvnEGGPM3r17jSSzdetWW5tvv/3WuLi4mN9//90YY8y7775rypYtaxuj7PeuVatWfnfplkVERJjHHnvMbluPHj1Mv379jDHFc0yu/V1t5Rj06tXLRERE2NXTokUL88QTT+RrH/PqZuYvW7ZsMZLM0aNHjTHFd0x+++03c8cdd5jdu3ebkJAQu1CqMI0Jl+8VoMuXLysuLk4dO3a0bXN1dVXHjh0VGxt7U8f43//+p4yMDPn7+xdUmZZzdFwmTpyogIAARUZGWlGmUzgyNl9//bXCwsIUFRWlwMBA1a9fX6+++qoyMzOtKrvAOTIu//jHPxQXF2e7HOTw4cNauXKlunbtaknNhVVsbKzdOEpSeHj4TX8mFRdZWVk6f/78bfXZ66gFCxbo8OHDGj9+vLNLwW0iP+ZHRUlKSook2T5P4uLilJGRYdf/2rVrq0qVKrb+x8bGqkGDBgoMDLS1CQ8PV2pqqvbs2WNrU9Q+z6OiohQREZGj7uI4Jl9//bWaNWumf/3rXwoICFCTJk30/vvv2/YnJiYqKSnJrj++vr5q0aKF3Zj4+fmpWbNmtjYdO3aUq6urNm/ebGvTtm1beXh42NqEh4crISFBZ8+eLehu5sk//vEPrV27Vr/++qskaceOHfrxxx/VpUsXScVzTK5l5RgUpb9P10pJSZGLi4v8/PwkFc8xycrKUv/+/TVq1CjVq1cvx/7CNCbueeoZ8uSPP/5QZmam3S9PSQoMDNT+/ftv6hhjxoxRcHBwjj/oosyRcfnxxx81f/58xcfHW1Ch8zgyNocPH9a6devUr18/rVy5UgcPHtTTTz+tjIyM2+YfkY6MS9++ffXHH3+odevWMsboypUrevLJJ/Xvf//bipILraSkpFzHMTU1VRcvXpS3t7eTKitc3njjDaWlpalXr17OLsWpDhw4oBdeeEE//PCD3N2ZMiB/5Mf8qKjIysrS8OHD1apVK9WvX1/SX5/DHh4etn8sZQsMDFRSUpKtTW7jk73vRm0K6+f5kiVL9Msvv2jr1q059hXHMTl8+LDmzp2rkSNH6t///re2bt2qZ599Vh4eHhowYICtT7n15+r+BgQE2O13d3eXv7+/XZvQ0NAcx8jeV7Zs2QLpnyNeeOEFpaamqnbt2nJzc1NmZqamTJmifv36SVKxHJNrWTkG1/v7lH2MwurSpUsaM2aM+vTpIx8fH0nFc0xee+01ubu769lnn811f2EaE2aYhdi0adO0ZMkSbdiwQV5eXs4ux2nOnz+v/v376/3331f58uWdXU6hk5WVpYCAAL333ntyc3NT06ZN9fvvv+v111+/bUIpR2zYsEGvvvqq3n33XbVo0UIHDx7UsGHDNGnSJL388svOLg+F2OLFi/XKK6/oq6++yvHLujjJzMxU37599corr6hmzZrOLgcokqKiorR79279+OOPzi7FqY4fP65hw4YpJiamWM9pr5aVlaVmzZrp1VdflSQ1adJEu3fv1rx58zRgwAAnV+ccS5cu1aJFi7R48WLVq1dP8fHxGj58uIKDg4vtmCBvMjIy1KtXLxljNHfuXGeX4zRxcXGaPXu2fvnlF7m4uDi7nL/F5XsFqHz58nJzc8tx55Dk5GQFBQXd8LVvvPGGpk2bpjVr1qhhw4YFWabl8jouhw4d0pEjR3T//ffL3d1d7u7u+uijj/T111/L3d1dhw4dsqr0AufIz0zFihVVs2ZNubm52bbVqVNHSUlJunz5coHWaxVHxuXll19W//79NXjwYDVo0EAPPvigXn31VU2dOlVZWVlWlF0oBQUF5TqOPj4+heobZGdZsmSJBg8erKVLl95WZ6g64vz589q2bZuGDh1q++ydOHGiduzYIXd3d61bt87ZJaKIupX5UVEydOhQLV++XOvXr1elSpVs24OCgnT58mWdO3fOrv3V/b/eZ3X2vhu1KYyf53FxcTp16pTuuusu2+fJ999/r7feekvu7u4KDAwsdmNSsWJF1a1b125bnTp1dOzYMUn/16cb/T0JCgrSqVOn7PZfuXJFZ86cydO4FRajRo3SCy+8oN69e6tBgwbq37+/RowYoalTp0oqnmNyLSvH4HptCusYZQdSR48eVUxMjO0sKan4jckPP/ygU6dOqUqVKrbP3KNHj+q5555T1apVJRWuMSGUKkAeHh5q2rSp1q5da9uWlZWltWvXKiws7Lqvmz59uiZNmqRVq1bZXeN5u8jruNSuXVu7du1SfHy87fHAAw+offv2io+PV+XKla0sv0A58jPTqlUrHTx40C5o+fXXX1WxYkW763+LMkfG5X//+59cXe0/4rKDO3PVrYWLm7CwMLtxlKSYmJgbfiYVF5988okGDRqkTz75RBEREc4ux+l8fHxyfPY++eSTqlWrluLj49WiRQtnl4giytH5UVFhjNHQoUP1xRdfaN26dTkufWjatKlKlChh1/+EhAQdO3bM1v+wsDDt2rXL7h8M2f/Iyg4yitLneYcOHXJ8njRr1kz9+vWz/X9xG5NWrVop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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "panda_df = df.select(\"locusSize\", \"locusLength\").toPandas()\n", + "\n", + "plt.figure(figsize=(12, 6))\n", + "\n", + "# Histogram for locusLength\n", + "plt.subplot(1, 2, 1) # 1 row, 2 columns, 1st subplot\n", + "plt.hist(panda_df[\"locusLength\"], bins=30, alpha=0.7)\n", + "plt.xlabel(\"Locus Length\")\n", + "plt.ylabel(\"Frequency\")\n", + "plt.title(\"Histogram of Locus Length\")\n", + "\n", + "# Histogram for locusSize\n", + "plt.subplot(1, 2, 2) # 1 row, 2 columns, 2nd subplot\n", + "plt.hist(panda_df[\"locusSize\"], bins=30, alpha=0.7)\n", + "plt.xlabel(\"Locus Size\")\n", + "plt.ylabel(\"Frequency\")\n", + "plt.title(\"Histogram of Locus Size\")\n", + "\n", + "plt.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAA2MAAAIjCAYAAACOHsPRAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/TGe4hAAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOz9d5xdd3Xvjb93P33O9KI2GhU3yXJvsrGNsY1xyDUdm+JCCpeWhOcm9+dLHrBxCJd2Q0ISSB6eYAMPxEAw3bZsbAzYYNxtWb1L0+vpu39/f+xzjmY0M9KojmV/36+XXpL2OXvv765nre9a67MUIYRAIpFIJBKJRCKRSCQnFHW+ByCRSCQSiUQikUgkr0WkMyaRSCQSiUQikUgk84B0xiQSiUQikUgkEolkHpDOmEQikUgkEolEIpHMA9IZk0gkEolEIpFIJJJ5QDpjEolEIpFIJBKJRDIPSGdMIpFIJBKJRCKRSOYB6YxJJBKJRCKRSCQSyTwgnTGJRCKRSCQSiUQimQekMyaRSCQnmF27dqEoCnffffd8D2UKDzzwAGeddRaxWAxFUZiYmJjvIb3ieKVeO8mrB0VR+MhHPjLfw5BIJCcI6YxJJJJjxksvvcTb3/52lixZQiwWY8GCBVx99dV85StfOW77/M53vsOXv/zlacv7+vq44447eP7554/bvg/kV7/6FYqi1P8YhkFPTw/vf//72bFjxzHZxxNPPMEdd9xxzB2l0dFR3vnOdxKPx/mXf/kXvvWtb5FMJmf87t13342iKDz99NPHdAzzzU9/+lMuv/xy2traSCQS9PT08M53vpMHHnhgvod2XHk1Xs9bbrmFVCo138OYleP1HEskkpMP6YxJJJJjwhNPPMF5553HCy+8wJ/+6Z/yz//8z/zJn/wJqqryj//4j8dtvwdzxu68884T6ozV+NjHPsa3vvUt/v3f/53rr7+ee++9l/PPP5++vr6j3vYTTzzBnXfeecyNuKeeeopCocBdd93FBz7wAd773vdiGMYx3ccrmS9+8Yv88R//MYqicPvtt/MP//APvO1tb2Pr1q3853/+Z/17S5YsoVKp8L73vW8eRys52Tlez7FEIjn50Od7ABKJ5NXBZz7zGRoaGnjqqafIZrNTPhsaGpqfQR0HSqXSrBGjGpdddhlvf/vbAbj11ltZuXIlH/vYx7jnnnu4/fbbT8QwD5vaNTrw2r0W8H2fu+66i6uvvpp169ZN+3zy/asoCrFY7EQOTyKRSCSvYmRkTCKRHBO2b9/OGWecMaMx39bWNm3Zt7/9bS644AISiQSNjY287nWvm2II//jHP+b666+nq6sLy7JYtmwZd911F0EQ1L9zxRVX8POf/5zdu3fXUwO7u7v51a9+xfnnnw9EzlDts8l1Pk8++SRvfOMbaWhoIJFIcPnll/P4449PGeMdd9yBoihs2LCBm266icbGRi699NLDPjevf/3rAdi5c+dBv/fII49w2WWXkUwmyWaz/Lf/9t/YuHHjlPH89V//NQBLly6tH9euXbsOut3vf//7nHvuucTjcVpaWnjve99Lb29v/fMrrriCm2++GYDzzz8fRVG45ZZbDvs4D+S5557juuuuI5PJkEqluOqqq/j9738/7XsTExP81V/9Fd3d3ViWxcKFC3n/+9/PyMgIsD+N7sDjrKWF/upXv6ov27p1K29729vo6OggFouxcOFC3v3ud5PL5WYd58jICPl8nrVr1874+eT798CasQNTUyf/6e7unrKd+++/v3590+k0119/PS+//PJBziA8/fTTKIrCPffcM+2zBx98EEVR+NnPfgZAoVDgL//yL+vnsa2tjauvvppnn332oPuYKyfL9TwcDuc9sG3bNm655Ray2SwNDQ3ceuutlMvlKd+tVCp87GMfo6WlhXQ6zR//8R/T29uLoijccccd9e3N5Tn+0Y9+xKpVq7AsizPOOONVny4rkbxWkZExiURyTFiyZAm/+93vWL9+PatWrTrod++8807uuOMOLrnkEj796U9jmiZPPvkkjzzyCNdccw0QGWypVIqPf/zjpFIpHnnkET75yU+Sz+f5whe+AMAnPvEJcrkc+/bt4x/+4R8ASKVSnHbaaXz605/mk5/8JH/2Z3/GZZddBsAll1wCRE7Pddddx7nnnsunPvUpVFXlG9/4Bq9//ev5zW9+wwUXXDBlvO94xztYsWIFf//3f48Q4rDPzfbt2wFobm6e9TsPP/ww1113HT09Pdxxxx1UKhW+8pWvsHbtWp599lm6u7t561vfypYtW/jud7/LP/zDP9DS0gJAa2vrrNu9++67ufXWWzn//PP57Gc/y+DgIP/4j//I448/znPPPUc2m+UTn/gEp5xyCv/+7//Opz/9aZYuXcqyZcsO+zgn8/LLL3PZZZeRyWT4m7/5GwzD4N/+7d+44ooreOyxx7jwwgsBKBaLXHbZZWzcuJHbbruNc845h5GREX7yk5+wb9+++jHOBdd1ufbaa3Ech49+9KN0dHTQ29vLz372MyYmJmhoaJhxvba2NuLxOD/96U/56Ec/SlNT05z3edppp/Gtb31ryrKJiQk+/vGPT3HivvWtb3HzzTdz7bXX8rnPfY5yucxXv/pVLr30Up577rlpjluN8847j56eHr73ve/VHeYa9957L42NjVx77bUAfPCDH+QHP/gBH/nIRzj99NMZHR3lt7/9LRs3buScc86Z8zHNxMl0PefK4b4H3vnOd7J06VI++9nP8uyzz/L1r3+dtrY2Pve5z9W/c8stt/C9732P973vfVx00UU89thjXH/99VO2M5fn+Le//S0//OEP+dCHPkQ6neaf/umfeNvb3saePXsO+h6RSCQnIUIikUiOAevWrROapglN08TFF18s/uZv/kY8+OCDwnXdKd/bunWrUFVVvOUtbxFBEEz5LAzD+r/L5fK0ffz5n/+5SCQSwrbt+rLrr79eLFmyZNp3n3rqKQGIb3zjG9P2sWLFCnHttddO29/SpUvF1VdfXV/2qU99SgDixhtvnNM5ePTRRwUg/uM//kMMDw+Lvr4+8fOf/1x0d3cLRVHEU089JYQQYufOndPGdtZZZ4m2tjYxOjpaX/bCCy8IVVXF+9///vqyL3zhCwIQO3fuPOR4XNcVbW1tYtWqVaJSqdSX/+xnPxOA+OQnP1lf9o1vfEMA9TEejLl894YbbhCmaYrt27fXl/X19Yl0Oi1e97rX1Zd98pOfFID44Q9/OG0btetT29+Bx1w7348++qgQQojnnntOAOL73//+IY/hQGrjSCaT4rrrrhOf+cxnxDPPPDPtezNduwPH/Ed/9EcilUqJl19+WQghRKFQENlsVvzpn/7plO8ODAyIhoaGacsP5PbbbxeGYYixsbH6MsdxRDabFbfddlt9WUNDg/jwhz8810Ou82q8njfffLNIJpOzfn4k74HJ51oIId7ylreI5ubm+v+feeYZAYi//Mu/nPK9W265RQDiU5/6VH3ZwZ5jQJimKbZt21Zf9sILLwhAfOUrXznksUskkpMLmaYokUiOCVdffTW/+93v+OM//mNeeOEFPv/5z3PttdeyYMECfvKTn9S/96Mf/YgwDPnkJz+Jqk59BSmKUv93PB6v/7tQKDAyMsJll11GuVxm06ZNRzzO559/nq1bt3LTTTcxOjrKyMgIIyMjlEolrrrqKn79618ThuGUdT74wQ8e1j5uu+02Wltb6erq4vrrr6dUKnHPPfdw3nnnzfj9/v5+nn/+eW655ZYpUZkzzzyTq6++ml/84heHf6BEKW5DQ0N86EMfmlLndP3113Pqqafy85///Ii2eyiCIGDdunXccMMN9PT01Jd3dnZy00038dvf/pZ8Pg/Af/3Xf7FmzRre8pa3TNvO5PthLtQiJQ8++OC09LFDceedd/Kd73yHs88+mwcffJBPfOITnHvuuZxzzjlTUkUPxV133cXPfvYz7r77bk4//XQAHnroISYmJrjxxhvr99vIyAiapnHhhRfy6KOPHnSb73rXu/A8jx/+8If1ZevWrWNiYoJ3vetd9WXZbJYnn3zymAjFTOZkvJ6H4li8By677DJGR0frx15LI/zQhz405Xsf/ehHD3t8b3jDG6ZEp88880wymcwxU2WVSCSvHF7Tztivf/1r3vzmN9PV1YWiKPzoRz867G0IIfjiF7/IypUrsSyLBQsW8JnPfObYD1YiOQk4//zz+eEPf8j4+Dh/+MMfuP322ykUCrz97W9nw4YNQJSyp6pq3VCdjZdffpm3vOUtNDQ0kMlkaG1t5b3vfS/AUdWLbN26FYCbb76Z1tbWKX++/vWv4zjOtO0vXbr0sPbxyU9+koceeohHHnmEF198kb6+voOq7+3evRuAU045Zdpnp512Wt1IPFwOtt1TTz21/vmxZnh4mHK5POvxhGHI3r17geh+OFRa61xZunQpH//4x/n6179OS0sL1157Lf/yL/8y5/vlxhtv5De/+Q3j4+OsW7eOm266ieeee443v/nN2LZ9yPUfeOAB7rzzTm6//Xbe9ra31ZfX7rnXv/710+65devWHVLgZs2aNZx66qnce++99WX33nsvLS0t9XpEgM9//vOsX7+eRYsWccEFF3DHHXccE+P9ZL2eB+NI3gOLFy+e8v/GxkYAxsfHgeh5U1V12vti+fLlhz2+A/dV219tXxKJ5NXDa7pmrFQqsWbNGm677Tbe+ta3HtE2/uIv/oJ169bxxS9+kdWrVzM2NsbY2NgxHqlEcnJhmibnn38+559/PitXruTWW2/l+9//Pp/61KfmtP7ExASXX345mUyGT3/60yxbtoxYLMazzz7L//yf/3PajPXhUFv3C1/4AmedddaM3zmwP9HkKN1cWL16NW94wxuOaHyS6cwWUZks5lLjS1/6Erfccgs//vGPWbduHR/72Mf47Gc/y+9//3sWLlw4p/1lMhmuvvpqrr76agzD4J577uHJJ5/k8ssvn3WdnTt38p73vIerr76av/u7v5vyWe2e+9a3vkVHR8e0dXX90D/F73rXu/jMZz7DyMgI6XSan/zkJ9x4441T1n3nO9/JZZddxn333ce6dev4whe+wOc+9zl++MMfct11183p2E8EJ/p6zsSRvAc0TZvxe+II6kgPxYncl0QimV9e087Yddddd9AfKMdx+MQnPsF3v/tdJiYmWLVqFZ/73Oe44oorANi4cSNf/epXWb9+fX3G8HBn0CWSVzu11Lz+/n4Ali1bRhiGbNiwYVYj6Fe/+hWjo6P88Ic/5HWve119+UxqhLMZdrMtr6X+ZDKZV4zDtGTJEgA2b9487bNNmzbR0tJSl9M/nFSvydudHEGpLat9fqxpbW0lkUjMejyqqrJo0SIguh7r168/6PZqEYgDezLNFtlbvXo1q1ev5m//9m954oknWLt2LV/72temOUlz4bzzzuOee+6p378zUalUeOtb30o2m+W73/3utPTb2j3X1tZ2xPfcu971Lu68807+67/+i/b2dvL5PO9+97unfa+zs5MPfehDfOhDH2JoaIhzzjmHz3zmM0fljL2armeN4/EeWLJkCWEYsnPnTlasWFFfvm3btmnfPdyUTYlE8urlNZ2meCg+8pGP8Lvf/Y7//M//5MUXX+Qd73gHb3zjG+vpDT/96U/p6enhZz/7GUuXLqW7u5s/+ZM/kZExyWuSRx99dMZZ21q9U23C4oYbbkBVVT796U9Pi3DV1q/NCk/enuu6/Ou//uu07SeTyRnTlmrOy4EG37nnnsuyZcv44he/SLFYnLbe8PDwrMd4vOjs7OSss87innvumTLe9evXs27dOt70pjfVl812XDNx3nnn0dbWxte+9jUcx6kvv//++9m4ceM0lbdjhaZpXHPNNfz4xz+eItc9ODjId77zHS699FIymQwAb3vb23jhhRe47777pm2ndv1rhvOvf/3r+mdBEPDv//7vU76fz+fxfX/KstWrV6Oq6pTjP5Byuczvfve7GT+7//77gZlTPWt88IMfZMuWLdx33311R2My1157LZlMhr//+7/H87xpn8/lnjvttNNYvXo19957L/feey+dnZ1TJiqCIJj2HLS1tdHV1XXQY58LJ9v1nAvH4z1QU7U88D31la98Zdp3D+c5lkgkr25e05Gxg7Fnzx6+8Y1vsGfPHrq6ugD4H//jf/DAAw/wjW98g7//+79nx44d7N69m+9///t885vfJAgC/uqv/oq3v/3tPPLII/N8BBLJieWjH/0o5XKZt7zlLZx66qm4rssTTzzBvffeS3d3N7feeisQ1U984hOf4K677uKyyy7jrW99K5Zl8dRTT9HV1cVnP/tZLrnkEhobG7n55pv52Mc+hqIofOtb35rR2Tv33HO59957+fjHP875559PKpXizW9+M8uWLSObzfK1r32NdDpNMpnkwgsvZOnSpXz961/nuuuu44wzzuDWW29lwYIF9Pb28uijj5LJZPjpT396ok8fX/jCF7juuuu4+OKL+cAHPlCXtm9oaKj3J6odL0Sy/u9+97sxDIM3v/nNMzaiNgyDz33uc9x6661cfvnl3HjjjXVp++7ubv7qr/7qqMb8H//xHzP2PvqLv/gL/u7v/o6HHnqISy+9lA996EPous6//du/4TgOn//85+vf/eu//mt+8IMf8I53vIPbbruNc889l7GxMX7yk5/wta99jTVr1nDGGWdw0UUXcfvttzM2NkZTUxP/+Z//Oc1Qf+SRR/jIRz7CO97xDlauXInv+3zrW99C07QpNVwHUi6XueSSS7jooot44xvfyKJFi5iYmOBHP/oRv/nNb7jhhhs4++yzZ1z35z//Od/85jd529vexosvvsiLL75Y/yyVSnHDDTeQyWT46le/yvve9z7OOecc3v3ud9Pa2sqePXv4+c9/ztq1a/nnf/7nQ57vd73rXXzyk58kFovxgQ98YEoErlAosHDhQt7+9rezZs0aUqkUDz/8ME899RRf+tKXDrltePVczxqe580YPWtqauJDH/rQMX8PnHvuubztbW/jy1/+MqOjo3Vp+y1btgBTo2GH8xxLJJJXOfOm4/gKAxD33Xdf/f816edkMjnlj67r4p3vfKcQQog//dM/FYDYvHlzfb2atO2mTZtO9CFIJPPK/fffL2677TZx6qmnilQqJUzTFMuXLxcf/ehHxeDg4LTv/8d//Ic4++yzhWVZorGxUVx++eXioYceqn/++OOPi4suukjE43HR1dVVl8pnkvS1EEIUi0Vx0003iWw2K4ApMvc//vGPxemnny50XZ8mR/7cc8+Jt771raK5uVlYliWWLFki3vnOd4pf/vKX9e/UJK2Hh4fndA5q0tyHkuKeTR794YcfFmvXrhXxeFxkMhnx5je/WWzYsGHa+nfddZdYsGCBUFV1TjL39957b/1cNzU1ife85z1i3759U75zJNL2s/3Zu3evEEKIZ599Vlx77bUilUqJRCIhrrzySvHEE09M297o6Kj4yEc+IhYsWCBM0xQLFy4UN998sxgZGal/Z/v27eINb3iDsCxLtLe3i//1v/6XeOihh6bcDzt27BC33XabWLZsmYjFYqKpqUlceeWV4uGHHz7o8XieJ/6f/+f/ETfccINYsmSJsCxLJBIJcfbZZ4svfOELwnGc+ncPvHYHOxcHtlx49NFHxbXXXisaGhpELBYTy5YtE7fccot4+umnD3nOhYjaQtS2/dvf/nbKZ47jiL/+678Wa9asEel0WiSTSbFmzRrxr//6r4fc7qvtegoRSdvPdjzLli2rf+9o3gMzSfSXSiXx4Q9/WDQ1NYlUKiVuuOEGsXnzZgGI//2///eU9Wd7joEZWxQsWbJE3HzzzYc8dolEcnKhCCGrQSGasbrvvvu44YYbgEip6j3veQ8vv/zytELaVCpFR0cHn/rUp6alnVQqFRKJBOvWrePqq68+kYcgkUgkEonkFcbzzz/P2Wefzbe//W3e8573zPdwJBLJKwyZpjgLZ599NkEQMDQ0xGWXXTbjd9auXYvv+2zfvr2eA19LRzhehfESiUQikUhemVQqlWnqq1/+8pdRVXVKjZ9EIpHUeE07Y8VicYrK0c6dO3n++edpampi5cqVvOc97+H9738/X/rSlzj77LMZHh7ml7/8JWeeeSbXX389b3jDGzjnnHO47bbb+PKXv0wYhnz4wx/m6quvZuXKlfN4ZBKJRCKRSE40n//853nmmWe48sor0XWd+++/n/vvv58/+7M/qytOSiQSyWRe02mKv/rVr7jyyiunLb/55pu5++6768W/3/zmN+nt7aWlpYWLLrqIO++8k9WrVwPQ19fHRz/6UdatW0cymeS6667jS1/6Ek1NTSf6cCQSiUQikcwjDz30EHfeeScbNmygWCyyePFi3ve+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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plt.figure(figsize=(10, 6))\n", + "plt.scatter(panda_df[\"locusSize\"], panda_df[\"locusLength\"], alpha=0.5)\n", + "plt.title(\"Scatter Plot of Locus Size vs Locus Length\")\n", + "plt.xlabel(\"Locus Size\")\n", + "plt.ylabel(\"Locus Length\")\n", + "plt.grid(True)\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "24/08/07 09:53:33 WARN SharedInMemoryCache: Evicting cached table partition metadata from memory due to size constraints (spark.sql.hive.filesourcePartitionFileCacheSize = 262144000 bytes). This may impact query planning performance.\n" + ] + } + ], + "source": [ + "susie_fm = StudyLocus.from_parquet(session, \"/Users/dc16/output/ukb_ppp_fm\")\n", + "susie_fm.df = (\n", + " susie_fm.df\n", + " .filter(f.col(\"pValueExponent\") < -11)\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Total credible sets:\n" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "data": { + "text/plain": [ + "57880" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "susie_fm.df.count()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Check for NaN and nulls in the credible set logBF\n" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Number of credible sets with 'not a number' as the logBF: 25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[Stage 73:====================================================> (868 + 8) / 893]\r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Number of credible sets with 'null' as the logBF: 0\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + } + ], + "source": [ + "nan = susie_fm.df.filter(f.isnan(\"credibleSetlog10BF\"))\n", + "null = susie_fm.df.filter(f.isnull(\"credibleSetlog10BF\"))\n", + "print(\"Number of credible sets with 'not a number' as the logBF: \", nan.count())\n", + "print(\"Number of credible sets with 'null' as the logBF: \", null.count())" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "-RECORD 0---------------------------\n", + " meanTopPP | 0.9005192231704642 \n", + " minTopPP | 0.011231041748358246 \n", + " q1TopPP | 0.9884181401759444 \n", + " medianTopPP | 0.9999999997648601 \n", + " q3TopPP | 1.0 \n", + " maxTopPP | 1.0 \n", + "\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "-RECORD 0------------------------------\n", + " meanCredSetSize | 4.344101633393829 \n", + " minCredSetSize | 1 \n", + " q1CredSetSize | 1 \n", + " medianCredSetSize | 1 \n", + " q3CredSetSize | 2 \n", + " maxCredSetSize | 1767 \n", + "\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "-RECORD 0----------------------------------\n", + " meanPurityMeanR2 | 0.8042287002688577 \n", + " minPurityMeanR2 | 0.011839476509578747 \n", + " q1PurityMeanR2 | 0.6278035788726534 \n", + " medianPurityMeanR2 | 1.0 \n", + " q3PurityMeanR2 | 1.0 \n", + " maxPurityMeanR2 | 1.0 \n", + "\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[Stage 87:> (0 + 1) / 1]\r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "-RECORD 0--------------------------------\n", + " meanPurityMinR2 | 0.7062586247097518 \n", + " minPurityMinR2 | 0.0 \n", + " q1PurityMinR2 | 0.06978249208480057 \n", + " medianPurityMinR2 | 1.0 \n", + " q3PurityMinR2 | 1.0 \n", + " maxPurityMinR2 | 1.0 \n", + "\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + } + ], + "source": [ + "susie_results = (\n", + " susie_fm.df.withColumn(\"credSetSize\", f.size(\"locus\"))\n", + " .withColumn(\n", + " \"locus\",\n", + " f.slice(order_array_of_structs_by_field(\"locus\", \"posteriorProbability\"), 1, 1)[\n", + " 0\n", + " ],\n", + " )\n", + " .withColumn(\"topPP\", f.col(\"locus\").getField(\"posteriorProbability\"))\n", + " .filter(~f.isnan(\"topPP\"))\n", + ")\n", + "(\n", + " susie_results.select(\n", + " f.mean(\"topPP\").alias(\"meanTopPP\"),\n", + " f.min(\"topPP\").alias(\"minTopPP\"),\n", + " f.percentile_approx(\"topPP\", 0.25).alias(\"q1TopPP\"),\n", + " f.percentile_approx(\"topPP\", 0.5).alias(\"medianTopPP\"),\n", + " f.percentile_approx(\"topPP\", 0.75).alias(\"q3TopPP\"),\n", + " f.max(\"topPP\").alias(\"maxTopPP\"),\n", + " ).show(vertical=True)\n", + ")\n", + "(\n", + " susie_results.select(\n", + " f.mean(\"credSetSize\").alias(\"meanCredSetSize\"),\n", + " f.min(\"credSetSize\").alias(\"minCredSetSize\"),\n", + " f.percentile_approx(\"credSetSize\", 0.25).alias(\"q1CredSetSize\"),\n", + " f.percentile_approx(\"credSetSize\", 0.5).alias(\"medianCredSetSize\"),\n", + " f.percentile_approx(\"credSetSize\", 0.75).alias(\"q3CredSetSize\"),\n", + " f.max(\"credSetSize\").alias(\"maxCredSetSize\"),\n", + " ).show(vertical=True)\n", + ")\n", + "(\n", + " susie_results.select(\n", + " f.mean(\"purityMeanR2\").alias(\"meanPurityMeanR2\"),\n", + " f.min(\"purityMeanR2\").alias(\"minPurityMeanR2\"),\n", + " f.percentile_approx(\"purityMeanR2\", 0.25).alias(\"q1PurityMeanR2\"),\n", + " f.percentile_approx(\"purityMeanR2\", 0.5).alias(\"medianPurityMeanR2\"),\n", + " f.percentile_approx(\"purityMeanR2\", 0.75).alias(\"q3PurityMeanR2\"),\n", + " f.max(\"purityMeanR2\").alias(\"maxPurityMeanR2\"),\n", + " ).show(vertical=True)\n", + ")\n", + "(\n", + " susie_results.select(\n", + " f.mean(\"purityMinR2\").alias(\"meanPurityMinR2\"),\n", + " f.min(\"purityMinR2\").alias(\"minPurityMinR2\"),\n", + " f.percentile_approx(\"purityMinR2\", 0.25).alias(\"q1PurityMinR2\"),\n", + " f.percentile_approx(\"purityMinR2\", 0.5).alias(\"medianPurityMinR2\"),\n", + " f.percentile_approx(\"purityMinR2\", 0.75).alias(\"q3PurityMinR2\"),\n", + " f.max(\"purityMinR2\").alias(\"maxPurityMinR2\"),\n", + " ).show(vertical=True)\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "data": { + "image/png": "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+ik3N1dvvvmmAgIC9Nprr2nOnDm6//77dfvtt+utt95S48aN9cILL+jLL7+85rUaPny4Jk+erLZt22r27Nm69957FRkZqf79+5s1//73v9WpUye5urqa16pz585XPe6JEyfUq1cv+fv7a/r06apbt65Gjx6dr/kojD///FM9e/aUn5+f5syZo65du+arad68uV599VVJFxqpS8c7cOBAZWdna9myZXavycrK0sqVK9WnTx+5ubnZ7RswYICSk5PtGsCYmBh169ZNHh4e1z32gwcPqm/fvrr//vs1c+ZM3XbbbRo8eLD27t17zdfmNaW33XbbNWtTUlIkyfwkEABQttAf0R9drjT0R6mpqerYsaO++OILhYeHa+7cuWrcuLGGDRumOXPmmHXp6elauHChunTporfeektTp07V8ePHFRwcXOBcWDExMZoxY4aeeuopvfbaa/r111/16KOPXtffB/orlAgGgBJn0aJFhqSrPlq0aGH3mvr16xuhoaHm8zZt2hghISFXPU9YWJhR0D8Dn376qSHJeO211+y29+3b13BycjIOHjxoGIZhJCYmGpKMMWPG2NUNHjzYkGRMmTLF3DZlyhRDkvH444/nO9+ZM2fybfv4448NScaXX36Z7xgjR440t2VnZxt169Y1nJycjDfffNPcfuLECaNixYp216QgSUlJhiRj+PDhdttfeOEFQ5KxceNGc1toaKhRuXLlqx4vz7333mtIMmbOnGluy8zMNPz8/AwPDw8jKyvLMIyLP+vDhw/bvX7Tpk2GJGPTpk35jhkVFVXg+e69917z+fbt2w1JxqJFi/LVBgYGGgEBAXbbVq1aVeD58v6ctWvXzhg2bJhhGBeurYuLi7F48WJznCtWrDBfV9B7ql+/fr6f57FjxwxXV1fj+eefz/e+P/jgA+P48ePG0aNHjXXr1hmNGzc2nJycjG3btuV7P5cbNmyY4ezsbPz000/XrAUAlB70R/RHpbk/GjZsmOHl5WX88ccfdufo37+/4e7ubv68s7OzjczMTLuaEydOGLVr1zaGDh1qbjt8+LAhyahRo4bx119/mds/++wzQ5Lx+eefm9vy/owcOHDAOH78uPHrr78aH3zwgVGxYkWjVq1aRkZGRr7rcanMzEzD19fX8PHxMc6fP3/VWqCwuFMKKMHmz5+vuLi4fI/WrVtf87XVqlXT3r17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nM6fP6/u3bsrIyPDrBk7dqw+//xzrVixQlu2bNHRo0ftQq+81YuzsrK0detWLV68WNHR0Zo8ebJZk7d6cdeuXZWUlKQxY8Zo+PDhWr9+vVmTt3rxlClT9P3336tNmzYKDg6268sAAACupEir7xWXp59+WjExMfrss8/UrFkzc7u7u7sqVqwoSRo9erTWrFmj6Oho2Ww2PfPMM5KkrVu3SrrQVPn5+alOnTqaPn26UlJSNHDgQA0fPlxvvPGGpAtNVcuWLRUWFqahQ4dq48aNevbZZxUbG6vg4GBJF5qq0NBQ/fOf/1SHDh00Z84cLV++XPv3788311RBWDkGAIAbcyusvnczlObVi6WSf30BACjpSvPqe0W6U0qSsrOz9cUXX+if//ynTp06JUk6evSoTp8+fd3HeO+995SWlqYuXbrIy8vLfCxbtsysmT17th544AH16dNHnTt3lqenp1atWmXud3Z21urVq+Xs7KzAwEA9+eSTGjRokF599VWzxsfHR7GxsYqLi1ObNm00c+ZMLVy40AykJKlfv356++23NXnyZPn5+SkpKUnr1q27rkAKAADgehVHD3Wpwq5eLOmKqxenp6dr7969Zk1BqxfnHSNv9eJLa661erF0YQXj9PR0uwcAALg1lS/Ki/73v/+pR48eOnLkiDIzM3X//feratWqeuutt5SZmamoqKjrOs713KTl5uam+fPna/78+VesqV+/vtasWXPV43Tp0kU7d+68ak14eLjCw8OvOSYAAICiKK4eKo8jVy8+ceLEFVcv3r9//xXHHBkZqVdeeaVQ7xMAAJRNRbpT6rnnnlO7du104sQJ82t2kvTII4/km7sJAAAAFxR3D1XaVi+WWMEYAABcVKQ7pb766itt3bpVLi4udtsbNGig//u//yuWgQEAAJQ1xdlD5a1e/OWXX15x9eJL75a6fPXiy1fJK+zqxc7OzoVevVi6sIKxq6trod4rAAAom4p0p1Rubq5ycnLybf/9999VtWrVGx4UAABAWVQcPRSrFwMAgLKiSKFU9+7dNWfOHPO5k5OTTp8+rSlTpqhXr17FNTYAAIAypTh6qLCwMH300UeKiYlR1apVlZKSopSUFJ09e1bShVWMhw0bpoiICG3atEmJiYkaMmSIAgMD1bFjR3Mcvr6+GjhwoH744QetX79ekyZNUlhYmHkX06hRo/TL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1ezatUudOnWSm5ubvL29NX369HxjWbFihe644w65ubmpVatWWrNmTbG/XwAAAAAAAFzg0FAqIyNDbdq00fz58wvcP336dP3jH/9QVFSUvvvuO1WuXFnBwcE6d+6cWfPEE09o7969iouL0+rVq/Xll19q5MiR5v709HR1795d9evXV2JiombMmKGpU6dqwYIFZs3WrVv1+OOPa9iwYdq5c6d69+6t3r17a8+ePTfvzQMAAAAAANzCyjvy5D179lTPnj0L3GcYhubMmaNJkybp4YcfliR9+OGHql27tj799FP1799fP/74o9atW6ft27erXbt2kqR33nlHvXr10ttvv606depoyZIlysrK0gcffCAXFxe1aNFCSUlJmjVrlhlezZ07Vz169NC4ceMkSdOmTVNcXJzmzZunqKgoC64EAAAAAADAraXEzil1+PBhpaSkKCgoyNzm7u6ugIAAJSQkSJISEhJUrVo1M5CSpKCgIJUrV07fffedWdO5c2e5uLiYNcHBwTpw4IBOnDhh1lx6nryavPMUJDMzU+np6XYPAAAAAAAAXJ8SG0qlpKRIkmrXrm23vXbt2ua+lJQUeXh42O0vX768qlevbldT0DEuPceVavL2FyQyMlLu7u7mw9vbu7BvEQAAoEiYlxMAAJQFJTaUKukmTpyotLQ08/Hbb785ekgAAOAWwbycAACgLHDonFJX4+npKUlKTU2Vl5eXuT01NVV+fn5mzbFjx+xel52drb/++st8vaenp1JTU+1q8p5fqyZvf0FcXV3l6upahHcGAABwY0rzvJyZmZnKzMw0nzMFAgAAt64Se6eUj4+PPD09FR8fb25LT0/Xd999p8DAQElSYGCgTp48qcTERLNm48aNys3NVUBAgFnz5Zdf6vz582ZNXFycmjVrpttuu82sufQ8eTV55wEAACgtSvq8nEyBAAAA8jg0lDp9+rSSkpKUlJQk6UITlZSUpCNHjsjJyUljxozRa6+9pv/+97/avXu3Bg0apDp16qh3796SpObNm6tHjx4aMWKEtm3bpm+++Ubh4eHq37+/6tSpI0kaMGCAXFxcNGzYMO3du1fLli3T3LlzFRERYY7jueee07p16zRz5kzt379fU6dO1Y4dOxQeHm71JQEAALghJX1eTqZAAAAAeRz69b0dO3aoa9eu5vO8oCg0NFTR0dEaP368MjIy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t912m2677TYFBQVd8+eDiwr7ZzvP0qVL5eTkpN69e9/cAZYxhb3eJ0+eVFhYmLy8vOTq6qqmTZvy70khFPZ6z5kzR82aNVPFihXl7e2tsWPH6ty5cxaNtvT68ssv9eCDD6pOnTpycnLSp59+es3XbN68WW3btpWrq6saN26s6Ojomz5O3Fz0StajX7IefZO16JusR+9krVLRQxlwuKVLlxouLi7GBx98YOzdu9cYMWKEUa1aNSM1NbXA+m+++cZwdnY2pk+fbuzbt8+YNGmSUaFCBWP37t0Wj7x0Kuz1HjBggDF//nxj586dxo8//mgMHjzYcHd3N37//XeLR176FPZa5zl8+LBx++23G506dTIefvhhawZbBhT2emdmZhrt2rUzevXqZXz99dfG4cOHjc2bNxtJSUkWj7x0Kuz1XrJkieHq6mosWbLEOHz4sLF+/XrDy8vLGDt2rMUjL33WrFljvPzyy8aqVasMScYnn3xy1fpffvnFqFSpkhEREWHs27fPeOeddwxnZ2dj3bp11gwYxY5eyXr0S9ajb7IWfZP16J2sVxp6KEKpEqBDhw5GWFiY+TwnJ8eoU6eOERkZWWD93/72NyMkJMRuW0BAgPHUU0/d1HGWFYW93pfLzs42qlataixevPhmDbHMKMq1zs7ONu666y5j4cKFRmhoKM1VIRT2er/33ntGw4YNjaysLKuGWKYU9nqHhYUZ9913n922iIgI4+67776p4yxrrqehGj9+vNGiRQu7bf369TOCg4Nv4shwM9ErWY9+yXr0Tdaib7IevZNjldQeiq/vOVhWVpYSExMVFBRkbitXrpyCgoKUkJBQ4GsSEhLs6iUpODj4ivW4qCjX+3JnzpzR+fPnVb169Zs1zDKhqNf61VdflYeHh4YNG2bFMMuMolzv//73vwoMDFRYWJhq166tli1b6o033lBOTo5Vwy61inK977rrLiUmJpq3qf/yyy9as2aNevXqZcmYbyX8nixb6JWsR79kPfoma9E3WY/eqXRwxO/P8jftyLguf/zxh3JyclS7dm277bVr19b+/fsLfE1KSkqB9SkpKTdtnGVFUa735SZMmKA6derk+8sKe0W51l9//bXef/99JSUlWTDCsqUo1/uXX37Rxo0b9cQTT2jNmjU6ePCgnn76aZ0/f15TpkyxYtilVlGu94ABA/THH3/onnvu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mqbrVaFCBbvnTk5Oys3Ntdvm6empxo0bq3Hjxlq0aJF69eqlffv25Qudli5dquHDh2vFihUKCgq67jEAAICypTT1SKdPn5YkxcbG6vbbb7fb5+rqKulCj/PCCy9o5syZCgwMVNWqVTVjxgx99913dvXX01e5u7urcePGkqTly5ercePG6tixY77ead++ferWrZtGjhypSZMmXfV6ALgxhFIASqzLm41vv/1WTZo0kbOzs2rVqmU3n8HPP/+sM2fOFPocLi4uBX6qWKNGDfXu3VuLFi1SQkLCVeeJ6tGjh7KysuTk5JRvTobi1KFDB/n7++v111+3m+Dz448/1tChQ7V06VKFhITctPMDAICSoaz0SL6+vnJ1ddWRI0d07733FniMb775RnfddZc55YEku7uoiqpKlSp67rnn9MILL2jnzp3mnWd79+7Vfffdp9DQUL3++us3fB4AV0coBaDEOnLkiCIiIvTUU0/p+++/1zvvvKOZM2dKku677z7NmzdPgYGBysnJ0YQJE/J9QnY9GjRooMOHDyspKUl169ZV1apVzU/mhg8frgceeEA5OTkKDQ294jGcnZ31448/mv99M40ZM0aPPPKIxo8fr9tvv10xMTEKDQ3V3LlzFRAQoJSUFEkX5oJwd3e/qWMBAACOUVZ6pKpVq+qFF17Q2LFjlZubq3vuuUdpaWn65ptvZLPZFBoaqiZNmujDDz/U+vXr5ePjo3//+9/avn27fHx8Cv2eLvfUU09p2rRp+s9//qO+fftqz549uu+++xQcHKyIiAizr8oL+wAUP+aUAlBiDRo0SGfPnlWHDh0UFham5557TiNHjpR0YeU6b29vderUSQMGDNALL7ygSpUqFfocffr0UY8ePdS1a1fVqlVLH3/8sbkvKChIXl5eCg4OVp06da56HJvNJpvNVujzF1aPHj3k4+NjfnK3YMECZWdnKywsTF5eXubjueeeu+ljAQAAjlGWeqRp06bp73//uyIjI9W8eXP16NFDsbGxZuj01FNP6dFHH1W/fv0UEBCgP//80+6uqRtRvXp1DRo0SFOnTlVubq5Wrlyp48eP66OPPrLrq9q3b18s5wOQn5Nx+ReOAaAE6NKli/z8/DRnzhyHjeH06dO6/fbbtWjRoiuuTgMAAGAleiQAZQlf3wOAy+Tm5uqPP/7QzJkzVa1aNT300EOOHhIAAIDD0SMBKG6EUgBwmSNHjsjHx0d169ZVdHS0ypfnn0oAAAB6JADFja/vAQAAAAAAwHJMdA4AAAAAAADLEUoBAAAAAADAcoRSAAAAAAAAsByhFAAAAAAAACxHKAUAAAAAAADLEUoBAAAAAADAcoRSAAAAAAAAsByhFAAAAAAAACxHKAUAAAAAAADLEUoBAAAAAADAcoRSAAAAAAAAsByhFAAAAAAAACxHKAUAAAAAAADLEUoBKJQGDRpo8ODBjh5GmTdjxgw1bNhQzs7O8vPzc/RwAAAo0+hvrFFa+pvS8udh6tSpcnJycvQwgBtCKAXcwqKjo+Xk5KQdO3YUuL9Lly5q2bLlDZ9nzZo1mjp16g0f51axYcMGjR8/XnfffbcWLVqkN95444q1MTExmjNnjiXjymt88h6VKlWSr6+vJk2apPT0dLMu789V3sPNzU1NmzZVeHi4UlNTLRkrAODWRX9TMhWmvymJfv31Vw0ZMkSNGjWSm5ubPD091blzZ02ZMqVIx7van5/Tp09rypQpatmypSpXrqwaNWrIz89Pzz33nI4ePXoD7+L/sXfv8T3X///H7zvYgdl7TtvsY1jOcsowKym1rKyD0ifKR2iIRlhFyoeoT0Q5FNFBpiKHz7dUhDRRsRyWFYqcimKjD9tY7Pj8/dFvL95tTrO9ZnO7Xi7vS96v1+P9ej9eTy+9n7vv9X69gCuPe2k3AKBs2bVrl1xdLy3P/uyzzzRz5kwmbhdpzZo1cnV11Zw5c+Th4XHe2gULFmj79u0aNmyYPc1JmjVrlnx8fHTy5El9/vnn+s9//qM1a9Zo/fr1Tr+tGz9+vEJCQnT69Gl98803mjVrlj777DNt375dFStWtK1fAAAuhPlNybuU+c2VZs+ePWrbtq28vb31yCOPqG7dujp8+LC+++47vfTSSxo3btwlb/Ncx092drY6duyonTt3qnfv3hoyZIhOnjypHTt2aMGCBbr33nsVFBQkSRo9erSefvrp4thFoNQQSgG4JJ6enqXdwiXLyMhQpUqVSruNi3bkyBF5e3tfsRO2+++/X9WrV5ckDRw4UN26ddOHH36ob7/9VuHh4VbdHXfcoTZt2kiS+vXrp2rVqmnKlCn6+OOP9eCDD5ZK7wAAFIb5TcmzY35TUmMydepUnTx5UklJSapTp47TuiNHjhTrey1dulRbt27V/Pnz9dBDDzmtO336tLKysqzn7u7ucnfnR3qUbXx9D8Al+ft37LOzszVu3Dg1aNBAXl5eqlatmjp06KDVq1dLkvr06aOZM2dKktNXuvJlZGToiSeeUHBwsDw9PdWoUSO9/PLLMsY4ve+pU6f0+OOPq3r16qpcubLuvvtu/f7773JxcXH6DVP+V8x+/PFHPfTQQ6pSpYo6dOggSfrhhx/Up08fXXPNNdZp14888oj+97//Ob1X/jZ+/vln/etf/5LD4VCNGjX073//W8YYHTx4UPfcc498fX0VGBioV1555aLGLicnR88//7zq1asnT09P1a1bV88884wyMzOtGhcXF82dO1cZGRnWWMXFxRW6vZtvvlnLly/Xr7/+atXWrVvXWn/kyBFFR0crICBAXl5eatmypebNm+e0jV9++UUuLi56+eWXNXXqVNWpU0fe3t666aabtH379ovar1tuuUWStH///mKpAwDAbsxvrpz5Tb6NGzeqS5cuqlKliipVqqQWLVpo+vTp1vo+ffrIx8dHe/fuVZcuXVS5cmX17NlTkpSXl6dp06bp2muvlZeXlwICAvToo4/q+PHjTu9hjNELL7ygWrVqqWLFiurUqZN27NhRoJe9e/eqVq1aBQIpSfL39y+wbMWKFbrxxhtVqVIlVa5cWVFRUU7bPd/xs3fvXknSDTfcUGC7Xl5e8vX1tZ7//ZpSffr0cdre2Y+zj6fMzEyNHTtW9evXl6enp4KDgzVixAinvzPALsSqAJSWlqY//vijwPLs7OwLvva5557ThAkT1K9fP7Vr107p6enasmWLvvvuO91222169NFHdejQIa1evVrvvfee02uNMbr77rv15ZdfKjo6Wq1atdKqVav01FNP6ffff9fUqVOt2j59+mjx4sXq1auX2rdvr3Xr1ikqKuqcff3zn/9UgwYN9OKLL1oTwNWrV2vfvn3q27evAgMDtWPHDr355pvasWOHvv322wIXiuzevbuaNGmiiRMnavny5XrhhRdUtWpVvfHGG7rlllv00ksvaf78+XryySfVtm1bdezY8bxj1a9fP82bN0/333+/nnjiCW3cuFETJkzQTz/9pI8++kiS9N577+nNN9/Upk2b9Pbbb0uSrr/++kK39+yzzyotLU2//fabNVY+Pj6S/prk3nzzzdqzZ48GDx6skJAQLVmyRH369FFqaqqGDh3qtK13331XJ06cUExMjE6fPq3p06frlltu0bZt2xQQEHDe/cqfPFWrVq1Y6gAAKA7Mb8rm/CZ/n+68807VrFlTQ4cOVWBgoH766SctW7bMaQ6Tk5OjyMhIdejQQS+//LJ1eYBHH31UcXFx6tu3rx5//HHt379fM2bM0NatW7V+/XpVqFBBkjRmzBi98MIL6tKli7p06aLvvvtOnTt3djobSZLq1KmjL774QmvWrLF+yXYu7733nnr37q3IyEi99NJL+vPPPzVr1ix16NBBW7duVd26dc97/OQHX++++65Gjx59SRcyf/TRRxUREeG0bOXKlZo/f74VnuXl5enuu+/WN998owEDBqhJkybatm2bpk6dqp9//llLly696PcDioUBcNWaO3eukXTex7XXXuv0mjp16pjevXtbz1u2bGmioqLO+z4xMTGmsP/dLF261EgyL7zwgtPy+++/37i4uJg9e/YYY4xJTEw0ksywYcOc6vr06WMkmbFjx1rLxo4daySZBx98sMD7/fnnnwWWffDBB0aS+eqrrwpsY8CAAdaynJwcU6tWLePi4mImTpxoLT9+/Ljx9vZ2GpPCJCUlGUmmX79+TsuffPJJI8msWbPGWta7d29TqVKl824vX1RUlKlTp06B5dOmTTOSzPvvv28ty8rKMuHh4cbHx8ekp6cbY4zZv3+/kWS8vb3Nb7/9ZtVu3LjRSDLDhw+3luWPy65du8zRo0fN/v37zRtvvGE8PT1NQECAycjIMMacOa6++OILc/ToUXPw4EGzcOFCU61atQLvAwBAcWN+U7bnNzk5OSYkJMTUqVPHHD9+3GldXl6e0/Ykmaefftqp5uuvvzaSzPz5852Wr1y50mn5kSNHjIeHh4mKinLa7jPPPGMkOe379u3bjbe3t5FkWrVqZYYOHWqWLl1qzX3ynThxwvj5+Zn+/fs7LU9OTjYOh8Np+bmOnz///NM0atTISDJ16tQxffr0MXPmzDEpKSkFavP/Ts9l9+7dxuFwmNtuu83k5OQYY4x57733jKurq/n666+damfPnm0kmfXr159ze0BJ4Ot7ADRz5kytXr26wKNFixYXfK2fn5927Nih3bt3X/L7fvbZZ3Jzc9Pjjz/utPyJJ56QMUYrVqyQ9NdveCTpsccec6obMmTIObc9cODAAsu8vb2tP58+fVp//PGH2rdvL0n67rvvCtT369fP+rObm5vatGkjY4yio6Ot5X5+fmrUqJH27dt3zl6kv/ZVkmJjY52WP/HEE5Kk5cuXn/f1l+qzzz5TYGCg07WbKlSooMcff1wnT57UunXrnOq7du2qf/zjH9bzdu3aKSwszOr7bI0aNVKNGjUUEhKiRx99VPXr19fy5csLXLw8IiJCNWrUUHBwsHr06CEfHx999NFHTu8DAEBJYX5TNuc3W7du1f79+zVs2DD5+fk5rSvsrKFBgwY5PV+yZIkcDoduu+02/fHHH9YjNDRUPj4++vLLLyVJX3zxhbKysjRkyBCn7RZ285hrr71WSUlJ+te//qVffvlF06dPV9euXRUQEKC33nrLqlu9erVSU1P14IMPOr23m5ubwsLCrPc+H29vb23cuFFPPfWUpL/uJhkdHa2aNWtqyJAhF/0Vu4yMDN17772qUqWKPvjgA7m5uVnj06RJEzVu3Nipx/wzwC6mR6A48fU9AGrXrp11QeqzValSpdDT3s82fvx43XPPPWrYsKGaNWum22+/Xb169bqoCd+vv/6qoKAgVa5c2Wl5kyZNrPX5/3V1dVVISIhTXf369c+57b/XStKxY8c0btw4LVy4sMBFKdPS0grU165d2+m5w+GQl5eXdZHvs5f//boNf5e/D3/vOTAwUH5+fta+Fpdff/1VDRo0KHAnob+Pbb4GDRoU2EbDhg21ePHiAsv/7//+T76+vqpQoYJq1aqlevXqFdrDzJkz1bBhQ7m7uysgIECNGjW65DsbAQBQVMxvyub8Jv/r/s2aNbtgrbu7u2rVquW0bPfu3UpLSyv0Wk/SmQuT5/f29zlQjRo1VKVKlQKva9iwod577z3l5ubqxx9/1LJlyzRp0iQNGDBAISEhioiIsELMc33F7+zrQZ2Pw+HQpEmTNGnSJP3666+Kj4/Xyy+/rBkzZsjhcOiFF1644Db69++vvXv3asOGDU6XTti9e7d++ukn1ahRo9DXFfeF24ELIZQCcFk6duyovXv36uOPP9bnn3+ut99+W1OnTtXs2bOdfhNnt7N/a5jvgQce0IYNG/TUU0+pVatW8vHxUV5enm6//Xbl5eUVqM//jdKFlkkqcOHSc7mU6wJcqTp27Fhg4lqYc/0wAADAlY75zV+u9PmNp6dngV945eXlyd/fX/Pnzy/0NecKYy6Wm5ubmjdvrubNmys8PFydOnXS/PnzFRERYY33e++9p8DAwAKvLcqd8urUqaNHHnlE9957r6655hrNnz//gqHU9OnT9cEHH+j9999Xq1atnNbl5eWpefPmmjJlSqGvDQ4OvuQegctBKAXgslWtWlV9+/ZV3759dfLkSXXs2FHPPfecNWk710Ql/6KRJ06ccPpt4s6dO631+f/Ny8vT/v37nX6btWfPnovu8fjx44qPj9e4ceM0ZswYa3lRTssvivx92L17t/WbUklKSUlRampqoXdzuRjnG9sffvhBeXl5TpO1v49tvsLG4eeff3a6mx8AAFcT5jcXVhLzm/wzsLdv317got0X+/ovvvhCN9xwQ6Eh3tm9S3+N1TXXXGMtP3r0aIG79J1L/i/fDh8+7NS7v7//BXu/1CCvSpUqqlev3gXvjvz111/rySef1LBhw6y7EZ6tXr16+v7773XrrbeWi1+WouzjexQALsvfT+v28fFR/fr1nb7vXqlSJUlSamqqU22XLl2Um5urGTNmOC2fOnWqXFxcdMcdd0iSIiMjJUmvv/66U91rr7120X3m/wbw77/xmzZt2kVv43J06dKl0PfL/y3V+e60cz6VKlUq9NT8Ll26KDk5WYsWLbKW5eTk6LXXXpOPj49uuukmp/qlS5fq999/t55v2rRJGzdutP4OAAC4mjC/uTglMb9p3bq1QkJCNG3atAJjezFnbj3wwAPKzc3V888/X2BdTk6Otc2IiAhVqFBBr732mtN2Cxu7r7/+utC7NuZfU6tRo0aS/vo79fX11Ysvvlho/dGjR60/n+v4+f777wv9eumvv/6qH3/80Xqvwhw+fFgPPPCAOnTooMmTJxda88ADD+j33393uhZWvlOnTikjI+Oc2wdKAmdKAbgsTZs21c0336zQ0FBVrVpVW7Zs0X//+18NHjzYqgkNDZUkPf7444qMjJSbm5t69Oihu+66S506ddKzzz6rX375RS1bttTnn3+ujz/+WMOGDbN+2xQaGqpu3bpp2rRp+t///mfdMvnnn3+WdHG/afL19VXHjh01adIkZWdn6x//+Ic+//xz7d+/vwRGpaCWLVuqd+/eevPNN5WamqqbbrpJmzZt0rx589S1a1d16tSpSNsNDQ3VokWLFBsbq7Zt28rHx0d33XWXBgwYoDfeeEN9+vRRYmKi6tatq//+979av369pk2bVuA6F/Xr11eHDh00aNAgZWZmatq0aapWrZpGjBhRHLsPAECZwvzm4pTE/MbV1VWzZs3SXXfdpVatWqlv376qWbOmdu7cqR07dmjVqlXnff1NN92kRx99VBMmTFBSUpI6d+6sChUqaPfu3VqyZImmT5+u+++/XzVq1NCTTz6pCRMm6M4771SXLl20detWrVixosBlCl566SUlJibqvvvus64r9t133+ndd99V1apVrYuj+/r6atasWerVq5dat26tHj16qEaNGjpw4ICWL1+uG264wQorz3X8rF69WmPHjtXdd9+t9u3by8fHR/v27dM777yjzMxMPffcc+fc98cff1xHjx7ViBEjtHDhQqd1LVq0UIsWLdSrVy8tXrxYAwcO1JdffqkbbrhBubm52rlzpxYvXqxVq1Zx+QXYq7Ru+weg9OXfMnnz5s2Frr/pppsueMvkF154wbRr1874+fkZb29v07hxY/Of//zHZGVlWTU5OTlmyJAhpkaNGsbFxcXp1rUnTpwww4cPN0FBQaZChQqmQYMGZvLkyU635jXGmIyMDBMTE2OqVq1qfHx8TNeuXc2uXbuMJKdbGOffGvfo0aMF9ue3334z9957r/Hz8zMOh8P885//NIcOHTrnbZf/vo1z3cq4sHEqTHZ2thk3bpwJCQkxFSpUMMHBwWbUqFHm9OnTF/U+hTl58qR56KGHjJ+fn3Xr4HwpKSmmb9++pnr16sbDw8M0b97czJ071+n1+/fvN5LM5MmTzSuvvGKCg4ONp6enufHGG83333/vVHu+sT3bhY4rAABKEvObsj+/McaYb775xtx2222mcuXKplKlSqZFixbmtddeu+jtvfnmmyY0NNR4e3ubypUrm+bNm5sRI0aYQ4cOWTW5ublm3LhxpmbNmsbb29vcfPPNZvv27QWOh/Xr15uYmBjTrFkz43A4TIUKFUzt2rVNnz59zN69ewu895dffmkiIyONw+EwXl5epl69eqZPnz5my5YtVs25jp99+/aZMWPGmPbt2xt/f3/j7u5uatSoYaKiosyaNWuc3if/7zTfTTfdZCQV+jj7WMjKyjIvvfSSufbaa42np6epUqWKCQ0NNePGjTNpaWkX/ssBipGLMRd59ToAuMIkJSXpuuuu0/vvv1/od+ZxYb/88otCQkI0efJkPfnkk6XdDgAAVz3mNwCuJlxTCkCZcOrUqQLLpk2b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JScny8PDQ35+fk7LAwIClJycbNWcHUjlr89fd76a9PR0nTp1Sn/88Ydyc3MLrcnfRmFGjRqltLQ063Hw4MGL22kAAAAAAADIvbTe+ODBgxo6dKhWr14tLy+v0mqjyDw9PeXp6VnabQAAAAAAAJRJpXamVGJioo4cOaLWrVvL3d1d7u7uWrdunV599VW5u7srICBAWVlZSk1NdXpdSkqKAgMDJUmBgYEF7saX//xCNb6+vvL29lb16tXl5uZWaE3+NgAAAAAAAFC8Si2UuvXWW7Vt2zYlJSVZjzZt2qhnz57WnytUqKD4+HjrNbt27dKBAwcUHh4uSQoPD9e2bduc7pK3evVq+fr6qmnTplbN2dvIr8nfhoeHh0JDQ51q8vLyFB8fb9UAAAAAAACgeJXa1/cqV66sZs2aOS2rVKmSqlWrZi2Pjo5WbGysqlatKl9fXw0ZMkTh4eFq3769JKlz585q2rSpevXqpUmTJik5OVmjR49WTEyM9dW6gQMHasaMGRoxYoQeeeQRrVmzRosXL9by5cut942NjVXv3r3Vpk0btWvXTtOmTVNGRob69u1r02gAAAAAAABcXUr97nvnM3XqVN15553q1q2bOnbsqMDAQH344YfWejc3Ny1btkxubm4KDw/Xv/71Lz388MMaP368VRMSEqLly5dr9erVatmypV555RW9/fbbioyMtGq6d++ul19+WWPGjFGrVq2UlJSklStXFrj4OQAAQGl77rnn5OLi4vRo3Lixtf706dOKiYlRtWrV5OPjo27duhW4TMGBAwcUFRWlihUryt/fX0899ZRycnKcatauXavWrVvL09NT9evXV1xcXIFeZs6cqbp168rLy0thYWHatGlTiewzAAAon0rtTKnCrF271um5l5eXZs6cqZkzZ57zNXXq1NFnn3123u3efPPN2rp163lrBg8erMGDB190rwAAAKXl2muv1RdffGE9d3c/M6UbPny4li9friVLlsjhcGjw4MG67777tH79eklSbm6uoqKiFBgYqA0bNujw4cN6+OGHVaFCBb344ouSpP379ysqKkoDBw7U/PnzFR8fr379+qlmzZrWL/YWLVqk2NhYzZ49W2FhYZo2bZoiIyO1a9cu+fv72zgaAACgrLqiz5QCAABAQe7u7goMDLQe1atXlySlpaVpzpw5mjJlim655RaFhoZq7ty5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XH0CAACUG8yhAAAALjOU2rJlix577DHVrFlTU6ZM0ZNPPqm9e/dq9erVOnTokO65557i6hMAAKDcYA4FAAAguRflRVOmTNHcuXO1a9cudenSRe+++666dOkiV9e/Mq6QkBDFxcWpbt26xdkrAABAmcYcCgAA4IwihVKzZs3SI488oj59+qhmzZqF1vj7+2vOnDmX1RwAAEB5whwKAADgjCKFUrt3775gjYeHh3r37l2UzQMAAJRLzKEAAADOKNI1pebOnaslS5YUWL5kyRLNmzfvspsCAAAoj5hDAQAAnFGkUGrChAmqXr16geX+/v568cUXL7spAACA8og5FAAAwBlFCqUOHDigkJCQAsvr1KmjAwcOXHZTAAAA5RFzKAAAgDOKFEr5+/vrhx9+KLD8+++/V7Vq1S67KQAAgPKIORQAAMAZRQqlHnzwQT3++OP68ssvlZubq9zcXK1Zs0ZDhw5Vjx49irtHAACAcoE5FAAAwBlFuvve888/r19++UW33nqr3N3/2kReXp4efvhhrocAAABwDsyhAAAAzihSKOXh4aFFixbp+eef1/fffy9vb281b95cderUKe7+AAAAyg3mUAAAAGcUKZTK17BhQzVs2LC4egEAALgqMIcCAAAoYiiVm5uruLg4xcfH68iRI8rLy3Nav2bNmmJpDgAAoDxhDgUAAHBGkUKpoUOHKi4uTlFRUWrWrJlcXFyKuy8AAIByhzkUAADAGUUKpRYuXKjFixerS5cuxd0PAABAucUcCgAA4AzXorzIw8ND9evXL+5eAAAAyjXmUAAAAGcUKZR64oknNH36dBljirsfAACAcos5FAAAwBlF+vreN998oy+//FIrVqzQtddeqwoVKjit//DDD4ulOQAAgPKEORQAAMAZRQql/Pz8dO+99xZ3LwAAAOUacygAAIAzihRKzZ07t7j7AAAAKPeYQwEAAJxRpGtKSVJOTo6++OILvfHGGzpx4oQk6dChQzp58mSxNQcAAFDeMIcCAAD4S5HOlPr11191++2368CBA8rMzNRtt92mypUr66WXXlJmZqZmz55d3H0CAACUecyhAAAAzijSmVJDhw5VmzZtdPz4cXl7e1vL7733XsXHxxdbcwAAAOUJcygAAIAzinSm1Ndff60NGzbIw8PDaXndunX1+++/F0tjAAAA5Q1zKAAAgDOKdKZUXl6ecnNzCyz/7bffVLly5ctuCgAAoDwqjjnUrFmz1KJFC/n6+srX11fh4eFasWKFtf706dOKiYlRtWrV5OPjo27duiklJcVpGwcOHFBUVJQqVqwof39/PfXUU8rJyXGqWbt2rVq3bi1PT0/Vr19fcXFxBXqZOXOm6tatKy8vL4WFhWnTpk0XtQ8AAABSEUOpzp07a9q0adZzFxcXnTx5UmPHjlWXLl2KqzcAAIBypTjmULVq1dLEiROVmJioLVu26JZbbtE999yjHTt2SJKGDx+uTz/9VEuWLNG6det06NAh3Xfffdbrc3NzFRUVpaysLG3YsEHz5s1TXFycxowZY9Xs379fUVFR6tSpk5KSkjRs2DD169dPq1atsmoWLVqk2NhYjR07Vt99951atmypyMhIHTly5DJHCQAAXC1cjDHmUl/022+/KTIyUsYY7d69W23atNHu3btVvXp1ffXVV/L39y+JXq9o6enpcjgcSktLk6+vb2m3AwBAmRMdt/myXj+nT9ti6sRZcX7Gl9QcqmrVqpo8ebLuv/9+1ahRQwsWLND9998vSdq5c6eaNGmihIQEtW/fXitWrNCdd96pQ4cOKSAgQJI0e/ZsjRw5UkePHpWHh4dGjhyp5cuXa/v27dZ79OjRQ6mpqVq5cqUkKSwsTG3bttWMGTMk/XUWWHBwsIYMGaKnn376onsv6TnU5RxXJXVMAQBQ3l3s53uRzpSqVauWvv/+ez3zzDMaPny4rrvuOk2cOFFbt269KgMpAACAi1Hcc6jc3FwtXLhQGRkZCg8PV2JiorKzsxUREWHVNG7cWLVr11ZCQoIkKSEhQc2bN7cCKUmKjIxUenq6dbZVQkKC0zbya/K3kZWVpcTERKcaV1dXRUREWDXnkpmZqfT0dKcHAAC4OhXpQueS5O7urn/961/F2QsAAEC5VxxzqG3btik8PFynT5+Wj4+PPvroIzVt2lRJSUny8PCQn5+fU31AQICSk5MlScnJyU6BVP76/HXnq0lPT9epU6d0/Phx5ebmFlqzc+fO8/Y+YcIEjRs37pL3GQAAlD9FCqXefffd865/+OGHi9QMAABAeVZcc6hGjRopKSlJaWlp+u9//6vevXtr3bp1xdFiiRs1apRiY2Ot5+np6QoODi7FjgAAQGkpUig1dOhQp+fZ2dn6888/5eHhoYoVKxJKAQAAFKK45lAeHh6qX7++JCk0NFSbN2/W9OnT1b17d2VlZSk1NdXpbKmUlBQFBgZKkgIDAwvcJS//7nxn1/z9jn0pKSny9fWVt7e33Nzc5ObmVmhN/jbOxdPTU56enhe1nwAAoHwr0jWljh8/7vQ4efKkdu3apQ4dOuiDDz4o7h4BAADKhZKaQ+Xl5SkzM1OhoaGqUKGC4uPjrXW7du3SgQMHFB4eLkkKDw/Xtm3bnO6St3r1avn6+qpp06ZWzdnbyK/J34aHh4dCQ0OdavLy8hQfH2/VAAAAXEiRryn1dw0aNNDEiRP1r3/964LXEgAAAMBfLnUONWrUKN1xxx2qXbu2Tpw4oQULFmjt2rVatWqVHA6HoqOjFRsbq6pVq8rX11dDhgxReHi42rdvL0nq3LmzmjZtql69emnSpElKTk7W6NGjFRMTY53BNHDgQM2YMUMjRozQI488ojVr1mjx4sVavny51UdsbKx69+6tNm3aqF27dpo2bZoyMjLUt2/fkhkoAABQ7hRbKCX9deHOQ4cOFecmAQAAyr1LmUMdOXJEDz/8sA4fPiyHw6EWLVpo1apVuu222yRJU6dOlaurq7p166bMzExFRkbq9ddft17v5uamZcuWadCgQQoPD1elSpXUu3dvjR8/3qoJCQnR8uXLNXz4cE2fPl21atXS22+/rcjISKume/fuOnr0qMaMGaPk5GS1atVKK1euLHDxcwAAgHNxMcaYS33RJ5984vTcGKPDhw9rxowZCg4O1ooVK4qtwbIiPT1dDodDaWlp8vX1Le12AAAoc6LjNl/W6+f0aVtMnTgrzs945lAFlfQc6nKOq5I6pgAAKO8u9vO9SGdKde3a1em5i4uLatSooVtuuUWvvPJKUTYJAABQ7jGHAgAAOKNIoVReXl5x9wEAAFDuMYcCAAA4o0h33wMAAAAAAAAuR5HOlIqNjb3o2ilTphTlLQAAAMod5lAAAABnFCmU2rp1q7Zu3ars7Gw1atRIkvTzzz/Lzc1NrVu3tupcXFyKp0sAAIBygDkUAADAGUUKpe666y5VrlxZ8+bNU5UqVSRJx48fV9++fXXjjTfqiSeeKNYmAQAAygPmUAAAAGcU6ZpSr7zyiiZMmGBNpiSpSpUqeuGFF7hzDAAAwDkwhwIAADijSKFUenq6jh49WmD50aNHdeLEictuCgAAoDxiDgUAAHBGkUKpe++9V3379tWHH36o3377Tb/99pv+7//+T9HR0brvvvuKu0cAAIBygTkUAADAGUW6ptTs2bP15JNP6qGHHlJ2dvZfG3J3V3R0tCZPnlysDQIAAJQXzKEAAADOKFIoVbFiRb3++uuaPHmy9u7dK0mqV6+eKlWqVKzNAQAAlCfMoQAAAM4o0tf38h0+fFiHDx9WgwYNVKlSJRljiqsvAACAcos5FAAAQBFDqf/973+69dZb1bBhQ3Xp0kWHDx+WJEVHR3MrYwAAgHNgDgUAAHBGkUKp4cOHq0KFCjpw4IAqVqxoLe/evbtWrlxZbM0BAACUJ8yhAAAAzijSNaU+//xzrVq1SrVq1XJa3qBBA/3666/F0hgAAEB5wxwKAADgjCKdKZWRkeH02718x44dk6en52U3BQAAUB4xhwIAADijSKHUjTfeqHfffdd67uLiory8PE2aNEmdOnUqtuYAAADKE+ZQAAAAZxTp63uTJk3Srbfeqi1btigrK0sjRozQjh07dOzYMa1fv764ewQAACgXmEMBAACcUaQzpZo1a6aff/5ZHTp00D333KOMjAzdd9992rp1q+rVq1fcPQIAAJQLzKEAAADOuOQzpbKzs3X77bdr9uzZevbZZ0uiJwAAgHKHORQAAICzSz5TqkKFCvrhhx9KohcAAIByizkUAACAsyJ9fe9f//qX5syZU9y9AAAAlGvMoQAAAM4o0oXOc3Jy9M477+iLL75QaGioKlWq5LR+ypQpxdIcAABAecIcCgAA4IxLCqX27dununXravv27WrdurUk6eeff3aqcXFxKb7uAAAAygHmUAAAAAVdUijVoEEDHT58WF9++aUkqXv37nr11VcVEBBQIs0BAACUB8yhAAAACrqka0oZY5yer1ixQhkZGcXaEAAAQHnDHAoAAKCgIl3oPN/fJ1gAAAC4MOZQAAAAlxhKubi4FLjeweVc/2DChAlq27atKleuLH9/f3Xt2lW7du1yqjl9+rRiYmJUrVo1+fj4qFu3bkpJSXGqOXDggKKiolSxYkX5+/vrqaeeUk5OjlPN2rVr1bp1a3l6eqp+/fqKi4sr0M/MmTNVt25deXl5KSwsTJs2bSryvgEAAOQr7jkUAABAeXBJ15QyxqhPnz7y9PSU9FdgNHDgwAJ3jvnwww8vanvr1q1TTEyM2rZtq5ycHD3zzDPq3LmzfvzxR2ubw4cP1/Lly7VkyRI5HA4NHjxY9913n9avXy9Jys3NVVRUlAIDA7VhwwYdPnxYDz/8sCpUqKAXX3xRkrR//35FRUVp4MCBmj9/vuLj49WvXz/VrFlTkZGRkqRFixYpNjZWs2fPVlhYmKZNm6bIyEjt2rVL/v7+lzJMAAAATop7DgUAAFAeuJhLOH+8b9++F1U3d+7cIjVz9OhR+fv7a926derYsaPS0tJUo0YNLViwQPfff78kaefOnWrSpIkSEhLUvn17rVixQnfeeacOHTpkXSx09uzZGjlypI4ePSoPDw+NHDlSy5cv1/bt26336tGjh1JTU7Vy5UpJUlhYmNq2basZM2ZIkvLy8hQcHKwhQ4bo6aefvmDv6enpcjgcSktLk6+vb5H2HwCAq1l03ObLev2cPm2LqRNnxfEZX9JzqLKspOdQl3NcldQxBQBAeXexn++XdKZUSU+U0tLSJElVq1aVJCUmJio7O1sRERFWTePGjVW7dm0rlEpISFDz5s2d7l4TGRmpQYMGaceOHbruuuuUkJDgtI38mmHDhkmSsrKylJiYqFGjRlnrXV1dFRERoYSEhEJ7zczMVGZmpvU8PT398nYeAACUW1dj2AQAAHAhl3Wh8+KUl5enYcOG6YYbblCzZs0kScnJyfLw8JCfn59TbUBAgJKTk62av99OOf/5hWrS09N16tQp/fHHH8rNzS20Jn8bfzdhwgQ5HA7rERwcXLQdBwAAAAAAuApdMaFUTEyMtm/froULF5Z2Kxdl1KhRSktLsx4HDx4s7ZYAAAAAAADKjEv6+l5JGTx4sJYtW6avvvpKtWrVspYHBgYqKytLqampTmdLpaSkKDAw0Kr5+13y8u/Od3bN3+/Yl5KSIl9fX3l7e8vNzU1ubm6F1uRv4+88PT2ti5UCAAAAAADg0pTqmVLGGA0ePFgfffSR1qxZo5CQEKf1oaGhqlChguLj461lu3bt0oEDBxQeHi5JCg8P17Zt23TkyBGrZvXq1fL19VXTpk2tmrO3kV+Tvw0PDw+FhoY61eTl5Sk+Pt6qAQAAAAAAQPEp1TOlYmJitGDBAn388ceqXLmydf0mh8Mhb29vORwORUdHKzY2VlWrVpWvr6+GDBmi8PBwtW/fXpLUuXNnNW3aVL169dKkSZOUnJys0aNHKyYmxjqTaeDAgZoxY4ZGjBihRx55RGvWrNHixYu1fPlyq5fY2Fj17t1bbdq0Ubt27TRt2jRlZGRc9N1yAAAAAAAAcPFKNZSaNWuWJOnmm292Wj537lz16dNHkjR16lS5urqqW7duyszMVGRkpF5//XWr1s3NTcuWLdOgQYMUHh6uSpUqqXfv3ho/frxVExISouXLl2v48OGaPn26atWqpbfffluRkZFWTffu3XX06FGNGTNGycnJatWqlVauXFng4ucAAAAAAAC4fC7GGFPaTZQH6enpcjgcSktLk6+vb2m3AwBAmRMdt/myXj+nT9ti6sQZn/Elq6TH93KOq5I6pgAAKO8u9vP9irn7HgAAAAAAAK4ehFIAAAAAAACwHaEUAAAAAAAAbEcoBQAAAAAAANsRSgEAAAAAAMB2hFIAAAAAAACwHaEUAAAAAAAAbEcoBQAAAAAAANsRSgEAAAAAAMB2hFIAAAAAAACwHaEUAAAAAAAAbEcoBQAAAAAAANsRSgEAAAAAAMB2hFIAAAAAAACwHaEUAAAAAAAAbEcoBQAAAAAAANsRSgEAAAAAAMB2hFIAAAAAAACwHaEUAAAAAAAAbEcoBQAAAAAAANsRSgEAAAAAAMB2hFIAAAAAAACwHaEUAAAAAAAAbEcoBQAAAAAAANsRSgEAAAAAAMB2hFIAAAAAAACwHaEUAAAAAAAAbEcoBQAAAAAAANsRSgEAAAAAAMB2hFIAAAAAAACwHaEUAAAAAAAAbEcoBQAAAAAAANsRSgEAAAAAAMB2hFIAAAAAAACwHaEUAAAAAAAAbEcoBQAAAAAAANsRSgEAAJQhEyZMUNu2bVW5cmX5+/ura9eu2rVrl1PN6dOnFRMTo2rVqsnHx0fdunVTSkqKU82BAwcUFRWlihUryt/fX0899ZRycnKcatauXavWrVvL09NT9evXV1xcXIF+Zs6cqbp168rLy0thYWHatGlTse8zAAAonwilAAAAypB169YpJiZG3377rVavXq3s7Gx17txZGRkZVs3w4cP16aefasmSJVq3bp0OHTqk++67z1qfm5urqKgoZWVlacOGDZo3b57i4uI0ZswYq2b//v2KiopSp06dlJSUpGHDhqlfv35atWqVVbNo0SLFxsZq7Nix+u6779SyZUtFRkbqyJEj9gwGAAAo01yMMaa0mygP0tPT5XA4lJaWJl9f39JuBwCAMic6bvNlvX5On7bF1ImzK/0z/ujRo/L399e6devUsWNHpaWlqUaNGlqwYIHuv/9+SdLOnTvVpEkTJSQkqH379lqxYoXuvPNOHTp0SAEBAZKk2bNna+TIkTp69Kg8PDw0cuRILV++XNu3b7feq0ePHkpNTdXKlSslSWFhYWrbtq1mzJghScrLy1NwcLCGDBmip59++qL6L+nxvZzjqqSOKQAAyruL/XznTCkAAIAyLC0tTZJUtWpVSVJiYqKys7MVERFh1TRu3Fi1a9dWQkKCJCkhIUHNmze3AilJioyMVHp6unbs2GHVnL2N/Jr8bWRlZSkxMdGpxtXVVREREVZNYTIzM5Wenu70AAAAVydCKQAAgDIqLy9Pw4YN0w033KBmzZpJkpKTk+Xh4SE/Pz+n2oCAACUnJ1s1ZwdS+evz152vJj09XadOndIff/yh3NzcQmvyt1GYCRMmyOFwWI/g4OBL33EAAFAuEEoBAACUUTExMdq+fbsWLlxY2q1ctFGjRiktLc16HDx4sLRbAgAApcS9tBsAAADApRs8eLCWLVumr776SrVq1bKWBwYGKisrS6mpqU5nS6WkpCgwMNCq+ftd8vLvznd2zd/v2JeSkiJfX195e3vLzc1Nbm5uhdbkb6Mwnp6e8vT0vPQdBgAA5Q5nSgEAAJQhxhgNHjxYH330kdasWaOQkBCn9aGhoapQoYLi4+OtZbt27dKBAwcUHh4uSQoPD9e2bduc7pK3evVq+fr6qmnTplbN2dvIr8nfhoeHh0JDQ51q8vLyFB8fb9UAAACcD2dKAQAAlCExMTFasGCBPv74Y1WuXNm6fpPD4ZC3t7ccDoeio6MVGxurqlWrytfXV0OGDFF4eLjat28vSercubOaNm2qXr16adKkSUpOTtbo0aMVExNjncU0cOBAzZgxQyNGjNAjjzyiNWvWaPHixVq+fLnVS2xsrHr37q02bdqoXbt2mjZtmjIyMtS3b1/7BwYAAJQ5hFIAAABlyKxZsyRJN998s9PyuXPnqk+fPpKkqVOnytXVVd26dVNmZqYiIyP1+uuvW7Vubm5atmyZBg0apPDwcFWqVEm9e/fW+PHjrZqQkBAtX75cw4cP1/Tp01WrVi29/fbbioyMtGq6d++uo0ePasyYMUpOTlarVq20cuXKAhc/BwAAKIyLMcaUdhPlQXp6uhwOh9LS0uTr61va7QAAUOZEx22+rNfP6dO2mDpxxmd8ySrp8b2c46qkjikAAMq7i/1855pSAAAAAAAAsB2hFAAAAAAAAGxHKAUAAAAAAADbEUoBAAAAAADAdoRSAAAAAAAAsB2hFAAAAAAAAGxHKAUAAAAAAADbEUoBAAAAAADAdoRSAAAAAAAAsB2hFAAAAAAAAGxHKAUAAAAAAADbEUoBAAAAAADAdoRSAAAAAAAAsB2hFAAAAAAAAGxHKAUAAAAAAADbEUoBAAAAAADAdoRSAAAAAAAAsB2hFAAAAAAAAGxHKAUAAAAAAADbEUoBAAAAAADAdoRSAAAAAAAAsB2hFAAAAAAAAGxHKAUAAAAAAADbEUoBAAAAAADAdoRSAAAAAAAAsB2hFAAAAAAAAGxHKAUAAAAAAADbEUoBAAAAAADAdoRSAAAAAAAAsB2hFAAAAAAAAGxHKAUAAAAAAADbEUoBAAAAAADAdoRSAAAAAAAAsB2hFAAAAAAAAGxHKAUAAAAAAADbEUoBAAAAAADAdoRSAAAAAAAAsB2hFAAAAAAAAGxHKAUAAAAAAADbEUoBAAAAAADAdoRSAAAAAAAAsB2hFAAAAAAAAGxHKAUAAAAAAADbEUoBAAAAAADAdoRSAAAAAAAAsB2hFAAAAAAAAGxHKAUAAAAAAADbEUoBAAAAAADAdoRSAAAAAAAAsB2hFAAAAAAAAGxHKAUAAAAAAADblWoo9dVXX+muu+5SUFCQXFxctHTpUqf1xhiNGTNGNWvWlLe3tyIiIrR7926nmmPHjqlnz57y9fWVn5+foqOjdfLkSaeaH374QTfeeKO8vLwUHBysSZMmFehlyZIlaty4sby8vNS8eXN99tlnxb6/AAAAAAAA+EuphlIZGRlq2bKlZs6cWej6SZMm6dVXX9Xs2bO1ceNGVapUSZGRkTp9+rRV07NnT+3YsUOrV6/WsmXL9NVXX2nAgAHW+vT0dHXu3Fl16tRRYmKiJk+erOeee05vvvmmVbNhwwY9+OCDio6O1tatW9W1a1d17dpV27dvL7mdBwAAAAAAuIq5GGNMaTchSS4uLvroo4/UtWtXSX+dJRUUFKQnnnhCTz75pCQpLS1NAQEBiouLU48ePfTTTz+padOm2rx5s9q0aSNJWrlypbp06aLffvtNQUFBmjVrlp599lklJyfLw8NDkvT0009r6dKl2rlzpySpe/fuysjI0LJly6x+2rdvr1atWmn27NmF9puZmanMzEzreXp6uoKDg5WWliZfX99iHx8AAMq76LjNl/X6OX3aFlMnztLT0+VwOPiMLyElPb6Xc1yV1DEFAEB5d7Gf71fsNaX279+v5ORkRUREWMscDofCwsKUkJAgSUpISJCfn58VSElSRESEXF1dtXHjRqumY8eOViAlSZGRkdq1a5eOHz9u1Zz9Pvk1+e9TmAkTJsjhcFiP4ODgy99pAAAAAACAq8QVG0olJydLkgICApyWBwQEWOuSk5Pl7+/vtN7d3V1Vq1Z1qilsG2e/x7lq8tcXZtSoUUpLS7MeBw8evNRdBAAAAAAAuGq5l3YDZZWnp6c8PT1Luw0AAAAAAIAy6Yo9UyowMFCSlJKS4rQ8JSXFWhcYGKgjR444rc/JydGxY8ecagrbxtnvca6a/PUAAAAAAAAoXldsKBUSEqLAwEDFx8dby9LT07Vx40aFh4dLksLDw5WamqrExESrZs2aNcrLy1NYWJhV89VXXyk7O9uqWb16tRo1aqQqVapYNWe/T35N/vsAAAAAAACgeJVqKHXy5EklJSUpKSlJ0l8XN09KStKBAwfk4uKiYcOG6YUXXtAnn3yibdu26eGHH1ZQUJB1h74mTZro9ttvV//+/bVp0yatX79egwcPVo8ePRQUFCRJeuihh+Th4aHo6Gjt2LFDixYt0vTp0xUbG2v1MXToUK1cuVKvvPKKdu7cqeeee05btmzR4MGD7R4SAAAAAACAq0KpXlNqy5Yt6tSpk/U8Pyjq3bu34uLiNGLECGVkZGjAgAFKTU1Vhw4dtHLlSnl5eVmvmT9/vgYPHqxbb71Vrq6u6tatm1599VVrvcPh0Oeff66YmBiFhoaqevXqGjNmjAYMGGDVXH/99VqwYIFGjx6tZ555Rg0aNNDSpUvVrFkzG0YBAAAAAADg6uNijDGl3UR5kJ6eLofDobS0NPn6+pZ2OwAAlDnRcZsv6/Vz+rQtpk6c8Rlfskp6fC/nuCqpYwoAgPLuYj/fr9hrSgEAAAAAAKD8IpQCAAAAAACA7QilAAAAAAAAYDtCKQAAAAAAANiOUAoAAAAAAAC2I5QCAAAAAACA7QilAAAAAAAAYDtCKQAAAAAAANiOUAoAAAAAAAC2I5QCAAAAAACA7QilAAAAAAAAYDtCKQAAAAAAANiOUAoAAKCM+eqrr3TXXXcpKChILi4uWrp0qdN6Y4zGjBmjmjVrytvbWxEREdq9e7dTzbFjx9SzZ0/5+vrKz89P0dHROnnypFPNDz/8oBtvvFFeXl4KDg7WpEmTCvSyZMkSNW7cWF5eXmrevLk+++yzYt9fAABQPhFKAQAAlDEZGRlq2bKlZs6cWej6SZMm6dVXX9Xs2bO1ceNGVapUSZGRkTp9+rRV07NnT+3YsUOrV6/WsmXL9NVXX2nAgAHW+vT0dHXu3Fl16tRRYmKiJk+erOeee05vvvmmVbNhwwY9+OCDio6O1tatW9W1a1d17dpV27dvL7mdBwAA5YaLMcaUdhPlQXp6uhwOh9LS0uTr61va7QAAUOZEx22+rNfP6dO2mDpxdqV/xru4uOijjz5S165dJf11llRQUJCeeOIJPfnkk5KktLQ0BQQEKC4uTj169NBPP/2kpk2bavPmzWrTpo0kaeXKlerSpYt+++03BQUFadasWXr22WeVnJwsDw8PSdLTTz+tpUuXaufOnZKk7t27KyMjQ8uWLbP6ad++vVq1aqXZs2dfVP8lPb6Xc1yV1DEFAEB5d7Gf75wpBQAAUI7s379fycnJioiIsJY5HA6FhYUpISFBkpSQkCA/Pz8rkJKkiIgIubq6auPGjVZNx44drUBKkiIjI7Vr1y4dP37cqjn7ffJr8t+nMJmZmUpPT3d6AACAqxOhFAAAQDmSnJwsSQoICHBaHhAQYK1LTk6Wv7+/03p3d3dVrVrVqaawbZz9HueqyV9fmAkTJsjhcFiP4ODgS91FAABQThBKAQAAwDajRo1SWlqa9Th48GBptwQAAEoJoRQAAEA5EhgYKElKSUlxWp6SkmKtCwwM1JEjR5zW5+Tk6NixY041hW3j7Pc4V03++sJ4enrK19fX6QEAAK5OhFIAAADlSEhIiAIDAxUfH28tS09P18aNGxUeHi5JCg8PV2pqqhITE62aNWvWKC8vT2FhYVbNV199pezsbKtm9erVatSokapUqWLVnP0++TX57wMAAHA+hFIAAABlzMmTJ5WUlKSkpCRJf13cPCkpSQcOHJCLi4uGDRumF154QZ988om2bdumhx9+WEFBQdYd+po0aaLbb79d/fv316ZNm7R+/XoNHjxYPXr0UFBQkCTpoYcekoeHh6Kjo7Vjxw4tWrRI06dPV2xsrNXH0KFDtXLlSr3yyivauXOnnnvuOW3ZskWDBw+2e0gAAEAZ5F7aDQAAAODSbNmyRZ06dbKe5wdFvXv3VlxcnEaMGKGMjAwNGDBAqamp6tChg1auXCkvLy/rNfPnz9fgwYN16623ytXVVd26ddOrr75qrXc4HPr8888VExOj0NBQVa9eXWPGjNGAAQOsmuuvv14LFizQ6NGj9cwzz6hBgwZaunSpmjVrZsMoAACAss7FGGNKu4nyID09XQ6HQ2lpaVwbAQCAIoiO23xZr5/Tp20xdeKMz/iSVdLjeznHVUkdUwAAlHcX+/nO1/cAAAAAAABgO0IpAAAAAAAA2I5QCgAAAAAAALYjlAIAAAAAAIDtCKUAAAAAAABgO0IpAAAAAAAA2I5QCgAAAAAAALYjlAIAAAAAAIDtCKUAAAAAAABgO0IpAAAAAAAA2I5QCgAAAAAAALYjlAIAAAAAAIDtCKUAAAAAAABgO0IpAAAAAAAA2I5QCgAAAAAAALYjlAIAAAAAAIDtCKUAAAAAAABgO0IpAAAAAAAA2I5QCgAAAAAAALYjlAIAAAAAAIDtCKUAAAAAAABgO0IpAAAAAAAA2I5QCgAAAAAAALYjlAIAAAAAAIDtCKUAAAAAAABgO0IpAAAAAAAA2I5QCgAAAAAAALYjlAIAAAAAAIDtCKUAAAAAAABgO0IpAAAAAAAA2I5QCgAAAAAAALYjlAIAAAAAAIDtCKUAAAAAAABgO0IpAAAAAAAA2I5QCgAAAAAAALYjlAIAAAAAAIDtCKUAAAAAAABgO0IpAAAAAAAA2I5QCgAAAAAAALYjlAIAAAAAAIDtCKUAAAAAAABgO0IpAAAAAAAA2I5QCgAAAAAAALYjlAIAAAAAAIDtCKUAAAAAAABgO0IpAAAAAAAA2I5QCgAAAAAAALYjlAIAAAAAAIDtCKUAAAAAAABgO0IpAAAAAAAA2I5QCgAAAAAAALYjlAIAAAAAAIDtCKUAAAAAAABgO0IpAAAAAAAA2I5QCgAAAAAAALYjlAIAAAAAAIDtCKUAAAAAAABgO0IpAAAAAAAA2I5QCgAAAAAAALYjlAIAAAAAAIDtCKUAAAAAAABgO0IpAAAAAAAA2I5QCgAAAAAAALYjlAIAAAAAAIDtCKUAAAAAAABgO0IpAAAAAAAA2M69tBsAAADlR3Tc5tJuAQAAAGUEZ0oBAAAAAADAdoRSAAAAAAAAsB2hFAAAAAAAAGzHNaUAAIATrgsFAAAAOxBKAQBQzhAqAQAAoCwglAJw1SqrP7jP6dO2tFuADcrq8QkAAABcLEIplEuX+8Pc5fzQzw+SKGkcYwAAAADKA0Kpv5k5c6YmT56s5ORktWzZUq+99pratWtX2m2VWWX1h+ey2jcAAKWB+RMAACgKQqmzLFq0SLGxsZo9e7bCwsI0bdo0RUZGateuXfL39y/t9oqMgAUAAJSU8jp/ki5vDsVXrQEAuDDX0m7gSjJlyhT1799fffv2VdOmTTV79mxVrFhR77zzTmm3BgAAcEVi/gQAAIqKM6X+v6ysLCUmJmrUqFHWMldXV0VERCghIaFAfWZmpjIzM63naWlpkqT09PQS6S9mfmKJbBcAgPKipD6D87drjCmR7Zdllzp/kuyfQ2WdOlki272QXrO+LJX3laSZPUNL7b0BAJAufv5EKPX//fHHH8rNzVVAQIDT8oCAAO3cubNA/YQJEzRu3LgCy4ODg0usRwAAcG7vP1ay2z9x4oQcDkfJvkkZc6nzJ4k5lB1K+t8CAAAX60LzJ0KpIho1apRiY2Ot53l5eTp27JiqVasmFxeXIm83PT1dwcHBOnjwoHx9fYujVVwAY24vxtt+jLn9GHP7leSYG2N04sQJBQUFFet2r1YlNYf6O/4dMgYSYyAxBhJjIDEGEmMg2TsGFzt/IpT6/6pXry43NzelpKQ4LU9JSVFgYGCBek9PT3l6ejot8/PzK7Z+fH19r9p/KKWFMbcX420/xtx+jLn9SmrMOUOqcJc6f5JKfg71d/w7ZAwkxkBiDCTGQGIMJMZAsm8MLmb+xIXO/z8PDw+FhoYqPj7eWpaXl6f4+HiFh4eXYmcAAABXJuZPAADgcnCm1FliY2PVu3dvtWnTRu3atdO0adOUkZGhvn37lnZrAAAAVyTmTwAAoKgIpc7SvXt3HT16VGPGjFFycrJatWqllStXFrh4Z0ny9PTU2LFjC5zWjpLDmNuL8bYfY24/xtx+jHnpuRLmT4XhmGAMJMZAYgwkxkBiDCTGQLoyx8DFcH9jAAAAAAAA2IxrSgEAAAAAAMB2hFIAAAAAAACwHaEUAAAAAAAAbEcoBQAAAAAAANsRSpWCmTNnqm7duvLy8lJYWJg2bdp03volS5aocePG8vLyUvPmzfXZZ5/Z1Gn5cSlj/tZbb+nGG29UlSpVVKVKFUVERFzw7wjOLvUYz7dw4UK5uLioa9euJdtgOXSpY56amqqYmBjVrFlTnp6eatiwIf9vuUSXOubTpk1To0aN5O3treDgYA0fPlynT5+2qduy7auvvtJdd92loKAgubi4aOnSpRd8zdq1a9W6dWt5enqqfv36iouLK/E+cWUp6mfRlW7ChAlq27atKleuLH9/f3Xt2lW7du1yqrn55pvl4uLi9Bg4cKBTzYEDBxQVFaWKFSvK399fTz31lHJycuzclSJ77rnnCuxf48aNrfWnT59WTEyMqlWrJh8fH3Xr1k0pKSlO2yjL+y9JdevWLTAGLi4uiomJkVQ+j4ELfRYYYzRmzBjVrFlT3t7eioiI0O7du51qjh07pp49e8rX11d+fn6Kjo7WyZMnnWp++OEH3XjjjfLy8lJwcLAmTZpU0rt20c43BtnZ2Ro5cqSaN2+uSpUqKSgoSA8//LAOHTrktI3Cjp2JEyc61ZTVMZCkPn36FNi/22+/3ammPB8Hkgr9f4OLi4smT55s1VxRx4GBrRYuXGg8PDzMO++8Y3bs2GH69+9v/Pz8TEpKSqH169evN25ubmbSpEnmxx9/NKNHjzYVKlQw27Zts7nzsutSx/yhhx4yM2fONFu3bjU//fST6dOnj3E4HOa3336zufOy6VLHO9/+/fvNP/7xD3PjjTeae+65x55my4lLHfPMzEzTpk0b06VLF/PNN9+Y/fv3m7Vr15qkpCSbOy+7LnXM58+fbzw9Pc38+fPN/v37zapVq0zNmjXN8OHDbe68bPrss8/Ms88+az788EMjyXz00Ufnrd+3b5+pWLGiiY2NNT/++KN57bXXjJubm1m5cqU9DaPUFfWzqCyIjIw0c+fONdu3bzdJSUmmS5cupnbt2ubkyZNWzU033WT69+9vDh8+bD3S0tKs9Tk5OaZZs2YmIiLCbN261Xz22WemevXqZtSoUaWxS5ds7Nix5tprr3Xav6NHj1rrBw4caIKDg018fLzZsmWLad++vbn++uut9WV9/40x5siRI077v3r1aiPJfPnll8aY8nkMXOizYOLEicbhcJilS5ea77//3tx9990mJCTEnDp1yqq5/fbbTcuWLc23335rvv76a1O/fn3z4IMPWuvT0tJMQECA6dmzp9m+fbv54IMPjLe3t3njjTfs2s3zOt8YpKammoiICLNo0SKzc+dOk5CQYNq1a2dCQ0OdtlGnTh0zfvx4p2Pj7P9/lOUxMMaY3r17m9tvv91p/44dO+ZUU56PA2OM074fPnzYvPPOO8bFxcXs3bvXqrmSjgNCKZu1a9fOxMTEWM9zc3NNUFCQmTBhQqH1DzzwgImKinJaFhYWZh599NES7bM8udQx/7ucnBxTuXJlM2/evJJqsVwpynjn5OSY66+/3rz99tumd+/ehFKX6FLHfNasWeaaa64xWVlZdrVY7lzqmMfExJhbbrnFaVlsbKy54YYbSrTP8uhiQqkRI0aYa6+91mlZ9+7dTWRkZAl2hivJ5X72lyVHjhwxksy6deusZTfddJMZOnToOV/z2WefGVdXV5OcnGwtmzVrlvH19TWZmZkl2W6xGDt2rGnZsmWh61JTU02FChXMkiVLrGU//fSTkWQSEhKMMWV//wszdOhQU69ePZOXl2eMKf/HwN8/C/Ly8kxgYKCZPHmytSw1NdV4enqaDz74wBhjzI8//mgkmc2bN1s1K1asMC4uLub33383xhjz+uuvmypVqjiNwciRI02jRo1KeI8u3cV8Hm7atMlIMr/++qu1rE6dOmbq1KnnfE1ZH4ML/SxxNR4H99xzT4F56JV0HPD1PRtlZWUpMTFRERER1jJXV1dFREQoISGh0NckJCQ41UtSZGTkOevhrChj/nd//vmnsrOzVbVq1ZJqs9wo6niPHz9e/v7+io6OtqPNcqUoY/7JJ58oPDxcMTExCggIULNmzfTiiy8qNzfXrrbLtKKM+fXXX6/ExETr60P79u3TZ599pi5dutjS89WGz86rW3F89pclaWlpklRgnjJ//nxVr15dzZo106hRo/Tnn39a6xISEtS8eXMFBARYyyIjI5Wenq4dO3bY0/hl2r17t4KCgnTNNdeoZ8+eOnDggCQpMTFR2dnZTn//jRs3Vu3ata2///Kw/2fLysrS+++/r0ceeUQuLi7W8vJ+DJxt//79Sk5Odvp7dzgcCgsLc/p79/PzU5s2bayaiIgIubq6auPGjVZNx44d5eHhYdVERkZq165dOn78uE17U3zS0tLk4uIiPz8/p+UTJ05UtWrVdN1112ny5MlOX9ssD2Owdu1a+fv7q1GjRho0aJD+97//WeuutuMgJSVFy5cvL/TnrCvlOHAv1q3hvP744w/l5uY6/c9fkgICArRz585CX5OcnFxofXJycon1WZ4UZcz/buTIkQoKCirwAw4KKsp4f/PNN5ozZ46SkpJs6LD8KcqY79u3T2vWrFHPnj312Wefac+ePXrssceUnZ2tsWPH2tF2mVaUMX/ooYf0xx9/qEOHDjLGKCcnRwMHDtQzzzxjR8tXnXN9dqanp+vUqVPy9vYupc5gh+L47C8r8vLyNGzYMN1www1q1qyZtfyhhx5SnTp1FBQUpB9++EEjR47Url279OGHH0o697+R/HVXurCwMMXFxalRo0Y6fPiwxo0bpxtvvFHbt29XcnKyPDw8CvwQfvb8uazv/98tXbpUqamp6tOnj7WsvB8Df5ff8/l+bkpOTpa/v7/Tend3d1WtWtWpJiQkpMA28tdVqVKlRPovCadPn9bIkSP14IMPytfX11r++OOPq3Xr1qpatao2bNigUaNG6fDhw5oyZYqksj8Gt99+u+677z6FhIRo7969euaZZ3THHXcoISFBbm5uV91xMG/ePFWuXFn33Xef0/Ir6TgglALOY+LEiVq4cKHWrl0rLy+v0m6n3Dlx4oR69eqlt956S9WrVy/tdq4aeXl58vf315tvvik3NzeFhobq999/1+TJkwmlSsjatWv14osv6vXXX1dYWJj27NmjoUOH6vnnn9e///3v0m4PQBkVExOj7du365tvvnFaPmDAAOvPzZs3V82aNXXrrbdq7969qlevnt1tFrs77rjD+nOLFi0UFhamOnXqaPHixVdl6DxnzhzdcccdCgoKspaV92MA55edna0HHnhAxhjNmjXLaV1sbKz15xYtWsjDw0OPPvqoJkyYIE9PT7tbLXY9evSw/ty8eXO1aNFC9erV09q1a3XrrbeWYmel45133lHPnj0L/Cx7JR0HfH3PRtWrV5ebm1uBu3+kpKQoMDCw0NcEBgZeUj2cFWXM87388suaOHGiPv/8c7Vo0aIk2yw3LnW89+7dq19++UV33XWX3N3d5e7urnfffVeffPKJ3N3dtXfvXrtaL7OKcozXrFlTDRs2lJubm7WsSZMmSk5OVlZWVon2Wx4UZcz//e9/q1evXurXr5+aN2+ue++9Vy+++KImTJigvLw8O9q+qpzrs9PX1/eq/IH1anM5n/1lyeDBg7Vs2TJ9+eWXqlWr1nlrw8LCJEl79uyRdO5/I/nryho/Pz81bNhQe/bsUWBgoLKyspSamupUc/bff3na/19//VVffPGF+vXrd9668n4M5Pd8vn/3gYGBOnLkiNP6nJwcHTt2rFwdG/mB1K+//qrVq1c7nSVVmLCwMOXk5OiXX36RVD7G4GzXXHONqlev7nTsXw3HgSR9/fXX2rVr1wX//yCV7nFAKGUjDw8PhYaGKj4+3lqWl5en+Ph4hYeHF/qa8PBwp3pJWr169Tnr4awoYy5JkyZN0vPPP6+VK1c6fd8Y53ep4924cWNt27ZNSUlJ1uPuu+9Wp06dlJSUpODgYDvbL5OKcozfcMMN2rNnj1MY8vPPP6tmzZpO3xtH4Yoy5n/++adcXZ0/cvNDQWNMyTV7leKz8+pW1M/+ssIYo8GDB+ujjz7SmjVrCny9ojD5X5GvWbOmpL/+jWzbts3pB7P8H16bNm1aIn2XpJMnT2rv3r2qWbOmQkNDVaFCBae//127dunAgQPW33952v+5c+fK399fUVFR560r78dASEiIAgMDnf7e09PTtXHjRqe/99TUVCUmJlo1a9asUV5enhXahYeH66uvvlJ2drZVs3r1ajVq1KhMfGUrP5DavXu3vvjiC1WrVu2Cr0lKSpKrq6v1lbayPgZ/99tvv+l///uf07Ff3o+DfHPmzFFoaKhatmx5wdpSPQ6K/dLpOK+FCxcaT09PExcXZ3788UczYMAA4+fnZ935olevXubpp5+26tevX2/c3d3Nyy+/bH766SczduxYU6FCBbNt27bS2oUy51LHfOLEicbDw8P897//dbpF5okTJ0prF8qUSx3vv+Pue5fuUsf8wIEDpnLlymbw4MFm165dZtmyZcbf39+88MILpbULZc6ljvnYsWNN5cqVzQcffGD27dtnPv/8c1OvXj3zwAMPlNYulCknTpwwW7duNVu3bjWSzJQpU8zWrVutuwk9/fTTplevXlb9vn37TMWKFc1TTz1lfvrpJzNz5kzj5uZmVq5cWVq7AJtd6N9oWTZo0CDjcDjM2rVrneYpf/75pzHGmD179pjx48ebLVu2mP3795uPP/7YXHPNNaZjx47WNnJyckyzZs1M586dTVJSklm5cqWpUaOGGTVqVGnt1iV54oknzNq1a83+/fvN+vXrTUREhKlevbo5cuSIMcaYgQMHmtq1a5s1a9aYLVu2mPDwcBMeHm69vqzvf77c3FxTu3ZtM3LkSKfl5fUYuNBnwcSJE42fn5/5+OOPzQ8//GDuueceExISYk6dOmVt4/bbbzfXXXed2bhxo/nmm29MgwYNzIMPPmitT01NNQEBAaZXr15m+/btZuHChaZixYrmjTfesH1/C3O+McjKyjJ33323qVWrlklKSnL6/0P+HdQ2bNhgpk6dapKSkszevXvN+++/b2rUqGEefvhh6z3K8hicOHHCPPnkkyYhIcHs37/ffPHFF6Z169amQYMG5vTp09Y2yvNxkC8tLc1UrFjRzJo1q8Drr7TjgFCqFLz22mumdu3axsPDw7Rr1858++231rqbbrrJ9O7d26l+8eLFpmHDhsbDw8Nce+21Zvny5TZ3XPZdypjXqVPHSCrwGDt2rP2Nl1GXeoyfjVCqaC51zDds2GDCwsKMp6enueaaa8x//vMfk5OTY3PXZduljHl2drZ57rnnTL169YyXl5cJDg42jz32mDl+/Lj9jZdBX375ZaH/X84f4969e5ubbrqpwGtatWplPDw8zDXXXGPmzp1re98oXef7N1qWFfZvQZJ1jB84cMB07NjRVK1a1Xh6epr69eubp556yqSlpTlt55dffjF33HGH8fb2NtWrVzdPPPGEyc7OLoU9unTdu3c3NWvWNB4eHuYf//iH6d69u9mzZ4+1/tSpU+axxx4zVapUMRUrVjT33nuvOXz4sNM2yvL+51u1apWRZHbt2uW0vLweAxf6LMjLyzP//ve/TUBAgPH09DS33nprgbH53//+Zx588EHj4+NjfH19Td++fQv84vn77783HTp0MJ6enuYf//iHmThxol27eEHnG4P9+/ef8/8PX375pTHGmMTERBMWFmYcDofx8vIyTZo0MS+++KJTYGNM2R2DP//803Tu3NnUqFHDVKhQwdSpU8f079+/wC8kyvNxkO+NN94w3t7eJjU1tcDrr7TjwMUYvjcAAAAAAAAAe3FNKQAAAAAAANiOUAoAAAAAAAC2I5QCAAAAAACA7QilAAAAAAAAYDtCKQAAAAAAANiOUAoAAAAAAAC2I5QCAAAAAACA7QilAAAAAAAAYDtCKQAAAADAJfnll1/k4uKipKSk0m5FknTzzTdr2LBhpd0GgEtEKAXgqlJSE5abb75ZLi4ucnFxkZeXl5o2barXX3/dWh8XF2etd3V1Va1atdS3b18dOXKk2HsBAAAoDR999JHat28vh8OhypUr69prr73keZeLi4uWLl3qtCw3N1cTJ05U48aN5e3trapVqyosLExvv/22VfPhhx/q+eefL4a9AGAn99JuAADKi/79+2v8+PH6888/9e677yomJkZVqlTRgw8+KEny9fXVrl27lJeXp++//159+/bVoUOHtGrVqlLuHAAAXK2ys7NVoUKFy95OfHy8unfvrv/85z+6++675eLioh9//FGrV6++7G2PGzdOb7zxhmbMmKE2bdooPT1dW7Zs0fHjx62aqlWrXvb7ALAfZ0oBuGr06dNH69at0/Tp062zln755RetW7dO7dq1k6enp2rWrKmnn35aOTk51utuvvlmDR48WIMHD5bD4VD16tX173//W8YYp+1XrFhRgYGBuuaaa/Tcc8+pQYMG+uSTT6z1Li4uCgwMVFBQkO644w49/vjj+uKLL3Tq1CnbxgAAAJR/eXl5mjRpkurXry9PT0/Vrl1b//nPf6yv3C1atEg33XSTvLy8NH/+fEnS22+/rSZNmsjLy0uNGzd2OuNbkjZt2qTrrrtOXl5eatOmjbZu3eq0/tNPP9UNN9ygp556So0aNVLDhg3VtWtXzZw506nu448/VuvWreXl5aVrrrlG48aNs+ZddevWlSTde++9cnFxsZ5/8skneuyxx/TPf/5TISEhatmypaKjo/Xkk09a2z37bPi1a9dac72zH3369LmoPgDYhzOlAFw1pk+frp9//lnNmjXT+PHjJf11OniXLl3Up08fvfvuu9q5c6f69+8vLy8vPffcc9Zr582bp+joaG3atElbtmzRgAEDVLt2bfXv3/+c7+ft7a2srKzzrs/Ly2MCBAAAitWoUaP01ltvaerUqerQoYMOHz6snTt3WuuffvppvfLKK1bINH/+fI0ZM0YzZszQddddp61bt6p///6qVKmSevfurZMnT+rOO+/Ubbfdpvfff1/79+/X0KFDnd4zMDBQCxYs0Pbt29WsWbNC+/r666/18MMP69VXX9WNN96ovXv3asCAAZKksWPHavPmzfL399fcuXN1++23y83Nzdr2mjVr9Nhjj6lGjRoX3P/rr79ehw8ftp7/9NNP6tKlizp27HhRfQCwkQGAq8hNN91khg4daj1/5plnTKNGjUxeXp61bObMmcbHx8fk5uZar2nSpIlTzciRI02TJk0K3W5OTo557733jCQzY8YMY4wxc+fONQ6Hw6r/+eefTcOGDU2bNm1KYC8BAMDVKj093Xh6epq33nqrwLr9+/cbSWbatGlOy+vVq2cWLFjgtOz555834eHhxhhj3njjDVOtWjVz6tQpa/2sWbOMJLN161ZjjDEnT540Xbp0MZJMnTp1TPfu3c2cOXPM6dOnrdfceuut5sUXX3R6n/fee8/UrFnTei7JfPTRR041O3bsME2aNDGurq6mefPm5tFHHzWfffaZU83f53j5/vjjD3PNNdeYxx577JL6AGAPvr4H4Kr2008/KTw8XC4uLtayG264QSdPntRvv/1mLWvfvr1TTXh4uHbv3q3c3Fxr2euvvy4fHx95e3urf//+Gj58uAYNGmStT0tLk4+PjypWrKhGjRopICDAOmUeAACgOPz000/KzMzUrbfees6aNm3aWH/OyMjQ3r17FR0dLR8fH+vxwgsvaO/evdY2W7RoIS8vL+t14eHhTtusVKmSli9frj179mj06NHy8fHRE088oXbt2unPP/+UJH3//fcaP3680/v0799fhw8ftmoK07RpU23fvl3ffvutHnnkER05ckR33XWX+vXrd96xyM7OVrdu3VSnTh1Nnz7dWl7UPgAUP76+BwDFpGfPnnr22Wfl7e2tmjVrytXVOfevXLmyvvvuO7m6uqpmzZry9vYupU4BAEB5dTHzi0qVKll/PnnypCTprbfeUlhYmFNd/tfnLkW9evVUr1499evXT88++6waNmyoRYsWqW/fvjp58qTGjRun++67r8Drzg68CuPq6qq2bduqbdu2GjZsmN5//3316tVLzz77rEJCQgp9zaBBg3Tw4EFt2rRJ7u5nfvS9nD4AFC9CKQBXFQ8PD6ezm5o0aaL/+7//kzHGOhNq/fr1qly5smrVqmXVbdy40Wk73377rRo0aOA0WXM4HKpfv/4539vV1fW86wEAAC5XgwYN5O3trfj4+AueSSRJAQEBCgoK0r59+9SzZ89Ca5o0aaL33ntPp0+ftkKbb7/99oLbrlu3ripWrKiMjAz9v/buJxTWL47j+OdH/iymJqFYMFZjTIlRJLMYG/kTuyllMRbI5G8NjaZhUDbKMJGdYm07sniwkyIpYTEbJquJBSvSJL/F7U7N7+Zm9bj97vtVz+p5zul7dqdP5/scSWpoaFAikfjtfigvLy9rr/YZp9MpSZm5/2t1dVW7u7s6OTlRcXFx1ruv1AHAHIRSAP4qVVVVOj09VTKZlMVi0cjIiGKxmMbHxzU2NqZEIqH5+XkFAoGsk0739/cKBAIaHh7WxcWFNjY2FI1Gv3ElAAAAvyosLNTMzIyCwaDy8/Pldrv1+Piom5ubT1v6FhcXNTExIavVqo6ODr29ven8/FxPT08KBALq6+tTOBzW0NCQQqGQksmkVlZWsuZYWFjQy8uLurq6ZLPZ9Pz8rPX1daXTabW1tUmSIpGIuru7VVlZKa/Xq5ycHF1eXur6+lpLS0uSfuzVjo6O5Ha7VVBQoKKiInm9XrndbrW0tKisrEx3d3cKhUKy2+1yOBy/rOfw8FDBYFCbm5sqKSlRKpWS9OMUmdVq/VIdAMzBP6UA/FWmp6eVm5srp9Op0tJSpdNp7e/v6+zsTHV1dfL7/RoYGNDs7GzWOJ/Pp9fXVzU1NWl0dFSTk5OZW1oAAAD+JHNzc5qamlIkElFNTY16e3v18PDw6feDg4Pa2trS9va2amtr5fF4tLOzk2mLs1gsisfjurq6ksvlUjgc1vLyctYcHo9Ht7e38vl8cjgc6uzsVCqVkmEYqq6uliS1t7drb29PhmGosbFRzc3NWltbk81my8wTjUZ1cHCgiooKuVyuzLh4PK6enh7Z7Xb19/fL4XDIMIystryfjo+P9f7+Lr/fr/Ly8szz88bAr9QBwBz/fHx8fHx3EQDwJ2ttbVV9fb1isdh3lwIAAAAA/xuclAIAAAAAAIDpCKUAAAAAAABgOtr3AAAAAAAAYDpOSgEAAAAAAMB0hFIAAAAAAAAwHaEUAAAAAAAATEcoBQAAAAAAANMRSgEAAAAAAMB0hFIAAAAAAAAwHaEUAAAAAAAATEcoBQAAAAAAANP9C6kl2AG33XGVAAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "\n", + "pdf = susie_results.select(\"purityMinR2\", \"purityMeanR2\", \"topPP\", \"credSetSize\").toPandas()\n", + "plt.figure(figsize=(12, 12))\n", + "\n", + "# Histogram for purityMinR2\n", + "plt.subplot(2, 2, 1)\n", + "plt.hist(pdf[\"purityMinR2\"], bins=30, alpha=0.7)\n", + "plt.title(\"Histogram of purityMinR2\")\n", + "plt.xlabel(\"purityMinR2\")\n", + "plt.ylabel(\"Frequency\")\n", + "\n", + "# Histogram for purityMeanR2\n", + "plt.subplot(2, 2, 2)\n", + "plt.hist(pdf[\"purityMeanR2\"], bins=30, alpha=0.7)\n", + "plt.title(\"Histogram of purityMeanR2\")\n", + "plt.xlabel(\"purityMeanR2\")\n", + "plt.ylabel(\"Frequency\")\n", + "\n", + "# Histogram for topPP\n", + "plt.subplot(2, 2, 3)\n", + "plt.hist(pdf[\"topPP\"], bins=30, alpha=0.7)\n", + "plt.title(\"Histogram of topPP\")\n", + "plt.xlabel(\"topPP\")\n", + "plt.ylabel(\"Frequency\")\n", + "\n", + "# Histogram for credSetSize\n", + "plt.subplot(2, 2, 4)\n", + "plt.hist(pdf[\"credSetSize\"], bins=30, alpha=0.7)\n", + "plt.title(\"Histogram of credSetSize\")\n", + "plt.xlabel(\"credSetSize\")\n", + "plt.ylabel(\"Frequency\")\n", + "\n", + "# Adjust layout to prevent overlap\n", + "plt.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Repeating the same steps, but filtering for only the first credible set" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Total number of primary credible sets and number of unique studyIds:\n" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Number of primary credible sets: 9495\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[Stage 209:====================================================>(880 + 8) / 893]\r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Number of unique studyIds in primary credible sets: 2015\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + } + ], + "source": [ + "first_credset = susie_results.filter(f.col(\"credibleSetIndex\") == 1)\n", + "print(\"Number of primary credible sets: \", first_credset.count())\n", + "print(\"Number of unique studyIds in primary credible sets: \", first_credset.select(\"studyId\").distinct().count())" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "-RECORD 0---------------------------\n", + " meanTopPP | 0.8085156719419792 \n", + " minTopPP | 0.011231041748358246 \n", + " q1TopPP | 0.6270685668930966 \n", + " medianTopPP | 0.9999984922517341 \n", + " q3TopPP | 1.0 \n", + " maxTopPP | 1.0 \n", + "\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "-RECORD 0------------------------------\n", + " meanCredSetSize | 5.875934702474987 \n", + " minCredSetSize | 1 \n", + " q1CredSetSize | 1 \n", + " medianCredSetSize | 1 \n", + " q3CredSetSize | 4 \n", + " maxCredSetSize | 1022 \n", + "\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "-RECORD 0----------------------------------\n", + " meanPurityMeanR2 | 0.7587573150386597 \n", + " minPurityMeanR2 | 0.011839476509578747 \n", + " q1PurityMeanR2 | 0.520396112272186 \n", + " medianPurityMeanR2 | 0.9839697266684606 \n", + " q3PurityMeanR2 | 1.0 \n", + " maxPurityMeanR2 | 1.0 \n", + "\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[Stage 226:> (0 + 1) / 1]\r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "-RECORD 0---------------------------------\n", + " meanPurityMinR2 | 0.6480281642261705 \n", + " minPurityMinR2 | 0.0 \n", + " q1PurityMinR2 | 0.002472980432442... \n", + " medianPurityMinR2 | 0.9659616302635498 \n", + " q3PurityMinR2 | 1.0 \n", + " maxPurityMinR2 | 1.0 \n", + "\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + } + ], + "source": [ + "(\n", + " first_credset.select(\n", + " f.mean(\"topPP\").alias(\"meanTopPP\"),\n", + " f.min(\"topPP\").alias(\"minTopPP\"),\n", + " f.percentile_approx(\"topPP\", 0.25).alias(\"q1TopPP\"),\n", + " f.percentile_approx(\"topPP\", 0.5).alias(\"medianTopPP\"),\n", + " f.percentile_approx(\"topPP\", 0.75).alias(\"q3TopPP\"),\n", + " f.max(\"topPP\").alias(\"maxTopPP\"),\n", + " ).show(vertical=True)\n", + ")\n", + "(\n", + " first_credset.select(\n", + " f.mean(\"credSetSize\").alias(\"meanCredSetSize\"),\n", + " f.min(\"credSetSize\").alias(\"minCredSetSize\"),\n", + " f.percentile_approx(\"credSetSize\", 0.25).alias(\"q1CredSetSize\"),\n", + " f.percentile_approx(\"credSetSize\", 0.5).alias(\"medianCredSetSize\"),\n", + " f.percentile_approx(\"credSetSize\", 0.75).alias(\"q3CredSetSize\"),\n", + " f.max(\"credSetSize\").alias(\"maxCredSetSize\"),\n", + " ).show(vertical=True)\n", + ")\n", + "(\n", + " first_credset.select(\n", + " f.mean(\"purityMeanR2\").alias(\"meanPurityMeanR2\"),\n", + " f.min(\"purityMeanR2\").alias(\"minPurityMeanR2\"),\n", + " f.percentile_approx(\"purityMeanR2\", 0.25).alias(\"q1PurityMeanR2\"),\n", + " f.percentile_approx(\"purityMeanR2\", 0.5).alias(\"medianPurityMeanR2\"),\n", + " f.percentile_approx(\"purityMeanR2\", 0.75).alias(\"q3PurityMeanR2\"),\n", + " f.max(\"purityMeanR2\").alias(\"maxPurityMeanR2\"),\n", + " ).show(vertical=True)\n", + ")\n", + "(\n", + " first_credset.select(\n", + " f.mean(\"purityMinR2\").alias(\"meanPurityMinR2\"),\n", + " f.min(\"purityMinR2\").alias(\"minPurityMinR2\"),\n", + " f.percentile_approx(\"purityMinR2\", 0.25).alias(\"q1PurityMinR2\"),\n", + " f.percentile_approx(\"purityMinR2\", 0.5).alias(\"medianPurityMinR2\"),\n", + " f.percentile_approx(\"purityMinR2\", 0.75).alias(\"q3PurityMinR2\"),\n", + " f.max(\"purityMinR2\").alias(\"maxPurityMinR2\"),\n", + " ).show(vertical=True)\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "data": { + "image/png": "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/vjjeuCBB/TGG28oKChII0eO1FdffXXbY9W3b1+NGzdOdevW1ezZs9W0aVNNnTpVXbp0scx5//339eijj8rZ2dlyrJo0aXLL9Z47d05t27ZVcHCwpk+frrJly+qFF17I0njkxN9//602bdqoTp06mjNnjpo3b55lTrVq1TRp0iRJ/zZR19fbvXt3paWl6aOPPrL6TEpKij7++GN17NhRLi4uVsuee+45nT592qr5W7FihR577DH5+Pjcce2//fabOnXqpMcff1wzZ85U8eLF1bNnTx08ePC2n81sSIsXL37bufHx8ZJkOQsIACh86JHokW5UEHqkhIQENWrUSF9++aUGDhyouXPnKigoSH369NGcOXMs85KSkrRo0SI1a9ZMb7zxhiZMmKCzZ88qNDQ023thrVixQjNmzFD//v01ZcoUHT9+XB06dLijfx/osXBPMgDY1JIlSwxJt3zVqFHD6jMBAQFGeHi45f2DDz5ohIWF3XI7ERERRnb/yn/22WeGJGPKlClW4506dTLs7OyM3377zTAMw4iNjTUkGUOHDrWa17NnT0OSMX78eMvY+PHjDUnGs88+m2V7ly9fzjL24YcfGpKMr776Kss6+vXrZxlLS0szypYta9jZ2RnTpk2zjJ87d85wdXW1OibZiYuLMyQZffv2tRofOXKkIcnYsmWLZSw8PNwoVqzYLdeXqWnTpoYkY+bMmZax5ORko06dOoaPj4+RkpJiGMa1n/WxY8esPr9161ZDkrF169Ys61ywYEG222vatKnl/Z49ewxJxpIlS7LMDQkJMRo2bGg1tmbNmmy3l/l7Vq9ePaNPnz6GYfx7bJ2cnIylS5da6ly9erXlc9ntU0BAQJaf55kzZwxnZ2djxIgRWfb7vffeM86ePWucOnXK2LBhgxEUFGTY2dkZ3333XZb9uVGfPn0Me3t745dffrntXABAwUKPRI9UkHukPn36GKVLlzb++usvq2106dLF8PT0tPy809LSjOTkZKs5586dM3x9fY3evXtbxo4dO2ZIMkqWLGn8888/lvHPP//ckGR88cUXlrHM35HDhw8bZ8+eNY4fP2689957hqurq+Ht7W1cunQpy/G4XnJyslG9enUjMDDQSE1NveVc4G5xpRRwj4iMjFRMTEyWV+3atW/7WS8vLx08eFC//vprjre7bt062dvba/DgwVbjI0aM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8mSlpaVp69atluVz5szR6NGjVb9+fVWqVEmvv/66KlWqpC+++OKOjzUAAChYCluflJGRoalTpyowMFCurq568MEH9fHHH1uWp6enq0+fPpblVapUyXL1Us+ePdWuXTu9+eabKl26tEqWLKmIiAilpqZazStatKj8/PwUEBCgXr16qXbt2oqJibEs7927t+bOnaumTZuqQoUK6tatm3r16mW1HwDyF6EUgHvC0qVL5eDgoO+++05z587VrFmztGjRohyt4+WXX9aQIUP0008/KTQ01GpZ586dNWLECNWoUUOnT5/W6dOn1blzZ/Xt21cbNmzQ6dOnLXPXrl2ry5cvq3Pnzlbr6N27t5YsWWJ5/95776lXr153VNvMmTNVr1497du3Ty+++KJeeOEFHT58ONu5aWlplkbPycnppuvMyMjQhQsXVKJEiTuqAQAAFEyFqU+aOnWqli1bpgULFujgwYMaNmyYunXrpu3bt0v6t78pW7asVq9erUOHDmncuHF65ZVXtGrVKqv1bN26VUeOHNHWrVu1dOlSRUVFWYK4GxmGoa+//lo///zzLXsrSUpMTKS3AkzkYOsCAED697Lv2bNny87OTlWqVNH+/fs1e/ZsPf/883e8jqFDh6pDhw7ZLnN1dZWbm5scHBzk5+dnGX/44YdVpUoVvf/++xo9erSkf79G95///Edubm5W6+jWrZvGjBmj33//XZK0c+dOrVy5Utu2bbttbW3bttWLL74oSXrppZc0e/Zsbd26VVWqVLHMefbZZ2Vvb68rV64oIyND5cuX1zPPPHPTdb755pu6ePHiLecAAICCr7D0ScnJyXr99df15ZdfKiQkRJJUoUIF7dixQ++8846aNm0qR0dHTZw40fKZwMBA7d69W6tWrbLqeYoXL6558+bJ3t5eVatWVVhYmDZv3mx1TN5++20tWrRIKSkpSk1NlYuLiwYPHnzTY7Rr1y599NFHio6Ovt3hBJBHuFIKwD2hUaNGsrOzs7wPCQnRr7/+qvT09DteR7169XK17b59+1rO7CUkJGj9+vXq3bt3lnne3t4KCwtTVFSUlixZorCwMJUqVeqOtlG7dm3Ln+3s7OTn56czZ85YzZk9e7bi4uK0fv16Va9eXYsWLbrpmboVK1Zo4sSJWrVqVZ7dDwIAANybCkuf9Ntvv+ny5ct6/PHH5ebmZnktW7ZM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OiazZ8/WxYsXFRcXp4CAAKtlZ86cydNtffbZZ9q3b5+WL1+u5557zmrZ1atXlZKSYnnv4OAgBwf+9x2FD1/fA3BLN37PPjU1VRMnTlSlSpXk4uKikiVLqnHjxoqJiZEk9ezZU5GRkZJk9ZWuTJcuXdKIESPk7+8vZ2dnValSRW+++aYMw7Da7pUrVzR48GCVKlVK7u7ueuqpp/Tnn3/Kzs7O6ixT5lfMDh06pOeee07FixdX48aNJUk//vijevbsqQoVKlguve7du7f+/vtvq21lruOXX35Rt27d5OnpKW9vb/33v/+VYRg6efKknn76aXl4eMjPz08zZ868o2OXlpamyZMnq2LFinJ2dlb58uX1yiuvKDk52TLHzs5OS5Ys0aVLlyzHKioqKtv1NWvWTNHR0fr9998tc8uXL29ZfubMGfXp00e+vr5ycXHRgw8+qKVLl1qt4/jx47Kzs9Obb76p2bNnKyAgQK6urmratKkOHDhwR/vVokULSdKxY8fyZB4AAGait7l3eptM3377rdq2bavixYurWLFiql27tubOnWtZ3rNnT7m5uenIkSNq27at3N3d1bVrV0lSRkaG5syZoxo1asjFxUW+vr7q37+/zp07Z7UNwzA0ZcoUlS1bVkWLFlXz5s118ODBLLUcOXJEZcuWzRJISZKPj0+WsfXr1+vRRx9VsWLF5O7urrCwMKv13ur358iRI5KkRx55JMt6XVxc5OHhYXl/4z2levbsabW+61/X/z4lJydr/PjxCgoKkrOzs/z9/TV69GirnxlgS0StwH0oMTFRf/31V5bx1NTU2352woQJmjp1qvr27asGDRooKSlJ33//vfbu3avHH39c/fv316lTpxQTE6P333/f6rOGYeipp57S1q1b1adPH9WpU0cbN27UqFGj9Oeff2r27NmWuT179tSqVavUvXt3NWrUSNu3b1dYWNhN6/rPf/6jSpUq6fXXX7c0gTExMTp69Kh69eolPz8/HTx4UAsXLtTBgwf1zTffZLlZZOfOnVWtWjVNmzZN0dHRmjJlikqUKKF33nlHLVq00BtvvKHly5dr5MiRql+/vpo0aXLLY9W3b18tXbpUnTp10ogRI/Ttt99q6tSp+umnn/Tpp59Kkt5//30tXLhQ3333nRYtWiRJevjhh7Nd36uvvqrExET98ccflmPl5uYm6d9Gt1mz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AABsRygFAAAAAAAA2xFKAQAAAAAAwHaEUmUsKSlJN998s3x8fNS+fXtt27btF+uXLVumJk2ayMfHRy1atNCqVats6rTyuZq1nzdvnu666y7VqlVLtWrVUnR09K/+s8KlXe3PfIklS5bIw8NDDzzwQPk2WEld7brn5uYqISFBISEhcjgcuvXWW/n3TSld7dpPnz5djRs3lq+vr8LCwjRixAidPXvWpm4rh40bN+q+++5TaGioPDw89PHHH//qa9avX682bdrI4XCoYcOGSk5OLvc+YZ/S/u7BeRMnTtTtt9+umjVrKjAwUA888IAyMzNdas6ePauEhATVqVNHNWrUUO/evZWTk+NSk5WVpdjYWFWrVk2BgYEaOXKkzp07Z+dUKpxJkybJw8NDw4cPt46x1mXrhx9+0COPPKI6derI19dXLVq00I4dO6xxY4zGjh2rkJAQ+fr6Kjo6Wt98843LOY4fP664uDj5+fkpICBA8fHxOnXqlN1Tua4VFRXphRdeUEREhHx9fdWgQQNNmDBBF36XGmtder+2/ymrtf3qq6901113ycfHR2FhYZo8eXJ5T82VQZlZsmSJ8fb2Nu+++67Zu3evGTRokAkICDA5OTmXrP/iiy+Ml5eXmTx5stm3b58ZM2aMqVq1qtm9e7fNnVd8V7v2ffv2NUlJSWbnzp1m//795tFHHzX+/v7m3//+t82dV2xXu+4lDh06ZH7zm9+Yu+66y9x///32NFuJXO265+fnm3bt2pmePXuaTZs2mUOHDpn169ebjIwMmzuv+K527RctWmQcDodZtGiROXTokFmzZo0JCQkxI0aMsLnzim3VqlXm+eefNx9++KGRZD766KNfrD948KCpVq2aSUxMNPv27TOzZs0yXl5eZvXq1fY0jHJV2t89cBUTE2MWLFhg9uzZYzIyMkzPnj1N/fr1zalTp6yaIUOGmLCwMJOammp27NhhOnToYO68805r/Ny5c6Z58+YmOjra7Ny506xatcrUrVvXjB492h1TqhC2bdtmbr75ZtOyZUszbNgw6zhrXXaOHz9uwsPDzaOPPmq2bt1qDh48aNasWWO+/fZbq2bSpEnG39/ffPzxx2bXrl3m97//vYmIiDBnzpyxarp3725uu+02s2XLFvPPf/7TNGzY0Dz88MPumNJ165VXXjF16tQxK1asMIcOHTLLli0zNWrU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LGuto6KitHv3bpf/6ElJSZGfn99FocCNrGvXrhftgdq1a6e4uDjrz6x12enYsaMyMzNdjh04cEDh4eGSpIiICAUHB7ust9Pp1NatW13WOzc3V+np6VbNunXrVFxcrPbt29swi4rhcvuckj0na11+ympto6KitHHjRhUWFlo1KSkpaty4sS0f3ZMkvn2vDC1ZssQ4HA6TnJxs9u3bZwYPHmwCAgKsb8no16+fee6556z6L774wlSpUsW88cYbZv/+/ebFF180VatWNbt373bXFCqsq137SZMmGW9vb/P//t//M0ePHrUeJ0+edNcUKqSrXfef49v3Sudq1z0rK8vUrFnTDB061GRmZpoVK1aYwMBA8/LLL7trChXW1a79iy++aGrWrGn+9re/mYMHD5q1a9eaBg0amD/96U/umkKFdPLkSbNz506zc+dOI8lMnTrV7Ny50/zrX/8yxhjz3HPPmX79+ln1Bw8eNNWqVTMjR440+/fvN0lJScbLy8usXr3aXVNAGfq1v4e4Mk888YTx9/c369evd9kL/fjjj1bNkCFDTP369c26devMjh07TFRUlImKirLGz507Z5o3b266detmMjIyzOrVq81NN91kRo8e7Y4pVSgXfvueMax1Wdq2bZupUqWKeeWVV8w333xjFi1aZKpVq2bef/99q2bSpEkmICDA/OMf/zBfffWVuf/++01ERIQ5c+aMVdO9e3fTunVrs3XrVrNp0ybTqFEj8/DDD7tjStetAQMGmN/85jdmxYoV5tChQ+bDDz80devWNaNGjbJqWOvS+7X9T1msbW5urgkKCjL9+vUze/bsMUuWLDHVqlUzb731lm3zJJQqY7NmzTL169c33t7e5o477jBbtmyxxu6++24zYMAAl/qlS5eaW2+91Xh7e5tmzZqZlStX2txx5XE1ax8eHm4kXfR48cUX7W+8grvan/kLEUqV3tWu++bNm0379u2Nw+Ewt9xyi3nllVfMuXPnbO66criatS8sLDTjxo0zDRo0MD4+PiYsLMw8+eST5sSJE/Y3XoF9/vnnl/x3dslaDxgwwNx9990XvaZVq1bG29vb3HLLLWbBggW2943y80t/D3FlLvV3SpLL35UzZ86YJ5980tSqVctUq1bNPPjgg+bo0aMu5/n+++9Njx49jK+vr6lbt675y1/+YgoLC22eTcXz81CKtS5bn3zyiWnevLlxOBymSZMm5u2333YZLy4uNi+88IIJCgoyDofDdO3a1WRmZrrU/O9//zMPP/ywqVGjhvHz8zMDBw7kf2D/jNPpNMOGDTP169c3Pj4+5pZbbjHPP/+8yc/Pt2pY69L7tf1PWa3trl27TKdOnYzD4TC/+c1vzKRJk+yaojHGGA9j+PwAAAAAAAAA7MU9pQAAAAAAAGA7QikAAAAAAADYjlAKAAAAAAAAtiOUAgAAAAAAgO0IpQAAAAAAAGA7QikAAAAAAADYjlAKAAAAAAAAtiOUAgAAAAAAgO0IpQAAAAAAl/X999/Lw8NDGRkZ7m5FktSlSxcNHz7c3W0AKAOEUgAqtfLatHTp0kUeHh7y8PCQj4+PmjZtqjfffNMaT05OtsY9PT1Vr149DRw4UMeOHSvzXgAAAOz20UcfqUOHDvL391fNmjXVrFmzq95zeXh46OOPP3Y5VlRUpEmTJqlJkyby9fVV7dq11b59e73zzjtWzYcffqgJEyaUwSwAuFsVdzcAABXVoEGDNH78eP3444967733lJCQoFq1aunhhx+WJPn5+SkzM1PFxcXatWuXBg4cqCNHjmjNmjVu7hwAANyICgsLVbVq1Ws+T2pqqh566CG98sor+v3vfy8PDw/t27dPKSkp13zul156SW+99ZZmz56tdu3ayel0aseOHTpx4oRVU7t27Wt+HwDXB66UAlBpPfroo9qwYYNmzJhhXbX0/fffa8OGDbrjjjvkcDgUEhKi5557TufOnbNe16VLFw0dOlRDhw6Vv7+/6tatqxdeeEHGGJfzV6tWTcHBwbrllls0btw4NWrUSMuXL7fGPTw8FBwcrNDQUPXo0UNPP/20PvvsM505c8a2NQAAAJVbcXGxJk+erIYNG8rhcKh+/fp65ZVXrI/cffDBB7r77rvl4+OjRYsWSZLeeecdRUZGysfHR02aNHG52luStm3bptatW8vHx0ft2rXTzp07XcY/+eQTdezYUSNHjlTjxo1166236oEHHlBSUpJL3T/+8Q+1adNGPj4+uuWWW/TSSy9Ze66bb75ZkvTggw/Kw8PDer58+XI9+eST+uMf/6iIiAjddtttio+P1zPPPGOd98Ir4devX2/t8y58PProo1fUBwD34kopAJXWjBkzdODAATVv3lzjx4+X9NMl4T179tSjjz6q9957T19//bUGDRokHx8fjRs3znrtwoULFR8fr23btmnHjh0aPHiw6tevr0GDBl32/Xx9fVVQUPCL48XFxWyCAABAmRk9erTmzZunadOmqVOnTjp69Ki+/vpra/y5557TlClTrJBp0aJFGjt2rGbPnq3WrVtr586dGjRokKpXr64BAwbo1KlT+t3vfqff/va3ev/993Xo0CENGzbM5T2Dg4O1ePFi7dmzR82bN79kX//85z/Vv39/zZw5U3fddZe+++47DR48WJL04osvavv27QoMDNSCBQvUvXt3eXl5Wedet26dnnzySd10002/Ov8777xTR48etZ7v379fPXv2VOfOna+oDwBuZgCgErv77rvNsGHDrOf/93//Zxo3bmyKi4utY0lJSaZGjRqmqKjIek1kZKRLzbPPPmsiIyMved5z586Zv/71r0aSmT17tjHGmAULFhh/f3+r/sCBA+bWW2817dq1K4dZAgCAG5HT6TQOh8PMmzfvorFDhw4ZSWb69Okuxxs0aGAWL17scmzChAkmKirKGGPMW2+9ZerUqWPOnDljjc+ZM8dIMjt37jTGGHPq1CnTs2dPI8mEh4ebhx56yMyfP9+cPXvWek3Xrl3Nq6++6vI+f/3rX01ISIj1XJL56KOPXGr27t1rIiMjjaenp2nRooX585//bFatWuVS8/P9XYn//ve/5pZbbjFPPvnkVfUBwH34+B6AG8r+/fsVFRUlDw8P61jHjh116tQp/fvf/7aOdejQwaUmKipK33zzjYqKiqxjb775pmrUqCFfX18NGjRII0aM0BNPPGGN5+XlqUaNGqpWrZoaN26soKAg67J5AACAa7V//37l5+era9eul61p166d9efTp0/ru+++U3x8vGrUqGE9Xn75ZX333XfWOVu2bCkfHx/rdVFRUS7nrF69ulauXKlvv/1WY8aMUY0aNfSXv/xFd9xxh3788UdJ0q5duzR+/HiX9xk0aJCOHj1q1VxK06ZNtWfPHm3ZskWPPfaYjh07pvvuu0+PP/74L65FYWGhevfurfDwcM2YMcM6Xto+ANiDj+8BQCnFxcXp+eefl6+vr0JCQuTp6Zrz16xZU19++aU8PT0VEhIiX19fN3UKAAAqoyvZW1SvXt3686lTpyRJ8+bNU/v27V3qSj4+dzUaNGigBg0a6PHHH9fzzz+vW2+9VR988IEGDhyoU6dO6aWXXlKvXr0uet2FgdeleHp66vbbb9ftt9+u4cOH6/3331e/fv30/PPPKyIi4pKveeKJJ3T48GFt27ZNVaqc/8/ca+kDQPkjlAJQqXl7e7tc3RQZGam///3vMsZYV0J98cUXqlmzpurVq2fVbd261eU8W7ZsUaNGjVw2bP7+/mrYsOFl39vT0/MXxwEAAK5Fo0aN5Ovrq9TU1F+9kkiSgoKCFBoaqoMHDyouLu6SNZGRkfrrX/+qs2fPWqHNli1bfvXcN998s6pVq6bTp09Lktq0aaPMzMxf3AtVrVrVZZ92OU2bNpUk69w/N3XqVC1dulSbN29WnTp1XMaupA8A7kMoBaBSu/nmm7V161Z9//33qlGjhp588klNnz5dTz31lIYOHarMzEy9+OKLSkxMdLnSKSsrS4mJifrzn/+sL7/8UrNmzdKUKVPcOBMAAABXPj4+evbZZzVq1Ch5e3urY8eO+s9//qO9e/de9iN9L730kp5++mn5+/ure/fuys/P144dO3TixAklJiaqb9++ev755zVo0CCNHj1a33//vd544w2Xc4wbN04//vijevbsqfDwcOXm5mrmzJkqLCzUb3/7W0nS2LFj9bvf/U7169fXH/7wB3l6emrXrl3as2ePXn75ZUk/7dNSU1PVsWNHORwO1apVS3/4wx/UsWNH3XnnnQoODtahQ4c0evRo3XrrrWrSpMlF8/nss880atQoJSUlqW7dusrOzpb001Vk/v7+V9QHAPfhnlIAKrVnnnlGXl5eatq0qW666SYVFhZq1apV2rZtm2677TYNGTJE8fHxGjNmjMvr+vfvrzNnzuiOO+5QQkKChg0bZn1TCwAAwPXihRde0F/+8heNHTtWkZGReuihh3Ts2LHL1j/++ON65513tGDBArVo0UJ33323kpOTrY/F1ahRQ5988ol2796t1q1b6/nnn9drr73mco67775bBw8eVP/+/dWkSRP16NFD2dnZWrt2rRo3bixJiomJ0YoVK7R27Vrdfvvt6tChg6ZNm6bw8HDrPFOmTFFKSorCwsLUunVr63WffPKJ7rvvPt16660aMGCAmjRporVr17p8LK/Epk2bVFRUpCFDhigkJMR6lHxj4JX0AcB9PIwxxt1NAMD1pEuXLmrVqpWmT5/u7lYAAAAAoNLiSikAAAAAAADYjlAKAAAAAAAAtuPjewAAAAAAALAdV0oBAAAAAADAdoRSAAAAAAAAsB2hFAAAAAAAAGxHKAUAAAAAAADbEUoBAAAAAADAdoRSAAAAAAAAsB2hFAAAAAAAAGxHKAUAAAAAAADb/X+pWVkjnevuxAAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "pdf = first_credset.select(\"purityMinR2\", \"purityMeanR2\", \"topPP\", \"credSetSize\").toPandas()\n", + "plt.figure(figsize=(12, 12))\n", + "\n", + "# Histogram for purityMinR2\n", + "plt.subplot(2, 2, 1)\n", + "plt.hist(pdf[\"purityMinR2\"], bins=30, alpha=0.7)\n", + "plt.title(\"Histogram of purityMinR2\")\n", + "plt.xlabel(\"purityMinR2\")\n", + "plt.ylabel(\"Frequency\")\n", + "\n", + "# Histogram for purityMeanR2\n", + "plt.subplot(2, 2, 2)\n", + "plt.hist(pdf[\"purityMeanR2\"], bins=30, alpha=0.7)\n", + "plt.title(\"Histogram of purityMeanR2\")\n", + "plt.xlabel(\"purityMeanR2\")\n", + "plt.ylabel(\"Frequency\")\n", + "\n", + "# Histogram for topPP\n", + "plt.subplot(2, 2, 3)\n", + "plt.hist(pdf[\"topPP\"], bins=30, alpha=0.7)\n", + "plt.title(\"Histogram of topPP\")\n", + "plt.xlabel(\"topPP\")\n", + "plt.ylabel(\"Frequency\")\n", + "\n", + "# Histogram for credSetSize\n", + "plt.subplot(2, 2, 4)\n", + "plt.hist(pdf[\"credSetSize\"], bins=30, alpha=0.7)\n", + "plt.title(\"Histogram of credSetSize\")\n", + "plt.xlabel(\"credSetSize\")\n", + "plt.ylabel(\"Frequency\")\n", + "\n", + "# Adjust layout to prevent overlap\n", + "plt.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Filtering credible sets with qc function" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "24/08/07 10:05:27 WARN package: Truncated the string representation of a plan since it was too large. This behavior can be adjusted by setting 'spark.sql.debug.maxToStringFields'.\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Number of high quality credible sets: 33544\n", + "Number of unique studyIds in high quality credible sets: 2188\n" + ] + } + ], + "source": [ + "qc_credsets = SUSIE_inf.credible_set_qc(\n", + " susie_fm, study_index, ld_index, 1e-5, 0.25, 0.8\n", + ").persist()\n", + "\n", + "qc_credsets = (\n", + " qc_credsets.df.withColumn(\"credSetSize\", f.size(\"locus\"))\n", + " .withColumn(\n", + " \"locus\",\n", + " f.slice(order_array_of_structs_by_field(\"locus\", \"posteriorProbability\"), 1, 1)[\n", + " 0\n", + " ],\n", + " )\n", + " .withColumn(\"topPP\", f.col(\"locus\").getField(\"posteriorProbability\"))\n", + " .filter(~f.isnan(\"topPP\"))\n", + ")\n", + "\n", + "print(\"Number of high quality credible sets: \", qc_credsets.count())\n", + "print(\n", + " \"Number of unique studyIds in high quality credible sets: \",\n", + " qc_credsets.select(\"studyId\").distinct().count(),\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "-RECORD 0---------------------------\n", + " meanTopPP | 0.9033882550691011 \n", + " minTopPP | 0.013988537311438214 \n", + " q1TopPP | 0.9937867852571437 \n", + " medianTopPP | 0.9999999999596412 \n", + " q3TopPP | 1.0 \n", + " maxTopPP | 1.0 \n", + "\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "-RECORD 0-------------------------------\n", + " meanCredSetSize | 3.2039709038874316 \n", + " minCredSetSize | 1 \n", + " q1CredSetSize | 1 \n", + " medianCredSetSize | 1 \n", + " q3CredSetSize | 1 \n", + " maxCredSetSize | 1022 \n", + "\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "-RECORD 0--------------------------------\n", + " meanPurityMeanR2 | 0.9789336464434549 \n", + " minPurityMeanR2 | 0.5417537849178955 \n", + " q1PurityMeanR2 | 1.0 \n", + " medianPurityMeanR2 | 1.0 \n", + " q3PurityMeanR2 | 1.0 \n", + " maxPurityMeanR2 | 1.0 \n", + "\n", + "-RECORD 0--------------------------------\n", + " meanPurityMinR2 | 0.9491503761431416 \n", + " minPurityMinR2 | 0.25018750677013313 \n", + " q1PurityMinR2 | 1.0 \n", + " medianPurityMinR2 | 1.0 \n", + " q3PurityMinR2 | 1.0 \n", + " maxPurityMinR2 | 1.0 \n", + "\n" + ] + } + ], + "source": [ + "(\n", + " qc_credsets.select(\n", + " f.mean(\"topPP\").alias(\"meanTopPP\"),\n", + " f.min(\"topPP\").alias(\"minTopPP\"),\n", + " f.percentile_approx(\"topPP\", 0.25).alias(\"q1TopPP\"),\n", + " f.percentile_approx(\"topPP\", 0.5).alias(\"medianTopPP\"),\n", + " f.percentile_approx(\"topPP\", 0.75).alias(\"q3TopPP\"),\n", + " f.max(\"topPP\").alias(\"maxTopPP\"),\n", + " ).show(vertical=True)\n", + ")\n", + "(\n", + " qc_credsets.select(\n", + " f.mean(\"credSetSize\").alias(\"meanCredSetSize\"),\n", + " f.min(\"credSetSize\").alias(\"minCredSetSize\"),\n", + " f.percentile_approx(\"credSetSize\", 0.25).alias(\"q1CredSetSize\"),\n", + " f.percentile_approx(\"credSetSize\", 0.5).alias(\"medianCredSetSize\"),\n", + " f.percentile_approx(\"credSetSize\", 0.75).alias(\"q3CredSetSize\"),\n", + " f.max(\"credSetSize\").alias(\"maxCredSetSize\"),\n", + " ).show(vertical=True)\n", + ")\n", + "(\n", + " qc_credsets.select(\n", + " f.mean(\"purityMeanR2\").alias(\"meanPurityMeanR2\"),\n", + " f.min(\"purityMeanR2\").alias(\"minPurityMeanR2\"),\n", + " f.percentile_approx(\"purityMeanR2\", 0.25).alias(\"q1PurityMeanR2\"),\n", + " f.percentile_approx(\"purityMeanR2\", 0.5).alias(\"medianPurityMeanR2\"),\n", + " f.percentile_approx(\"purityMeanR2\", 0.75).alias(\"q3PurityMeanR2\"),\n", + " f.max(\"purityMeanR2\").alias(\"maxPurityMeanR2\"),\n", + " ).show(vertical=True)\n", + ")\n", + "(\n", + " qc_credsets.select(\n", + " f.mean(\"purityMinR2\").alias(\"meanPurityMinR2\"),\n", + " f.min(\"purityMinR2\").alias(\"minPurityMinR2\"),\n", + " f.percentile_approx(\"purityMinR2\", 0.25).alias(\"q1PurityMinR2\"),\n", + " f.percentile_approx(\"purityMinR2\", 0.5).alias(\"medianPurityMinR2\"),\n", + " f.percentile_approx(\"purityMinR2\", 0.75).alias(\"q3PurityMinR2\"),\n", + " f.max(\"purityMinR2\").alias(\"maxPurityMinR2\"),\n", + " ).show(vertical=True)\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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1FNPPaVatWrpk08+4SweACBF9Ef/oj9KLjv7o6TPq1evXurTp0+KY5Ku9Pvoo48UFBSkTp06adSoUfL09JSdnZ2mTp2a7IYvUvo+4+bNm1tDyieffFK1a9dWz549FRkZmeLJv/DwcL366qt66aWX9MYbb6S4HyCzuFIKyMdKlCihvn376uOPP9bvv/+uOnXq2NzxJbUv/PLly+vs2bO6du2azfJffvnFuj7pfxMTE3Xq1CmbccePH09zjZcvX9aWLVv02muvaeLEiercubPatm2rihUrpnkbmZF0DPdexn/+/HlduXLFeqwZcfbsWd24ccNm2a+//irp37sBSXfOZl25csVmXGbOQEoPbiJfeOEF/frrr/rhhx+0fPly1a9fP8U7rdzt+eef17fffitXV1fTz5S9/fbbunXrVopXQJ04cULt27eXp6en1q9fL2dnZ1NrAwDkLfRHD0Z/lLX9kYeHh1xcXJSQkJDiVX5t2rSxTo7+ySefqGLFilq7dq169+6tgIAAtWnTJtnd/zLL2dlZ48ePV1RUlFavXp1s/RdffKH+/furS5cu1jtSAtmBUArIp+69XbCzs7MqV65scxvfpEun7/3CDwwMVEJCgubPn2+zfPbs2bJYLOrQoYMkKSAgQJL07rvv2oybN29emutMOrtz79mcu+9Ckp2Smod79zdr1ixJuu+dch4kPj5e77//vvX57du39f7778vDw0N+fn6SpEqVKkmSzV1wEhIStGjRogzvV0r9s03SoUMHlSpVStOmTdM333xz37OASbp166bx48fr3XffzfQl8ulVqVIlde3aVeHh4da7v0j/3gmmXbt2KlSokDZt2iQPDw9T6wIA5C30R2lDf5S1/ZGdnZ26du2qTz/9VIcOHUq2/uLFizZjJdvP/vvvv9eePXseWEt69ezZU2XLltW0adNslu/YsUM9evRQ8+bNtXz58gdOoQBkBr9vAPKpGjVqqGXLlvLz81OJEiW0b98+ffLJJwoNDbWOSfriHzx4sAICAmRnZ6cePXroySefVKtWrTR27FidPn1adevW1ebNm/XFF19o6NCh1kbBz89PXbt21Zw5c/T333+rSZMm+uabb6xnu9Jyyberq6uaN2+u6dOnKy4uTg899JA2b96c7Oxidqlbt6769OmjRYsW6cqVK2rRooX27t2rJUuWqFOnTineUjitypQpo2nTpun06dOqWrWqVq1apaioKC1atEhFihSRJNWsWVNNmjTRmDFjdOnSJZUoUUIrV65UfHx8po6rUqVKcnd318KFC+Xi4qJixYqpcePG1rkoihQpoh49emj+/Pmys7PTc88998Bturm52ZxJNtuoUaO0evVqzZkzR2+//bYkqX379jp58qRGjx6tnTt3aufOndbxXl5e1tt6AwAg0R+lFf1R1vdHb7/9trZt26bGjRvrxRdfVI0aNXTp0iXt379fX3/9tS5duiRJeuKJJ7R27Vp17txZHTt21KlTp7Rw4ULVqFFD169fz9Tx36tIkSIaMmSIRo0apY0bN6p9+/b67bff9NRTT8lisahbt25as2aNzWvq1KmTppsKAGmWI/f8A3BfSbfB/eGHH1Jcf/etaJPce8vjyZMnG40aNTLc3d0NJycn4+GHHzbeeust6612DePfW84OGjTI8PDwMCwWi83tj69du2YMGzbMKFOmjFGkSBGjSpUqxowZM4zExESb/d64ccMICQkxSpQoYTg7OxudOnUyjh49akiyuQVx0q1oL168mOx4/vjjD6Nz586Gu7u74ebmZjzzzDPG2bNnU71t8r3bSO1WxCm9TymJi4szJk6caPj6+hpFihQxfHx8jDFjxhi3bt1K035SkrTvffv2Gf7+/oajo6NRvnx5Y/78+cnGnjhxwmjTpo3h4OBgeHl5Ga+//roRERFx31sQp7S/u295bBj/3hK4Ro0aRuHChVO8/fHevXsNSUa7du3uewz3k9Itj1O6jXP58uVTvAX3vXWntL27tWzZ0nB1dTWuXLliGIZx39uC3/t+AADyNvoj+qO83B8ZhmGcP3/eCAkJMXx8fIwiRYoY3t7exuOPP24sWrTIOiYxMdGYMmWKUb58ecPBwcGoX7++8dVXXxl9+vQxypcvbx136tQpQ5IxY8aMZPtP69+IYRhGTEyM4ebmZn2fkmpP7XH3doGsYDGMNM5yBwBpFBUVpfr16+ujjz5Sz549c7qcHNGyZUv99ddfKV6inVv8+OOPqlevnpYuXarevXvndDkAAORr9Ef0RwCS48ehADLln3/+SbZszpw5KlSokJo3b54DFSGt/ve//8nZ2VldunTJ6VIAAMhX6I/yLvojwFzMKQUgU6ZPn67IyEi1atVKhQsX1oYNG7RhwwYNGDBAPj4+OV0eUvDl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d+7cWVu2bEnzdq5fv66oqChFRUVJkk6dOqWoqCidOXNG169f16hRo/Tdd9/p9OnT2rJli55++mlVrlxZAQEBkqTq1aurffv2evHFF7V3717t2rVLoaGh6tGjh8qUKSNJev7552Vvb6/g4GAdPnxYq1at0ty5c20uNR8yZIg2btyomTNn6pdfftGECRO0b98+hYaGZuTtAQAASFFW9VDpxdXmAAAgN8pQKPXtt9/qjTfesJljQJIqVKigP//8M83b2bdvn+rXr6/69etLkoYPH6769etr3LhxsrOz08GDB/XUU0+patWqCg4Olp+fn7799lubs2vLly/Xww8/rMcff1yBgYFq2rSpFi1aZF3v5uamzZs369SpU/Lz89OIESM0btw46wSdkvToo49qxYoVWrRokerWratPPvlEn3/+OXeNAQAAWSqreqj0ut/V5klSutp8x44diouLs45J7Wrzu3G1OQAASKsM/XwvMTHROifB3f744w+5uLikeTstW7aUYRiprt+0adMDt1GiRAnrrYtTU6dOHX377bf3HfPMM8/omWeeeeD+AAAAMiqreqjr169br3qS7lxtXqJECZUoUUITJ05U165d5e3trRMnTmj06NGpXm2+cOFCxcXFpXi1+cSJExUcHKxXX31Vhw4d0ty5czV79mzrfocMGaIWLVpo5syZ6tixo1auXKl9+/bZnCAEAABITYaulGrXrp3mzJljfW6xWHT9+nWNHz9egYGBWVUbAABAvpJVPRRXmwMAgPzAYtzvUqVU/PHHHwoICJBhGDp27JgaNGigY8eOqVSpUtqxY0eyu7kUBFevXpWbm5tiYmLk6uqa0+UAAJDnBIf/kKnXLw5qmEWV2MrK73h6qOTooQAAyJzM9FA53T9l6Od7ZcuW1Y8//qiVK1fq4MGDun79uoKDg9WzZ0+bSTsBAABwBz0UAADAHRkKpSSpcOHC6tWrV1bWAgAAkO/RQwEAAPwrQ6HU0qVL77v+hRdeyFAxAAAA+Rk9FAAAwB0ZCqWGDBli8zwuLk43b96Uvb29ihYtSkMFAACQAnooAACAOzJ0973Lly/bPK5fv66jR4+qadOm+vjjj7O6RgAAgHyBHgoAAOCODIVSKalSpYrefvvtZGcAAQAAkDp6KAAAUFBlWSgl/Ttx59mzZ7NykwAAAPkePRQAACiIMjSn1P/93//Z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a/TNN9/o7Nmz6tKli3V9QkKCOnbsqNu3b2v37t1asmSJwsPDNW7cOOuYU6dOqWPHjmrVqpWioqI0dOhQ9e/fX5s2bTL1OAEAALIKJ/YAAEBeUDinC3iQwoULy9vbO9nymJgYLV68WCtWrFDr1q0lSWFhYapevbq+++47NWnSRJs3b9aRI0f09ddfy8vLS/Xq1dOkSZP06quvasKECbK3t9fChQvl6+urmTNnSpKqV6+unTt3avbs2QoICDD1WAEAALJKzZo19fXXX1ufFy58p+0bNmyY1q1bpzVr1sjNzU2hoaHq0qWLdu3aJenOiT1vb2/t3r1b586d0wsvvKAiRYpoypQpku6c2HvppZe0fPlybdmyRf3791fp0qXpoQAAQJrk+iuljh07pjJlyqhixYrq2bOnzpw5I0mKjIxUXFyc2rRpYx378MMPq1y5ctqzZ48kac+ePapdu7a8vLysYwICAnT16lUdPnzYOububSSNSdpGamJjY3X16lWbBwAAQG6RdGIv6VGqVClJd07szZo1S61bt5afn5/CwsK0e/dufffdd5JkPbH30UcfqV69eurQoYMmTZqkBQsW6Pbt25Jkc2KvevXqCg0NVbdu3TR79uz71kUPBQAAkuTqUKpx48YKDw/Xxo0b9d577+nUqVNq1qyZrl27pujoaNnb28vd3d3mNV5eXoqOjpYkRUdH2wRSSeuT1t1vzNWrV/XPP/+kWtvUqVPl5uZmffj4+GT2cAEAALJMbj2xRw8FAACS5OpQqkOHDnrmmWdUp04dBQQEaP369bpy5YpWr16d06VpzJgxiomJsT5+//33nC4JAABAUu4+sUcPBQAAkuT6OaXu5u7urqpVq+r48eNq27atbt++rStXrtg0VefPn7fOQeXt7a29e/fabCNpEs+7x9w7sef58+fl6uoqJyenVGtxcHCQg4NDVhwWAABAlurQoYP1n+vUqaPGjRurfPnyWr169X37GzPQQwEAgCS5+kqpe12/fl0nTpxQ6dKl5efnpyJFimjLli3W9UePHtWZM2fk7+8vSfL399dPP/2kCxcuWMdERETI1dVVNWrUsI65extJY5K2AQAAkNfdfWLP29vbemLvbvee2EvppF3SuvuNedCJPQAAgCS5OpQaOXKkvvnmG50+fVq7d+9W586dZWdnp+eee05ubm4KDg7W8OHDtW3b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D8XP9wqo27dvKzIyUm3atLEuK1SokNq0aaM9e/Y88PWGYWjLli06evSomjdvnp2lZqmMHvebb74pT09PBQcHm1FmlsroMV+/fl3ly5eXj4+Pnn76aR0+fNiMcrNERo75//7v/+Tv76+QkBB5eXmpVq1amjJlihISEswqO1My+++0JC1evFg9evRQsWLFsqvMLJWRY3700UcVGRlpvYz85MmTWr9+vQIDA02pObMycsyxsbHJfn7r5OSknTt3ZmutOWnPnj0275EkBQQEpPnfBSA3KYjfablZQfy+zc0KYi+Qm9Gn5H050UMVzrYtI1f766+/lJCQIC8vL5vlXl5e+uWXX1J9XUxMjB566CHFxsbKzs5O7777rtq2bZvd5WaZjBz3zp07tXjxYkVFRZlQYdbLyDFXq1ZNH374oerUqaOYmBi98847evTRR3X48GGVLVvWjLIzJSPHfPLkSW3dulU9e/bU+vXrdfz4cb3yyiuKi4vT+PHjzSg7UzL673SSvXv36tChQ1q8eHF2lZjlMnLMzz//vP766y81bdpUhmEoPj5eL730kl5//XUzSs60jBxzQECAZs2apebNm6tSpUrasmWL1q5dm6//z2l0dHSK79HVq1f1zz//yMnJKYcqA9KvIH6n5WYF8fs2NyuIvUBuRp+S9+VED8WVUkgXFxcXRUVF6YcfftBbb72l4cOHa/v27TldVra5du2aevfurf/9738qVapUTpdjGn9/f73wwguqV6+eWrRoobVr18rDw0Pvv/9+TpeWbRITE+Xp6alFixbJz89P3bt319ixY7Vw4cKcLs0UixcvVu3atdWoUaOcLiVbbd++XVOmTNG7776r/fv3a+3atVq3bp0mTZqU06Vlm7lz56pKlSp6+OGHZW9vr9DQUPXt21eFCtECAPlVQf9Oy80KyvdtblYQe4HcjD4FXClVQJUqVUp2dnY6f/68zfLz58/L29s71dcVKlRIlStXliTVq1dPP//8s6ZOnaqWLVtmZ7lZJr3HfeLECZ0+fVpPPvmkdVliYqIkqXDhwjp69KgqVaqUvUVnUkY/67sVKVJE9evX1/Hjx7OjxCyXkWMuXbq0ihQpIjs7O+uy6tWrKzo6Wrdv35a9vX221pxZmfmcb9y4oZUrV+rNN9/MzhKzXEaO+T//+Y969+6t/v37S5Jq166tGzduaMCAARo7dmyub4AycsweHh76/PPPdevWLf39998qU6aMXnvtNVWsWNGMknOEt7d3iu+Rq6srV0khzymI32m5WUH8vs3NCmIvkJvRp+R9OdFD8W9cAWVvby8/Pz9t2bLFuiwxMVFbtmyRv79/mreTmJio2NjY7CgxW6T3uB9++GH99NNPioqKsj6eeuoptWrVSlFRUfLx8TGz/AzJis86ISFBP/30k0qXLp1dZWapjBzzY489puPHj1tDR0n69ddfVbp06TzRvGfmc16zZo1iY2PVq1ev7C4zS2XkmG/evJms2Uz6P22GYWRfsVkkM5+zo6OjHnroIcXHx+vTTz/V008/nd3l5hh/f3+b90iSIiIi0vX9BuQWBfE7LTcriN+3uVlB7AVyM/qUvC9Heqhsm0Idud7KlSsNBwcHIzw83Dhy5IgxYMAAw93d3YiOjjYMwzB69+5tvPbaa9bxU6ZMMTZv3mycOHHCOHLkiPHOO+8YhQsXNv73v//l1CFkSHqP+1558e576T3miRMnGps2bTJOnDhhREZGGj169DAcHR2Nw4cP59QhpFt6j/nMmTOGi4uLERoaahw9etT46quvDE9PT2Py5Mk5dQjpltG/7aZNmxrdu3c3u9wskd5jHj9+vOHi4mJ8/PHHxsmTJ43NmzcblSpVMp599tmcOoR0S+8xf/fdd8ann35qnDhxwtixY4fRunVrw9fX17h8+XIOHUH6Xbt2zThw4IBx4MABQ5Ixa9Ys48CBA8Zvv/1mGIZhvPbaa0bv3r2t45NuZzxq1Cjj559/NhYsWJDttzMGslNB/E7LzQri921uVhB7gdysIPYpuVle6KEIpQq4efPmGeXKlTPs7e2NRo0aGd999511XYsWLYw+ffpYn48dO9aoXLmy4ejoaBQvXtzw9/c3Vq5cmQNVZ156jvteeTGUMoz0HfPQoUOtY728vIzAwEBj//79OVB15qT3c969e7fRuHFjw8HBwahYsaLx1ltvGfHx8SZXnTnpPeZffvnFkGRs3rzZ5EqzTnqOOS4uzpgwYYJRqVIlw9HR0fDx8TFeeeWVPNf4pOeYt2/fblSvXt1wcHAwSpYsafTu3dv4888/c6DqjNu2bZshKdkj6Tj79OljtGjRItlr6tWrZ9jb2xsVK1Y0wsLCTK8byEoF8TstNyuI37e5WUHsBXKzgtan5GZ5oYeyGAbXKAIAAAAAAMBczCkFAAAAAAAA0xFKAQAAAAAAwHSEUgAAAAAAADAdoRQAAAAAAABMRygFAAAAAAAA0xFKAQAAAAAAwHSEUgAAAAAAADAdoRQAAAAAAABMRygFoEAJDw+Xu7u76ftt2bKlhg4davp+AQAA0iKneiQABRuhFIACpXv37vr111+tzydMmKB69eqleztBQUGyWCx66aWXkq0LCQmRxWJRUFCQddnatWs1adKkdO3DYrFYH66urmrYsKG++OILmzFr165V27Zt5eHhIVdXV/n7+2vTpk3pPh4AAFCw5VSPZJaWLVta+ypHR0dVrVpVU6dOlWEY1jE//vijnnvuOfn4+MjJyUnVq1fX3LlzTa8VKEgIpQAUGHFxcXJycpKnp2eWbM/Hx0crV67UP//8Y11269YtrVixQuXKlbMZW6JECbm4uKR7H2FhYTp37pz27dunxx57TN26ddNPP/1kXb9jxw61bdtW69evV2RkpFq1aqUnn3xSBw4cyPiBAQCAAiUneyQzvfjiizp37pyOHj2qMWPGaNy4cVq4cKF1fWRkpDw9PfXRRx/p8OHDGjt2rMaMGaP58+fnWM1AfkcoBSBXatmypUJDQxUaGio3NzeVKlVK//nPf6xnsywWiz7//HOb17i7uys8PFySdPr0aVksFq1atUotWrSQo6Ojli9fbnNpenh4uCZOnKgff/zReuYsPDxc/fr10xNPPGGz7bi4OHl6emrx4sXWZY888oh8fHy0du1a67K1a9eqXLlyql+/frLjufvnexUqVNCUKVPUr18/ubi4qFy5clq0aFGy98Hd3V3e3t6qWrWqJk2apPj4eG3bts26fs6cORo9erQaNmyoKlWqaMqUKapSpYq+/PLLNL/XAAAg78hvPVJiYqKmTp0qX19fOTk5qW7duvrkk0+s6xMSEhQcHGxdX61atWRXLwUFBalTp0565513VLp0aZUsWVIhISGKi4uzGVe0aFF5e3urfPny6tu3r+rUqaOIiAjr+n79+mnu3Llq0aKFKlasqF69eqlv3742xwEgaxFKAci1lixZosKFC2vv3r2aO3euZs2apQ8++CBd23jttdc0ZMgQ/fzzzwoICLBZ1717d40YMUI1a9bUuXPndO7cOXXv3l39+/fXxo0bde7cOevYr776Sjdv3lT37t1tttGvXz+FhYVZn3/44Yfq27dv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lJo1a5ZmzJhhTqYkqVatWnrhhRf45hgAAIBLYA4FAABwTolCKYfDoaNHj16w/ejRozp58uR1NwUAAFAZMYcCAAA4p0Sh1AMPPKBhw4bpo48+0k8//aSffvpJ//rXvxQdHa1+/fqVdo8AAACVAnMoAACAc0p0Tan4+Hg99dRTGjRokAoKCn47UJUqio6O1iuvvFKqDQIAAFQWzKEAAADOKVEoVa1aNb355pt65ZVXtH//fklSo0aNVL169VJtDgAAoDJhDgUAAHBOiT6+V+zw4cM6fPiwmjRpourVq8swjNLqCwAAoNJiDgUAAFDCUOqXX35Rjx491LRpU/Xp00eHDx+WJEVHR/NVxgAAAJfAHAoAAOCcEoVSY8eOVdWqVZWVlaVq1aqZ2wcMGKCkpKRSaw4AAKAyYQ4FAABwTomuKbVmzRqtXr1a9erVc9repEkT/ec//ymVxgAAACob5lAAAADnlGilVG5urtP/7hU7duyYPDw8rrspAACAyog5FAAAwDklCqW6du2qDz/80Lzv4uKioqIizZw5U927dy+15gAAACoT5lAAAADnlOjjezNnzlSPHj20fft25efna/z48dqzZ4+OHTumr776qrR7BAAAqBSYQwEAAJxTopVSLVu21Pfff68uXbro/vvvV25urvr166cdO3aoUaNGpd0jAABApcAcCgAA4JxrXilVUFCgXr16KT4+XpMmTSqLngAAACod5lAAAADOrnmlVNWqVbVz586y6AUAAKDSYg4FAADgrEQf3/vzn/+s9957r7R7AQAAqNSYQwEAAJxTogudnz17Vu+//74+//xztW/fXtWrV3faP3v27FJpDgAAoDJhDgUAAHDONa2UOnDggIqKirR79261a9dONWvW1Pfff68dO3aYt/T09DJqFQAAoGIq7TnUhg0bdN999ykoKEguLi5avny50/6hQ4fKxcXF6darVy+nmmPHjmnw4MHy9vaWr6+voqOjderUKaeanTt3qmvXrvL09FRwcLBmzpx5QS/Lli1T8+bN5enpqVatWmnVqlVXfR4AAODmdk0rpZo0aaLDhw/riy++kCQNGDBAr7/+uvz9/cukOQAAgMqgtOdQubm5atOmjR599FH169fvojW9evXSwoULzfseHh5O+wcPHqzDhw8rOTlZBQUFGjZsmEaMGKHExERJksPhUM+ePRUeHq74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JESzZs2SJLVo0UIbN27UnDlzFBERccm+8vLylJeXZ953OBylfOYAAAAAAACV1w2/UuqHH35QUFCQGjZsqMGDBysrK0uSlJaWpoKCAoWHh5u1zZs3V/369ZWamipJSk1NVatWreTv72/WREREyOFwaM+ePWbN+ccorik+xqXMmDFDPj4+5i04OLhUzhcAAAAAAOBmcEOHUmFhYUpISFBSUpIWLFigzMxMde3aVSdPnpTdbpe7u7t8fX2dHuPv7y+73S5JstvtToFU8f7ifZercTgcOn369CV7mzhxonJycszbwYMHr/d0AQAAAAAAbho39Mf3evfubf65devWCgsLU4MGDbR06VJ5eXmVY2eSh4eHPDw8yrUHAAAAAACAiuqGXin1e76+vmratKn27dungIAA5efn68SJE0412dnZ5jWoAgICLvg2vuL7V6rx9vYu9+ALAAAAAACgsqpQodSpU6e0f/9+BQYGqn379qpatapSUlLM/RkZGcrKypLNZpMk2Ww27dq1S0eOHDFrkpOT5e3trdDQULPm/GMU1xQfAwAAAAAAAKXvhg6lnnrqKa1fv14//vijNm3apAceeEBubm4aOHCgfHx8FB0drbi4OH3xxRdKS0vTsGHDZLPZ1KlTJ0lSz549FRoaqiFDhuibb77R6tWrNXnyZMXExJgfvRs5cqQOHDig8ePHa+/evXrzzTe1dOlSjR07tjxPHQAAAAAAoFK7oa8p9dNPP2ngwIH65ZdfdMstt6hLly7avHmzbrnlFknSnDlz5Orqqv79+ysvL08RERF68803zce7ublpxYoVGjVqlGw2m6pXr66oqCg9//zzZk1ISIhWrlypsWPHau7cuapXr57effddRUREWH6+AAAAAAAAN4sbOpRavHjxZfd7enpq/vz5mj9//iVrGjRooFWrVl32ON26ddOOHTtK1CMAAAAAAACu3Q398T0AAAAAAABUToRSAAAAAAAAsByhFAAAAAAAACxHKAUAAAAAAADLEUoBAAAAAADAcoRSAAAAAAAAsByhFAAAAAAAACxHKAUAAAAAAADLEUoBAABUMtOmTZOLi4vTrXnz5ub+M2fOKCYmRnXq1FGNGjXUv39/ZWdnOx0jKytLkZGRqlatmvz8/DRu3DidPXvWqWbdunVq166dPDw81LhxYyUkJFhxegAAoJIglAIAAKiEbrvt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FRwcrJkzZ5b1qTkzYJnFixcb7u7uxvvvv2/s2bPHGD58uOHr62tkZ2dftP6rr74y3NzcjJkzZxrffvutMXnyZKNq1arGrl27LO684rrWMR80aJAxf/58Y8eOHcZ3331nDB061PDx8TF++uknizuvuK51zItlZmYaf/jDH4yuXbsa999/vzXNVgLXOt55eXlGhw4djD59+hgbN240MjMzjXXr1hnp6ekWd15xXeuYL1q0yPDw8DAWLVpkZGZmGqtXrzYCAwONsWPHWtx5xbVq1Spj0qRJxkcffWRIMj7++OPL1h84cMCoVq2aERcXZ3z77bfGG2+8Ybi5uRlJSUnWNIxyV9L3IvwmIiLCWLhwobF7924jPT3d6NOnj1G/fn3j1KlTZs3IkSON4OBgIyUlxdi+fbvRqVMn48477zT3nz171mjZsqURHh5u7Nixw1i1apVRt25dY+LEieVxSje0rVu3GrfeeqvRunVrY/To0eZ2xvj6HTt2zGjQoIExdOhQY8uWLcaBAweM1atXG/v27TNrXn75ZcPHx8dYvny58c033xh/+tOfjJCQEOP06dNmTa9evYw2bdoYmzdvNr788kujcePGxsCBA8vjlG5IL774olGnTh1jxYoVRmZmprFs2TKjRo0axty5c80axvnaXWn+UxpjmpOTY/j7+xuDBw82du/ebfzzn/80vLy8jLfeesuq0zQIpSx0xx13GDExMeb9wsJCIygoyJgxY8ZF6//nf/7HiIyMdNoWFhZm/OUvfynTPiuTax3z3zt79qxRs2ZN44MPPiirFiudkoz52bNnjTvvvNN49913jaioKEKpa3Ct471gwQKjYcOGRn5+vlUtVjrXOuYxMTHGPffc47QtLi7O6Ny5c5n2WVldTSg1fvx447bbbnPaNmDAACMiIqIMO8ON5Hrf/+HsyJEjhiRj/fr1hmEYxokTJ4yqVasay5YtM2u+++47Q5KRmppqGMZvv0y5uroadrvdrFmwYIHh7e1t5OXlWXsCN7CTJ08aTZo0MZKTk427777bDKUY49IxYcIEo0uXLpfcX1RUZAQEBBivvPKKue3EiROGh4eH8c9//tMwDMP49ttvDUnGtm3bzJrPPvvMcHFxMf773/+WXfMVSGRkpPHoo486bevXr58xePBgwzAY59Lw+/lPaY3pm2++adSqVcvp34wJEyYYzZo1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8OF6/vnn9euvv+rDDz9UTEyMatWqpYEDB0qSvL29lZGRoaKiIn3zzTcaNmyYDh06pNWrV5dz5wAA4GZVUFCgqlWrXvdxUlJSNGDAAL344ov605/+JBcXF3377bdKTk6+7mM/99xzeuuttzRv3jx16NBBDodD27dv1/Hjx82a2rVrX/fzALAeK6UA3DSGDh2q9evXa+7cueaqpR9//FHr16/XHXfcIQ8PDwUGBurpp5/W2bNnzcd169ZNsbGxio2NlY+Pj+rWratnn31WhmE4Hb9atWoKCAhQw4YNNW3aNDVp0kSffPKJud/FxUUBAQEKCgpS79699de//lWff/65Tp8+bdkYAACAyq+oqEgzZ85U48aN5eHhofr16+vFF180P3K3ZMkS3X333fL09NSiRYskSe+++65atGghT09PNW/e3GnFtyRt3bpVt99+uzw9PdWhQwft2LHDaf+nn36qzp07a9y4cWrWrJmaNm2qvn37av78+U51//73v9WuXTt5enqqYcOGeu6558x516233ipJeuCBB+Ti4mLe/+STT/T444/roYceUkhIiNq0aaPo6Gg99dRT5nHPXw2/bt06c653/m3o0KFX1QcA67BSCsBNY+7cufr+++/VsmVLPf/885J+Ww7ep08fDR06VB9++KH27t2r4cOHy9PTU9OmTTMf+8EHHyg6Olpbt27V9u3bNWLECNWvX1/Dhw+/5PN5eXkpPz//svuLioqYAAEAgFI1ceJEvfPOO5ozZ466dOmiw4cPa+/eveb+p59+WrNmzTJDpkWLFmnKlCmaN2+ebr/9du3YsUPDhw9X9erVFRUVpVOnTunee+/VH//4R/3jH/9QZmamRo8e7fScAQEBSkxM1O7du9WyZcuL9vXll1/qkUce0euvv66uXbtq//79GjFihCRp6tSp2rZtm/z8/LRw4UL16tVLbm5u5rHXrl2rxx9/XLfccssVz//OO+/U4cOHzfvfffed+vTpo7vuuuuq+gBgIQMAbiJ33323MXr0aPP+M888YzRr1swoKioyt82fP9+oUaOGUVhYaD6mRYsWTjUTJkwwWrRocdHjnj171vj73/9uSDLmzZtnGIZhLFy40PDx8THrv//+e6Np06ZGhw4dyuAsAQDAzcrhcBgeHh7GO++8c8G+zMxMQ5Lx2muvOW1v1KiRkZiY6LRt+vTphs1mMwzDMN566y2jTp06xunTp839CxYsMCQZO3bsMAzDME6dOmX06dPHkGQ0aNDAGDBggPHee+8ZZ86cMR/To0cP46WXXnJ6nr///e9GYGCgeV+S8fHHHzvV7Nmzx2jRooXh6upqtGrVyvjLX/5irFq1yqnm93O8Yj///LPRsGFD4/HHH7+mPgBYg4/vAbipfffdd7LZbHJxcTG3de7cWadOndJPP/1kbuvUqZNTjc1m0w8//KDCwkJz25tvvqkaNWrIy8tLw4cP19ixYzVq1Chzf05OjmrUqKFq1aqpWbNm8vf3N5fMAwAAlIbvvvtOeXl56tGjxyVrOnToYP45NzdX+/fvV3R0tGrUqGHeXnjhBe3fv988ZuvWreXp6Wk+zmazOR2zevXqWrlypfbt26fJkyerRo0aevLJJ3XHHXfo119/lSR98803ev75552eZ/jw4Tp8+LBZczGhoaHavXu3Nm/erEcffVRHjhzRfffdp8cee+yyY1FQUKD+/furQYMGmjt3rrm9pH0AKH18fA8ASsngwYM1adIkeXl5KTAwUK6uzrl/zZo19fXXX8vV1VWBgYHy8vIqp04BAEBldTXzi+rVq5t/PnXqlCTpnXfeUVhYmFNd8cfnrkWjRo3UqFEjPfbYY5o0aZKaNm2qJUuWaNiwYTp16pSee+459evX74LHnR94XYyrq6s6duyojh07asyYMfrHP/6hIUOGaNKkSQoJCbnoY0aNGqWDBw9q69atqlLl3K++19MHgNJFKAXgpuLu7u60uqlFixb617/+JcMwzJVQX331lWrWrKl69eqZdVu2bHE6zubNm9WkSROnyZqPj48aN258yed2dXW97H4AAIDr1aRJE3l5eSklJeWKK4kkyd/fX0FBQTpw4IAGDx580ZoWLVro73//u86cOWOGNps3b77isW+99VZVq1ZNubm5kqR27dopIyPjsvOhqlWrOs3VLiU0NFSSzGP/3uzZs7V06VJt2rRJderUcdp3NX0AsAahFICbyq233qotW7boxx9/VI0aNfT444/rtdde0xNPPKHY2FhlZGRo6tSpiouLc1rplJWVpbi4OP3lL3/R119/rTfeeEOzZs0qxzMBAAC4kKenpyZMmKDx48fL3d1dnTt31tGjR7Vnz55LfqTvueee01//+lf5+PioV69eysvL0/bt23X8+HHFxcVp0KBBmjRpkoYPH66JEyfqxx9/1Kuvvup0jGnTpunXX39Vnz591KBBA504cUKvv/66CgoK9Mc//lGSNGXKFN17772qX7++HnzwQbm6uuqbb77R7t279cILL0j6ba6WkpKizp07y8PDQ7Vq1dKDDz6ozp07684771RAQIAyMzM1ceJENW3aVM2bN7/gfD7//HONHz9e8+fPV926dWW32yX9torMx8fnqvoAYA2uKQXgpvLUU0/Jzc1NoaGhuuWWW1RQUKBVq1Zp69atatOmjUaOHKno6GhNnjzZ6XGPPPKITp8+rTvuuEMxMTEaPXq0+S0tAAAAN5Jnn31WTz75pKZMmaIWLVpowIABOnLkyCXrH3vsMb377rtauHChWrVqpbvvvlsJCQnmx+Jq1KihTz/9VLt27dLtt9+uSZMm6W9/+5vTMe6++24dOHBAjzzyiJo3b67evXvLbrdrzZo1atasmSQpIiJCK1as0Jo1a9SxY0d16tRJc+bMUYMGDczjzJo1S8nJyQoODtbtt99uPu7TTz/Vfffdp6ZNmyoqKkrNmzfXmjVrnD6WV2zjxo0qLCzUyJEjFRgYaN6KvzHwavoAYA0XwzCM8m4CAG5k3bp1U9u2bfXaa6+VdysAAAAAUGmwUgoAAAAAAACWI5QCAAAAAACA5fj4HgAAAAAAACzHSikAAAAAAABYjlAKAAAAAAAAliOUAgAAAAAAgOUIpQAAAAAAAGA5QikAAAAAAABYjlAKAAAAAAAAliOUAgAAAAAAgOUIpQAAAAAAAGC5/wN/Y9JYTDDNOAAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "pdf = qc_credsets.select(\"purityMinR2\", \"purityMeanR2\", \"topPP\", \"credSetSize\").toPandas()\n", + "plt.figure(figsize=(12, 12))\n", + "\n", + "# Histogram for purityMinR2\n", + "plt.subplot(2, 2, 1)\n", + "plt.hist(pdf[\"purityMinR2\"], bins=30, alpha=0.7)\n", + "plt.title(\"Histogram of purityMinR2\")\n", + "plt.xlabel(\"purityMinR2\")\n", + "plt.ylabel(\"Frequency\")\n", + "\n", + "# Histogram for purityMeanR2\n", + "plt.subplot(2, 2, 2)\n", + "plt.hist(pdf[\"purityMeanR2\"], bins=30, alpha=0.7)\n", + "plt.title(\"Histogram of purityMeanR2\")\n", + "plt.xlabel(\"purityMeanR2\")\n", + "plt.ylabel(\"Frequency\")\n", + "\n", + "# Histogram for topPP\n", + "plt.subplot(2, 2, 3)\n", + "plt.hist(pdf[\"topPP\"], bins=30, alpha=0.7)\n", + "plt.title(\"Histogram of topPP\")\n", + "plt.xlabel(\"topPP\")\n", + "plt.ylabel(\"Frequency\")\n", + "\n", + "# Histogram for credSetSize\n", + "plt.subplot(2, 2, 4)\n", + "plt.hist(pdf[\"credSetSize\"], bins=30, alpha=0.7)\n", + "plt.title(\"Histogram of credSetSize\")\n", + "plt.xlabel(\"credSetSize\")\n", + "plt.ylabel(\"Frequency\")\n", + "\n", + "# Adjust layout to prevent overlap\n", + "plt.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# WIP" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Clumped loci filtered for usage with PICS\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Number of unique studyIds\n" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "15" + ] + }, + "execution_count": 40, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pics_loci.df.select(\"studyId\").distinct().count()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Number of loci to fine map with PICS\n" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "18" + ] + }, + "execution_count": 41, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pics_loci.df.count()" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": {}, + "outputs": [], + "source": [ + "df = pics_loci.df.withColumns(\n", + " {\n", + " \"locusSize\": f.size(\"locus\"),\n", + " \"locusLength\": f.col(\"locusEnd\") - f.col(\"locusStart\"),\n", + " }\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "How many loci with less than 100 variants from summary statistics?\n" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "18" + ] + }, + "execution_count": 43, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.filter(f.col(\"locusSize\") < 100).count()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "How many loci with more than 15,000 variants from summary statistics?\n" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0" + ] + }, + "execution_count": 44, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.filter(f.col(\"locusSize\") > 15_000).count()" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "-RECORD 0------------------------------\n", + " meanLocusLength | 273867.6666666667 \n", + " q1LocusLength | 200000 \n", + " medianLocusLength | 200000 \n", + " q3LocusLength | 302688 \n", + "\n", + "-RECORD 0-----------------------------\n", + " meanLocusSize | 30.055555555555557 \n", + " minLocusSize | 2 \n", + " q1LocusSize | 12 \n", + " medianLocusSize | 19 \n", + " q3LocusSize | 57 \n", + " maxLocusSize | 79 \n", + "\n" + ] + } + ], + "source": [ + "length = df.select(\n", + " f.mean(\"locusLength\").alias(\"meanLocusLength\"),\n", + " f.percentile_approx(\"locusLength\", 0.25).alias(\"q1LocusLength\"),\n", + " f.percentile_approx(\"locusLength\", 0.5).alias(\"medianLocusLength\"),\n", + " f.percentile_approx(\"locusLength\", 0.75).alias(\"q3LocusLength\"),\n", + ")\n", + "size = df.select(\n", + " f.mean(\"locusSize\").alias(\"meanLocusSize\"),\n", + " f.min(\"locusSize\").alias(\"minLocusSize\"),\n", + " f.percentile_approx(\"locusSize\", 0.25).alias(\"q1LocusSize\"),\n", + " f.percentile_approx(\"locusSize\", 0.5).alias(\"medianLocusSize\"),\n", + " f.percentile_approx(\"locusSize\", 0.75).alias(\"q3LocusSize\"),\n", + " f.max(\"locusSize\").alias(\"maxLocusSize\"),\n", + ")\n", + "length.show(vertical=True)\n", + "size.show(vertical=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABKUAAAJOCAYAAABm7rQwAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/TGe4hAAAACXBIWXMAAA9hAAAPYQGoP6dpAABq3ElEQVR4nO3deVhV5f7//xeDDA6AqICkIjnPmppyHNI0UTmlacccMjXMBiyHUvNUag5pVg6V6alM7Jtm2mlUU8khG3AicZYccCgFLRXEo4hw//7ox/64BU22sDbI83Fd+6q91r3Xft+3uLl97bXu5WKMMQIAAAAAAAAs5OrsAgAAAAAAAFD8EEoBAAAAAADAcoRSAAAAAAAAsByhFAAAAAAAACxHKAUAAAAAAADLEUoBAAAAAADAcoRSAAAAAAAAsByhFAAAAAAAACxHKAUAAAAAAADLEUoBhUjVqlU1cOBAZ5dx23v99dd15513ys3NTY0bN3Z2ObgJGzZskIuLiz777DNnlwIAKISYQ1mDOdTfi46OlouLi44cOeLsUoAigVAKKCDZv5C2bduW6/527dqpfv36t/w+K1eu1IQJE275OMXFmjVrNHr0aLVq1UoLFizQq6++et22AwcOVOnSpS2sruBVrVpV//znP51dxnUtXrxYs2bNcnYZAAAnYg5VOBX3OdTly5c1e/ZsNWnSRD4+PvLz81O9evU0ZMgQ7d+/39nlAUWWu7MLAPB/EhIS5Oqat6x45cqVmjNnDpOqm7Ru3Tq5urpq/vz58vDwcHY5uMbixYu1e/duDR8+3NmlAACKEOZQBa+4z6F69uypb7/9Vn369NHjjz+ujIwM7d+/X8uXL9c//vEP1a5dW5LUv39/9e7dW56enk6uGCgaCKWAQqQo/vK6cOGCSpUq5ewybtqpU6fk7e1dLCdTAADcrphDFbziPIfaunWrli9frilTpujf//633b533nlH586dsz13c3OTm5ubxRUCRReX7wGFyLXrIWRkZOiVV15RjRo15OXlpXLlyql169aKiYmR9Nep0XPmzJEkubi42B7ZLly4oOeee06VK1eWp6enatWqpTfeeEPGGLv3vXjxop599lmVL19eZcqU0QMPPKDff/9dLi4udt8eTpgwQS4uLtq7d6/69u2rsmXLqnXr1pKknTt3auDAgbrzzjvl5eWloKAgPfbYY/rzzz/t3iv7GL/++qseeeQR+fr6qkKFCnr55ZdljNHx48fVrVs3+fj4KCgoSG+++eZNjd2VK1c0adIkVatWTZ6enqpatar+/e9/Kz093dbGxcVFCxYs0IULF2xjFR0dfVPHv5Fly5apadOm8vb2Vvny5fXII4/o999/z9Fu//796tWrlypUqCBvb2/VqlVLL774om3/wIEDVbVq1Ryvyx6zq8XExKh169by8/NT6dKlVatWrRyTpFvx8ccf2/rk7++v3r176/jx43Ztsi+f2Lt3r9q3b6+SJUvqjjvu0PTp03Mc7+jRo3rggQdUqlQpBQQEaMSIEVq9erVcXFy0YcMG2/FWrFiho0eP2v58rh2PrKwsTZkyRZUqVZKXl5c6dOiggwcP5lu/AQBFE3Mo5lAFOYc6dOiQJKlVq1Y59rm5ualcuXK259euKZVdQ26Pq39ms7KyNGvWLNWrV09eXl4KDAzUE088obNnz96wNqCo40wpoIClpKTojz/+yLE9IyPjb187YcIETZ06VYMHD9bdd9+t1NRUbdu2Tb/88ovuu+8+PfHEEzpx4oRiYmL0//7f/7N7rTFGDzzwgNavX6/IyEg1btxYq1ev1qhRo/T7779r5syZtrYDBw7U0qVL1b9/f7Vs2VLff/+9IiIirlvXv/71L9WoUUOvvvqqbXIWExOjw4cPa9CgQQoKCtKePXv03nvvac+ePdq0aVOOCcHDDz+sOnXqaNq0aVqxYoUmT54sf39//ec//9G9996r1157TYsWLdLzzz+v5s2bq23btjccq8GDB2vhwoV66KGH9Nxzz2nz5s2aOnWq9u3bpy+++EKS9P/+3//Te++9py1btuiDDz6QJP3jH//42z+HG4mOjtagQYPUvHlzTZ06VcnJyZo9e7Z++uknbd++XX5+fpL+mnC2adNGJUqU0JAhQ1S1alUdOnRI33zzjaZMmZKn99yzZ4/++c9/qmHDhpo4caI8PT118OBB/fTTT7fUl2xTpkzRyy+/rF69emnw4ME6ffq03n77bbVt29auT5J09uxZde7cWT169FCvXr302WefacyYMWrQoIG6dOki6a+J/b333quTJ09q2LBhCgoK0uLFi7V+/Xq7933xxReVkpKi3377zfbzee16FNOmTZOrq6uef/55paSkaPr06erXr582b96cL30HABQezKGYQ0mF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u5off/zRJCYmmg0bNpj4+HiLKy9YeR2XRYsWGU9PT7No0SKTmJhoVq9ebSpWrGhGjBhhceUFa+XKlebFF180n3/+uZFkvvjiixu2P3z4sClZsqQZOXKk2bt3r3n77beNm5ubWbVqlTUFWySv4zJs2DDz2muvmS1btphff/3VjB071pQoUcL88ssv1hRskbyOS7azZ8+aO++803Tq1Mk0atSoQGtE8eDoPKAoCA8PNwsWLDC7d+828fHxpmvXrqZKlSomLS3N1ubJJ580lStXNmvXrjXbtm0zLVu2NP/4xz9s+69cuWLq169vOnbsaLZv325Wrlxpypcvb8aOHWtrU1Q/z7ds2WKqVq1qGjZsaIYNG2bbXtzG5MyZMyYkJMQMHDjQbN682Rw+fNisXr3aHDx40NZm2rRpxtfX13z55Zdmx44d5oEHHjChoaHm4sWLtjadO3c2jRo1Mps2bTI//PCDqV69uunTp49tf0pKigkMDDT9+vUzu3fvNp988onx9vY2//nPfyzt782YMmWKKVeunFm+fLlJTEw0y5YtM6VLlzazZ8+2tSkOY/J3v6utGoOffvrJuLm5menTp5u9e/eal156yZQoUcLs2rWrwMfgWjcak3PnzpmOHTuaTz/91Ozfv9/Exsaau+++2zRt2tTuGMVpTK72+eefm0aNGpng4GAzc+ZMu32FZUwIpQrY3XffbaKiomzPMzMzTXBwsJk6depNvf7KlSumTJkyZuHChQVVolM4Mi5Xrlwx//jHP8wHH3xgBgwYcNuGUnkdm7lz55o777zTXL582aoSnSKv4xIVFWXuvfdeu20jR440rVq1KtA6nelmQobRo0ebevXq2W17+OGHTXh4eAFW5lx5CV+uVrduXfPKK6/kf0GFRF7G5eGHHzYvvfSSGT9+PKEU8sWtzo+KklOnThlJ5vvvvzfG/PUPqBIlSphly5bZ2uzbt89IMrGxscaYv/6x4erqapKSkmxt5s6da3x8fEx6eroxpmh+np8/f97UqFHDxMTEmHvuuccWShXHMRkzZoxp3br1dfdnZWWZoKAg8/rrr9u2nTt3znh6eppPPvnEGGPM3r17jSSzdetWW5tvv/3WuLi4mN9//90YY8y7775rypYtaxuj7PeuVatWfnfplkVERJjHHnvMbluPHj1Mv379jDHFc0yu/V1t5Rj06tXLRERE2NXTokUL88QTT+RrH/PqZuYvW7ZsMZLM0aNHjTHFd0x+++03c8cdd5jdu3ebkJAQu1CqMI0Jl+8VoMuXLysuLk4dO3a0bXN1dVXHjh0VGxt7U8f43//+p4yMDPn7+xdUmZZzdFwmTpyogIAARUZGWlGmUzgyNl9//bXCwsIUFRWlwMBA1a9fX6+++qoyMzOtKrvAOTIu//jHPxQXF2e7HOTw4cNauXKlunbtaknNhVVsbKzdOEpSeHj4TX8mFRdZWVk6f/78bfXZ66gFCxbo8OHDGj9+vLNLwW0iP+ZHRUlKSook2T5P4uLilJGRYdf/2rVrq0qVKrb+x8bGqkGDBgoMDLS1CQ8PV2pqqvbs2WNrU9Q+z6OiohQREZGj7uI4Jl9//bWaNWumf/3rXwoICFCTJk30/vvv2/YnJiYqKSnJrj++vr5q0aKF3Zj4+fmpWbNmtjYdO3aUq6urNm/ebGvTtm1beXh42NqEh4crISFBZ8+eLehu5sk//vEPrV27Vr/++qskaceOHfrxxx/VpUsXScVzTK5l5RgUpb9P10pJSZGLi4v8/PwkFc8xycrKUv/+/TVq1CjVq1cvx/7CNCbueeoZ8uSPP/5QZmam3S9PSQoMDNT+/ftv6hhjxoxRcHBwjj/oosyRcfnxxx81f/58xcfHW1Ch8zgyNocPH9a6devUr18/rVy5UgcPHtTTTz+tjIyM2+YfkY6MS9++ffXHH3+odevWMsboypUrevLJJ/Xvf//bipILraSkpFzHMTU1VRcvXpS3t7eTKitc3njjDaWlpalXr17OLsWpDhw4oBdeeEE//PCD3N2ZMiB/5Mf8qKjIysrS8OHD1apVK9WvX1/SX5/DHh4etn8sZQsMDFRSUpKtTW7jk73vRm0K6+f5kiVL9Msvv2jr1q059hXHMTl8+LDmzp2rkSNH6t///re2bt2qZ599Vh4eHhowYICtT7n15+r+BgQE2O13d3eXv7+/XZvQ0NAcx8jeV7Zs2QLpnyNeeOEFpaamqnbt2nJzc1NmZqamTJmifv36SVKxHJNrWTkG1/v7lH2MwurSpUsaM2aM+vTpIx8fH0nFc0xee+01ubu769lnn811f2EaE2aYhdi0adO0ZMkSbdiwQV5eXs4ux2nOnz+v/v376/3331f58uWdXU6hk5WVpYCAAL333ntyc3NT06ZN9fvvv+v111+/bUIpR2zYsEGvvvqq3n33XbVo0UIHDx7UsGHDNGnSJL388svOLg+F2OLFi/XKK6/oq6++yvHLujjJzMxU37599corr6hmzZrOLgcokqKiorR79279+OOPzi7FqY4fP65hw4YpJiamWM9pr5aVlaVmzZrp1VdflSQ1adJEu3fv1rx58zRgwAAnV+ccS5cu1aJFi7R48WLVq1dP8fHxGj58uIKDg4vtmCBvMjIy1KtXLxljNHfuXGeX4zRxcXGaPXu2fvnlF7m4uDi7nL/F5XsFqHz58nJzc8tx55Dk5GQFBQXd8LVvvPGGpk2bpjVr1qhhw4YFWabl8jouhw4d0pEjR3T//ffL3d1d7u7u+uijj/T111/L3d1dhw4dsqr0AufIz0zFihVVs2ZNubm52bbVqVNHSUlJunz5coHWaxVHxuXll19W//79NXjwYDVo0EAPPvigXn31VU2dOlVZWVlWlF0oBQUF5TqOPj4+heobZGdZsmSJBg8erKVLl95WZ6g64vz589q2bZuGDh1q++ydOHGiduzYIXd3d61bt87ZJaKIupX5UVEydOhQLV++XOvXr1elSpVs24OCgnT58mWdO3fOrv3V/b/eZ3X2vhu1KYyf53FxcTp16pTuuusu2+fJ999/r7feekvu7u4KDAwsdmNSsWJF1a1b125bnTp1dOzYMUn/16cb/T0JCgrSqVOn7PZfuXJFZ86cydO4FRajRo3SCy+8oN69e6tBgwbq37+/RowYoalTp0oqnmNyLSvH4HptCusYZQdSR48eVUxMjO0sKan4jckPP/ygU6dOqUqVKrbP3KNHj+q5555T1apVJRWuMSGUKkAeHh5q2rSp1q5da9uWlZWltWvXKiws7Lqvmz59uiZNmqRVq1bZXeN5u8jruNSuXVu7du1SfHy87fHAAw+offv2io+PV+XKla0sv0A58jPTqlUrHTx40C5o+fXXX1WxYkW763+LMkfG5X//+59cXe0/4rKDO3PVrYWLm7CwMLtxlKSYmJgbfiYVF5988okGDRqkTz75RBEREc4ux+l8fHxyfPY++eSTqlWrluLj49WiRQtnl4giytH5UVFhjNHQoUP1xRdfaN26dTkufWjatKlKlChh1/+EhAQdO3bM1v+wsDDt2rXL7h8M2f/Iyg4yitLneYcOHXJ8njRr1kz9+vWz/X9xG5NWrVop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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "panda_df = df.select(\"locusSize\", \"locusLength\").toPandas()\n", + "\n", + "plt.figure(figsize=(12, 6))\n", + "\n", + "# Histogram for locusLength\n", + "plt.subplot(1, 2, 1) # 1 row, 2 columns, 1st subplot\n", + "plt.hist(panda_df[\"locusLength\"], bins=30, alpha=0.7)\n", + "plt.xlabel(\"Locus Length\")\n", + "plt.ylabel(\"Frequency\")\n", + "plt.title(\"Histogram of Locus Length\")\n", + "\n", + "# Histogram for locusSize\n", + "plt.subplot(1, 2, 2) # 1 row, 2 columns, 2nd subplot\n", + "plt.hist(panda_df[\"locusSize\"], bins=30, alpha=0.7)\n", + "plt.xlabel(\"Locus Size\")\n", + "plt.ylabel(\"Frequency\")\n", + "plt.title(\"Histogram of Locus Size\")\n", + "\n", + "plt.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAA2MAAAIjCAYAAACOHsPRAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/TGe4hAAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOz9d5xdd3Xvjb93P33O9KI2GhU3yXJvsrGNsY1xyDUdm+JCCpeWhOcm9+dLHrBxCJd2Q0ISSB6eYAMPxEAw3bZsbAzYYNxtWb1L0+vpu39/f+xzjmY0M9KojmV/36+XXpL2OXvv765nre9a67MUIYRAIpFIJBKJRCKRSCQnFHW+ByCRSCQSiUQikUgkr0WkMyaRSCQSiUQikUgk84B0xiQSiUQikUgkEolkHpDOmEQikUgkEolEIpHMA9IZk0gkEolEIpFIJJJ5QDpjEolEIpFIJBKJRDIPSGdMIpFIJBKJRCKRSOYB6YxJJBKJRCKRSCQSyTwgnTGJRCKRSCQSiUQimQekMyaRSCQnmF27dqEoCnffffd8D2UKDzzwAGeddRaxWAxFUZiYmJjvIb3ieKVeO8mrB0VR+MhHPjLfw5BIJCcI6YxJJJJjxksvvcTb3/52lixZQiwWY8GCBVx99dV85StfOW77/M53vsOXv/zlacv7+vq44447eP7554/bvg/kV7/6FYqi1P8YhkFPTw/vf//72bFjxzHZxxNPPMEdd9xxzB2l0dFR3vnOdxKPx/mXf/kXvvWtb5FMJmf87t13342iKDz99NPHdAzzzU9/+lMuv/xy2traSCQS9PT08M53vpMHHnhgvod2XHk1Xs9bbrmFVCo138OYleP1HEskkpMP6YxJJJJjwhNPPMF5553HCy+8wJ/+6Z/yz//8z/zJn/wJqqryj//4j8dtvwdzxu68884T6ozV+NjHPsa3vvUt/v3f/53rr7+ee++9l/PPP5++vr6j3vYTTzzBnXfeecyNuKeeeopCocBdd93FBz7wAd773vdiGMYx3ccrmS9+8Yv88R//MYqicPvtt/MP//APvO1tb2Pr1q3853/+Z/17S5YsoVKp8L73vW8eRys52Tlez7FEIjn50Od7ABKJ5NXBZz7zGRoaGnjqqafIZrNTPhsaGpqfQR0HSqXSrBGjGpdddhlvf/vbAbj11ltZuXIlH/vYx7jnnnu4/fbbT8QwD5vaNTrw2r0W8H2fu+66i6uvvpp169ZN+3zy/asoCrFY7EQOTyKRSCSvYmRkTCKRHBO2b9/OGWecMaMx39bWNm3Zt7/9bS644AISiQSNjY287nWvm2II//jHP+b666+nq6sLy7JYtmwZd911F0EQ1L9zxRVX8POf/5zdu3fXUwO7u7v51a9+xfnnnw9EzlDts8l1Pk8++SRvfOMbaWhoIJFIcPnll/P4449PGeMdd9yBoihs2LCBm266icbGRi699NLDPjevf/3rAdi5c+dBv/fII49w2WWXkUwmyWaz/Lf/9t/YuHHjlPH89V//NQBLly6tH9euXbsOut3vf//7nHvuucTjcVpaWnjve99Lb29v/fMrrriCm2++GYDzzz8fRVG45ZZbDvs4D+S5557juuuuI5PJkEqluOqqq/j9738/7XsTExP81V/9Fd3d3ViWxcKFC3n/+9/PyMgIsD+N7sDjrKWF/upXv6ov27p1K29729vo6OggFouxcOFC3v3ud5PL5WYd58jICPl8nrVr1874+eT798CasQNTUyf/6e7unrKd+++/v3590+k0119/PS+//PJBziA8/fTTKIrCPffcM+2zBx98EEVR+NnPfgZAoVDgL//yL+vnsa2tjauvvppnn332oPuYKyfL9TwcDuc9sG3bNm655Ray2SwNDQ3ceuutlMvlKd+tVCp87GMfo6WlhXQ6zR//8R/T29uLoijccccd9e3N5Tn+0Y9+xKpVq7AsizPOOONVny4rkbxWkZExiURyTFiyZAm/+93vWL9+PatWrTrod++8807uuOMOLrnkEj796U9jmiZPPvkkjzzyCNdccw0QGWypVIqPf/zjpFIpHnnkET75yU+Sz+f5whe+AMAnPvEJcrkc+/bt4x/+4R8ASKVSnHbaaXz605/mk5/8JH/2Z3/GZZddBsAll1wCRE7Pddddx7nnnsunPvUpVFXlG9/4Bq9//ev5zW9+wwUXXDBlvO94xztYsWIFf//3f48Q4rDPzfbt2wFobm6e9TsPP/ww1113HT09Pdxxxx1UKhW+8pWvsHbtWp599lm6u7t561vfypYtW/jud7/LP/zDP9DS0gJAa2vrrNu9++67ufXWWzn//PP57Gc/y+DgIP/4j//I448/znPPPUc2m+UTn/gEp5xyCv/+7//Opz/9aZYuXcqyZcsO+zgn8/LLL3PZZZeRyWT4m7/5GwzD4N/+7d+44ooreOyxx7jwwgsBKBaLXHbZZWzcuJHbbruNc845h5GREX7yk5+wb9+++jHOBdd1ufbaa3Ech49+9KN0dHTQ29vLz372MyYmJmhoaJhxvba2NuLxOD/96U/56Ec/SlNT05z3edppp/Gtb31ryrKJiQk+/vGPT3HivvWtb3HzzTdz7bXX8rnPfY5yucxXv/pVLr30Up577rlpjluN8847j56eHr73ve/VHeYa9957L42NjVx77bUAfPCDH+QHP/gBH/nIRzj99NMZHR3lt7/9LRs3buScc86Z8zHNxMl0PefK4b4H3vnOd7J06VI++9nP8uyzz/L1r3+dtrY2Pve5z9W/c8stt/C9732P973vfVx00UU89thjXH/99VO2M5fn+Le//S0//OEP+dCHPkQ6neaf/umfeNvb3saePXsO+h6RSCQnIUIikUiOAevWrROapglN08TFF18s/uZv/kY8+OCDwnXdKd/bunWrUFVVvOUtbxFBEEz5LAzD+r/L5fK0ffz5n/+5SCQSwrbt+rLrr79eLFmyZNp3n3rqKQGIb3zjG9P2sWLFCnHttddO29/SpUvF1VdfXV/2qU99SgDixhtvnNM5ePTRRwUg/uM//kMMDw+Lvr4+8fOf/1x0d3cLRVHEU089JYQQYufOndPGdtZZZ4m2tjYxOjpaX/bCCy8IVVXF+9///vqyL3zhCwIQO3fuPOR4XNcVbW1tYtWqVaJSqdSX/+xnPxOA+OQnP1lf9o1vfEMA9TEejLl894YbbhCmaYrt27fXl/X19Yl0Oi1e97rX1Zd98pOfFID44Q9/OG0btetT29+Bx1w7348++qgQQojnnntOAOL73//+IY/hQGrjSCaT4rrrrhOf+cxnxDPPPDPtezNduwPH/Ed/9EcilUqJl19+WQghRKFQENlsVvzpn/7plO8ODAyIhoaGacsP5PbbbxeGYYixsbH6MsdxRDabFbfddlt9WUNDg/jwhz8810Ou82q8njfffLNIJpOzfn4k74HJ51oIId7ylreI5ubm+v+feeYZAYi//Mu/nPK9W265RQDiU5/6VH3ZwZ5jQJimKbZt21Zf9sILLwhAfOUrXznksUskkpMLmaYokUiOCVdffTW/+93v+OM//mNeeOEFPv/5z3PttdeyYMECfvKTn9S/96Mf/YgwDPnkJz+Jqk59BSmKUv93PB6v/7tQKDAyMsJll11GuVxm06ZNRzzO559/nq1bt3LTTTcxOjrKyMgIIyMjlEolrrrqKn79618ThuGUdT74wQ8e1j5uu+02Wltb6erq4vrrr6dUKnHPPfdw3nnnzfj9/v5+nn/+eW655ZYpUZkzzzyTq6++ml/84heHf6BEKW5DQ0N86EMfmlLndP3113Pqqafy85///Ii2eyiCIGDdunXccMMN9PT01Jd3dnZy00038dvf/pZ8Pg/Af/3Xf7FmzRre8pa3TNvO5PthLtQiJQ8++OC09LFDceedd/Kd73yHs88+mwcffJBPfOITnHvuuZxzzjlTUkUPxV133cXPfvYz7r77bk4//XQAHnroISYmJrjxxhvr99vIyAiapnHhhRfy6KOPHnSb73rXu/A8jx/+8If1ZevWrWNiYoJ3vetd9WXZbJYnn3zymAjFTOZkvJ6H4li8By677DJGR0frx15LI/zQhz405Xsf/ehHD3t8b3jDG6ZEp88880wymcwxU2WVSCSvHF7Tztivf/1r3vzmN9PV1YWiKPzoRz867G0IIfjiF7/IypUrsSyLBQsW8JnPfObYD1YiOQk4//zz+eEPf8j4+Dh/+MMfuP322ykUCrz97W9nw4YNQJSyp6pq3VCdjZdffpm3vOUtNDQ0kMlkaG1t5b3vfS/AUdWLbN26FYCbb76Z1tbWKX++/vWv4zjOtO0vXbr0sPbxyU9+koceeohHHnmEF198kb6+voOq7+3evRuAU045Zdpnp512Wt1IPFwOtt1TTz21/vmxZnh4mHK5POvxhGHI3r17geh+OFRa61xZunQpH//4x/n6179OS0sL1157Lf/yL/8y5/vlxhtv5De/+Q3j4+OsW7eOm266ieeee443v/nN2LZ9yPUfeOAB7rzzTm6//Xbe9ra31ZfX7rnXv/710+65devWHVLgZs2aNZx66qnce++99WX33nsvLS0t9XpEgM9//vOsX7+eRYsWccEFF3DHHXccE+P9ZL2eB+NI3gOLFy+e8v/GxkYAxsfHgeh5U1V12vti+fLlhz2+A/dV219tXxKJ5NXDa7pmrFQqsWbNGm677Tbe+ta3HtE2/uIv/oJ169bxxS9+kdWrVzM2NsbY2NgxHqlEcnJhmibnn38+559/PitXruTWW2/l+9//Pp/61KfmtP7ExASXX345mUyGT3/60yxbtoxYLMazzz7L//yf/3PajPXhUFv3C1/4AmedddaM3zmwP9HkKN1cWL16NW94wxuOaHyS6cwWUZks5lLjS1/6Erfccgs//vGPWbduHR/72Mf47Gc/y+9//3sWLlw4p/1lMhmuvvpqrr76agzD4J577uHJJ5/k8ssvn3WdnTt38p73vIerr76av/u7v5vyWe2e+9a3vkVHR8e0dXX90D/F73rXu/jMZz7DyMgI6XSan/zkJ9x4441T1n3nO9/JZZddxn333ce6dev4whe+wOc+9zl++MMfct11183p2E8EJ/p6zsSRvAc0TZvxe+II6kgPxYncl0QimV9e087Yddddd9AfKMdx+MQnPsF3v/tdJiYmWLVqFZ/73Oe44oorANi4cSNf/epXWb9+fX3G8HBn0CWSVzu11Lz+/n4Ali1bRhiGbNiwYVYj6Fe/+hWjo6P88Ic/5HWve119+UxqhLMZdrMtr6X+ZDKZV4zDtGTJEgA2b9487bNNmzbR0tJSl9M/nFSvydudHEGpLat9fqxpbW0lkUjMejyqqrJo0SIguh7r168/6PZqEYgDezLNFtlbvXo1q1ev5m//9m954oknWLt2LV/72temOUlz4bzzzuOee+6p378zUalUeOtb30o2m+W73/3utPTb2j3X1tZ2xPfcu971Lu68807+67/+i/b2dvL5PO9+97unfa+zs5MPfehDfOhDH2JoaIhzzjmHz3zmM0fljL2armeN4/EeWLJkCWEYsnPnTlasWFFfvm3btmnfPdyUTYlE8urlNZ2meCg+8pGP8Lvf/Y7//M//5MUXX+Qd73gHb3zjG+vpDT/96U/p6enhZz/7GUuXLqW7u5s/+ZM/kZExyWuSRx99dMZZ21q9U23C4oYbbkBVVT796U9Pi3DV1q/NCk/enuu6/Ou//uu07SeTyRnTlmrOy4EG37nnnsuyZcv44he/SLFYnLbe8PDwrMd4vOjs7OSss87innvumTLe9evXs27dOt70pjfVl812XDNx3nnn0dbWxte+9jUcx6kvv//++9m4ceM0lbdjhaZpXHPNNfz4xz+eItc9ODjId77zHS699FIymQwAb3vb23jhhRe47777pm2ndv1rhvOvf/3r+mdBEPDv//7vU76fz+fxfX/KstWrV6Oq6pTjP5Byuczvfve7GT+7//77gZlTPWt88IMfZMuWLdx33311R2My1157LZlMhr//+7/H87xpn8/lnjvttNNYvXo19957L/feey+dnZ1TJiqCIJj2HLS1tdHV1XXQY58LJ9v1nAvH4z1QU7U88D31la98Zdp3D+c5lkgkr25e05Gxg7Fnzx6+8Y1vsGfPHrq6ugD4H//jf/DAAw/wjW98g7//+79nx44d7N69m+9///t885vfJAgC/uqv/oq3v/3tPPLII/N8BBLJieWjH/0o5XKZt7zlLZx66qm4rssTTzzBvffeS3d3N7feeisQ1U984hOf4K677uKyyy7jrW99K5Zl8dRTT9HV1cVnP/tZLrnkEhobG7n55pv52Mc+hqIofOtb35rR2Tv33HO59957+fjHP875559PKpXizW9+M8uWLSObzfK1r32NdDpNMpnkwgsvZOnSpXz961/nuuuu44wzzuDWW29lwYIF9Pb28uijj5LJZPjpT396ok8fX/jCF7juuuu4+OKL+cAHPlCXtm9oaKj3J6odL0Sy/u9+97sxDIM3v/nNMzaiNgyDz33uc9x6661cfvnl3HjjjXVp++7ubv7qr/7qqMb8H//xHzP2PvqLv/gL/u7v/o6HHnqISy+9lA996EPous6//du/4TgOn//85+vf/eu//mt+8IMf8I53vIPbbruNc889l7GxMX7yk5/wta99jTVr1nDGGWdw0UUXcfvttzM2NkZTUxP/+Z//Oc1Qf+SRR/jIRz7CO97xDlauXInv+3zrW99C07QpNVwHUi6XueSSS7jooot44xvfyKJFi5iYmOBHP/oRv/nNb7jhhhs4++yzZ1z35z//Od/85jd529vexosvvsiLL75Y/yyVSnHDDTeQyWT46le/yvve9z7OOecc3v3ud9Pa2sqePXv4+c9/ztq1a/nnf/7nQ57vd73rXXzyk58kFovxgQ98YEoErlAosHDhQt7+9rezZs0aUqkUDz/8ME899RRf+tKXDrltePVczxqe580YPWtqauJDH/rQMX8PnHvuubztbW/jy1/+MqOjo3Vp+y1btgBTo2GH8xxLJJJXOfOm4/gKAxD33Xdf/f816edkMjnlj67r4p3vfKcQQog//dM/FYDYvHlzfb2atO2mTZtO9CFIJPPK/fffL2677TZx6qmnilQqJUzTFMuXLxcf/ehHxeDg4LTv/8d//Ic4++yzhWVZorGxUVx++eXioYceqn/++OOPi4suukjE43HR1dVVl8pnkvS1EEIUi0Vx0003iWw2K4ApMvc//vGPxemnny50XZ8mR/7cc8+Jt771raK5uVlYliWWLFki3vnOd4pf/vKX9e/UJK2Hh4fndA5q0tyHkuKeTR794YcfFmvXrhXxeFxkMhnx5je/WWzYsGHa+nfddZdYsGCBUFV1TjL39957b/1cNzU1ife85z1i3759U75zJNL2s/3Zu3evEEKIZ599Vlx77bUilUqJRCIhrrzySvHEE09M297o6Kj4yEc+IhYsWCBM0xQLFy4UN998sxgZGal/Z/v27eINb3iDsCxLtLe3i//1v/6XeOihh6bcDzt27BC33XabWLZsmYjFYqKpqUlceeWV4uGHHz7o8XieJ/6f/+f/ETfccINYsmSJsCxLJBIJcfbZZ4svfOELwnGc+ncPvHYHOxcHtlx49NFHxbXXXisaGhpELBYTy5YtE7fccot4+umnD3nOhYjaQtS2/dvf/nbKZ47jiL/+678Wa9asEel0WiSTSbFmzRrxr//6r4fc7qvtegoRSdvPdjzLli2rf+9o3gMzSfSXSiXx4Q9/WDQ1NYlUKiVuuOEGsXnzZgGI//2///eU9Wd7joEZWxQsWbJE3HzzzYc8dolEcnKhCCGrQSGasbrvvvu44YYbgEip6j3veQ8vv/zytELaVCpFR0cHn/rUp6alnVQqFRKJBOvWrePqq68+kYcgkUgkEonkFcbzzz/P2Wefzbe//W3e8573zPdwJBLJKwyZpjgLZ599NkEQMDQ0xGWXXTbjd9auXYvv+2zfvr2eA19LRzhehfESiUQikUhemVQqlWnqq1/+8pdRVXVKjZ9EIpHUeE07Y8VicYrK0c6dO3n++edpampi5cqVvOc97+H9738/X/rSlzj77LMZHh7ml7/8JWeeeSbXX389b3jDGzjnnHO47bbb+PKXv0wYhnz4wx/m6quvZuXKlfN4ZBKJRCKRSE40n//853nmmWe48sor0XWd+++/n/vvv58/+7M/qytOSiQSyWRe02mKv/rVr7jyyiunLb/55pu5++6768W/3/zmN+nt7aWlpYWLLrqIO++8k9WrVwPQ19fHRz/6UdatW0cymeS6667jS1/6Ek1NTSf6cCQSiUQikcwjDz30EHfeeScbNmygWCyyePFi3ve+9/GJT3xiTv3kJBLJa4/XtDMmkUgkEolEIpFIJPOF7DMmkUgkEolEIpFIJPOAdMYkEolEIpFIJBKJZB54zSUwh2FIX18f6XR6SgNGiUQikUgkEolE8tpCCEGhUKCrqwtVPfFxqtecM9bX1ycVjSQSiUQikUgkEkmdvXv3snDhwhO+39ecM5ZOp4HohGcymROyT8/zWLduHddccw2GYZyQfUqODHmtTg7kdTp5kNfq5EBep5MHea1ODuR1OnkYGxtj6dKldR/hRPOac8ZqqYmZTOaEOmOJRIJMJiMfyFc48lqdHMjrdPIgr9XJgbxOJw/yWp0cyOt08uB5HsC8lS9JAQ+JRCKRSCQSiUQimQekMyaRSCQSiUQikUgk84B0xiQSiUQikUgkEolkHpDOmEQikUgkEolEIpHMA9IZk0gkEolEIpFIJJJ5QDpjEolEIpFIJBKJRDIPSGdMIpFIJBKJRCKRSOYB6YxJJBKJRCKRSCQSyTwgnTGJRCKRSCQSiUQimQekMyaRSCQSiUQikUgk84B0xiQSiUQikUgkEolkHpDOmEQikUgkEolEIpHMA9IZk0gkEolEIpFIJJJ5QJ/vAbzW8f2QZ/eOM1pyaU6anLOoEV2fm48choLeiQol1ydp6izIxlFV5bitd7TrHq9th6Fgz1iJp3aNU/F8sgmTntYkDTFz1m3MtC+AfWNlAH67dZie9gYWNSbq609eJ2FoCKDiBbOOdaZ9hKGY9XrPtv3Z9jXb+Zp8T2XjBp4X8Ni2ERwvoKc1wTndTbieIGXpJAyNgYLNeNmjIa5DAJuHC2wayLN3pEzFC2lvsFi7opmelhSOFzJScBguOuwaLWHpKoubE5Rdj2d25dFQaErqtGZMFEUjrik8tXucTQMFXD+gMWlw9qIsS9pTFEouL+4rUHQD2pI6Zy1txFIMRooORdcjaWm0pExyZZ9do2WECGlOWsRMFQ1YA9zxkxcZLftsHyhQ9ATpmEZz3KA3Z1PxQzKmztLWBJ3ZGOOVAN8XDBUqVGyPCTtAiJB03OL0ziQx3WC04oEIKVVsntlTwhWHvm9VwFQgALw5fP9IOCUNOQy8IERVQBECLxTkbUFwfHZ5zLA0wecvgFV3PIgTHJt3heTY82q8ThpgqmBoUPQgnOE7CiCIjCFDAaGAE0bPtQao1fWzSZOUpREGAlVV8EJBoeIxUQ5wZnjuTSAZU0hZBjFDpTFu0t4YY6zgsHGgwFhl/2g0oCOt05Y2KQegKgqtaYtFjTHyFQ8hNBY2x3nLmQsYKjs8tnGQ1cCXHtxEOmFRtB0e3zLMhsEKoYCUATddvICWdIrxskcmZnL16W0sbkzSn7fJ2S47hktMFF3KXkBDwqA5adI7UaHi+QzlHBwvIGf7xHSFdFzH9QWqprCgIcGqrgx9eZuhvIOmQL7iUXJ8UjGdRc1JVAVyFZ+ErpGK6/SPl9k2XKYxaXLVaW1c2N08xc6p/YY/uXOU5/aM8cS2MfwgZHlriv/rTSsxFJ2i45MwNQoVn73jZdwgpKc1SaNl8O2n9jBScOnKmlx/Vhe+DxU3wAtCXurNsW0wT8UTLGlOcHpXhvO7m9BUlZLjU7A9Sm70Fo0bGrYXoCgKi5vi9Odsntk9DsC5S7K0J+M8s2+MLYNFMjGdC5Y2c/6SJnRdjY5htMRTu8fYN1HBcQNMLWQZ8P89uYtTOhrpyMZw/HCKzTGTHXI8bKyaXTBcdBBC0N2cpCE+1UY6nvbdgduPGxoKUD6IDfVaQhFCHCfz4ZVJPp+noaGBXC5HJpM5Ifv0PI9f/OIXvOlNb8IwjPryX24c5O7Hd7FrtIQXhBiaSndzklvWdnPVae0H3ea2oQIPrh9k+3AR2w+I6RrLWlNcu6qd5W3pY77e0a57KI7meP710W38ZusIedvDDwSqAgnL4PTONJcub522jZn2lU0YTJRdtg/muW3JBP+wOUnCsrhoaRM3XbQYoL7OSNFhpOgACi0pk5aUNW2sM+1DINgzWmao4Ey73kuaEzNuP2GqlN1g2r5O7Uyzqb8w7Xxl4jrrXh5k12iJgu1RcHyCAywQFcjEdRKmju0FBKEgFALHD/ECwcFeCCozGzQnmshwDPibP2ivGsPx1Yq8VicH8jqdPBzutVIB01BZ0BAjFTPYPVqm4HiEIQd93x8PVAWWNif4X9efzlWntdd/w3+5cYic7c+4jqFBc9Ki5PjYXoAgcqK9WX6MDBVQFLxg5qOzNIXGpImqKBQdnyAMCYUgDBV0DXRNxXaDWX8Pa8sMVWFFW4obL1zMs3vGeWzzMBMVj1DU9rP/OgVCIR0zWNaaZHFTkmzCAAETFW+KHXLgsmNhY9Vsza1DBYqOTxgK4qbOyvZU3UYCjpt9B1NtosjGcQFBS8qa0YY60YyOjtLS0nJCfYPJyMjYPPHLjYN89v5NFGyP5qRJ3NSouAFbhgp89v5NALM6ZNuGCnzj8V2MlVw6G2IkzDhl12d9X46+XIVb13bPeEMf6XpHu+6hOJrjuetnG3h61ziBECAEmhK9KEuOz0u9eVw/nLKNmfbVN1HmFy/1U7B9WpMaAC1Jk+GSz0MbB9k+UiQdMwhCQdxQGS05lB0fgYKiQEvKnDJWYNo+Ng/keWLHKGEo6GqI0ZaJ16/3nT/dwNKWBAlTn7J9NxD05wLihoqhafV9/X7nKPc930tnJsaK9lT9fD2yeZCtg0UMTYlmEG2fmX6LQmCi4pOr+KgK6NVZ3nAOv8qvBEdMIpFIJHMnBGwvZPtIuV6bMl/v8lDA9pEy/7//epGPXbWChzcO8uSOMWx/9hF5AQzkHWpup6YcPAshctJm/4ITCAbyDhpgGAp+AGHVhvBCCN2pY6lFTyf/X1HADwUbBwrc9fONCCHwDzKZ6YeQK3tsqf5GP7XLBuD87kZ6WlL0TZR5aMPglGXHwsaq2ZrjJZcgDNEVBcVQsb2Ajf153CBk40AegCAUx9y+g6k2XmTjuJQcHwXB6Aw21Hw5ZPOJrBmbB3w/5O7Hd1GwPRY3xknHDHRVJR0zWNwYp2B73PPELvwZXk5hKHhw/SBjJZcVbSnSMQNNjWZcVrSlGCu5rHt5kPAAy/pI1zvadQ/F0RzP/S/1s743eonoCiiKimloWIaGpoDjBwzlbUYKNuteHsT3w2n7UhXoz9k4XpSmoCrR694yNNozFqamsr43z+aBPMtaEgzkHBwvpC0Toz1j4XgBA3mH5a1JxkouD64f5IGXBqbsQwE2DxQQocDSNRxfoClK/XqPlRzW9+bpaY5P2b4CuH6Iqii0pU0cL6A/Z+N6PhNll7ztEYZRJDBp6gzlbBw/IKarTJTcGR2xyQhAEeAFc3PEJBKJRHJyE7LfEZvP+OdoyeXfH9vGC3vGD+qITUYQRdb8Y/R7FQC+LwhDgRCgqcz4W3jgoto41OrkrzuHrBKIznvZ9dnQW0BXBKauVp1MwUDOwdSU+jJV4ahtrLqtWfGI6QqKopCwdBKmRiam4wWCoZzDpv48WwYLLG9NHlP7DqbaeMtbk/RXU2DbMxZtmRiOF06xoY5mXycz0hmbB57dO86u0RLNSRNVnXoJVFWlOWmyc6TEs3vHp63bO1Fh+3CRzoYYijL1VaooCp0NMbYNFemdqByT9Y523UNxNMfz1K5xHD/A1FUCAZqqRDNWRGkGKjBe9tBUhW1DRZ7dOz5tXwXbZ6jggKJE0clJeQ+KomDpKo4f4PjRC2Os7JKK6ShK9GJLxXTGSi5FJ6CzIcaLvRO81Jubso/+fIWJikfC0rEMlYoX4FZ/fLwgcswcP2DHSLm+fdcPsf2wPiYvEKRiOvvGK2wZKuH5IduHi/x66whP7Rpn82CenO2TMHUKTkB5tvyNA1FktEsikUgkJ4bar3wooD/vUPbmt+q15thpCoecwDyQI3JmQyi6Pqqmka7aD/05m7GySzpu1JcVqimbR2Nj1WzNTFzH9iPnr2ZmqWpk84xXXCqOTxAKis7Ua3G09h1MtfGKTsB42SUVM2a1oY5mXycz0hmbB0ZLLl4QGdozETc1vCBktORO+6zk+th+QMKcOcM0bmo4fkDJ9Y/Jeke77qE4muMpOh6ilpooYLIvV/t3IKKoj+MHjJbcaftygxAvCAGBoSocWEKpqCCq2yh7AX4Y1XrVMDQVPwxxq9ez7AaUPH/KPipuVJdlaEp1rCJKq6yOT1GiWbmC69e3H417/5gCIfCDkLGSi+0GWLqKoUV/hgs2mwYKeEGIpSvVGrC5nf/X3vyTRCKRSGD+3/9hOHMk6mActzEfmIt4qHGIIxtLOGk3Nfthsm0x2aaocaQ2Vs3W1DWVUEQTv5Mx1Mhe8Ksjcg8sMD+KfdeYbOO5QYgfhBja/nEYmkowyYY6mn2dzEhnbB5oTpoYmkrFnXlGqOIGGFoUITuQpKkT0zXKs9ysFTfA0jWSBzg3R7re0a57KI7meFJWNLsSVB2xyX6UqM92KagKWLpGc9Kcti+z+vKDqG7qwOicCKPZIVWBhKGhq2rVeYvwghBdVTGr1zNhaiQNfco+4qaGpkbFxNFYlfpLUVMUhIhqz9KmXt9+NO79Y1KBkaKLQGAZKiFRSmXcUGlKmpEDFgpsL0RTo/HOBVmmL5FIJK9N5vv9r6rM+beqhnK8vLGaKshcx6Ec2flTJ+2mZj9Mti0m2xQ1jtTGqtmafhCVOwQHTDZ7oUBTFfTqiCbv82j3XWOyjWdqKrqmThFW8YIQbZINdTT7OpmRztg8cM6iRrqbk4yWXMJw6kxEGEYRsaUtSc5Z1Dht3QXZOMtaU/Tn7GlRHCEE/Tmb5W2pukTq0a53tOseiqM5nvO7G7F0DdcPoxSDMMrZFoAfhIRAYyIS3ljeluKcRY3T9pWO6bSlLRCCihuJZUzev+OHWLqGpat0ZCyaEiZF20cIgRCCou3TVJU87s/ZnLkgy+oFDVP20ZmJk40blB0fxwuJGxpmVdbX0KIXpKVr9LQk6ts3dZWYrtbHJISg5PhkYgYJQ6svj9IOFFpSFpqqUHZ90pZGwpjjoy3kS0AikUgkJ4bar7yqQGfGImHMnCE0K8fYg9TrWTRRquLhcER+oQopUycMAgpV+6GzIUZTwqRQ8erL0rHIITkaG6tma+YrUYsC1w/rE9VhGNk8jXGTuKWjqQopa+q1OFr7DqbaeClLozFhUrS9WW2oo9nXyYy0w+YBXVe5ZW036ZjBnvEKBdvDD0MKtsee8QqZmMHNl3TP2G9MVRWuXdVOU9Jk61Bxyrpbh4o0JU2uOaN9Wr+GI13vaNc9FEdzPNet7mTVgkiC1A8FQoS4XoDjBQQCYoZGWyZGSzrGNWe0o+vqtH0FIlIPsqo/CGH1TWV7AYN5BzcIWbUgwykdGbaPlOlosLAMlcG8zWDewTI0OjIW24ZLNCVNrl3VzhtXd0zZR4jglI40ihrVhll65IDVrndz0mLVggw7RitTti8AU4/SC0ZKHoqikIkb6LqKZaioioIbRJK8gigf3NA0bD8kmzQP+cOiEPXUMbS5R9IkEolEcvKist/wm880xeakyZ9dvpw1ixuJzbG3qkLkNB2rnysN0HUFVY2yU4JwZqP4wP0pROmVYXUs0W+vcshxqUDC1Dl9QRpfRM5RR8YiBDoaLNxA1JfVbISjsbHqtmbcwPYj56fs+JTdgLzto2sKbQ0Wp3ZmWNmeZttw6ZjadzDVxts2XKKzwcIyNAbzDoN5G8tQp9hQR7Ovk5nXXizwFUJNtr7WZ2ys5GJoKqe0p7n5koP3GVvelubWtd31ng2DeRtL11i9oIFrzpi9T8ORrne06x6Kozme//uPTp/SZyyoqgumLJ3TOtNctqJ1yjZm29ebVnfW+4xBmbGSS9KyuLiniRsvnNpnrDlpVWeXlGoqqTJtrAfuIx0zuPb0DnaPlhgqOPSOV6Zc78l9xiZvv6vaZ8wLQvwwJAgFCxsTtKRMRgouY+VIIjYU0QzUtas6eGpntWg3ppOfoc+YBqTjOklLr9ezmSdZnzGJRCKRzA0VsAyVrmyMlDX/fcZ6WhLc/qaoz9jFy5oPu89YGKnQz/pbpCugqHPvM6YpYdW5UtDVmfuMqew/V4Jo/4amsLItxbsvmLnP2JQxqZCJGfS0JulsSHBaZ0O9p9iukRKWrnH16e3Tlh2tjTXZ1qz3GfNCEqbOivZU3UYCjot9B9PtruakGdX5I2hOWsxkQ73WkE2fTwCzNX2G/V3RR0suzUmTcxY1zhgRm4kj7ZZ+NF3Wj2eH9qM5nj1jJZ7aNU7F88kmTHpakzTEzFm3MdO+AHYP53nx978is+J8etobWNSYmLE7fcLQEEDlIN3jZ9pHGIpZr/ds208YGqEQ3P34bnaOFjlzQQOqGqUuFmwfxw/onahwQXcz//2KZVP2kY0beF7AY9tGcLyAntYE53Q34XqClKWTMDQGCjbjZY+GuA4BbB4usGkgz96RMhUvpL3BYu2KZnpaUjheyEjBYbjosGu0hKWrLG5OUHY9ntmVR0OhKanTmjFRFI24pvDU7nE2DRRw/YDGpMHZi7IsaU9RKLm8uK9A0Q1oS+qctbQRSzEYKToUXY+kpdGSMsmVfXaNlhEipDlpETNVNGANu/iDv5DRss/2gQJFT5COaTTHDXpzNhU/JGPqLG1N0JmNMV4J8H3BUKFCxfaYsAOECEnHLU7vTBLTDUYrHoiQoYkSLw3Y817gXiMG6KaKqVVVQ0VIxRcU3fkvwj8UspnwycGr9TrVjmS256Sm26ADhhJlC9gHWPkqkLJUWlIGhhJFUrxQUKh4TJQDnFk2rgMxHTRNIWboxAyVouPjByG5SStpQEdapy1tUg6ieuDWtMWixhj5iocQGgub47zlzAUMlR0e2zjIarGDjVoP6YTFntECv9o8wmDRr2/v3O40Zy9uRtdUMjGTq09vY3Fjkv68Tc522TFcYqLoUvYCGhIGzUmT3okKFc9nqCo/nrN9XM9nuOgwUfEJhUI6pnNGZ5pFzQkgEqXKVzxKjk8qprOoOYmqQK7ik9A1UnGd/vEy24bLNCZNrjqtjQu7m6fYObXf8Cd3jvLcnjGe2DaGH4Qsb03xf71pJYaiU3T8qH9mxWfveJl9ExUGcjYjeZutI0V8X9CZtXj/Jd10VPt4ekHIS705tg3mqXiCJc0JTu/KcH53E5qqUnJ8CrZHqVq/Hzc0bC9AURQWN8Xpz9k8sztStT53SZb2ZJxn9o2xZbBIJqZzwdJmzl/ShK6r0TGMlnhq9xj7Jio4boCphSyztzPefDqndDTSkY3h+OEUm2MmO+R42Fg1W3O46CCEoLs5SUN8qo10PO27A7cfNzQUImG047Gvw2W+mz5LZ+wEcDBnTPLK4pV8rQ5sWF1rFN6fs2lKmq+pZonH8zpNbwweCbL0Tdj056I04rMXZwF4atcYmwcKBGGIUBTihkY2FhkOtVneRY0J/ujMTq5d1XHQ6zPX67ttqFCfYax4AWE11faq09pZu6xlTj9oe8fK/MNDW8gmDNKx6eevYHtMlD3+6uqVLMjG6Z2osLE/z89f6sfxArqy8fp56c/ZaKpCW8piouJh+wExXWNZa4prV7WzpDE25Vodzr4XNSXqyzcN5PmnX26lpyWFNukYR4oOj2wapFjxqPghuqqgqyqpmM6qBRlaUxbP7JlgUWMCy1DrYzu1M83j20b4/Y5Rdo+WKVcNMl0BVPCD6Qa8qkTpVZ3ZGCUnYPWCBhw/pClpcvPF3cRNbYohs3e8zH//9rOUHJ/2jIXthYyVHCpelF7s+CEpS+cLb1/N+t4C6/tyrGhLMV522T5UYqzs4gcBZTdkeVuKv/2j01jZPvPv1rahAv/x2130TpRpTJhkYgaaGjXLne394Psht979FFuGCixrsnhX5xiffSmGqun4QcBoyUNRIGlqhKKqtiaqKrVhpDZraiquH2LoKs0Jk4uXNWP7IVsHi3hBdH8O5GwMTcWu1qyYWtTvaGFjnJ6WJKBMu95HyuTnw/aCeir6XJ+P2Z7/ubxnw1Dw1V9tr1/HyYJQQgi2DhVZvaCBD16+7KgMz8nvv93j9hGPd/K4D2aEH28j/Uh5pY6rxivZnpBMZb6dMZmmKJGcJBzPVFFJxIFNyGvGVDpmsLJdp+T65CseWwYLpGMGg3mbIIzkPGO6Rns6cqIaEiYNtk/B8WlNW7x5TReLm5MH3fdcru9kQzFuqIyXXIaLDi/sneCxzcNceUobN120+JD3Qq2oen1fjpSlTzMa+3M2qxc0UPF8vvqr7WwdzPPCvhxFx2dhY5yWlEU6FjUGdf2Ax7aMEDc11i5rpsuKU3Z91vfl6MtVeP+FCwF4ZvcY43ZIyfapuD5d1Uhxf74SCdKYGp2ZOHFTYzBvT5M3nqzKNdmJG8zbjBRdgkCgaUq1ZYhCvuLxh53jpC0NgUJT0qA9M3VsN1/czTVntPPZX2yif6ICCNxAoKsKBcdHVaLWEn41XSlpanQ3J/BCgaGpNCaiQvvn9k5w18820JIycYKw7vA1Jg0mKi6tKQul2suwy4jj+iGBEHiBIF9xEUR1FX25CluHop48Zy3OMlxw6M9VaE5ZfPiK5axsP/h1jekqwwWXrUNFFKAhbnBRTzM3XTjzPdFfrdloTBiMl6tRFTVK3YJqbUwYPRe6rlVrVKHWo1cJwRORg+X5IQMFmye2DWP7AjcIycYNYoaGpqosbkqgqQojBZeGhMEF3Y00JEwCIdg1UjpmctbL29L0XJHiie0jPLxhiP5chcG8zX3P9vLi3hzXrpr9XXmw5z9l6WwdKrLu5UF6WlIHra/uy1XYMlgkHYuEEYIwymJoTh3bmpijHS8c4LweMJFSO0+qqhwTR/lY80odl0RyuEhnTCI5iagZGq/k2cCTmUM1IV/RlmLPWJnFTUm2DxfIVyIRmIaYQVPCRFWg7PpoikLC0nCCEIGYc2PTg13fyYZXc9LghX05Km5AOqbTmDAYLrj8dvsIth9w26VLD+qQTTYaa8b/gZG4UzrS3PPEbvaMlhkvu4wUHQC2DhXpy9lcuLSZ7uYEO4bLqEq1pkJAyfFxg5D2tMVA3uHrv9nJpTH4xH3rKXkChUhwpz9nM1ZymahEtZ6aqpCNG5zSkSYdM6bIG4dhVHyeiRlsHy6yuitDyQ1xvICXe3MEgUBUe/iVnQBVVdBVhZLjU/ECzl2cpbMhjqIoUwzVhzcOcsWprTQmjWp6EoyVXLxA1KWmVaVaqK9CSzpyqoq2R1smRjqmM152GcrbFGyfjoZmFjSm6g5fxQvw/egeEELUnTCtGkVVlCglSlQVVS9f2crTu8YZLti4QaTkesmylkNOtkx20i9c2kgQQt72GC+72Ae590pupNx6zuJG9o0WgWpfoTAkCKNjF4BQFFKmRqHi1ZvkKkTy3pqmEPpR2w4ElNxovZihUXKDegqYAOKmTluDgu2FqGqkBFtx/GMuZ71tuMD3n9nHaNGhsyFGWzpGxQvqTvhs0aJDPf+Tm9LO5gQsb0vz+lPbuPvxXbzcl8MLov5R3c1J3nHewmM6adafs49qvNOjgFMnK15L2RYSyXwinTGJ5CRDzgYeP/Y3qJxZWjduRm0Obji7i6Lj8+WHt7BvvBJFqcpePW1QVRQMTcHQVBKGfliG5mzXt2YodmRibB4oUHEDmpJm3QhrTBrYblQ/eKjZcIiMxpsv7ub7z+zl5b48XhDSmDBZszDL1ae389CGwbojlqt4oIBV7UNTtH2e3DFKxfXoz1XqDc+f2zuB40diM5EzEzBWsLn07EhUJ5vSKTs+O0bKjOzLYWiQiZsYWlRsP1J0GN3hcu3pHfX6idrM/bahAr0TFXaNlnhhb46UFdVSDuadqEVQtd+gpkYNgBw/iuIQRk7cZGN1sqF6XncjjXGTQsUnV/FoT1sMFd1qzcn+An6DKE1xrOQSN3WWtaYA2D5Uwg9CEqaGqUc9BWsO3wv7JkCB4byNpqr19MRaj8BQCOKmzhPbRvnpC/3YfoClqbSmLc5b2sRpHZlDTrb4fsj3ntrH7tESy1tTpKvH2pg0WdyUqEdHupuieqHJTn4t2hgztCj11h7m4mUtFJyQTQN5dnklVKL7uOAEUxwxreqoqcrUbrlBGCJUlbimIlQRqbapCrYXkLJ0DC2qm3KDcEoUdi5y1rOlpU2u11m/L8dvt42Qq7hkExYjRZfGRCSZvawlwVO7x/nKL7dx04WLOHdx05Tapbk8/zNFbSezbajAI5uGSFoaF/VEtUlBGFKwfR7ZNMSS5sQxc3COZrzHIqo2V17p6YQSyXwjnTGJRCKpMlsqXI1aU8p0zODUjgyXLGvh+0/vo2/CRlcVTENDU9SqNHBkhHZlY8ekb0rN8EqFOmNll1RsanqhoakUhU9jwjzk7D1ERuN/PrWH320fYazkEgLjJY8FDTEGCzbbhgqUXZ+87eH6AY4X4vphPXVvrOzy5I4x/GpUyw0Evh/S1hDD0HQ8P2TXSBGlqnmWiun4QiUdM9CUyMkJw2pvn2pUpdYcffdoiTAU7Bgp8o3Hd7FntEzZ9RktuRRtHycIqbg+MVOLGqADuhZFwwRRs3aIdKdr0ZsDqRmqKUtneVuakaKL44fkbA/PD9FUMFTwqil5Xgh7xm16WhKctShLU9IkX/EYK7tYRlRTNblpqqIo9LQk2TFcYrjoRBLYmlrvLThe9giFwNQ19o6Xq3V4UWRi73iFkjtMT0vyoEbrtqEC33tqL/evH4hSAIsujQmT5W0pmpJmdN4tnV9vHWbvWAnbC6ekUV59ens9XTXdGt2jqgLbh4uUHR9NiWrvOtIWAwUH1d4v5x0dJNXWGvsJRLQNN4jUX2OGStzQMDSVsZKLqVfbcvjBYUlnz5ZOd2pnmp+92Mdjm4fJVTxqAnoqkTpeWybGcMGmL1fB8QKKjs8Le3P8Ydcoy1vT3LJ2v3rxgc9/TSTJDcLqtRUHjeJNdnBWtqdnrBk7Vg7OTOM9kIM10T0WUcC5MJc0SInktY50xiQSiaTKXGupajO715zewU9f6MMPRd1JCUQUldHUqEZIVY7NDHDN8Kr1gTG0qa9vL4iiUemYzljJPeTs/Zcf3soLeyfQFGhviKGgMFH2eHjTENtHSlS8yPnJV6Wa9WrtCwq4gaguE5iqgl2NQrlBSBiCqis4VWPc1PafP4CC4+OHkaMTCCg5AX4ooohRNb1w61CRHz/fx0DerkfnKl6A7YWYenSMeTtqy6AQyUarqhKdc0OLnIQQcpXIyZxJSm+yY11L2RRCMFxwKLl+1EReQMxQaUtbFKs1gOMlr34sbhDiBQEIhfaGWL1Raw3bj/r1BEGIH4Jd9ew0NTqfqqIiBKxoS6GqkSM3OTLx4PpBjDXqjKqttRSz3aMlNBWaUyZBCMMFm4Lt0d5gMVJwGS06jJZctg8VWdyU4JSONDFDq6eivf7UNvpyFbYPl+hJw/ahIvmKh6FppCyBpalYhkZL0mSs6CJEdM5DomikEFE7EUWJ0lRrKau2F5CNG2QTBrYfsqI9xWjBZfdYmXRMxw/EnOtdZ0un+/3OUb795G7GSi5+tZ6tRgiMl6MU2GzCoC9ng4BMTEdXQxKGxpahAp+9fxMQSYBPfv5dP2DHcDkSUQlDNEVBCLh0RcuskysnysGp0dkQm/P76kCORRTwUMg0SIlkbkhnTCKRSKrMpZZq8ix+3NRY2BgJUQwXXYpOUK+XqSnFjZe9Y2J81QzFP+waRVMUvGpNEUSGV9H2acvE0FXlkLP3D6wfYMtAAVNTaK6KSwC0Z1RGSy57xspUXJ+xkhsZ2GpkTIYiSourBp0IQkGgKAQCMjGNQERpfF1GDLfafF2rxlEcL0A3NPwgrPfoCf0oJFZrmqoq4AeCkuvz3T/spiFhUHaj3kIpU2Oi7GEZGrqqkI5B0Y7OdyAiFUQ/FChK1CdIqKKeRtcQnxo1qBmqq7oaCIXADwVnLmxgc3+OfMWtC3YkDJXOhjhNKYtK3GffeIWJisfz+8Z53YpWXD+k4oakYzrtaYvRkoupqfVasid3jFLxAixdRQujKFLkQEapf6GInNCiE5CJT42qxQ2Vn7/Ux4v7JiJp9EkRhZ6WVD0Cs7w1FQmYhFHUJjBU9oyX2TpUiOrdqr2k0jGNXMXjpd4cZy3KsqItxdahIpsHCtx8yRIeXt8PxT56Jyromk57JsYZKZOdI6V6RCtmqJScAEEUiU1UPe2i40dOsaaytCXJkuYE24aKVSebalpmJGxzfkOM68/snFMKZu1+3X+sSYpOwGjJYaLs0j9RZihvE4jIua/5IjWBEQEUbJ+y40fy9ZqKoipoInLCm5Ime8Yr3PPELi5f0Yquq1y7qp2NA3ke2zKCqkBDwsBEJ1eNZA4VHHaMFGd0Ik6EgzOZw31fTeZoompz4USmQUokJzvSGZNIJCc1x7oe4XBUKzcO5Nk7XkFRoCGuE4SQjumc0p5icXPymCrF1Qyv3okK/RM24yWX1rSFH0aOWNzU6WlJMpB3DlqD0ztR4aXeHIEQpOPTa6kMVWG44FC0/XoKoIqCqiiESiRpDlWlPSFoTJpVp01B0xQqnk9frsJw3iEU4FTDFTuHS7Q0RAYxCPyAaqNViGkKrh/ihZGzEgrYO1GmP6+SNDVSMYMgjOqtNCVyWnRVRVMDdE1BhALXC1HVKAUw8MNIodHQiJsa/XmbhKVPMVQ1VWG06PCPD29lpOiwd6xMEEbNUI0wRKv28stVz23c1OnKxtg3XmG44LKxP082btLZEGOkFP3fDwW6FqkTlp2AiYqHqkQRu0xcJwgjBUXXjyJ8Zden5ES9AqOqtIixksPmwUI93W1hY2JKROGNqzrqEZiUpdOUMBkq2ASmYCDvYLtR7WIyplOwI2GS8VIkOlJ2A7YPlzhviVmP1Lx5TRcfuHQpDzywiSUtCRY3ZcgmonujIW5EMvslB12LjkVXFRQlevY0NWqi6wSCdEznrEVZmlMWTUmTbYPFKZGwMxcevvJrLdoUN1Se2T3BnrESoyW3mga5/3u1RryqqqAqoh4lC4nuMVON7tea6I2hKaiqSnMycjif3TvOBUujfoptKSuKagNlN0BXVRZUJ1dGS+6sTsTxdnBmYqb3lampLGqKc153E5auEYZi2lgPJwvgSDjRUUKJ5GRGOmMSieSkZcdwkYc3jR7zeoS5qFZuGyrw8xf6Kdo+2YRBQ8LECwRF22P7SJl0VZjiSIyv2RzM5W1pbru0m5ih8uimIfaNV0haOi0piwXZGKMl95A1OCXXp+z6QCTPPpmK6zNSdKi4Pqoa1V4JqDtItU3Won+GpnL2wgZe6s9juwGOH1JyIyEMpdoQtoYThuwZL9OeslAAt1aLFYTkKgJFiVI9g0BgmSqaolSVDXUaEiaIyCEMhECv/m1oCpqqoWsKthtg+yElJ8DQVJqSBm2ZGGsWZmlKmOwYKdUd686GGEMFh/68TUcmRt9ElKKoKFHtmwBShgYIKl5Yj/bpmkpbJkZT0uSd5y8mbel89w97GCo42F5AJmGgoLB3rMJY2aUhpuMoIYau4YeiLgoSCIHtByiATYDr7/cqhBBsHypF91XcoDFhThEF2TpU5JcbB6l4Pl1mpBC5rC1J3vboHa/g+gGiWsdVcqNUTl2DohNgj5VpiBv05yoU7DQJa3+kRk1HzkNrMoauKXUDuilp0dhtUrB99oyV2TxYoD1t4fghBccnCEI0LcQKYWFjHFNXq2m06hFFwma6X0eKDqMlh7GSG9U3hkT3wKT8Uz+MJg6o3qeTUxYhip6GoUAQYnu1yFHkdI2VXEZLLhA5ERMVj7XLmgGlXi+WrtZomro6qxNxvB2c2Zj8vtrYn48UOfM2P3qulwf0gRnfiUcTVZsLJzpKKJGczEhnTCKRnLR8+8k9jJT841KPcDDVyloKjuOHLGlKMFx0SFlg6SpmNVK0bahAQ9zgzIXZwzK+DlXwvrwtzd9efzqvP7Wt3kcp8qmUOdXgJE2dhKkD+1MdRbUB8WDeoVKVQo/pGgKB40fRKkQkHw/RzLapqWSTBk0pi85MnMGCTUNcYddogKZCU7VWyHY9ADTADkL25SowKaIRRcciy1kQ1R/Vol+CKAXO9QIsQyNuRE2VNSNqNGwZGnFdw9AUcorPgkad7uZkJLceQHPa4qYLF9PTst+xThgaP3m+j/6czYq2FAXbZ6LikU2YhEIwVnJxvABPVzANHVOParYcL5Jpb0gYdGZinNGZ4acv9BMKuHxlS72+KAiDqIZNiaKkth85W44X1cZNPu7o77DqHEcUbJ/RkgMoNKWsKXVotYhC70QFBPUITFPSYkV7it7xShR5q57foLoTRVHQNYUgjCI9Rcdn+0iR9nQMU1OnTBYsbUnyUn9xijMRtQSIzsU1p7fTlDDZPlxkouKiKirL21Kc193IloHilGjykUTCDiRhaIwUHUq2T8n2CcPoOROAFwbT6sREKKIIniLqYh5APZUxG9PRNJWSG+AGNmkrmlRorgqe1JyILis+pbl4jYM5EcfbwTkYqqrg+AGPbRme1gB6tnfi8exdOR9RQonkZEU+BRKJ5KQjrFpg4yWXFW2Zo6pHOJI0x1oKTlc2RmvapFitr0rFIuluU1fZPVrm/KVNh2V8zbXgXVUVLl3RyiXLWg577AuycVYvaGDncIlCxSOwBOMlj5LjU3A8hKj2hDJUTF2Loh+hwAsiw9dQIBACS4/qqTJxoxqZcembsAmFiGTno05UpC0dCBAo9bSy1pRBVzbB5oECjh/W4xuqAg0xHdPQKDkBmgIKCr05mwXZGNmEQcXzGS+5aGokmGKqKo0JnZihRTVzmoqlayzvSk0xKGuO9d6xMjtGSvX0KTeInKGCLbC9sBoJhPGyT0NcqUd6xsoeDXGDhKGzoj2NgHoaVs0hqinvOX7Ac7vHcfyQpKkzUnRxg0j4ota7CyVSkgwFvLA3R3smRsLS660EWlIWy1pT01K84qaGpkQqgf05u+401SJuuqZETp8CqogclEhghnpzZi8MeWHPOEnLYFlriornU0uTvOq0Nnrz7qzOxLvPX0zMUNkxUgIi521RYwJVVbjq1GMvYV51JyMFTS+I6r6qm9RmiIApQBBUj5+6UCcqkE2YUbqtEBhqlBo74PqcsyjLOYsagaN3InpaUly3qoOHNwzROx5NlMQM/Zg4OAfjSGu0jlfvyvmKEkokJyPSGZNIJCcd/TkbgI7M0dUjHKns8uQUHE1VOGtRNqqrKbuUHL8eSbh+deecja+5GlMz9Ys6HMNJVRXeuKqDTQMFnt41xmDBQQUUdX8URBECLxQ0WjpeKLA9nyCMjFhUED6UvICEqVbTBVUakxYFJ4q6hCIS4kiaOm1JHXBoy8Tw8w5BKDhvSVPk0AjBy335en8wtZoGpimRmIepqcQtnaSpMVxwMfWqyEcoqPgCCMlXokjSRT3N3HxJN61p66Dn5cD0qbLrk69ETmjM1DA1nVAIPD8kZ/uY1TqphoROY9xkcXOCa85oj9QdJ21HURQyVaEQIQT70hV2jpZojBsM5m2USYqDAjBUBava48rxA3rHKxi6ih8KmpIWK9v3y9NPpuIGxAyNN5zexv3rB9g6VKQjY7FvvFxX/TO0qGG1aWiEIsT1owinEBAoAkOPRFdiRiTAcc8Tu3n/hQsB6GlNzRotOaUjzUMbZn9ejkcPxIoX0JIyKdheXVa/loapKlPrw6Caokh0nhXA1BXa0hbjZS+q4YPqRqJJBVPX+KM1XfV+Y0fjREx+n1S8ABRoy8S46rR21i5rOa5CFUdTo3U8rtt8RgklkpMN6YxJJJKTjlqKUE3N7UDm2pz1SGWXD5w9n1xX4wZRPy4/CDmtMzPnY5qLMfXsnnE+/+BmRorOUdXILW9L87HXr+D2H77IlsFCZLwGAq3qRKqKQskNKLs+DXGdkuNHSoWArqhk0zpxXWP7UAnXF7SkLC7uaeaGs7r44oObiZsamZhBEAomKg4A+YqHF1TrwkJRPaY4G/sLkTNWVWv0QoEbBBhVCXvXF3zwdcvZPJjnyR2jDOQiYRBDhbihoaoqjh/y+2rPs0+86XQAtgwVZnTKJl+7lKUzkLOjtgRExx8IQdzQWZg1GCw4eIGgOWWyvCXFyo5MPbqxd6w8awRFUaL+coNVpb9avV0tmldL84ybOtmETtEOuOaMDlYtbKinUb7cn69/t8ZkZ+CSZS10NMR4cP0gL+wdZ9dICc8XuIToarRP2wswdRVdA6fasVmrqm1qqsLpXRl6WpJsHSryyKYhuibdHwdGSyqezz1P7D7hMuVJM6qJRMBQ3q63kVCUKF0xpipTGnT7VScspit0t6RImiorOjI8sW2EoYITRQ1DQInaCyRMjcbEfqf3SJ2IA98nXdXz05+zeWD9AJ0NseMq4/5KrNE6nmmQEsmrCemMSSSSk45ailDZDUjGp7/GDpVKdLSyyzPNntciI7XmrgdLwZkpNfJQxpTtBWwZLGB7ASvb00dtDMdNjcVNCZa2JKuGrGDvWJm87ZMwNfqqQgaOHxn3qhH1TGvPxLhgaRONCYMXe3MsbUly69qlLGpMEIaCHz3Xx5ahAglTY6jgooqoBs3UlUh4QYe+nE17Q5zmtEnC0nC8qCdZrRF0KqbTGNcpuyEJU+W0BWnefGYnN/2/v0dRFBKmSjpm1tPV4oZK3vZ5fm+OO3+ynrZMjIrnU3ZCGhMmV5zaypvPjKIfk69dezVi0paxGCu5lN1IAj1l6mhVQ10I+JPLerh8ZdsUx+5QEZSKF3LlqW1MlF32jJWqy0FTo/TPtKVHkS8l6rXWkrY4tSNy3t+4uoO+XIUX9k3QmDBJx3R0VWEg70xxBpa3pdnZUeK+Z/eRq/j1dM8w3N+Y2am2IoBIqr8tHYlWhAJaq20NOhti7Bgu0RXbf39MjpaEoeCrv9o+RV5+vBzJ+C9vTbJ1qMT3nt7LDWcvIG0ZxyTNrUbtPJccn9aUyWjZI2lq9Uiq7Ydk4wYFx6+ONeo3pigKI0WHEaJ+Y4amsqorQ9EJ8MIQQ43aKYwUXZ7ZPc4bTtvvYB2uE/FKkHF/pdZoHa80SInk1YR0xiQSySuGudZvdTbEeAEYyNv0xMzDrkc4Wtnl2WbPy47PjpESKUtn9cKGGfc9W2rkmYsasDSVwXwFU9emKLgJIdg8UMAPBMtbU3Vj62iMvZLr4wQhPY2pulBBQ9zg+b0TVNyA5pTJYN6p9pCK0ge7WxKsXpCtp88ta00xUY7k21U1+nPL2m7+/hcb2TlaRgUaq/2zKm6IZag0xHQqXsD24SIr26JUvFzZpeIJkqZGZ4OFqqqUHB9dV1nUGCdtGTzfO0HvRAVTU4iZOpMvm6oqGJpC0fHYNFgAhahZdMXDC0Ie3jTIt3+/mw9duZyrTmuvX7ttw0Uqnr8/8lKMImFFN2rwrKuRFP+2wRIX9QRTzu1cIig3XbgYTVV4cV+eouPRGDfQNAVdjeoKAQbzDg0xg5ihsmkgT9LUCcMohXC44LBtsAgKNMRNLu5p4sYLF9edgV9uHORz929mX64cjamaBlnTR1FFtfdWtX5KUxQmKh5jZY8FjXFSVhRZjpsaI/lg2j1Sex63Dxd5cd8ECVPl6d0TjJejJsu6FvUec/2Ql/tybBks0JSwjomi6UznuT0bp+AGVKrNv0W13UHZDVGIUlh1Tat+JvCCENsLGS97LGyMoapqvZ+bqIq1dGZjDOXtac/64TgRk98nEEWBJ6swnggZ91dyjdbxSIOUSF5NSGdMIpG8Ijic+q2aQdSYNI+oHuFYpPQcOHu+bajISDFSwRMC7nu2lxf35qaM/2CpkRv68/Tnyuwbr2BVnbG2jMXytjSaEtXJdWZj9bqkGkfas2emmfSmpFWvfxssRP2KDFWhK5tgWWuSRU2JKUbeTOfpqtPaGSk6fPHBzVS8gKIdGflNKZNFzWlGig75isdg3qanJUlTwiRf8cnEFBKWRqUaiWtNW+iqyjmLG1mQjbO+L4frhyhKlE44GSGoN5MOQsFLvXmCUBA3NVJWJAayebDAZ3+xqT7GW9d2872n9rJ7tMxo0SVmRJHCibJHEEYqk6oCtheyoX+C//OQzU0XLOaSSbU/c4mghKHgdStaeGjjIG4oSJuRep8bhBTsyCFuMU3u/cNenGqK63DBIRM3uHBpM0EoKNgeY2WXirdfhtL3Q+5+fBcjJYcw3C8MUmsn4Fdr0xDUxUK8MMT2owjkvrEyv9k2wuoF2XoLhslMfh6HizabBwqAQkxXaUpZGDGdgu2xYziK+qUsnY5MnISpHfPUxcnn2dRUtgwWq+0XooNOWTqKgIofkonpqGr0DFaqdY0TFZ/BvEMmpmMZOl4Q1nvzrWxPk694s6ojzuV5qr1PbE9jY//4FGe1MWHS3ZLA8YPjmiIoa7QkkpMX6YxJJJJ550jrt9574eJ6n7HDqUc4Vik9tdnzJ7aP8J0/7EFRoKclSdIypo2/pyU1ayqT6wc8vHGIihcShgFF28fQVMbLLgM5m8akga4pnNKemRbJgyOrB5ltJr0paZFdEqUgti7Kkq9EUZRMfGYxiZnO05pFWc5b0kjc1PB9H+jjTas6UTSdsZLD1sEie8fL7B4r0Zg08UNRjyBoqlJ1QHyaU1bdgGxOmlGjZEfUe43VCEIRqRUqkSCHpqpk40bd8ExYCp4fMFFxueeJXVy+opXlbWn+5tpTAYUN/TmWtSTZMlhkLHQRAsZKLhUvaphccny2D5fYPVLiutWdvHFVR/3+OlQERVUVbrpoMUNFhy2DBQr2/mvkhwJLU0mYOo1Jk7ih8fsdowzkbYIwxG9ORPWISZNFTYkpEdCn94yxdTBPGIqqOiD4Iqp9U9mvpAj7Uxa9QBAzVBKGhhsI9oyV8QNBY8Lkkp4sFKLvHfg8Ji2N9b15bC9AWFETYUVTKNpBXTDDDUJiunrcUvNq5/mPz+oiV3HZNVpirOTy8MtDJE2Vx3eMRY2a60I0YOoqrhcS0yOFyfGyj2WE6GrUL25ZawpDU3C88KjS95KmjuuHPLN7jCAUpGIGRkzHCwTDBZuxksOipsRxTxE8njVaR6I6K5FI5oZ0xiQSybxyNPUWPa0p/ntH9ojk3Y9lSs8Le3MIAWsWZmcd//VnqjOmRgohWN+Xp+j4ICL1NccPKbsBthdgeyHJmM6KthQxQ51x/0dSD3KomfSFjQluvribhzYMsr4vRzpmzPk8JU29Kk5hkLFiUIn2J4icvdM6FRoSBjdesDiqB3I9fvhMH9uHi4QiJBs3OXNhljec1o6la2wayNOWsuhpSfLCvhyO66NZRj1VMQijmjNNVRChIBHTptwDmqLgoZCJ6ewcKfHs3nEuWNqMrqu88/yFfONxn11jZfZNlCk5PkEY9T4TIlrXF1FkKW/7PLVrjP6cPWWC4FARlJpgyvef3sPLfXm8UJCNG1TcAEVROHtxdN9EEZqAzkws6gU2XKIxYdZrEmsR0Ce2j/C9p/cyVvYIhSAMIVAVdA3CmuplVTFQrQpdJC2dIAwRKKiaiqWC6wcM5G00VeGKU1rZ8vSmGZ/HXCVqJaApUT+6oYJNW9qi4gVYuoo9KWIHRx6tPRS187yIBKsWZNk0kOf3O8YIw6gXnnHAc68pCiiQtHTyts/yliRdTYl6+iBwRPWdB75fOjMxHC9kouKxuDGOqkbPqaUrGAmDPeMV2v2Qzkxspl0cU45HjdaRqs5KJJK5IZ0xiUQyrxyL+q3DNfaOZUrPXMe/c6Q0Y2pk3vbYN16JanqqRnNLSosUGUPBeMkhDAQ9LSn2TVSmOI9CCPIVj23DRU7vyhy2sTd5Jn3bUIGdIx6qAsvaUrz9nEWs7Eijqhz0PL3htPZpht9kZzfdOvV4hRAM5B3WLMzyuhWt7Bgp8ssNwwwXbAIRpSC2piNp9wNl1NsyMdKxMhNll8D2MLRIot32IqcmaemRgqA21WkNqqqECVNnpOgwWnKnnYNv/m43z+4eJxQQ01W8IBIdSVk6ICh7UT+yroYYo0X3sAQrtg0VeGjDICNFF9NQiSsqLSmToYLDkuZk/Xq6QaTCacR0UorOWMmlYPv11NS4qbFtqMh3/rCHsWK111oQ9RALhEAECqYGgVAIquqJgYi2m1EVGpMxyk5AxQsIwxAvEDQldVKxKFIM0f384r4J4qZGwfZJx6I+aZ4ffT/wfCpegBeEOH5IWK1/i5sa3iSN+ROh3leLcDte1JPO9kMMTUEhakcQiEh5MWGolN2Qsh85j3FTo+j4h3zW5+qE9OdtLEOlMWEwXvbq/QZr6ZDZuIGpq/Tn7RNSO3Usa7SORnVWIpHMDemMSSSSeWW+JJmPVUrPXMcPzJgaOV72cKoS5KCgVaMglqFhAaoKo0WXntYkZS+oO0W2F7B5oEB/zkbXFGKGxr/9escRydyHZwhyFY9cxaPoBmwbLPCDZ/by9nMjh2yqw+aiKirLWlN0tyb4zh9201+Vh48b+43VmrO7fbhETzqKXpW8cIoBvGOkOMXQW9CYoOz6bBwo8MjmYTozMVa0p+oGYH/OZmV7mn1jJfaNVyi5UWGUoSkkLY2YruJ4kcy5pdYcVnD9kKSlE4ZRT7TmA/p3LW9L86bVHTz08gBxU8PSo2tm6LUGwwp6tUnwaMlltOjOKFjR0zI9IjHbMW4ZLLBnrEx7Jk666kObmoquqXhBNM6SE7VKqFF2fEaKDooC5y1pZM9YORpn1fAPQkFlv3gi0cgjCXfbCwiFoD0TIxVojBRclCDAD0J2jZT41u/3sAb4Pw9u4nc7xjF1jZSp0ZAwyFV8AiFIWBqeH+L4IuonF0IsodGUNPGDaFkt6nQi1PtqTv/vdgyjEAln6CqoqoquRs9R2tKwfcGpnWkuXdbCztHynJ71w3FCSq6PqUf1jbtGyvV+g1o1HbK7OUFulrq0VzK1KOlo0aGjGrEXInLQV7SlTohKpETyWkA6YxLJa4xXWu7/fEoyzzWl52DnbK7j72lJzpoaGVabLGcsva6yt5/oe53ZOOcvbeLB9YM8t3ecLYORumJnNsYp7RlihnpEs9Xbhgrc88Ru9oyVKTs+Rcdn0A/YNFDkyZ1jfOyqFVx1Wjvh6ZCruORtj4Lt8cuNA4w+HRm/DQmT1pRFPBubMoZb13az7qU+KPaxe7SMrht1A7inJVWXS5+cnpqydHw/pGB7tKbM+rmqpX0+t3eCpKVz5sIGNFUlV3bpz1UoOT6Fik8I2L5LJqZhGVEtj6EpZOM6w0WXlW1pWtNWXbmwdi0zMYN0zCAIwyjiBHWhkJpAiKLAjuESQkQpkZMFKzZWUyknKl49itLTmmSs6M6Ygru8NcWO4RKbB/O0pFrqjcIbEybDBZukpUUy+Np+9b8dIyVAoacliaapnLukkYc2DuL5IZoKwQGCiGqUpUdYTbf0AsFQwSEMBRUvIBPXySYsSq7P73aMsKYHfrl5mEqgAAHjCvTmKphaJITiBoKkpWNogtZ0FNlzvIDhgoOqKqzvncDQNBrjBrqucnFP83FV71NVhVM709z3fC+oKpoaydoTCip+iKpGjaFb0xYfumI5V57SNqd33+GmTtfeATFD47zuxnq/wZpjWnT8KN34BMvKHy29ExWe2zvOeMll12h5iijJ8rbUCVGJlEheC5xcbwaJRHJUvBJz/+dbkvlQKT2HOmdzHf/CxsS01MiYoeH6AaAQBIJsYvr6ubJHQ9xkaUuSJc1Jul+X5PMPbsb2Apa3psjEjSmOzOHMVteMzj1jZcZLDrYXkorpZOKRqMhAzuaLD25mz1iJ5/fmcLyAhrhBf85mtOTi+ALD0qr9mhxKrs+ahQ2MllzWvTzIBy9fxgcuXcoDD2zizy9fRjpuIYhU7p7ePca2ocK09M6C7TNe8WhOmoyXvSlpelCLDrlcsLSRTQMFto+UCENRlTWP1PXcUDBRCYj7gsaEQdzUGC66xHSN1pTJV365bdq1TMcMFjcn2DdepmB7QCQMghJF1upNqYOQbMLE8SPBClGty3p29zhJS+PS5S10WVEU5aldY+wZLddrwiaTiRt0NsTon7DJVzwaqo2HOzIWwwWb3gmbJU2JarqgR99ENfpoKgRhdG/0tKa42PH5w84xyu5+T0wlksaPmSphKCi5AUXXJ21p5MoeihLdKy1Ji7LrY6gqe8fy0LNf9AOiFMcggCAIiBkqmgJFJyAdj+4R2wvonbAxNMGCbIxswqTiBuwYLZGJGZzSkT6uEz1hKNjUX6AzE6M1ZbJnrMxoya06zgoKkE0Y/M83nspVp7UDzMlpONzU6cnvgBVtqSn36/F+hx3PybWNA3m2DBYwVJV0fKooSdHxWbUgg11tU/FKmdyTSE5G5tUZ+/Wvf80XvvAFnnnmGfr7+7nvvvu44YYb5rTu448/zuWXX86qVat4/vnnj+s4JZJXA6/U3P9XiiSz74c8u3ec4YKDQNDdkmQwX+GLP1/P5mGXkMjIPavDomi7U87ZXMc/OTXyub3j7BkrU3EDDE3F9nx6J2zaM4J0zMCrSp+HQnBxTxOLGiMjsj9vM1J0WNmenhaJO1zhhN6JCtuGCpSrM/dNSXNSPVqkSLdrtMT/WbcVS4+c1jCkmoKlkI5FKXVFO6CzIWqgvGOkzCntKbYNFdkzWmIgF0mfbxkosG9ihJ2jZWw/wPEC9o5XOG9JE+lYZLQWbJ+hgh31/kpa5GxvSppewY76fykKrO/N0ztRQQhB3FARKPhB1O24LW0yVnIJQkEowPUFCxvjJE2d0bJLU8KkJWmhqUr9/r/54m7OXtSI44d4fkDJLVF0/Eh9sNr82Q1CGuI6JccnFdPZPFBgvOwyVHAoez5lV2ffeIUFWfBCQUM8UtXsm4gEUSYb9oqicEpHmuGiw7bhIm1pi74Jm+GiQ67s4ocwUfZY35vD1FUcL+qp1Z9zmCiP0J6OsawtyZkLszTEdB7dMoztBXh+pEyZjhn1fnB9ExVyFY+CE+AHkXhIU9Ikb/sYmsJQwWayBoemRNG0ehNpIF/2aEmbaKpO3NCYKHuU3RBLV1nYFEdVVHIVD11V6WlJoqsqmwcKXHlK25wmBY7Eoag5TSvaU6QsnVM7Mtiez3jJw/YC/FAQN1VWtqcOua3JHG7q9Hy9w3YMF+tqssd6ci0MBU/vHKuqbWpY+n5REjMZPV8v7J1ACMF3n9yDpimviMk9ieRkZF6dsVKpxJo1a7jtttt461vfOuf1JiYmeP/7389VV13F4ODgcRyhRPLq4GgUC08Ex1OSeS78cuMgdz++i61DBYpVByiEaSpxIfDsgAMDw5zeGUXFelpShzX+Wo3WlqECbWmLzoYYuqrwux1jjBQd+iZsGuJRDZmmKqxZlOXGCxfXr8uxrLEruVEUqlh1Lmr3RcX1GcjbVNzIeHd9n1BE/Z2CUNCUNAkFWKqKooiqoIMgFdOrThDsGSvz8e+9QK5s87GVcNfPNqBoOmcvbuDUjgaG8jYb+ws8s3uMUzrSjBTcai+tgPGSR8UJSMb0KWIcbhDieAGOFwldBNUasFoURNcUXF+goLCsJcFY2ec9Fy7mgqVN/OLFPn69dQwhQnYpJeK6RlPSoqc1wWjJ5eGNg1x9Rht9uQqjRZdzFhtsGshjuwEIQczQAEHJCVFVhZLjU7T9KNLnRoZ/zvN4dMswSVOjIW5gqCpuEDkaB0b4IIperWxP05gweHrXOBUvIGnpLG9L09lgMVb2qr3Tov5qLUmTkuMzVnIZzFfI2x4r2lOR4xfTSZo6ZTego8EiM0n9srslQd+EjaLASNHBNNS6iImqwETFoybUqRA54ZoCYbg/UuaJqPH0ed1NGJrKWMnlub3jZOI6l/REaZYHpuZtHSzw9O4xMnFjVierFnneNlRgvOKiVesR337eAla2Zw55/9aeBUVRyMQN/DAkb/uMlV28IFIj/Y/f7uK9Fy+e83vkSFKn5+Md9u0n9zBS8o/L5FrvRIXhgkNnQ4xcxcPStfr9pCiRQMqukRLtDTG6srEZ23lIh0wimRvz6oxdd911XHfddYe93gc/+EFuuukmNE3jRz/60bEfmETyKuNoFQtPBMdDknku/HLjIJ+9fxPjJZcgjBoO277A9sVB19vQX8DQBnjzmi4WNSUOq/7soZeHcP2QcxY31q/HZSta2DpYYMdIGVWFZS1J1izKcu2knlZwbGvskqaOpoDjB3VHQQjBWMnD9kK8IERU4yNxQ8MLQipeJGJh6QqBiFLXPBH1/orpGiXHZ8tgnk0DeWKGxoJ0FJ1RlSg98dndORKmQXdzgiVNCbYMFZnYMUrK0knHDdKWjlN1EhVFwfUD8pXIEbM9P+rFJgRJQ0cID+2A86uqCo4fYhgmmhqwvD3NrtEyP35hADeIopC6quBqUfuAguOxoi2K5L15TRe3ru3mO7/fw+93jmF70fHafqTGGISCmKniBwLbC0nHdPaMVXCqDacFREIWto8IBU0pk1AIRooOQwV7xvS1sxc1EoYhQwWHBdk4lq6RrjrGCxtDfvJCP0XHpyVp0DcRKU46QYgbwEgxqpeL6SpjZY+kpdORsfCDqfeuHwoyMZ1MXEdTFVTA1KIUvpITMFJwp3w/csgUFA3C6rYUYGFjguaUBUT3jOuHdDUnp6TK1rC9gJf783ztV9sJEdOcrDAUUX++J3ezZ7TEWDm651QFNvTleHLnaL1e8WD37+RnYazk8PzeCSpuQCpWq7/02TkaiajM1UE40tTpE/UOC6uqleMllxVtmeMyuVZyo4bkp3Skeak3x1jJ3a8S6YcM5W0EcHpnpt6D8JUyuSeRnGycdDVj3/jGN9ixYwff/va3+bu/+7tDft9xHBzHqf8/n88D4Hkenucdt3FOprafE7U/yZHzar1W+bKN53ukDBNFBNM+Txow4nvR99LTDfwTSUfaAKIxBIE/TZQAjt118v2Qbz+xA8dxyZhQ8cDSNSoFH0s79Pqb+icYLZaqY57b+HvHK+wazrMgY6KyX/quOaHT1J2luynOeMnh1rWLOXtRI6qqTDnOlrhGW1Jn02COnpZU3XCHyFAcypU5oytDW1I/5PlpS+qsaImzfTCPCHz0ag1bEHjoIiBUBHEjingEftQHzVQFiAARQOAJTFPH0iCmCgh9TEWwc6iAqQpWNFsoIjrAhrhGMlQo2D4besfobjRZ0ZZg90iBouPTnjJJ6OAFPilLBaERhgGPbx0kYep4YYjnCzQlRFFC0qZCTBNohOiqghACH4gbCroa4ns+SUOhXHb55hM7CQOPppiBrqkEQuD5AQEhFVswlC/TGDfJl210VcHzfTozOqe3N5GwomjfntEyQwWH0XwFLwgxVJVC2SEIAswDNFcE4Po+o4UAS1MIEGzYN0ZHyiBhaVTckIG8TUvSZHVXkp++0M+KlgSpWO0nObov+ifKlCt2FIXUTVKWFolw+D65igcIRKCSSugYqo7jh6iEmCoUyg6pmIauKpQqHqausrIlgSpCenM2i7IxFFVFhCFxQ6BVb0RTFQTVOjgAXYlSPRXAUALCwKPihgzmSjRYGouyU+9jgPGyy4t7xilVXMb1qNm0G4RsH8zx7K5h/ttZC8jbHj97oZ+94yUOCECjK9Gz/dVHNtOVNlk+S5phW1JneUucDf15UkaC3cMFfM+nLRU9f+MljwUNFmu6UuwYKfPQ+j4WrV06JwfhDac2M5ArsWMoT0cmRtxUp1y3q05pnvX9NJd32JHg+yEv9E6wtT9HBuhI69POvQIsyJjsHMqzZ6TAgsYjq1OLqZDUFRK6wjmLMuwcLjFe9nDdKFpradCUMOlITf1NOVb7fzXwarUnXo3M9zVShBAHn/49QSiKcsiasa1bt3LppZfym9/8hpUrV3LHHXfwox/96KA1Y3fccQd33nnntOXf+c53SCSk+o9EIpFIJBKJRPJapVwuc9NNN5HL5chkDp4efTw4aSJjQRBw0003ceedd7Jy5co5r3f77bfz8Y9/vP7/fD7PokWLuOaaa07YCfc8j4ceeoirr74aw5jfqIPk4Lxar1UYCv7f3+5kQ3+eZa3JaWk324dLnNGV4bY5zhrPN8fqOj20cZD//YuNZBMmQ3mbmKGRr3iUvLlPZf+Pa1ZyyyVL5/z93vEK//LoNhrixqRIyH6KdhT1+PCVy6fMKu8YLvLtJ/cwXnKJGyo7hkv0TlSoeAGqotCRsVi7vJV3nLeQvWNl/r8n97BnrBxFcTSVxU0J3nPhYi4/pW3aPh/bPMTXHtvOSNGNaojKbtSrS9cIRa15sCAMBQoCL9LJQFMVDE0lmzAisQRDY0lzgvW9ORY3J9BUFeH7vGvBBP+0OU5IpO5XsH3WrmghmzD5/Y4RTE1jVVcG09AwVZWkpfL83hxDBZsgFJzamaEtFSMV0xBCcP/6QYqOj6UrjBRdQiGiZr5G1Cw7BNrTMW5e282jGwfZMVLED6MUzpih1u9/P4wiZKqq8sYzOnjvRUv46q+20xA38MKQl/blqLgBZdfH8SKp9LIbEISRtH3FD+v1VX71nAiqaX7Vf6ctnQWNcUZLLpcsa+a9Fy8hbUZKiqqq1O8HiNLfRoouXrX583jZxa8qRSZNg6QVpZ+OlFwUJXquswmTtctaSMd1xssum/vzDBddlrYksHSN9kyMK05p5cKlzWwbLvK1x7aTjZvsGi0xUfbwwxDbC5goVrjj3JD/+2kVJ4xSGQVR/VgmZvDm1V3cdNHiqK7N1OlsiPGbrcP1+8bQFUxNw9RUhoo2QkDC0GjLWFMit3vHyuTKHjFTJWcf/DnTgLXLm/nE9WccNMKyY7jIvU/t5ZHNQ8R1LZJfTxosbUnRmKhGqMKQ3aNl/vzyZaxsn3stUxhG16WWdli7bieSxzYP8aWHtlJ0PJoSJpYK71k0wd8/b6BoOhcva2ZJ8/7J5dneIYfL5HfO5OjgztEi+8ZszlyYYUHj9EntY7X/k51Xqz3xamR0dHRe93/SOGOFQoGnn36a5557jo985CMAhGGIEAJd11m3bh2vf/3rp61nWRaWZU1bbhjGCX845mOfkiPj1XitrlndRW/eZctwZQa1rxhXr+rCssxDb+gVxEzX6XCU2VrScYSiUfEFnlARAfioOEE44/dnorMxeVj3yuIWne7WTCSDHTOnOca9eZfVCxpY3LJfFjwMBQ9vGmWk5NOctHhhX46KG9KRTRKEgtGSSyVQKHkhf9id457f7aZgR/Lw2ep13jBY4n+v24ai6dPqcN6wagGLW9P84Oletg7mKQ/kKZZcDEXFDSLpfS8UeD4IFBQlUpZMGjqarrCwKc2ythRXndaGrin89fdfJO8I0jEVTYvyPUuuQNUU3EDgo2IZBpqqUXIhkzVozyaBSDFx94RLb87F0nVQoSWdIFWtt1KA1YsaeXbPBO0Zi45sit0jRfKOT7kSoKsqp3Wm+e9XRIbgAxuGUTUDS4eSBzknxNSitEYvFJTdkIa4xqpFTdghlHxBm2mwYc8EeSckaRkMlXx0TQMFFE1BUQReGOKHCrqm4Ie1XnHUxwiRI5OMm6BqmIbBRCUkm4jX6zLDUKBqGl6o8Nvto3VJ9iAMq6Ig0dZ0DRKKyrgdMmFHDlrCVCm4Ie1Zg2TcRCgK2WScc5ZabOzP87bzF7Gqq2HK/Z9JxDB0A8PQOXtJ85R+WHtH88AQTqjgBkq9VUBT0uKcJY28++JueibVW20bKvDo1jHilkWzolF0fEpeyFDRqdbTGaQSMQLUehpdruIyUg5wfch74aQzNZWaIwvQl/ewQw76jJ3S1cjNl5r05lzipkZjwqyn79a2U/JCdN2IzsFhvtu72+bnvRiGgj2jJf71sV0Mlzy6m+JomoZG1YlVFApuyDN7cyxsSqKq6qzvkCPhlK5Gbl6r10VJnIKLpWucs6SVJc0O/XmbEHVO77DXMq9Ge+LVxnxfn5PGGctkMrz00ktTlv3rv/4rjzzyCD/4wQ9YunTuM9MSyWuR+VYsPBEcbh+1cxY10t2cZMtggZiuUPaiBsFzpcmAa07tOKwxHokMdk2ApSMTY/NAgYobTJGh1zQF2w3oHbd5YvsYFc9nSVMCVY2KmdIxlaSpsWe8wj1P7OLyFa3oBzSXXtme4e3nKvzgmb2UvZCSk6Nge/hhFPnRVAWt2scLRZA0DdYuayLvBNx26VJet6IVVVXw/TA6p0MFkqYW9f4iMuyLjocTQHMyqn8ayDu0pi0Shs5YyWHHcJmxskvZ9RktOli6xuLmBOkDIoid2TiLiy49LSnytkdjVWWwMWly+cpW/vjMLnRdZe9Ymca4QaHikat4tKcthooO+YqHF4R1tcCKG/LzF/vY1J/C9UOGCw5j5UiwIJLHjwQoAiFQFYXGlBE1Oq5Gp1RVQVUUlGoUS1NBhKDrKpmYznjJoyGu4/g+BSeqTZisIvjUrjHGSy6qopC09LpAA0SOiVpTKtRVbC/EDUJCO8TQNHpaUlOMYdsLaEyYrOpqmCbGM1mYYnlrcspnp3dmwBliVWcGr7r79nSMsxY3ThORmazOevbiLEDdsbPdgMe2DlN2AybfYhXXZzDv4AWRSMdk6fyDoSjKnMRoFjUmOHNhlvV9uSl1lHBi+hUea2r3x5M7R9k4kMfQVAbyDk1Ji7QVHZthaKhByFjJZd94hcakecyl9GcTJdkxEomizGc7Eonk1cK8OmPFYpFt27bV/79z506ef/55mpqaWLx4Mbfffju9vb1885vfRFVVVq1aNWX9trY2YrHYtOUSiWRm5kux8ERwJH3UdF3llrXddTVFISKZ9rnyV286A9Ocg9LHARyuY1yT8E6Fet1JmGxsGppKUfiESshwwaYrG687YjVUVaU5abJzpMSze8e5YGnzlM+3DRW453fR+Tu9I0PF83lpXz5SCBRMUejTFLD9gOf2TnBaZ4ZlrftV0yaf0z3jFTqqYgppS2fCdtFVhY4Gi7wdcObCBt5x3kLue66Xx7aMoCrQkDBA6Izi4gaCkhMwXvZoTBh1g9/1Q5qTJrdd2o2iKLPeywuycZa3pRkpuTh+QM728PwgUoCsfsfSFRpiUX8wxxcUbI+xkoMXBJETKEJURcEPQ7xAkDR1mpImfigoOwHjZZcwEHUnvtYoWSGKHu4aLaMqKl4QMl72+NGzvfT32DyyaShSqLM0bD/AMlTCEMpegAhDNFUFwshpEaApkWw/1XTRUFPobk6wqGm/c3Eop6M2EbBxIM+DGwajpta186DCsh74k8t7aE7FI3XLmDHj+2EmddZ0TKdg+whD0JQw2TNWouQEmHr0TI0VXTw/qKe3hiISCpmJ2mIF6GlNzMmBeqX0KzwWTH6X6VrUtiFmqJTcADewMRqiSF17OkaIy1jJY/dYCUVRjsvkmqoq0xz718LknkRyophXZ+zpp5/myiuvrP+/Vtt18803c/fdd9Pf38+ePXvma3gSyauSmX5YT3aOpo9aLWWv1mfM8UPmMmf/gUu7ed/F3Uc85sNxjGsS3lGkKsTQpr66vSBEV1VUouiNeUDUq0bc1BgrufUeUzUmnz9dhQde7me46Mx6FhRAhIKRoktfLupHNpnJ57RvvAhETsaKthTXnNHB5ae0kraMupH9+NYR4qaGSlSTpSsKzUkTIaKo1Eu9E8R1jfGKhxcEVNyQZa0pbD84aC+qyQY6AsZKLo4f4gcCIaLzsSAbJ5swqv3RIrn60aJL2QmwdJ+EqWFokQpkwtRIWRoFO+rhtmpBmhd787heSCjCKemJqgKBH+IIla4GA1WBbNJk92iZ32wdIW6qnLkgy1g5GlPair5TcHw8oZCuRuVyFQ83iBwaU9cwdBUUhYaEQTpmUHT8Qzodk1N3RwoOQuwPSykIHD+k7EfX8PtP7SWbjNcjyjPdjwf2uhsruWwbKkY1bkGIX222vW24iEpUb1jtx11PcU2YGgXn4BMfSUvjg69bPmcHquYgPPDSAC/15ih7PglD58yFDdOie69UDnyX9eUq6JpKKCBuqFS8yKkHiJka2biJAG68YAkX9TSf0Mm1V/PknkRyIplXZ+yKK67gYGKOd99990HXv+OOO7jjjjuO7aAkEslJx9H2UbvqtHYuX9HKs3vHGczZ/Muj2xjIV1iYTTBWchjIu/Xmt2lL48yFWW5/42lHPe65Osa19LI/7BpFUxS8IMTSo4icEFFfq7ZMjKSlViMoM9e8Vdyoz1ZzcmoNTO38+UHI73eMU3RmbxitKZFBHVRT8uKGxsMbB1neNtXRrZ3Tnz6/F3qfZ1lLCtPU2TpYJAypG/p7x8pMVDzWLmsGonQ8Q1WYKLu83J8nV/EYzFVoSpqkYgYIhXS1fuyeJ3YfsndUzUD/3lN72TVaIh2LImyZhEZHOkbCin4GUzGd8bLH6gUZYrpGytLpnajg+iFxU6vLs9dFU4DRkktM14gZKl6gkI6plN1IUKVW+6UokKt4dGVjLMjG2TtWZtdoCUvXKDkBiqIQhgKBQFVVYnokQuIFIW4gIudFRKmKCIHtRc72O85diKaoh4xKTE7drXgBu0dL+KHg/O5GTF1juOiwdbCAYkTXzvVDGuL6QSPKk/t7eYGo9vbyScUMjFiUciqAIBAEgKruFzYRQBCCbirEDYWKN7MNYKoKt65dyukLGma9trNSU1Cp/vsVIRk9Rw58l3Vm4mTjBqMlFzMe9U6rRe9FGDJadjmlPc1bzlowLfX4RPBqnNyTSE40J03NmEQikczGgTP1BxI3NQbzkSLabOi6Wk/dS1g6n71/E8Mll+akRWdjgoobMFpyycQMbrt06Qk1fGoRnt6JCv0TNuMll9a0hR9Gjljc1OlpSTJScGhNx6I6qoQxJVUxDKNmzae0pzlnUeOU7Zdcn4rrs6k/j+1FaXwoKn4YThFTgP21PpauRiqODdasju6usRLP7p3gPBV6WlPELHNa6qgfCmw/oMuKo6kKYyWXzYNRlMXxQoq2j+NHjkkooL0hxrLWSCVvrs1ll7elueGcBWwZKhDTNTYO5GlNWdVUwAhDUyk6PpqqYBkqf3L+Un7x0gCjRYekqbFtqMBQIagbwroWKUNWXB8/FJiaSjZhsmpBnLGSy/bhEqqqoKCgqgodDTF2jkQKhroaCWSoqkLZ8QkFlJ2ATFzF0KL6s7JXTelTFAxDYVFjHE1TyVdcYoaOpqj8+et66M/bs0YlDkzdTQU6WwYL+IHgxd48axY2MFZ0CUJBWypy0HMVH1BY0Zaa9fzWJgde6p0gV/GouH69hlEIwXjJQ1OiZyqqMxTYfrUxtgBB1DTb1DUEAfYkh0xXoCll8uErl3PzYaiUHni8C7JxEqZO2fV5uS9Pf86uO5aHI/JzojnwXaaqCmctzvKbrSPkKj4xQ0WvTg3tnbDJxExuvqR7XhwxiURybJDOmEQiOemZPFOfjk1XRaq4AZauzUkIAKam2e0aLTFWcjE0lVPa09x8Sfc0NcITwfK2NLdd2o2lKzy0YZCdIyWSlk5HJsbCqnR6c9riT1a0cM/vdrNnvEJz0qynsNUcyZkMt6SpU3IDxiseMT1KhVIVpjliAIYGCgq6qmLqSpQqZ/vTHN1autV4yYV0FHkSijItdfT6MztnjbKYmkKu4iJQiRkap3WkWdSUqEc/DxXxnEzaMmhKWOiqQtzQ8UOBNuk01FI9gzCS9D+tI0PS1Fn38gCPbRkmb3toikLC0MgmTUpOgB8EhIKqsAcMFx0MTWVJc4KxskfK0tGUKPVyuODWhVdKjk8gBLqq0Ja2mKh42G5A2fHQ9Sgt0vbCqPmyqpCNGZiGSskJaEiYrGhLsX24SH/envW4Z0rdHSk6KAq0pk0myh4b+vOUHH9KDaIfRgIhkyPKe0ZLDBWd6B5LmpyzqJFrV7WzZajA7n05sgmj2ug6YLzk4oUCU9cw9UjdryFu0D9hR20W9Ejh0NBUUqZOa8oipqs0pQxWLchyameaN57Wedi1mHNNVQ6F4KGXh+Ys8nMs8f2QZ/eOTzmPMz2LB77LlrZETa+f3zPBWNnFF5EztqItxXsu7pmX95FEIjl2SGdMIpGc9CzIxulpSfLU7jEWZONYurZf2voIldQmpy4ezHg60TSnLJa0JNk3VsH1AyYqLpm4wTmLG+spal3Z+GE5krW6KS8Iiek6SjW1S1WYJrIgqn80VSETNwhDZnR0JytAHujRTTb0FZg1ylJyQvwQGhMGmqowWHCmOB9ziXhOPsaeliR/2DWGqSmMl1za0lZdDrxo+7SmLQq2T1c2zk+e7+P5fRNsHyoymHfQ1OheysQNHC8kFIKYoeH4IaEHmhHl4hVsn/6cTUxX66Ieoro8E9cxNRVTj6JwKpGwSmcmRu9EhVBEEwe6GqX26YqKrqnEDBXHF7RlYixrTZKJG+waKR30uGdK3TU1FV1V8UMRpWWWXEKiYxJVAz8MBY4XIIQgbmq8uC/Hx7/3AsNFh4oXoKtRlO7PL1/O9as72diXJwgFE2UXTY2ig04Q4nhRuqntRyIshq5G6a1C1MsTkjGNXMUnacX42z8646D1f4diLqnKz+4ZZ/NgAdcP5yzyc6z45cbB+jNZ6/3XkbH4ozVdvP7U9np0brLiZcra7yQvbUmxuDHB07vH6WowgX38y43nEI9Pb90jkUhOLqQzJpFITnp2jBQZK7vsGS2zaaBAytJpSZksyMapeOERK6lNTl2cbyanYJ3SnuashVmGCw59uQoJU+OMBRlcP+QPO0fpzMa467+dwUDBZrzsHdSRrKVsndKe5uENgzh+VT1wFglyEULCipzdjkyMgu1z5sLpju7+dCsTnOnHU3Okyl4wa5SlYHuoqoKla1iayljRqTo1UcTgYBHPA1PRKp7PWNll71iZvO3j+gF526cpYQAKuh45KrqmMlRw2DpUZLiwP5qDACeIGlZ7QYimKthetJ9ACEquR8zQiRkqZSfaZ67igqKQiukUHQ+jGoozdZUkOkXHR1EVkjGdTNyoqgwS1QgVHTobYixuSiKqIcrGhEEmHol2mJpKvuKxaSA/Y6rdTKm76ZhOU8JkqGDXz7OCQsH2cBwPOqL6tpd6c/RO2IBg00A+ioJqCmEYUvIFL/Xm+Z//9SI3X7KEM7oyGJqKrin1WrfxkostArzqzeNU6+6EiKJ7rh8QhCF+AAsb4zQmTOLG0Zkjh0pVjhkae8bKtKUtzlnceFgiP0fLLzcO8tn7N9V7/wGMFBxe6s3zcn+BHz7Ty4U9zbz9vAWsbM8cVBVyWVuK91+4kE1P7Zv3iSGJRHJskM6YRCI5qZnspJy9OEvfhM1w0WH3aJmhvMPrT23jxgsXnxRKarMxWwpWZzaOqSv8Yec4n/7pBlTArhq+rWmLFW0prjqtnfOWNM1oYE4Rd3B9LCNq3mvp6qQIWOSA1SRBYtXeWQlTQ9dUmlP7Hd3JDlC+4mFpkaDFTEx2pBY1JaZFWfwwUjzUFRgqOFh6pMowXHSqkZzZI54H9pur9Q7LxIz6PdI7UWa87NV7nS1tjHP2okZGiw59ORu/qrrYnLKoeJHCpu2H+FVhDS0UWNWaKIHAD6Ho+OQrLnFTZ0HSYLjoAIKO1hg7RwNKjl8VyDBZ2pJgpOAyVnaxPR9VUXjjGZ1ctrKF5qTJj57rY0NfjoF8heGCW4+mtKZNvFCQMHS+++QenCCcMdVupnQ3RVFY1pak4HgMFxx0VcHQVPaNVzCVyOXubIgjVI2hvM2+iQogsDQFLwRT14gpCr4etQn4zpN7eOPp7WwfKeOHkcqfH4SUvQDbD1D8kExMx/FDNCVSfjG0EEMzWNKc4OxFWRKWzu7Rg0f55sKhUpWHCw4VNzhikZ8jxfdD7n58FwXbY3FjHMcPGcjb2H6IqggcL2TTYIHBfIUnd47ysatWcNVp7QeVjV/SGGPTMRuhRCKZb6QzJpFITlpmclIWNiYo2D6OH9A7UaEpadFTrbk4GQhDwb7xMjtGSgAsbYma8x6YgiWEYO94mZd6cxQqPmXXpzFhYOoqIwWHgZzN5v48j20e5spT2rjposXTVPYmizt0ZeP4oeDx7SN4QUhj0kAIKDkethfVRCUMnaSlkbQiB2pyamTNAdrcP8HWkRKeH8nSL0jrrD6gL/ZMjtRpnZl6lKXsBWwdLOArgvaGGKNFF9sLCIRg80ABU1MouyGWobK8PZLWrkWGJh9XRzoGFcGmvjzjFY+uhhjdLUkuWJqgYGewPZ+dI2VO6Uxz29pILOIfH95KJqaza7REKhalFcYNjZLrY2oKFXeyUqXACyJ1wFrLrv68i6l5NMQNrj69HQSMl6NWAhNljyXNCZa3pWlKmnQ3C/IVj23DRU7vyvA315xSj3b052weeHmAsZKDpigoikAIhb6cjaYqnNKeojGZqotUHJhqN1u6W1PSYs3CBv6wcxxdjXq0haHAtKL9xk2Vsi+oeD5+tdF0ICIp+poPY+gaaUshV/HYMVKmL1eh6Pg0J00aEgYCUW3DIKI2AoDjB/V/t2cszlyYpSFhUrC9w6rnnI3Zjnf//RZFkNvSsRnXP5yU18Ph2b3j7Bot0VxNvR0redhe5NSHQkHXovElLYOBvM0//XIrixoTrOyYXTbe87xD71gikZw0SGdMIpGctPTn7GlOiqIo1TQ2g5ihsX342M92Hy+2DRX4zpN7+P2OUXJlD6FANm6ysj3FWMmlK1vr6+SwbajI1qEiFTdK+QpCQIn6YYXVuhxVVXH9gP8/e38ebdl13/eBn73PeOc3v1dzoQagABLEQJCUSEqcNbSs2JbtOFa6I0dtx7HV7ay43SvJysrqeKUjO4mdOF7RSuQ4LclOKDkeNJsSKZIiKc4giBmFQs2v6s3vzvfMZ+/+Y597672qVwOAQgEFnu9atYB679577j3n3FP7e77f3/f7tbObRFnOz3/0gUma3F5K2yP7W/iO5Bvn2kSJwnckzYrLg4s+P/aeJX7kwTmCOL+hEPjMep9f+vI5vnexzXo/It3BV1Y6mj+/BMMow/PErj6sTz+8OFlsVh2rWEz36QUm4W+8gHWk4GovwkPQDxOeu9JjX9MnUxa/9f2r/IG9xrH5Gu872OJLr2xypRPQ8Cy+eHqddmCCM4SA82lOruHHHlmkWTGWv4pr0w1SZFEeHWU5Td+Z9LkJIZipOSR5TpJds2wqDUlmios1JvLflpApikV3woePz/HJUwtc7Ya8strn919YJU5zHMuUSIdJzvog5shsjX/7qUPYtiTLFE9fbvO/f+sSwzjF1IoZVVAAWucFAdQT0nEzq93Y7nZmfUjDt7GkIFfGavmBozO8/+g0v//8KqeWGgRRAkR0gxQlLBq+w9bQdK/Zls11YhJOUUZ8fmvIvqkK83WXzUHCMM5wpOTUYoPNoekdi5OcODUhLgenKzx6YIqZokfujcxz7oXrS5+Xmh65gn6U0gkSZmoevmMRpjkN60Z73+sN+blTbI+MqllxTWVBmBryqzTYlkAX55GUsNT02BzE/MtnlvlPf+LhMja+RIkfEJRkrESJEvct7kak/d3G64nNvr6M99e/c5nnr/SwBMw2XASCbpDy7QttJDBXd6l5Ns8ud+mHKbnSVBxJPzI2us1BjBQmNj3JFVFgLGxxrnlt/dpC/VZhB8fmG8zWPM5vjfix9yzyYBGFf7P5lDNrA/6r33uF71/uMNxhSbS4FvYB8K1zWxxZaE7sVg8tNfjCy+u7Uu2mqg5JlnOpHeyaHQtTxf5WhZMLdfpRxqvrA6QUHJ6pUnVtVroBv/PsCr/x3WWSNEdKQTdMERhbZSpN71eSKc5tDHmx5XFktk6SG/tclOaT4+XbFkppbCknfW4V18zHrXQjojRBApk2f8BYKW3bBHjYFhya8hkkOf/0mxf5+IPzHJqpcmimyrH52k2tZycWGpOQBxOjbwbtaq7FbN2h7ttkuTZkN1dc6Yb0w5RmxaEfpnSK8+HZyx2WOwFHZmucWGjwyVML/OrXL/LSSm9idTw6W+MvPHWQA9MV/ugVc05Y5BBt8f6jM9iWTT9KWW4HxLlmr7M3VRpZ7Lumbxs76o5ur6pn86H5OqMk57GDLZ6+1CFXmuPzNaqezSBKb1pS/UYx7pSb3NAIUzTmhsaxuRpzNZfVXnQT5ezukMLrMVtzcSxJmORYUpAVM4aWNGQ216a3z6STWri24NxbYJcsUaLEOxclGStRosR9i7sdaf9mcf2s0q1is/cq413vx1QdyUKrMlksLjYl28OEbpjy/JUeszWz+HYsidIaiVFpbCmIU1Us7IyaIjCpfGGSsTmIeOZyZ0L+bkVia75Nw7d56ugMp5ZunnB3dmPAL335LGc3Box2EDEBaGHUonFA+Uo/4v/7Fx5jtuoTphm/9o1LE4vkONVutReRaY1jm4j5TpBgS1mkCJpuse9caJPlioPTFRq+Q3tkwjZypVBKkylNHKekmcZzJIoiwa+YQUu15muvbXFuYwhSoHKN79hs9CM+emK+SHbsMV0xM19uTSKEwHcsap5Frhx823SHrfVipBSThbW0TOR/3XdwHYsLWyOeWe5MQmBOLNzcerYz5MF0uJmi5zBVrPYiDtvVySzfWOG53A5ojxKudEOiov9MAP/DF87wNz5+go1BxL965gpCwIcemMaWkkGU0Q0TfufZFX7m/Qcm359mYVOcrbloYRXqp000SFBKATs76zRhklN1LbRWXG4HaG0CQhzLkNjNQUw/SpmteXzqkUV+/L1Lk/PdzADuXVJ9NxClOfMNjwcXGzR9B0vCWpGIaUmxZzDG3SSFO/HkoWmOztY4szFgseEhAFWQMaXN+VqxLeqeRZqb7jWluac3kEqUKPH2oiRjJUqUuGO808pS9xUFwDefE3lr7nbvhetnsG4Vm71XGe/LK73JgjpKja0JDKlqVGySXNENjZpgFzHrQZIb9UlDRhGyoUEoU6yrtSFilpTEqWK5HTCIUxqe86ZJ7NjquD2KSfJ8ooBJwaTcNwfGdVFhkvPc5S7/tx96gP/5j8/dtA/quStdao7FI/sbuLaxdrm2xJaCfpSyOYypeTZeoWC9tNKnG6TM1FxcW9ENE5Jc41iCPNekmSlVFhgFAg2pgtV+TMWRpDlYMuXv/+GrpLkuyrUDtkcxWa5Y64Wmhy3NkUJQdW2khAdmq3SClJp3zcKXZMrMmRXBHu1RwvYoue25c33IQz/KQAgsS+AgTOhDL+KB2SpSmEW80ibpcBgbC2bNtY31Mc35+rktXlntk+WKYZIzVXHYGsTkWpPmGlBc2Apoj2JOzNeNWjRnZqm2Rwm2ZVP3LA5OV+lHGYM4QwgT1Z8WRMy1JQuFrS5JcxZ33EDwbAu3JlnvR6Ch6lgcnq3dlIi+WYyvS4Mo5be+v0J7lPDYwald14OG70xI2EzV5fzWaE918m7DtiV/+SNH+bufO8163yjXeXEMlDYVEUuFQj2MUlpVh6mKs+u7d/11d6FWLt1KlHg3ofxGlyhR4o7welSfe4Xr50Tu1d3u63GnhbPjIJG9ynhNEa5RcdqjhP3ONQvhOBLdDP1rhJBozNzJWLPQO+a0Mm1+Nh6N0UCY5ejQzG6dWmxOur2WmtqU9FqShm/+SbgTErvT6vjClR5QuNQK29WYkI1ZmgaudqLb9kEdm6uxOYi51A6xhaATpmRKTeLVe0HKiYU6aZ7z9XNd01VWFCv7tpnBUQos29gScwWuLUhzvaszLcs1kdA0PItmxeFqN+Tvf/5V/uPPnMR3LEZxRpDmjOKc9b5JHqz6Nk3fwS5skFKa7UkpJqRxpuoghCCMMxxLTqLM4ebfoX1T/iTkQUqJX5DPXJlZItsydsAk1/i2pB0kCMyxtCxJxZGAIMlNufUoTlmOcjxHMl932B4lZgYRE8TR8G0qjuTc5miiQn7xlU2OH4OnL2yTaIklBA8uNfjwiTn+xdPL9ArbpyUFrYrNvlaFA9NVokSRKc3eEGjENaL+JmagbnYjaOc+bQcJ5zaGLDQ85hs+Mzv2/TgxsRuk/OUPHzU9dvfoptK42+9Xvn6BV9cGhf1WU/Uk+5oVqp5Fe5TgO5Kqa3NysTH57u11zpyYq3DgLXu3JUqUuNcoyViJEiVui9ej+txrjOdEbjWL81bjTgpnx7HZcGMyomtJHEsihFkEj+KMXphScSxcW5Jkin6UgobZmkPDc1gfxNgyJ1WG6Kjr3pMGEOBYFhVHEqYKW2qqroWUglP7Gnz+5TWev9LDtU0RccOzqbo2h2ertyWxoyRjaxiblDylJtvUgNixNh+v06WAA9P+bS2S1eI9rPUjkkyZhL6KQ5jkrPQi4kwhhOa5Kz26QYoQhmAoDcP4mlUvyXURakJh1zSWxPFbu5bhIOiFpjvs/OaQ//xfv8jhmQoPLtY5MFXhtfU+vSinVXF438EpZmsOZzdH9AJjFR3EKTXXouY5zFRNIIhSiu1xH9yBKZbbwa4Aj/1TlV3foW9d2CZMMhaapsDXcyyavlMQUbPvlNIESTZRPBUKqSUVy6QdJpkpZDafTSK0JkpztoYQpDkCbfaB1kXEvkmJ7AYpozhHFmw+zjWZVshiRvBPP76fn3rfEr/29Uuc3xwhpGap4fPgUpMTi3W6gVH/2qOE+g6b4jDKqPs2szWXMN273uBOcTMSe2pfgy+d3phcl1xbcnFrSDdIeXa5y+OHpnYRsp3ddrey374VODJb5UNHZ5AIrnQD1vsxKEWQZEgpaFUd892bufbdu9l19+XVPgcacH5zyEP7p+/p5yhRosTdR0nGSpQocUu8HtXn7bIs3moW517g9QaJ7FXGu9Dw2BrEBGmKQpD3NI4lsaSx+IVpXpQXK7phSJyZoArfEqSZmoRJ7IRrSXzHLNYdS2BbgiDJObsx4EunN2hWjMozjE0VwGqUMd/w+OSphduS2I1+xNn1PnGmqLkWox2R77tKosef0XP4i08eZjNIbmmRDGIT07/U8LEtQSdI6YUptpScnK+z0os4sz6i5VvM1FyCJDd2L2EIV0VaWALCVE2IoQJcS6CVUccsCRVHEqSKKM2peTauZRMmMdsjE6O/OUgI0tzE80/5RKliaxhztOjHOrM+ZN+Uz8srPcJU0fRsHFsyiFK2RwlN30Tb//LXzvOdi9ucWx8R5zknF+rMN3wsKah7NgsNl/NbQ4I0pzOMmWsYkr7Y9EiLzq5UaRTQLiyPvmsRp4ZwiiTDtU3dQN212BwmeI4kSnPSXJkMRm3i6EGTK0PI40yhNcRpRnuUcHTaEMGxullxLNZ6IX/44hp//eMn+K//7KM3fL+udkPm6h5zdZfVXkwnMGmK4zm/paYHiDc1s3kzQvLC1R6ff3lt0h0nhFEpfcfGs80NjXObQ6ar1wqe7/UM6V6f4cRinfcdmuJqJ+DZ5S5JrpiqmGTSk4uNyQ2kW113G24NIvjS6Q1OLk3ds+vcO82mXqLEuwUlGStRosQt8XpUn7cz/WtsgRovGM5sDO7ZguH1BonsVcY73/DQjKPRNbaEXCm6QYbGkIkDMxWU0pzbHJHl4NnGNiZsic4UuTYqimQct24i0WuuLBQkm4pt8RvfvsxzVzrM1TyOzlRNUp8GRwrW+jGvrg34xEMLN91vZ9YG/N1/8wprg4SbOtQKjH/9Fz94CN+3OeBakzm/qiNZ68cEaU7VsVhqekW/muC9B5o0fIdBlJHkamKjfHV9wJ+8toVvSxqYsJJRbEqTfUcyU3MZRhkECaNE4ViChmeTKU2UKgQU/VpmZict1IlcaVJl9l2uFHFuuqC0ho1BwkzVpT1KGEQZzYrD/iljeft/fPIkv/fcKhe3R7SDBMeSPLTY4DOPLPJHr2zw4tUeYZoRJQop4bkrPVb7MY8dbHG5HXClExIkGWGiuLht+rqWWlUqromB3xpEbA4TpDDve3/Rp/XscofNYYIlBfN1l2bFISzIo4Us7KLCsFGtzf8X1tEsV+TK6KmdUUKY5rQD012llKYf5WyPzGt3RinvOzTFj5ycv+H7vbPb66kjUwzjfHKs6p7F2c3Rm5rZvBUhWWpqnr/SxbZ2zoXZzFRdNgYRNc/edbzu9Qzp7T7D4dkaB6crPH+1xwNzNf79jzzAoenq5Dt3u+suwPnN0T277r4TbeolSrxbUJKxEiVK3BLvxPj4m+HtWjBcXzgLTEiEIwVrvYjDc1UGcUrdtTk2V+Ol1f4kdERrzdYgoeXbIMxiOc4UaW7Kln3HwrIkjhSIYqZopHLSXKO1KuyIEl9CpjRKaXzbYrFVwbFMAIQtBTM1l//uD1/l2xe2izmfAVbx8w8+MMsDc7XCHnVzcn12Y8B/8dsv8NrG6I72jVssLv+fnzwJXJvz+87FbX79u1eIsxxdzJl5tsUDc9Uiwt/Z0Rl3DdNVl4pjUfNtrnYNkUkyhRQCt0g5tC3J4ZkalzshaW5URYHAsU2Qybh82JYm6GUQX7PRKYziNAhTbEtS8yyiVDGIjW00yY0COD7vHzs0xZ974iDPLHfYHiXM1lwePzDFf/Kbz/P0pTZaaTxbktsmCj7NFFc7Ie2hia6XQlBzLdAQZ4qtUUqUjTg4UzE/yzWWlHi2pFGxyZVmcxgzU/MYxBlJphnGhnBYRa1BlBgC71kmPTDIdFEabQI8euE4dVMQJKYXrGKbpJUwzfEcY20dpTnrg4jPfvsS+1r+Dd+hnTObZzdH7Gv5TFWNpfTs5uhNz2zeipCkSuPYgmGUTQiXEILjCzUGccowSsk1hGmGENzTGdI7/QxSSo7P1yc9dzvf1+2uu2CKtO/FdfedbFMvUeLdgJKMlXhXoLRPvHV4p8XH3wxv54Jh56L0+8tdgtgk0MVZTpgYotCLUq50wkmf1s6I7SzXrA8ipJQcnq5yYr7OKM14ZaVPw7dxbYur3ZBukNLwHWxLUnE0SaaouhY5JrFOqWIeiHGhrEIpSdO3GUQZ57dGtIcxmQLPFkhheo+2hglfeXUDWODQTOUGcr0zre5fP3OFV1b6plS6+IrtpY4JYF/L431LVWATteNBl7YDLmwFxFmOJQRCarQWxJmZCzsyU73p+ZYrjW0J0iw3HVw1D60VvdDYGy9vB9Q9mx9/zxLvPzLNr3z9Ahe3AgSKfpgSw7UgDwHJHuNMmQKlFT6gtJnbG8WG3LvFsNnO89625SS+HuDi5pA/eW0LpTTTVYck11DMTfmOZJQoBnFOwxXUfI9cayquYKFpsd6PCZKMS1sj6p6NFIKKa7Gv5VPz7Els/FjpjFIzs+XaEkuaoI84MwRQa5CFWhoVtk0owl2EOW5pbv5/e2TIoWMJcgRCGJtrrHLao+SmVuS3cmbzVoTEtSSebeyWY4IMMFPzePzQFC+v9NkYxKz3I6ar3j2dId2JN3oz63bXXeCeXHfvB5t6iRL3O0oyVuK+R2mfeGtxverzdsbH3wzvhAXDuGD3H33xNTYHMa4tEZjAhFwp2qOEB+bq+I5ktRdhScG+prG6bQ5jwjTn8HSVk4sNZmouW8OYC+6IerEQq7qGFAwiYydzbUmSa4LUEJoQQ1SiTCEFHJ+vs9D0Obs+4OzGkChVpAUhksJYnSxp7sanmZlN+u7FbdDTZEpTdYxScnZjwOdeWOO7F9tsj2KudkJGST7pNxtH2Y+hMUSs6lpUHJupuolMX+1FHF1wJzHucZZzarHBKM3JcmVUKMdiuROy0o1o+jYPLTVvON8GYYpnW4ySjCMzVaQ05Giq6hKleaHoVfh/ffpBLncDZuse26OEOM1B5lQcs49UEXF/Mxg7nyZKMiquRapMbH3Dt2973j99qcMwzvBswSAyASdGjdNY4lq6oJBmjivJlIksb/i0Ki6bw4j5msfh2Rrbw4iNQUKtIGaebZG7mqudEF0cyyBRXNoOkEKg0UgEVVcipSSIM4qxMQAcaVTUcfkwGEWuExqy2A8zlFBUHIssNwmRS81bW5HfqpnNWxGShm/T8GxWowjnuu1MV13mGz7vPzrNn3niAA3Pedtu0L3Rm1m3u+4CHJuvveXX3fvFpl6ixP2MkoyVuK9R2ifuLm6mML4T4uNvhXfCgkEpzSsrfVoVh6MzVbSA5e0AS8BMzaUTpFzcHvHUkWlOLtR5bWPIbN3j5z5ylAtbI37925fZP+XT8E2p8zDO0ArSzNgQq67Nw0sN1voRo40ho/haet4YriUQroWUktVeyKX2iCDOsaXEsQz5EBiiEWcKUagpUgrSVLHRj/na2W32tSr8zrMrPLy/yT/95iVevNozqYm5Is6MxU8XJGw8sjPu8BonKnq2UVes4j2O7/w/s9zh4vaIumex1o8nc05SCCqOKb/tRxndKOW5K12OzdWoevbkfPNci/1TPp0goROkuxL8giRnru7RqrisDSL+8MV1cqX58UcWudwJeeZyh+mKQ5YrTq8PbznvZiaqTH1ALzQx9Udmqwzj7LbnfZTlhhinhppaUuDZkiTfHQOvlCZMFY5lZt2EELi2pOLYuI5FkOQcmK7SDjLSXOPZgjDJWO9H5GpstZT4jlFGM63xLIFrW6ZPTJvus2RHpr/SkORGrbWE6YLb0UBAphVJbs6PimNi/5sVh/YouaUl7s3E1t8MtyIkYJI35xsea/3IhLfsuC7N1l3+7acOve3X/zd6M+tW192NXsCxBnzy1M3nOu8W7iebeokS9ytKMlbivsU7QQ15N+F2CuPbHR9/K9ytBcObsbt+/dwW/+bFNWO164ZoDb0oZa5uuqPq/u5AgX0tn3ObQ6QQ/OjJeV662udbF7bJMmUizXNFL0ppBzF1z+HQTHXyZ7Hp8a3zbaJU0fAkUzWPJFPm777N+w60+Ob5bUZJzmzdpenbXNwOkeRYEnJ1jZA5liDLTVqf0FD3bE4t1Xlxpc+/fOYKq/0QoaHi2vi2JFNpYeMzn3vsENupjgmg5hk7ZV48cHznf3uUmHTIxCQburbEEpJca/pRSprl5BoGQcZAZGwOEubqLnN1YzU7sVjnt75/lQfmalzcCmgHCaPYFFsvNH2OzlbphSnnt0YTgi6lZKbqUnNNQbNGYElQhUXRFkzSKMdHW2M+Y8WxyDVMFSSuG6S3Pe+Pz9cQQJprfMfMcSEErpAk6bXkS6UVNddlpuZOSr7TYofaUjBMzPlTdS16YYpTdWiPUtJcU/UsOsMEIQWzNZeZqsOF7QBZWBrX+jFhktPwbXphOiHiY0XUEhRkcTcyVVhBTXUZS00fW4q3xYp8uxtBh2eqfPLUAqdXB+/I69KdfIZbkfqbXXffs78JgxWOzdff8vd/v9jUS5S4n1F+e0rct3gnqCHvFtypwvh2xsffCndjwfBm7K5nNwb8+ncu0x7FLDb9iZ0wTHO2hwmuZeE5kmGc3RAAMSp6hk7ta/Cbz15lEKWmW6vqoNGsdCOSLOGhpTq51oSJmQl6ZH+LS1sjECZ0wZaSA9PmLrwtBUqZGPO67xQR+WJiVxsTMjCEQWmzULctwcNLTQ7N1Li4OWC5HZBr8CyIUqPEuZac9IrBNVvizmW97whsAVXHKHTMw2LDRKfPVB2SXKG1puE7jL+6Wmmy3Kg4lhQ8tNRgqmpi32uezZ998gAfOT7H1W7IH9hr+I7FU0enb0hbHMYZUeE/3EnQG74hk5fbAbnWjD+CgMnnByazUplSWFKyf8rnkX0tfvJ9+5hveJPzHmC5Hez5XVhqVah6Nv0oIyuIjSi2ZVmCvGBjTc9iX8ubWC211gyK56RZzlo/Zr1n5sOCOCdMcoIkx7WFKVvWUHcsZmqesScWASFJpkhzRZTl7G/5RglLFQqouxZhMVdmEjfZVYY9jrYfX1MXG4bY3cqK/FbO7O4kJGc3BlzYSpBCcmKhzp97/wEeXGzyiYcW3pHXpTHezM2sva67CzWbP/iD0/fkvd8PNvUSJe53lGSsxH2L0j5xd/B6FcZ3IrF9swuGN2N3He+/UZzRqhhyIYXAty08y1jT2qOE2bqDLeWeARBKaU6vDtjX9Jmvu5NuLceyeGixQSdIWenGuNYQ37EnCtFvPnOFuZpHPzJzQdOFpWx7lJAX5cCysL41fZsgyVDqWuGxLLyFZncJlhoeDy3VaY9inr7cNVH5FPH5gsnMmSOvzVuZqadrZExgiN76MKYbZcxWLZiHX/nGRX7s0f0sNH082zI2zCJyXWsIE0WmFEKYPrSmb9OsODx2cIrXNoa8cKXHR47P7TrWJxfqu9IWdx7rB+Zquwh6J0gZJTmZ0pPwkcLJhxAmuKJShKDEmekua3kWn354kZ94dN+u43874h5niuPzNc6sD00PWvG5zHs083SOLdDSYmMQ06o6gKAXpMS5wrMkvuuw2BR0g4SG75DnmmGSk+Q5AjlRNQ9MGaUlTnMsaQJZooKQGQJuglqEMIRXFvv7egJqT0qwr8GzJVujmCOztZuqN/diZvfEQgP1CPTChH6UkmvNRj/iCy9tIIXgxELjbau1uFO8mZtZ11930zR9K9/qDdt+p9vUS5S431GSsRL3LUr7xN3BW6kw3quUyzezYHizdtfx/js2VyfNNBuDCLcmcW1J1bWNQpZkdAM4MF3dMwBi/BonF+vUPfsGtWcQpaz0Iv7tDxzm+Hx98pz/M9e8vNo3JKMIwZiuuiw1PawiEU8VhGem5jIoYsCzsbUQoxBJaeLVnzgygxCCcxsj4myHdIRACIHUmrSYVRpjZxihFOBY18Ivqq7gkX0tYMjLq32u9hM+9tA8R2YrnNsc0Y9MOIZgTIAMEWtVnGu2wT3OwTs51oemqxPSVnMtzm4M0VpzZKZCO0iJM4UljFVSF0pQxZZkytg3G77F3/7xh/iLTx3eddzvhLjXXJupqst83WWlFxJngNJYEmbqLo8eaAGC6arDSyt9toemzLnlO8y5LlXX5onDU3SChGeXuwzjjOmaUUrzXOI5FtM1D6XNvBkYu6dry4LkGqshAvpBUiQOagQwiLOJdXRMom0hTK0CORVbGtJdnDfv2d/iLzx1cE9ida9mds9uDPi1b5rtHJmtUXXtG7YDvOODnN6pN7Nuh3e6Tb1Eifsd5Sq1xH2L0j5xd/BWKYz3OuXyjS4YxkRoqendQILuhIyO999+rzLpOGqPEuq+zVTVIUhShklGo+LcNABi5zHYq1ur6tnYUrDU8ifvYRRnXO2ErA8iFhum3ylTsDmITOJikbwXpznas6m4Nkdmq1zthrRH44JfQ6Bmag4/dGyOB+Zq9MOUdpAwVXFoD5NCRdFkmbE9ji1tAqOwzVRtgkTTqto8ur/FcjekF6TMVB16UcZKN4A6HJur8tpWxNMX2xyarjJVdXh1bWjmmXJFrjU1x2K24eHtiJCHG8/BOz3WY9L2/NUeG4OouE6Y3rb9UxVUYfscxSlJruiG6YS4/o2Pn+CjJ+Y5vdZnGGfUfZu6a/MHL6zdlrh/8tQCm4OYYZJzcr5OkpvC6TTPaVUc4lTzw8dn+A9+5BgrvbAoujax9//8O8tMF2Ee45j2cxumUFoWSYwV1+KHj81wYSuYkH8whKyGTZikEzusVsb26VrXqgx2HkMB1H0bzzGvUfcdcnJsS/LJU/P8v3/sIew9ZLN7NbN7J9v5P751me1hTDtI2N+q8MBsjTDNyyCnu4h3sk29RIn7HSUZK3HforRP3B28FQrj25VyeScLhuvVukGcsjWMWemGdIvgjLHCdGKhTrNi35KM7tx/1y+ec6WoeTaWlByYqpieq1TdQBpe7zE4szbgv/79V9gaxWS5YrkTUPdtZmsujhRc6QTUPJtjcxVWezHr/cIKJ0xAh2uZsIsffXCOzX5MJ0g4OmtInkn8U7QqDo4tSDJNnBlb3870QZPkJ6i4NvumXEZxzsYwIcu1CSsJMoZxxjCM4SA8u9xjrllhsx8z3/CJMsWffmwfa/2Y7WHC2c0hUxWLMNXM1Fwavn3Tz3+nx3pM2v73b17m7PoQgca2LBabPsfnawCc2xixOYzYHiYcmKrw6MEWH3tonrPrI/7O777E5e2AMM2puBbzDY/OKOXUUv2mKvJr6wO6QUqz4pArRZCacwABOtGs9WMcy+KTpxZY7UcEaT5RO89sDIhzRXXH55ypeUwfNapmmOac3xwyV3dpBylLLY9elLDejwBBw3d4sOVxaTtAD1Nyrag4NlXPoepaBLEhnnlk1DPPNmmMudKT4JAoyVAYBeff/8gDexIxuHczu7fbju9Ifu/5FYQwc4Fbw4SZqsvxhdoktfROSGHZVXl73K/KXokS73SUZKzEfY3SPvHmcbcVxrc75fJWC4a91DpLCs5tDA0Bq7k4vk2a64nCdGDKJ1PQD1OU0je85+v3387Fc5yZ3qunjszwbz2+nzDN91zo3eoYKKU4tznkgbkaSmvOrPf5pS+f49zmkPm6hxSwNUyNojVMig4iQVj0jzUrDnGq2B6aUt+pisOHHp7lZz90mBMLjQlxHt/QkALSVLEaR8zVPTb6EVmRvrjTnuhYhtgN4pz5hqTuCzqjhDjLSXNNpjSuLZDaLOY3BzHbYcZszeMnH93HKMk4txWwr+Wz0PTpRylXuiHzdY/j89fOm9vFf99ucXhiocHPf/Qoq/2QqmMxVXUnqifA9FGX1V5EexTz1z52nKmqw6994xKX2wGbg4hcmYTKOFVc7YQMoxQhTFrkTM3dta2Ka3FhK6UfZZxcqJPmVb57sc1r64MitMQEZlzYHvHff+FV6p6zSzV+36HWnqR8rJYKAQenq/zMkwd4brnHuc1hUXoNYFIVm77LJx6q891LbTqjFK1hquoUkfnmfHdsyTDKyJUiVaCVol8kmmTKbONvfuokDy42b7pf79XM7q220x7FvHi1xyDK2D/lM1PzSHPFxiBiEKc8fmjqjkhh2VVZokSJtxMlGStx36O0T7w53G2F8c3eMc8yxTPLHbZHCbM1lycPTd/07vzrwV5q3SjO+JOzWwzjjKZvm54uIfBsQe5YXOmGXNoesa9V4de/fZnvXujcsEC72f4TAjpBysHpKj/56BJHZms3fW/Xv8ZS0yNTmpVuyPnNkbEKKvjF33+FjUFMkuf4jpgUAQshCJKUODWWtKZvkeaQKZPOd2KhxmceWWL/VIVjczUOTlcnx3PnDY3vL3e43A7ohCYkYbrimPJfZWaOVBGP7kjBkZkqjiW50g0ZxTmOJYiznGGcI9DUPIdca0QREzFdc7jaS0DDqaUGx+ZrkwVwnEVM11wypWn6jonbV+quqdwHp6u878BUQXatXXbUumfCRN5/ZIYnD03zy189z/YwIctMUfNs3UMIQd3TrPdjQDAIU85tDpmuTu86x8MkL4JBjLp1uT1ivR+jMcTVsSRRaub2vnpmi4+emOPUvuZENb7aDZmqOKz2olveGPmhB2Y5PFOd2BuPzlYRQkzI/iA2xPbhpRYXtkZ0AtMRZkvJdM3Bicz51PRtekXq5xgfPjHLf/SZh3lw6dYk5F7N7N5sO1przm2MGMYZtiWo7yjFdmuS9ijh3OaIxw9NEWc3J4VlV2WJEiXebpRkrMS7AqV94s3hbiqMb+aO+RdfWedXv36Ri9sj0tyEExydrfGXP3KUTz28+IY/30617sR8jWGc0wkS4nRMHGwSpdkexjQqDlluFr5RakjGw/saTNfcmy7Q7sb+G7/GZ791mW9daLM1jBhGGZYULDQ9+mE6WdzblsC2JK6d0vSdQpFSRaGzJsmNAjNfdxkmOVe7EZ1Rwr/zgcN7EpoTCw3UezRnNgYsNDwemK2y3AnoBBmpMsRqyhK0RymuLTk8UzFkSymEMARcCmNxTDOFQCBFhgJmK9aOLQk0Zu5pr5soYZrxhZc27rrKPSa7r6z1+cOX1sn1OLpCYAnBg0sNfuw9i6z2I85tDotethH1wioZpzm51lRdi1FiFKX2MJ50xsE1snR8oc5mP2YUZTx7uUuSKaarDpnSRTS9UaDiTPHdi20WWx5zdZ+aa/H81R7TVRfHEpxZH7B/qnLDjZGHlhr88lfP76ninFoyStZyO8C3LXxH8oEd8f+OFLy6NqCTm+62Hzo2C8VNA6lz4Crv2d/ixMLt+6vu1czuzbYziDK2RzGWEPiOtWv7QohJr9/mIL4pKXy7VfwSJUqUgJKMlShRosDdUhjf6B3zL76yzt/93OlJz9Z4EXpmY8Df/Zzp1LkTQrbX7MdYras4kqcvdekECVmuyJUuipmNvalVcRklGVvDeLKIti1J3Xduu0C7W/svyhTzDRetNb4tqboWK72YTYxS6DsCpQVxmnO1E6KnzGI6KXqj0JBGGZ4lCIrS30GU8fyV3i41cud+qjoWn39xnSRTPHnYqD0LTZ+XVvoMo5QgzsG1mK+bYInxTNMwylBKkymF1iYkIlaQo0lDo1g0XPP5O6N0Mtc2VmL2uolyYr7x1qrck1I0ce3vBcY3Epq+Q6YUWS7YGkSEaW5SKYFca3zHoRumdIKEqrebLP35Jw/xhZfX+dprm3SChIprkSnNMMpIMoXSIKWpBBglGd88t817D7TYGiSsDyJe2xjywGwNKQSX2wGeLSek9KGlBl86vXFbFedm8f+90MyXpblmtm7T8G2klLQqLkLnEMKFrdEdzXndq5ndm22nEyT0wpTZusesFIziDM+WE0LlWJJhlLLaC/lwUYlwPcquyhIlSrwTUJKxEiVKTHA3FMadC8GaazGM812WsL3umGeZ4le/fpFBlHJ4ujIpwW34kpprcbkT8mvfuMjHTs7f0rJ4s9mPk0t1toYx2yOjhtV9B8e3GUWGeG0NY+qezal9DZJM8b1LHSqOhWtLokxNkv1ut0B7M/tvfJe+EyQ8MFtjvR8zU/PYGiaYuihjQ5NCYlsCKUx8/HInmKgtO5FrWO6GHCz2c5BmEzXy+v2UK81yO9wVTDFT8/jI8TkAVnshFcfifQdbnN0YFaqVZLUXkWQKKQRKa0aJKRa2ZREXjzZEDqj7Fodm64C4pXVtr334ZsMVxvs2V5off2TxhnPy7OaIz7+0zk+9bx++bU0Ks1d7IUqblEJLmM64JDWF1TXXJkxyLm6NblDwpIRvXdgmyRUVx2IYZUSZmszdaYWJsdSafpjx7fNt6r5NzTMq4nzDI0oVni35qcf28dBiA600v/L1i5zdGHBsrjbZv1rDdNXhSifgcy+s8W89LgnTnMcOtbjaDSYEJkpzvn+5y0o/wrUknSDh6UtdTizUd82+xVl+x3Ne92pmd6/tZEozU/N4aLFOzXN4drk7STF1LMkozggSxWzduykpLLsqS5Qo8U5AScZKlChxV7HLEvby+qTTCEx58IOLjRsWR88sd7i4PWK25k6I2LXXk8zWXC5sjXhmucMHH5jdc7u3mv14db3P1U5IpjSLTW9COOq+TdN3TGw4Atcyd9YtKah6Ft0gZaHp70r2e6sWaDvv0seZSTRU2iysPccs0tOCQERZjhCCubrDcie84bUsAZbQZDms9SPm6y5Vx6bm2nvup6udgPYo5tX13cEUUgres79JnOVsDxMGUYaU0I9MUmKWaywBjaqNAKJUEecKDTQ9C41gX9MBEnzbYhTnHJmrMohTltvBHZGqM+t9/uXTVzm3OSTXiinfYaFZ4amj0zy8r3lHr7Fz30opaVZ2n2Njgi2A4/N1XrjSJcsUUapoVeyimNoQtJZvk+aKY3N1/tP/yyniTN1AEE8sNPizTxzg+eUuwyQjTNWkCmBcJ5CZ1A3SXBFlmqWWX5RPS6YqDlTg7OaQL7y8zqurfb51oc3zyz00mtfWh1RcC0sILMtYLUeJsUX+mxdXWWx4TFddpmsu+5oWl9sBZ9YHRGlO1bGYa7hUXYfNQcQwznj80JQp54bXPed1r2Z2r99O1bH4nWdXeGm1z8Fph8cPTXF2Y0gnSBhGGUGSc2Khzi98/MRNSWHZVVmiRIl3AsorTIkSJd46TPqMNBqxO45vB7ZHCWmuqLjWnr+vuBbtUcL2KNnz97eb/XjuSpdBnOJbxt6nAEsIXFsyU3fpRWkRPmFKiDWwNTDzY8fnazeENNytBdpOxWetFxGmGfvdClqbsIUkM/Y4S0hAk2poVGzSkSLOVFGUvPs1BSaCPskBNKM4p+bmvO9gi31Nn//lK+e40jFESGtDDKaqLq2KwzDKbgimMOpDg+fSHq+uDYwiUXWxhKAfJfiOhdaQaqj6Nr5S9MOMIM1xbYlTKJnnt0c0K2b26n/60tk7Sqz74ivr/KMvvsbmIMYtXicp0hr/4MVVHlxq8MSh6dum3t2pAjKMMx471OLpi22CVGFLCBLTuZUpbciPlNQrppfLlpIHlvaer/pT793H//HNizy/0kMCjg2WlKS5IXWqSFaM8xzXkuTKkL+6b5u5rjClHyZ8/3KXqYqDFpArEwyS5DlbQxMW4tkSDQxCM6M3XBuw0g050Kow2/A4OFVhuupyeKbK8bkaZ9aHbA5jXMv0qbVHCWc3BtgLVRAwW3fY1/Rvui/3wr2a2b1+Oz/x6BKr/Wii/j1xuMXmIGa1FzFb9/iFTxznwcWbnxdlV2WJEiXeCSjJWIkSJe4qdlnC3nNzS9jOmavZmotjScIkp+HfaEMMkxzHMgrZXrjd7Md01SXLNSOlaW+OEMIs7FxL4tuSxaZPrjSdICVIMjzbIhOCxw62mKl5k9e6mwu0m1kFK47FwekqM1WXq92gSOfTk89SdSxiz6bqwvYwMn1fBc/Nd8TPT0ajMHHlp/Y1+eaFbf7Ni2smcr8TTvrUjs/XmK15XO0GewZTBIlif6HcHJiq0A1Snr/aw89tPFsQZ5o4y3Ets6Adzw4pBUGhIKapotK0ODxTperauxIEf/LRJeYb3i5V5czagH/0xddY60fsa/pk6lqoiiGAmk6Q8MLV26fe3YkCEmeK3/r+ClvDmH6cEqUpaQa50ggBFRumW1X2tSocma3SD1MGkVH4rleExsdWC4FSkAM6B6c4Iqogwb4jiTOFI2EQGfI6ijOGUUbds+ljCrcHcYpS4NgSSwpUan5uScEwzsiVOdYSQ/CiJGe5E5DkiijNGcU5H3pgmmbF5cQiDJNsYumTRajH8vaAxx+Bi1sBv/zV87ckuO+UTq7r7YtxZm6UfPj43B3ZJMuuyhIlSrwTUJKxEiVK3FXcqSVs58zVk4emOTpb48zGgJpr7bIqKqXYHiU8tNjgyUPTe27zdsqH0poozfFsiUKTJGZ+BwEVx+LRgxWWmhX+0ocO06w4bA5iPvfCGtujBNe27voCbadVcKnpU1c2/SghTHK+e7FD1bU5vlCjH6Wm7DfOkFLiu5JhnNGquBybq/LV17ZI8pS6a5MoRZyagIhxViAYonZgyufrZ7dY7YW0RzGLTR/XlpM+tWGc8cBclV6UsD1MbgimcG1JPzSv+P3LPQZRQidI0RgFzpGCNNf0wgxZkGGlYaHp8cEHpoEhVc/MnI3JUMN3SLKc71xo8+xylyOzFSqOzfH5Op86tcCvffMCK92QubpJF9waJiitafo2UaZItQnFeHS/x/ogvmXq3e0UkNc2hvTDFFsK9k9V+N6lmFGyu+F6kMKs0jx1ZJphnLE5iCfkbTyfeGy+xnzD4ytnNhnFGYenK1zeHrE9SlEa4sy8pmMJaq4hlKEyJHt/yydMjTo7U3NJMkWQmERRKUAUc3hhkexoS0GSqV1EbDxLOA6LbI8SHEvQC1OKTuddxeSr/ZCtQUyaaw5NVYGQg9PVW8a6v9M6ud6sTbLsqixRosTbjZKMlShR4q7ijQzF27bkL3/kKH/3c6e53Al3pSlujxKavsPPffjoTcM7bqV8pGnOMxfbRKkiSM2K1BbFwlUKcq15eWXAw0tNnjoyg5SCU0uGNL4VC7SdlsrZmsOrawPaQWISCVH0opSvvbbFJ0/N876DLZTWXNwK0MokI841fA5M+WwMTOiIZwl6UWbSF4vZMqU1qij0nW14PHGoxbfOb9PwbVpFebAs+tTcwqq2NUx4cKHOq3q4K5hiX8vn0vaI5650iYsQCrtY6I4DTpLUBHdorZHSBIuAQGkI4xyqsNTyJ2obmMLe5670iDNDLuZqHnGm+OLpdX7z+1fojJJJimEnSAlThe/IiaIZJTkS6IQpS01vQvDH6ZnXL8xvpoCsdCP6oakIeHCxwedeXONS+8Y5PICL7ZB/88IK+6aqu8hb1a2w0g347WcNOZMC5useG/2YIMnxHUmamVk6Wwp8xyhclpQobXrCHlys8+2LHepFIXWmFGmuqHkWSabwHElSvEaWayzJhIgBCGH2f1oUdCsUqTLqodaCfpQyXSjLMzWPqSMuXz+XE6U5Fcfi/UemgS513+ak7+6ZGvpO7eR6szbJsquyRIkSbydKMlaiRIm7ijc6FD+OrR/3jJm7+pKHFhv83Idv3TN2M+Xjm+e2ePpS54a5qkyDFGZuRyuIdc4g3h3I8VYt0HbG7D93pUeY5EUCnAmGSDJFL0w5sz5kqurw0GKD9x5okaSKMM0xwY6CR/Y3Tb8S8O0LbUZxhhBmrgnMQt2WgkcPtNBIemHKyYUGlpBsDCLc2ngGS2FJwVovxJaCn3p0P3/qsX2Eac7WIObXv3OZl1cHJLmJdndtSa40mdKoTGEJyARIbUhAmmuklNRdiyTNeeZymx89BScXmpPjMi7sDZOc+YbHxiDm+as9+lHK1iCedKZ59rjQOi9SLQWp0gxj05sVpzkvXOmy0DBK3yurfX7n2ZWbqjZ7KSCHZytkSnF4pkqaKc5uDG95/M5uBjhCM9es8eBiAyEE7VHMaxtD4tTE19d9G43m0nZAnCljH7QEqpgV01CQIJtPP7JIxbE4tzUiTDNqnkec5QwiY81teDZdlRXdbYJmxSHJIrIiKGWM8TkuAKQJC8lzRS/MmKt5dIKEwzPVyTEYxhmjOMO1LJZaFRNSE117vbpn871LbZ6+NM1TR2YA3tWdXNcTOqX0nhbUEiVKlLjbKMlYiRIl7irezFD8px5e5GMn53lmucP2yPRqPXlo+pZx9rD37MfzV7o8fal70+ckGThSY1kSVwq2h8kNcfVvRTDBKMkI05zOKCFIcuqebRIntcK1JfunKix3QvZN+fz8Rx+g4TmTfbWTGO5r+vzyV8/z4kqPp45O861zbVKlipQ+jWNLjszWeGRfk8vtwCQc+rYpae4FXNgaARTESpFkGtuSnNrX4MhsDaU0f/TSOq9tDHEtgSVAY9REKQUqNXNuWRFEYdmSuZpDP8qLhMDcKKRFJkt7GKGExLUkWmvagZlZGkYZ/TAFIM0UthTYrs0gTk0IiVD4tkmV7Ecpea4ns3FWEbBxfnNAruGXvvQarWIGbr+3t2ozJtiDKDV2w2HMmfUBFcfi6+c2b5Yxswv9WPHelsf2KMGRgrPrQ4I4L5QuY5+MUrMfrMI3qJWeDPLVPQcpBI4l+JknD7Kv5fN/fneZS9sB28MEz5bUPRuEsSW6EoI0x7YErYpDmuVsBykCRaZ221I1JpxGIlDCkIpW1WF/y9+lCrZHpuqhVXFYbFybi+wECa9thGyNYvphyi9/5TzfPdzhfYdaN53LhBvJ2/1MXN5pVswSJUq8u1GSsRIlStxVjInR1W7Ac1e6TFddGr6NLQVr/fi2M1e2LW8aX38r7FQ+zqz1eXa5e9vnZAoaniRVelcP11uJmmujtOZqNyDLNd0gRRUFVK5tQk7qrsUgzGh4zi4yeD0xHBPQ7WHCqaU6a/0Ip0j+m666PHHYzNh1goSKLfnG2S22A0MCx0qXYwm8oly65Tt86fQGR2areLbFC1d75EpTcS1c2yLLVWGRE7i2RZzmZFDYHs3/VF0LKS2avoPWMIpiAL5+dotmrULVs/FsSZBk1F2PjWGMFIKpisPVboTrWEggTCWagijm5vXHM1cC02Xm25LOKCEtFKfOKGW65tCPUh49MMVMzd1TtYmznC+f3uTc5tBE+q8NWOtFbA3iOzqGnSDl+Stm32gNmwPTe5XmmrSQqCSGLDqWIFcCWwqz/9CEac7JBZPCOIxNYMzf/sxDaOBLp9fZHiWEsUlHzHJd9MyBFBZpppBS4khJWKhjYyKWa7NNY2E0JeDNisNi0+On3ref55Z7nNsccnZjyGo3Is0UYZLxytqA7UHIsQX43sUOvdhYQpsVh5maw4srPV5a7TGMMvZfdxOlPYo5tzG6gbzdr8TlnWrFLFGixLsXJRkrUaLEWwLfsdgcxJxdH4KAVsXlh4/N8Jc+dPgtW8yMlY9/9KVXyW7sQb4BGohzE5Iw7uF6q3FgqkLFsdgaJniWxLLMIj3JTWpeeySYrbsEye3J4U4C+n2l2BolpLlm35TPg4sNHEvwWmG72x6l9KMUWXxuWRAopTW5guPzVX7o2Mwk7fLjp+YZpWb7riVxLIljCZLMECRdJDzaEubqHp5jUfMsolRRdS06IxPNnivzGrmGbphQ92w6QUI3SE3giIKllofGvBetBYkylkQhJKlS2JZE7bCRWtKQvijNiQtSOSY/Sao4vzliFOf80LFZZmrurtCYOMsni+2KYxS3IMnYGMQ32Fl3Ymc6pcYQ0mbFYaUbMiiKrV1bYGtjg1WYTjGRK6SQVBxJagkcKfEdk5rYjzL++Xcv84Wqx1TV4ZWVHpe3QzKtcYRJT/QcQZgohBDYlmQQm/lA2xJ4GCtoMQppag0UxEojJLR8hw8+MIMA5hoef/3jx/nGuS0++53L7JvyafgWvTDDswVXuyEswNVOgJYW3UAzVXWLucEKz13psjVMGMUpzYqZPWuPYp5d7hImJgmytYO83Y/E5XYVGfe7FbNEiRLvTJRkrESJEncVO+8sf+iBWXKlGUQp7SAhTO+AIb1JSCkYBOnreIbAsSQnFxv3rE/IscwsVKY1UZKjlXnfSIHWRi1ZbgdGqVm69WvttN69strn6YsdNgcmlCJOFUtNn2+c2yIu5rugIAnjtaQ20fkak+o3Ji5PHplCakGcqUkFQJCaEJGxtTEt5s1SpdlXdRglOY4lWO/HJJkhSl6xIVsKRpmmH6Z4jrEqRllOw7No+A6DKCVKc4JCEbKloO5JyCS+bTGQAqk0nmusjnFqAiosCbYwaY5CCHzXIs0V26OYsxsDPnB0ZhIaM4hSvnx6cxKe8tyVXpGGqMjvkIgBPLJQo5coai70wrSwBrLLiigxhCzJwbM1SW4CVpq+xcYgJkhzHpir8Z59LVZ7IV94aZ2NYYwQULUluYIkM4EoszWHVBnS++j+Bl8/3ybOcoTWuLZEpaoI7biGqmNxcLqCb0tATG40PLfcQ2t4/NAUnSDl2eUunSAhis13RqERmA4+ATx3pcfjh6Y4NldjcxBzfmvEYwfNLOh47m+66tApCtL3tcx36H4kLreryNgrCbZEiRIl3ixKMlaiRIm7hpvdWZ6uuRyaqd6TBdrZjQHPXO7e8eOlMIl4f+79B+7Ke7pdB9PVbkiWa47MVrmwNSLPNVYR5e8VClScK4QUPLfc5cPH5254X3tt49BMlUMzVT798OLkd1XH4p998yKdIMWzBVXXJUpzwjRHT+auBI4UDKOMQZRR9SzObgz53AtrbA1jukFCN0iouSYsJExzXEuQF0EdzYqNY0kQTOak4jQ39jmtkdY4UEST55ooVzx2eIrjC5rnr3QJUs1GL2SU5Chl5sFcW1BxLJLMkJuDMz7DJKPqwqEpn1TBlU6IKhQiNCS5nih+nmMRp4qNvulMEwI822IYm1LrpabPq2sDemFKLzAdXhVHkuWKve4X7CRiR2crPHJohmeXu6z0QuI0xxYmQCPT4NhiQnR18Z6M1VMyV/fY7EfEmWap6fHIvlYRnhKTa0WeK1xH0vQdlDZKYZIpXNui4Ugz+6cNoXWkKdTOcjWxSNrF53Qswb5WhVFRlfBjjyxOUiZ3ko2ZmstjB1t85cwmaSElKwU1T7LQ8PEdSXuUcG5zyOOHWszVPWqFQlT3bLZGpoy7E6RUXFNLMP7O34/E5Y0kwZYoUaLEm0VJxkqUKHHX8HbfWT67MeAf/tFrvLp+60S8nVhqefzNT53kwcXmXdn+7Qb/R0lGnCseXKiz0glQwsJx5CQuPskUUgiOzdU4tzm6YV/dbhs7Q0eW2wHnt0ZYlkDkZjbMlpAVRcYCYwsUAlKlSHJFr5uw3A4QAk7ta5DkirV+RD/KcW2BI0RhlYOZmsunH17kwyfm+Pb5bX73uRX6UYZrS6QQhEmG0uZzWZbAKkqgn13uUnXN/FOmNFd7CQIT+W7KjE30u4lu11zZDqk4kpprM0oVFceaxPNLIVC6+DzFz8y5p0mVIs5yOkHKowda1H2bKMupK5v2KCZMclKli/cLIMiKWau9MFdz+FPvO4AlBY8fmuLbF9oobQityg1x9G2LvNiXjmVeb6nhU/NthlHKIM6YrRn74EzNpR8a1di1i1oCRUEyjaIlpSBMc5LMRN13w5RMaVq+ZcJnirJ0dBFvXyhbxvKpyZVme5Sw3An2JBuOZeYF604FSPFsyVzdVEsA1H2b9ihhcxAzV/f4mScP8Nxyj2cut+mHKa2Kw0LT5/h8nZkdpez3I3F5o0mwJUqUKPFmUF5RSpQocdfwdt5ZVkrz2W9d5itnNid9YrdD07N4cLHBkdk3TwzPbgz4J189x+m1AY5tMVNxadTkDfMz4wWfUoqaZ5MpTZJpEqWwpMR3LSqOxf6pCu1Rsmtf3Um4wLG5a3H8az0TLFGxJKE2cfAm/MLMqVmWKNIXTSCELeDFq30cW/K+Ay2klNQ8mxeu9IrFfI6SpqD4vQen+HNPHuQjhXL3sZPzbA8Tvnxmw/Sg9WOEEBNrpAmiEGS5Zr0XgQDPliw2fdZ6Obk2vVsLNZtRohjFWaF0CfpxRsO36UcZaE2QZIUbUJMV6YqebayUUWGdHBOqq11TZPxj71nEsy1jeYxSwkwVxHdMYiDNCrsm16yJUoBnCaqOoFV1JzNTMzWPRw+0WOmERp3DBIMYxdH8XWuNLeGBuRq+a3G1GzKVKT724AKzdZNgmOSKTCl82xBMpXeTQUsIRplRG5WGdpAYK2uSU3VBIIp5MnNc06IWYJSYAm5LwncutvnF33+FI7PVokw6o+7ZDKKM9UFElObsa5jlgFFLr6WXOpZkGGWs9iI+fHxu8ufpS9P88lfOM1Nz2Neq3HDz5X4kLm8mCbZEiRIl3ijun6tkiRIl3vF4O+8sL3cCvn52g0F0Z0TPlYI//dg+toLsTVsnldL8vX/zCl8/t02am/kdIcz+eOLwFG2YbOPAVIWpisOXXjXvVQpDHGxL0PRtpBAstnxsKXbtqzsJF/jsty8zU3U5vzUiykz0/GY/NhbCTJHH2UQ1ylVRzizAtTStis2F7RFprnnisCFiYAqCf/TBefpRyko3Yhhn/EefOsEHjs7u2l+2LfmzTx7gmcsd2qN00l8W5ybcIlOaOC8W+xiSVfFsQ4ikpOZIolTRCTPmay4zNZdhbMiXlIJH9plo9a1hgso0Aj1JM/QdiwNTlYmtrhMkCCGouzYfPDrDj793iRMLDZTSHJ+v852L2witUdoQRK3NYrvYHUUypPkHsurZHJmp0g1T+mHKuc0Rjx9yEEKwv1VhpuayNYyxLWP3FJMBM1PALICnL3ewpWS65lD1bOIsv3YeWhJbSjxb4DmmiFrvYGNxlhMlObkG35E4QpNjZvmU1vi2BZjPUXEtSATzDc9YSTXUPItRnFNxLS63QzYHMZ1RMrEXRolRDrXKYT9UXZthbKydjmWCRoIkZ7bu7UpBferIDN893OHFld4N34f7lbjcqhx8tRfdNgm2RIkSJd4ISjJWokSJu4a3887yha0Ry93o9g8EbAGzDRcl5Ju2TiZJzn/8L77Pl05vogBXmhS8XJty4m+eb/Pk4dauNL+NYWy6xYAwMQvfUQz9MKPu2zy8r8FaP961r25nAa04ki+f3uDwbJXj83WqboVRnHF6dcDGMC4sa0ZNgh1zUNqoM70w5fBcDRDsn6re8PqtikvNs7m4NaJVdfdckH74+ByfOLXAF1/ZIMpyE4Mvxq9x7XE5hvBMV1yqjimktqTk4JRHlCnee2CKlW5Ikhn1MM4Ui02f2brH2Y0Bl7YDfFfi2CZRse7Z+K4hJZY07/XEYp2/+iPH+MjxOYBJge9jh1pc6QRc3g7ItSF1Wa5RxT4Za0LjAA7fsfAci1bR+WVJwZn1AQ3fxpKCwzNVNgYRw9gkQLq2RZrlEyLm2pJm8VjftogzxXcvdqi6NjM1t6g10Cy3QwRGCRuECfWKiy2gH6aTQJPZmkuYKhxA6Yw016DNrJ0QFPNlZt4uzRWzNbewS8pJxcTmMOLCVjBJwZypOwRJRjdIADi1VGeUCtpBwjBKCRLFiYU6v/CJ47uSEd+txOVm5eCPHmjxY++5P+P6S5Qo8c5GScZKlChx1/B2LtDM4v1OKnsxnVoVF0ca29zmMObc5vCGsI3b4Z998yL/61fPc7kTTn6WKEAqPMvCEpooU7x0dUDLtydpfrnSPH6oxTfObROkOWoslGiTPPmV1zZ5/+GZXfvqVhZQrTUr3YgwzTkwVZmokg3fZqpqs9YPUUXyYK7ZFeHuWoLHD7bwXRuVm/mpN6psSin42Q8dZnMQ86XTMY6taboCMBa7sWo0nu2qOrKIxDdqzHzDxdJmzqoTpoWqk7HQ9Gn4htx/4OgMB6crtEcpf+p9+3h+ucu3L3bYHpqOsKmKw4eOzfKzRYXCXjN2U1WHxw9N8eVXNxkVlsexHDWePdOYMIz5uleQX5O6+dihFt+72OWllT5pbuywlhTI3IRoxFlW/KyImteaXpRRLZS/+YZHkOR87ewWVUdypRMyjPMJOR53qPXDhEyZY+VaRjUbJSY8Jck1Dc9mlBhCZvatxrEkiy0fpTR13xyjQZTRqjjGQhmZOTJLwoFWhTBTDKKMmm/jSg1kDOKMJ47MsTVMWO2FzNY9fuHjJ3hw8UYS8m4lLjsTSm8WxFOiRIkSdwslGStRosRdxduxQFNKc2FrhCXgTkyKrm26nl5dM6pRmOb8+rcv89LV/h2X1f6zb17kv/vDVwmS/IbfmTGvHM+ysC3BKM1oj7Ib0vyqrk2Wqx2R/8Z2lynNas+kBY5xKwvoIMrYHMbUPBuvCIIY/zxOFVXXZhRnVBxroli5tgl/yLWx033wQIvX1of0gpRXkz4nFxo0K85EhbtTZfPEQoM//9RBvnW+Xcy7mecbQmGbJEcKKyBGdZuruwRJztYgoerZ5FoTphlpJql6u1P6hBAsNH2CJOfh/U3+9OMHWO4EXNgaAXBsrsbB6SpSipvO2K32IqarLj//0aP83vOrbA1i0lyRxYY0yuIcWWh4VFwLrTW9IMV3LM5vjqh5Nj98bJZhnPHi1S6Z0oVd1KIdJCaWPjdVAuNgFiklaaZY70c8MF/j7PqQlR0dYWNoIFXmPdQ8G9cWHJ6u0I8y1gYxcapxLEGqzYyc0opWxUFjSrD3t3wubo9Q2mKtH5kuN635zoW2UUCDFN+RnNrXwHdsktxUF+R5Blxkc5Bweq3PdNXjw8fndn1n90rxfLcSl51BOCVKlCjxVqIkYyVKlLjruNcLtKvdkK1BzAPzNU6v3TpJUQCtiiEngzAlU3B4usr+Kf+Oy2qTJOeffO0CcZbj24JhcqMil2RgC7MgT4oesZdWury00qXlO6z0QtJiXmqubpMrUFqRZJqFpscgyvhX37vKf/ITJiHxVhbQOMsZxRlHZ2s0/GuX9SRXhJlCoKk4FjN1l84owfYNEQPNKMlpjxKWOyFXuiFrvQgp4PzmiP1TFR5calBxrNelbC42fU4t1Vnrx6jc0OOqY5EhSXJFroyKM+YhtiWZLZL4PNtiGJm4+ammwyP7WrtS+gCCOCNTmrVeRM21OTRd5chsbddj7mTG7uB0hX/4Fx/nn33zImc3h5xdH9ILM0MUtWZ7FDOI0sl7nfdd4jTnoSWTvPn0xQ4aYxHVApLx59J5MTcokGhyLZACqp5FP8xY3g5MOuJ1RGxH9RsK8GxBzbNY68ckuUZiCp1zwLPM820peHCxwUNLDdBwtRcSpYokSwiTHNsyiZNhmjMIU4ZxTpDAs8s9njo6w1wRJCK0hNCQ2Z/5wGHeu7+16zt7uxTPkriUKFGixBtDScZKlPgBwe36r+427uWd5XFc/JOHp1nvx3RuUfq82HCpey7dMMG2TE/WycUGzYpLw3fuqAvt86fX2BxEVMd2vUTdUAwMRuEyc1rw8mqP711q71qAW8JEh4/T8DIlsS1dzPzoXbNst7KAXu2GVByb/VO758lcSyKBtOgy00VSn2tJhICsWMyPkoyvntmcpAFOVV1Ac7kdsDmMeXCxwZOHp+9Y2ay5NvMNn/mGx2Y/BIYIIYjSnGbFIUpNuEiY5ORK0Q8zKq7FB47M8JPv28dszeW3vr/C5faI6epuFXB7GPGdCx1sS/LPv3uZimPfUB8AN87Yaa0ZRNlECVpqejxzuc3l9ohL2wG9IAUBjg15bvZNEucMdI7AHKetoYmgr7YDFLDej2h4NkGSm5mtVKE05MW8WK41Ftd6x6IkJ8kVQZLfcK7sdaZ1g5Qs16RKU/dsPN/ByxRBmjNddZmquDx+eIqf/+gDHJo237UrnYB/8PlX+cqZLZIsQwoTaiIEVGzL1BwAa72Q71/u8MTh6V1kd6rq8t79rRvqFP5/f3KRq92AmarLXM3DkuKOb16UKFGiRImboyRjJUr8AOBO+q/uZ4wtfL5j8afet48vnd5gpRvtWvBKAacWGxycqfDSSh/fsVi8rh/pTrvQTEmvxrMFAjEJe7geWW5+LoBBlCMFux6baxhGGZYwHVtJpqi5NkIYm5zSale0/c0soB88OsvxuZjVfoTWeocKZOM7kiDJsS2FGimiVJHnmoprkSmNJQS9IMWSgppro9G0qg5JpqhLQd2zODZf4z/4kWPYtrz+I+6JnSreE4daEG/ywWMzvLIWECYpqRAorVjpBuQabGlmnT71yCI/cnIeMJ//V75+cRfxXO2GfPdiB4APHGiyf6p6Q7T/zj638YxdexRzbmNEO0jIlMKWZt9eaYfFcTfhF+O5NiEFlhDFgdIFUdIopbm4NeL85oiKKyfzWLY0sfZCCOyC+ElpSNlYBRyEKXGm9zxPdmLnOZsV76fqWoZEColjCZzcdL1NVV3+3R86vEsVTHLFIM4I08yUaKt8ss0sz7AtiSONWjaIUs5tDpmuTk9m5o7N13bZUJXSfPbbl3n6YhshDMm1pWSm6nJsvsr2KHnLi9xLlChR4t2MkoyVuGu418pLiTvDnXRT3e+EbOfi/+RCnT/35EE6QcIrq32CJEMj+IlHlviFT5zgT85t8U/+5DzHZutMVR2uTya8ky60pZaHJQRBoqAIRFB7rLIVhgTKQjbzXQulNUmqGGeN5Br6UUquLDzHZrrqMIpzWlWHqYp7Q1jGzSyg57eGe5KXTkG0wKT55bkmSo1CM04qBKi7kkxraq5Nw7PBo1BUBJt9Q/TuVOncqeKd3wo43oCm72BbgnaQTYhL1bE40PTY16qQa83vPLvCoekqDy41OLHQ4Oc+fIR/+fRVzm0OyZWZt6q4Fh88OjPp6dppO9xJCsYEfaUb8NrGkDDJqfs2jrTZHsVc2jZEsGJDxXXIcxN1nyuwpYnTdxw5KZjuRRlRmuLbAiElShtVcRhlptdMQ6YUMzWXUWGjBBPAkWQ5xW7GEuaYX4+bRc/UfZvpqkt7lBKmOVmu0MD+lk/dt1npRlQcm31Nn5VeyP/+zctc3h4VROwa8ReMg1sMOYwyRUsKtoYxq72QME451oBPnlrYdd3+xrktvnx6A601UzUXx5KkuWJjEDGIU04u1N/SIvcSJUqUeLejJGMl7gre7crL/Yo7mZt5N9zV3svC16w4vO/g1GTW6ace24eUgqpr4VkWYZoxxRvrQvuxU0v8YvU0a/0IxxK4tkTkiuuzPDwLE1qRZNi2sQmCib7XmZosyjNlOp1mag5hmuM7FlXH2Cf3CsvYywJ6vWq21ou4uD2iWXE4tdTglbUBozhDSIGUglwZUjZO70u1wLUkMzV3cp7UfVMM3A2TOy7qHt+UyZTmJ9+7xHOXtmEE3zi3zSBRVF2Lqmu2M4hy+mFGpgKkgAubI/6r33uZ/+KnH0YKwedfWufS9qggqyat8NEDrQkRG2MvRfPAVIVj8zV+59kVcqWYrXuESc5ad8T2KNm175XW6OL0lwVZylLFbM3BtiSZUihlyBrCFEdnucK2pCljzjVCCqZ9l4ot8RxJFucTdVMpo3DZ0lgEKfrRbqeSCaDl21Rcm/2ORZzmtIOUhm9TdS0ubo34J39y3kTmpwqF5szagF4xC2lL0GpnWIpR6hCCiivRmOj89ijlqcNNGKxwbL6+61j+0csbBGnOoenKpAzasy3cmrE/rvQiZqruW1LkXqJEiRI/CCjJWIk3jR8E5eV+xe26qd5sx9Y7CbdLcQT4n//4HGc3Biy3A15ZzTgyW+XEQmNiU7zTxEDbljyyr8nGICbNNMI2sedSaKJMI4Wxe83VbC5sRROlRCk9UUCkAKmNIjL+mdLQqjpUHZvDs9XXXQOwUzU7tznk1799mf1TPs2Ky8HpKi+t9NkYRPSDlFDlxJlCFu+l6sFS0yhqYziWJMlSpJB3VNS9102ZY7P+5PN6lqQdmLmrbpiRpDlJrhESDk5V8Oycc5tD/t7nTpMrzWo3ItdmDyWpohOmgKDuOzeEelyvaEopeOzQFP/qe1dQGjYHMeuDiCRTE5UKDBkLEzVJrhTCEBgNRGlOkCiyPCdRRtVKMmWSF5XGlqY4W2mwLMmTh2rMN3xqm0O2RwlNz6IdpAgBnVGCFMIkIeaaJFfEt6licKxxFYEmzRWjxBD1NFes9zN8x2Km6nJmfUAnSKnsKI02M2vXagTAvE+NmV17eH+DY3N1OkHCX/vYMR7b3+AP/uD0ru1f7Yas9kLqnk2mTFz/GEII6r7N5iCmVXHekiL3EiVKlPhBQHn1LPGm8IOivNyvuFU3FdyZJe9+wu0sfOMbBk8dneaZyx3Ob41ojxKePDL9uhIDr3ZDmhWHDxyd5uWVftH3ZBa+rYrNI/uaNCsOYZyjCVEaVK53WdHGXV+ONPNRh2dqtKo2UxWXk4uNN1wDMFbNRkmGZQlqnlH/Zuse79nfoHM2QUgzoxZnysxIIQgTNVHuxkgyRZKZ0t/bFXXvdVNmFGd8+dUN/r2Dpty64rlYUiLQdEYJWmuaFYc0M8XLNc8myRSvrAwIkozZmkOzaqxxozijHSSs9UNeuNrlR0/O77rBsJeiOVt3mW94dIKES9sBWa7ZkfwPGHKS5QohBEprLK6R42FiyKrGkBspjBVxTOa0AssSOEKQac3p9QG2Jfn0w4s8tNTga2e2+MLLa1gSLGli+ufrLp1RSj9KyfJsT8uiFNDwbGqeRTdISXONbUnmG0bdG0QptmWi9zf7MVmuOTxdYaUXFbZTjVccX62LIJGCSGkNUsK+VoVRkvP+IzM8dWSmiLbfjVGSISXM1z22hjHuDtUUivCXOGNfy39LitxLlChR4gcBJRkr8abwg6S83I+4VTcV3Jkl737D9Ra+vW4YNHyHDxyd4ez6kEvtgGcudXhkX/OOu9DGJPf9R2Z4/+Fpzm0NGcY5dc/i+FwdXVjujs5VeWmlB9x8JihVcHy6wj/4i48RFwEeb2becmwTXOtF5LlmFKc0Ky5aa15c6bM5iMmV4hrvMiXLuVZcbgccnavi2hZJlrPWj1lq+vy59x+45fvZax+3RzFnN4YsbwdwEPpRRicy5E4Is01BcQ46llHAcqNQjZKMXCkavjPpTat7ZnZqe5RwpRPSD1Na1Zsrmmc3BvzWM1dZ7UV0g4RcaVxH4khJrnaToFyDLbTpqdvjQAmMpTBT146jI6HuWeRaYBf216WWvyvs5ORCndV+SMWWXO6E9EKjXokahGmGEGBRqHGFiuXZFifmaxxfqNOPUkOU05x9LR/ftvjG+W0yBc2KzVLT55W1AXXfRkpJzbOByHSlCfBsEwqjYZLqKYXZl8M44+D0NfU1v7Euj5prU3FsKlPWpAKh7tuTubHOKKXi2Hzq4bemyL1EiRIlfhBwZ9FYbxG++tWv8tM//dPs378fIQS/9Vu/dcvH/+t//a/5zGc+w/z8PM1mkx/+4R/mD//wD+/Nmy2xJ64pL3sv5iuuZTqQ3iXKy/2GcbDFai+6QfXQWrPSjZhruAzilOV2gFK3tk2BWXgvtwNOr/VveM6tfvd24WY3DGZqHh94YIaPnJjj4HSFv/Shw/yHHzt+x9HtY5JrWZIHF5s8eXiaBxebWJYsSK7k0EwVjb4pERsjU4JDU1VOLTUnMfZvBGc3BvzPf3yO/+ELZ/jn311muRPw9XPbbA9j+lHKpe2AJC8UMAG+Y1H3LCwpUEoTZTm9MGVzELE5SNjX9PmbnzrJg4vNyTb2OsbX7+P2KObZ5S4r3XDyvDTXRqnBbGu8U6LMpDtKTLKkZ1vkeW4SD3d8NiEEMzWXiiMZRhkrvZBMKQZRymsbw12K5lilu9wOaVUcsqKAWSltSqevOyAaQ8hc+7obShiCZFli8jgoLKZS4NoWNdcydk8peO/+JluDhNV+BMD+VoUjMzW2RgmHZ6pUHIv2KEFKwVQR2W9JQdW12d+q8J79LX7skUU+9tAC+6YqeLbFX3jqED98bI5cwcV2MCFmjx+aourZZErhFLKXb0scS2JbgiQzZNexBDXXlI/b0myv6Tt88OjsbS3k47m77VHC4ZmKqSVIcjpBQpTkeI7kk6fm+cjxuTs5PUuUKFGixB54W2+Hj0YjHnvsMX7+53+en/mZn7nt47/61a/ymc98hl/8xV9kamqKX/mVX+Gnf/qn+fa3v80TTzxxD95xievxg6i83E+4VTfVaxtD+mFKphT/05fO3lHoyq2CWoAb54Xmazx2aIr5hve2JWzeyqophGCh6REkGc2Kc8fv7VYFzFprXtsYEiQZzy536Ed7SA4FbGHCPAZxyjPLHT74wOzr/4AFrrcJ7ncrVBzJdy92+MqZTQ5NVxhGpn9NSIklBRXXKhbvku7IqEcN32Gh4XF8oc6ff/IQDy6Zc0EpzTfObfFHL2+w2guRkknH18ml+mQfa605tzEiTHIavkOcJGa/AI4UpoeLIkm94GRjUlXzXeYbLpfaI4Qo4uV3oOLazDV8Vrshwyjn4tZo11zgiYXGLpXuwcU6tiW4uD0iVTm6mNkTAoTerVZqDXFm1DHXlmg0tpTk47ANcW3mypbG2pkqjdYa3zH7M9dMbj6Nvyvntwac3xzx6tqAVsXGErA1TBjFGa4lOTBd4aGlJvN1j4Z/7VwKY0NMH97X5NMPL94wB9jwHVa6IVmuGcYZjeI8rHo2AhjFplNNIPAdwXTVIc40i02P//ynHuajJ+Zve76f3xrSHiZc3jYksOpaNH2H2bpLpjQHpsxNjFIVK1GiRIk3jrd1hfyTP/mT/ORP/uQdP/4f/sN/uOvvv/iLv8hv//Zv87u/+7slGbsF3srI+dstSu8kDKHEW4u9gi3iTNEPU5q+w+GZKlXXvm3oyq2CWl5Z6wMmqW38u5VuwO88u8K/+t4VDs1Umat7ryth826dt2/FDYPbkdzL2wFxlmNJgWtds+SNF/8WZm7HtSVWseDfHiV3vP0sUzyz3GF7lDBbc3n8wNSes5uHZmpUXYvvXOhwcXtUpDaa9+QXRAxMUEej4jCMcz7zyCJ/9omD7Gv6rPYjTq/12RrE/NHLa/zR6U3CJKPm2cWckMWLKz3OrA9IMmVqBDS0A2NnM+kk5r2IIqXQkkV/l7xWiK20SZ08MV+j4VtYwiT9KaUIEtOF5hYdZ3GqODRd5W9++gRTVfeGc+N6lW6+7jHf8FjvR4Tjcm4BvmNeLylSLUVh65uuOrz/6AwvXe1jWwLfsQiTjJVeBFozSkw6IlKjlEmcnKrYRJliUCh7W4OYz724xuV2QBBnuLZgEOV0ghSB6Q2brXtUHYupmsOxudotr51j6+2BqQovXe3zrfPbZErRGSX0w5StYUzLt7Gk5OB0hSzX9MKUXpAiBdRcC61hruHwyVOL+I6FUvqW36ed3/cnDk+x0o3YHMas9SN6YconTi3wsx86XIYzlShRosSbxH0tVyilGAwGzMzM3PQxcRwTx/Hk7/2+WTSmaUqapm/5exxva+d/7yXObw754isbXNgaTdSKB+ZqfOrhhV0Rxm8Gnz41y1pvxPmNfpHGJgkTxVo/Yq7m8qmHZsnzbM+ZhHca3s5j9VbiyLTPX/nIYVZ7phvo959bxZea45OFu6LpSRrzFc5tjvjCiysc+sgDk8WaUprPv7BCbxTx4Hxt13Pqcz5ffGUTBHzq1DxSSjpBxMXNARY5WoDKM6b9Cq+sdFjrjfi/fujwLc+/m523n3hogYprMQiNDSxJbk9gFmo2J+YqvLzap+HeuOjd6AW8Z3+ThZq953HPMsVzV7u0g5SZqsNjB6awbcmRaZ9/70MHJ+9zq5/jWhKbHFdqqr5kuuaCylEqnxCxcZS8LQSZVqAUFcth2pd3dN595dUN/o9vX+ZyOyDNjUVtseFiWZKHFptI1C7JZ7Zq8+ShBi+vDBgEJoq/4UukNOXEudIorRBK0XDgPUs1gijmH39/mQtbI7ZHMReKoBOlFZ5lEQQ556KYzjDiQw/M0Bml5FnGRnfEdM1F6JxqQZ4KNx4tV5AqQaYUuYSGLQkzYxm0hWIYRbyykiGFZK5q0Q9TrnZGWEIUlsDCgifgI8fmeOJAc3J+7ry+9IOINEupO+Z9ND3BoZZHnmW0dYIpcRY0KhaWgEGk8WzJicU6URG9P1e1OdBy2RzEWAiiJEWoHND49rXI+QNTPq5j5qeEgkEY8cShab52eo2za12GUYbSmoYrSTyJK0z4R9URPHGgTjtMWetFvLDc5vh8/Y6unQ8tVPi950KGccpM1eXQlMdaL2QQxviOzaGpBr4teXl1QNU2KlaSKbaHMUmS8vvPLfP5F69yeKbKv/uhw3zsoQVg97Vvr+/7oSmPYZST5DkrvZC5qsWhlveuu1beD3i3/jv1bkN5nO4fvN3HSOjrB0neJggh+M3f/E3+zJ/5M3f8nP/2v/1v+Xt/7+9x+vRpFhYW9nzMf/lf/pf8nb/zd274+Wc/+1mq1TJQokSJEiVKlChRokSJH1QEQcDP/uzP0uv1aDabt3/CXcZ9S8Y++9nP8lf/6l/lt3/7t/n0pz9908ftpYwdOnSIra2te7bD0zTlC1/4Ap/5zGdwnBttUm8FlNL8b39ygZdX+xyfv1ENOLc54j37m/z8DvXjbmxztRdNbGX7Wv59N0vwdhyre40z6wP+l6+c44HZ2p7HJ1eKS9sBf+1jx3lwsXHb52yPEp6+sA0InnpgBldKvnOxje+YgAOtNZ0g5cHFOp1RyuYgJsxy3rPU5D0HWrtU2pudt50g4fnlLlujhANTPh88PMXx9DxfGizRrPm3Vdpgt9oWZ8aaeGy+xidP7a0Sf+XVDf7BF16bKBAVV9ILUq52QpJi9kjCJPr7//7RYzx5ZJq///nTrHUjoxAJQZLmnNscEaT5rhklVwqEANeyOLZQ5b/5mcc4OFO9qSr4sQfn+fuff5Wzm0MOTfkIeS1/KUpyzm4Mma45/FuP7S/UyYQXrvQIE1M+PO45u9oN0JpJsIhETOaz5hoeTd8uCrNbDKKM331uhWGc3VBQLAvfpRBwYMrn4HSVf+eDhzlb1Fl0goSW7zBXt/gz823+wUseiYIk1zhSEKU5Sms828J3LaYqDnGmCNOcXGkOTlVwLMH6ICHJFa5lSqk/emKev/3jD9302nKzc6gdJHz9zCZbwwTPkUxVHCquzSjJGEYpSaZxbUnVtRhGGb5rwjk6owQNxJkiV5qKazFVdeiHJpRobD+teTZZ0T+WpLkpeS7KoaNUFfN5ArSxRk7VXH7kxDxCQDdI+PNPHaThO7e8dl7thPzSl8+aXi/PMkqVUrhSUvMsNgYxnVHMv//RB3ji0DRKaf7GZ5/Z85zRSrHcjTi5UOeX/tKTaJ1Prn0X2tHrvkaUuHf4Qfh36t2A8jjdP9je3mbfvn1vGxm7L22Kv/Ebv8Ff+St/hX/xL/7FLYkYgOd5eJ53w88dx7nnX457uc3ldsDZrZCFVhWkvTvNTcBCq8prmyEbo+yuRs4fXXBv/6D7AG/H+XGv0Kz6OLbDMNU0/BsvAaNUYduOeVyxD271HNuySbSc/H+UK8Jc43sOmRbEWU6Uw+n1gFxpqp5NogWO6/DC6pCr/WQyo7bXeWsCMUIGiWamXqEbKUaFo+DofIMzmyFffHWbk0tTyCIVcOes2Xj2SUuLn3r8IAII0vyWc2hZpvi1b12hHWYcnq4ipSRIMpZ7CcMUTHwDuBKyHC53E/6bz5/lP/jRB3Adl0TFdCOFJU2qnZYWriMZRNnkuxjnpkTYtgVXeym/9q0r/MiDc3zp9MZkLm+xmOV7YXXI96/0eWV9xEzNIxf2xIqotSZDIi2b1UHK1W7CgZkqr22E9GPFdNWlE6QsNH2OzVVJzwsutQOUhqotTZiHgLmGz3v2NfnOxTZaWvQixcurQ7aCHDPxdnNc6sT0Ik3Fc/nrn3iIxw7P8tnvXGYUZxybrQBtGlWf9WGK70rCNGeY5oasarAcibQcqpZmbTCi4lpsBhnTVReEZQiVkFR8mwud6LbXrR97dD9X+wlnNsPJPJ9t2eyfaZCLgJmaw/H5Oq+uDVgbpGgNvmMz1/SxLUmqYzpBSjvIma272FKy5NvMNVyC2Mx+ea4gSHIavs1MzTVzf8MY15W0Q0MoW1KQKcEw1QRZZgJJihJmO1FECqaqDuEgYape4dTSrRcBkQoZZZpFzwUpqFd3fxdnm5JBopiqV/A8l+9c2ObsVkijsvucAUBIGhWP1zZDXlgb8sRBs23HcWhWed3XiBL3Hu/mf6feTSiP0zsfb/fxue/I2K//+q/z8z//8/zGb/wGP/VTP/V2v513LH7Qyn5L3DneSOjKrZ5T96zJIrPuWQxjsKWZo3EtQ0DyXJOhmK17JMWc03TVpeHvLga//rzVWrPSC1nthRNlYZQoEqVA3thlF2f5rkTHJFPEqcJzJK4td6U/3mox/8yyCbyYrblIKdHaBGyM4mvDOxqQlsCRkiTLCZOMf/W9K3zs5CxPX8yI+lEROiEIkxylFbIIsRgj19CLMqQQnN8a8v3lDk3f4YnDUzcUqH/ttS2Gccb+KX/y/DDJaI9SwjQnUzlprvnG+W3el+RsjWJcW9IJUiquST2cqbk8erDF9jAhznPqFYeKY7PY9EwSodZorbiwOWKjH7FdqEJ3gjBV/MvvXWH/VIWPnpxnqeXzhy+uc3GzDz4cmq7guw5XuiFBnCEwUeyeY4qe1/oRrYqNFIIoVQRxTq5MWbVjCdJc0wtStoYJr6z1b3n8xqE1f/DiGi9c7REkJgnwh47N8pf3HeX06oDnrnQ4tzlCaU2r4jBf96h65p/EfS2fXCl6Ycp7D7RYaPiTpEOtNYMoI0gyvnOxzVLTp+pKvn2hM+n3ynNFqih6wkxSowIcy4SVKKUZxRlBnOHZ8o4DZF5vGM32KCHNjSq3Fyquidq/PjymDGYqUaJEiXuHt5WMDYdDzp49O/n7hQsXePbZZ5mZmeHw4cP8Z//Zf8bVq1f5p//0nwLGmvhzP/dz/I//4//Ihz70IdbW1gCoVCq0Wq235TO8U1FGzpe4GW6VBLjai3b1Nd3pc8bx52c3Ryw1PaYqDqu9ENuSpi/K0jQq5jwcRhkLzWuL251kaud5m+aKcxsjVnshG4MY3zEBDhXXwt1htxrfWHhltc9XzmxOVKUolTxzuUMnSJmqOLz/yAy+I2+ZGDnG9YvYJDMLcw0TjciodhRdThbo3IQxrAxwLEmcCVQOtmWev6szC6OKjct4u2GGJWBzEGNbN6pQQgj2TXm8utanH2bM1k3C32ovIskUtiWwpIVvm7TCF1d6xGnObN1joelPiBhA1bWZqTmkyub4XJ1GxcaRglwpLm6P2B4mJqI9N2T2TuBYkqmqTXuUTIj1iYUGxz5e5/LWgOe+ucx/8hOn+L0X1/nKmU0EEKU5thRICZYWpLlJI5TCJBZaUjBTdfCKIBDPFmjfYnOQ8/TFNp8+dQdFw5P4fI1Wmm4Qk+s6jx5s8vxyh0wpXClIMmWSDoWJzxdC0PSNophkimbFQWtNP0wLy6RJwAyTnCudgLV+TJIb/dCSYAmBRpuofIydVZlO66Lvy0Thr/ZCwlTxvoN3RmxeL0marbk4Re9dw7+xVjRMchxLMlvb7Wh4I9eIEiVKlCjxxvC2rsSffvppPvGJT0z+/rf+1t8C4Od+7uf41V/9VVZXV7l8+fLk9//4H/9jsizjF37hF/iFX/iFyc/Hjy9xDeWdzRK3wl5x99f3Nb3e58C1njHXlkghsKTg4LTPxe0RSkN7lExUmvE5uVOlfXChwfH5Ot+6sE1nFE9mbcYx5GObX1ooY2AWlK4lefpiZxLtDnB6dUCWaw5PV9gYJLy00uOJQ1OcmK9xdnM0IQ17LShnay62FPSClIprkWSKLDfEZGdE/fhrNf5vmms6o4QfOjbDha0hV7sRYZLvfhJmwS4wKosAlNa8sNKn4giGUcYgMr1nO3F0pk7V7dAOEqarDuv9mEGhMIWpIldQ92x+5MQsF7ZDNgcxjx5osn+quuv771qSJFeM4pzXNgcEcT6J3g/TnFQZdce6TsW7FVxbFrNOlQmxHpdXH5iu8ByGUJ7fHLHY8FntRiS5YhgrbCkRhXVPa40UkizPaVYcPOeaoqO1ZhTn7Jvy2ezHk23shZ2x7AemK0Rpzum1Ac9c7vIvv3cVSxpSJIUw5EsKRklGkudFIqyNawtsKWgHCdvDmHObIzpBQpYrc25EKd0wIctNxL3A7DelYGzs1JhONXHtQyCFxHMkTc/mcjtksVW5LbHZab197FCLq93gjkjSk4emOTpb48zGgJprIXfcxFBKsT1KeGixwZOHptF6d9ztG7lGlChRokSJ14+3lYx9/OMf51b5IdcTrD/+4z9+a9/Quwjlnc0St8NYuXg9XV63e87O320NYp693OWFlR5RqkCntKou+6cq2EWsuhBil0orpeAzjyzy+ZfX2BwmLDV9HEvgFHbHqmvhWZKL2yPeP1/YGLsR0zWHsxt95urGwjeIMtpBgm0JVnsxwzhjexQziDIWmz77Wt4u0nA9mp6DJSXLnZCqY6yGqrhUjbUiKSZ8kFxp0iJRfhhnnF4bMF11+OjxObpRwvcvd+iH1wI8lGZy7RPC/L0bJFg1F0sqkvxGRSrKck4u1lnpRby2OWJUFDhLKdAIbEtQdS1eXB1yYr5GP0rZHCbsn9r9+ZIspxdlpIXqpTAErR+lJLlmfPgH8Z2pYp5tlKWqZzPf8Li0Pdplf1bFjvvyqxs8e6WLUpqtYUxaEMBcKywkSZ4TZ+a92FLgW2JiaU1zxTDKqLgWDy026IXpTS3WO0ufTy7U6QQJXz+7xcYgJi06xcBYBjVm7qtZcag4FmGa0w5S9jsWvdDM2TV9m6+c2UQKwVTVwbUFW4OE7WFCUryYOUOYnCPX/6smhFHLKq7EsS0qtmVKsG3Jhx6Y4djczcNn9ipan6o67GtadIP0liTJtiV/+SNH+bufO83lTshszZ38O7A9Smj6Dj/34aPYtiRNb+weeSPXiBIlSpQo8fpQetTexSjvbL71eCsLte8FxmWyd+s5u363BB8+PseVTsB///kzPHe1yyhKOb2acraYGTs+X2N7lOxSaSuuxXzDw5aCUZIzSow6pgHPktR9m+1hAvPw/NUe7SCnGyRc3B7RqkRc6XjM1F2CJCNMjOrj2gKRG5vj5iCiH6XM1tw9F/RnNwb8s29fYq7h0g0SoizHtXbP3AjAtQSyKGyOUoXGqEkHp30QFpuDmK2hIYRJpndZHClmi8ypIkBrlIYgyVEabAG9IKETpqBhqmKzPoj5kZPznFio8//5nRfpB0Zh0xoqtsVSy2eq6tAeJaz0ImZrLjXP3nUzJogzvnuxQ9WxSIUgyhQ177p5Is0NyYk3PReEIU9CCPZPGQXKtST9MJ2URT93aZuDwK994yLrQ1NCbBVJkmluip8zrSYExrE0D8xVqfsOozijm5m5q+mayyP7mri2JErVTS3WO0ufAb57sc1K1/TS2ZZEFSQ0y419UakcKTQVzzEziXHGWi9EI/jRk/OA5monQggIkoxMaYIkI1fXKNet9pfAzFJWXZv9LZ9D0xUutkM6gbHCfuXVTTqjdM8y9JsVra/2IqarLn/2yQPMN7xbXns+9bBRrX/16xe5uG364hxL8tBig5/78NHJ7296jN/ANaJEiRIlStw5SjL2Lkd5Z/Otw153rMfhECXRNZDSqBuZ1mS5mdtpVh0EgpVuyJVOwGOHpnaptKMkw7UlP3RsliDJJzM6aZ5zfjNgaxQTxUYVGoQpTd9jqeXRCRIsKdgYRGyNYgahKdyteTa5NopPxZG4ts16PzYkxtlNRHaqKh85PkfTd3jmUodRkrFTrCpGkUxseUG0HCmYrjkgJJ4tyR3JpXaILQUVRxKmyqgnxXNtAQiT/igFxecXaA1fOr1BP8omCpktDdn5C08d4sHFBu/d30ToHrKw+Pm2nMy31X2brWHMifk6P/vBwzy33JvcjMmUxrYkjx1scWZjiJMo0tz80bqYbXodx9e1TKS7Y0mkgBev9vBsya9/+zLbo4TldkDFFvy1Y6bo2rONwunaEs+xyPIMpa9Z/IzdsbDTCRMjH2cKhSaIM85tDLFtyQ8fm72pxXqUZIRpRj23ubg14uKWCemoOBaqiPPfeRxzDWGm0ORYEpLcFD8fX6jx6MEWXzuzyUdOzAEQZznPLnfZ2EO5vBk0MFvzaFUdOmHKKMnJcoVAcGSmxv4pf885xusVvusDXV7bGPLClR7/4ceO3/Z6/qmHF/nYyXmeWe6wPUqYrbk8eWga275xjqxEiRIlStxblGTsBwDlnc27j5vdsb6TcIgfJIwXlLnSfOzBOc5vBrSDhFzl+I5Ea1hoeLtsWtdCPHbbpmZqHjM1j9VeRG8UAgFLTZ9jiya850onYnMQMV112BjExHmOU9ghk8woKe5k8akROwLbs0zxzHKHV9cGfPv8Nsfmq3SChK1hzFzdY156oE164dYwMV1Smd7xniUfODpDkmk2BhFuTdIJzDyXEGYx3guzXTNYmeLaeyjUopmqTTfM6Ecpubr2O60FG4OYX/vGRX7ivUuEqVHQtgaxsTsKgS0jmr7DXMNlFGfsn6rw4eNzfPj4HFe7IYMo5aWVPr/17BUc20JiVLws14Rpzno/YhhlqOs9dreAb1sMoxSN4I9f3UApmG14zNU9kkyhtVGRAHphRqYM+YkzQwClAMsS5EpT9xwOTPvERUfXha0QW8Jc3ZtY685vj2j6Dg8tNW5KQDYHMZe2Q86sDxlEKVGmsaWZy8u1vsFCCNeUOimKOTLjYeT3n19huRPy1JEZ5uou/W7KlU6I0uY5Ote3Ja8SMytZ9y16QYpnS6qeTbNic3KxQbPi0vCdXamiUopdCt/OmT+4MUX0Tq7vti354AOzt31ciRIlSpS4tyjJWIkSrxN3csf6VuEQP0jYuaBs+A4zNY9Bofi4lgQ03SDdtaA8MFVhqurwJ69tIQTkWmNLyUzV5dh8lWGccWy+BhkstSqT/X9ioc4wzugEqVkoa1Np3I8yfMfM2STF7FHdt5mteQRpzhdfWZ9YuIIkI0hyzm8NqXs2mdLM1t3JNpR2qbg2rYpD3bdZanqcXu3z3v0tkJIgzuhHySSQxLUFSa4JU8Vi02dzGLFzNGessFkwmY8b9SIcKWlUTcx7mmuiNKMfpjx9scOl7RHtYTwpnhbSFDbnStMOEvpRykzN5VMPL1xTG6OMf/rNS7yy2udqJ6TqBgSpwrEtWhUH15b0wpRB9PqqLrqR+TASDKEUEKc5L6/2SXKF71p0BiY2PVeKiuOQZIo012TaqGU2htg0K7YhOUKYImqtmal5RKkiznIcy+LYXA1bSl5dG/CJhxZu+H6d3RjwuRfWyHJFniv8gnznCiKlbkqcbCHxbEGQKubrLh89MUvdd9noR7yyOuCb57bwbMlKL6IfZbsSNW8FS4BrGzvoej8mTHPqvs3idQmXe5Grsp6kxL3A/W61L1Hi3YCSjJUo8Tpxt+9Yv5tx/YJSCLErJTBTio1BvGtBeX5ryMbALFylELSqDqC52g1YLmyNTxyeJjoP1R39STM1l8cPTXF2Y8h6P0RrYWLwLYllmfLpTEkWmj5LTQ8QPLfc5X/92gUGxQxZq+Kw3A7YGiWs9eNJ4e101UEW3Wm2JXlgrsYgzjg8U+N7l3p880LbFPlaEt+R+I7F9ihBKYEG5hse79nf4rX1Pt+92JkoZPbYmudZ2JYwqosC37PwbEmmIMlN8IeUgkzltEcJYaYAQcOzyJQmUxopBJlSZAqWmh4/VKgg/+ybF/mlL5+jFxpSlOWKYWze60o3xJFiklg5SYnk9kRjDMcS1F3JMDYZgt0gJcsVSjNRP82xNp/Xsy20zorURqNIKQXdIKU9SnBtSZLm5NrUIHi2Rd1zODZX49CMIeN7fb/GN0k6QcIHH5jmuSs9rnZC4BrpvRk00A8zpIDHD03TqnoALLV85hsup9cGaG1m9CQUNwluvV9sKWj6Np4j6QUpIFhoePzoyXmma+4N144xuRpEKcvtgLVeRJ5rRnFKs+Le8Po/aPUkJWm4+yit9iVKvDPwg3EVL1HiLqK8Y33neL19d7ttjfPX4sSVKmZ+YLHhcXKhwQvnTeBFrXLtMjZTc/nA0WlWuj7QYb7h8YEj06YoulDj6p7F2c0Rj+xr8rvPrjCIUg5PVyblzkJg0h+BTpDSCVI8S7DU8nEsWaifA5bbId+9sE2UmqjzgzMV3MK2J6VgyndQmAX9R47PIoQo+qts4ixHSsliw2em5hClORe3jVoFMIxTwsykc+TKpE4qpck1pHmOZcbLCDNFsygqzrUmyQQIge/YrPYjTq/1+R/+6DVGcUrds4vwi5xBlJHmpmPqcjvAtQTDJIdifmv8Zy8laedcmWcZkiilxJIaS0CijO1Ra02mLFpFQIgplIaKK0lyEyGZ5BpLCzxboJQiK7q78iLEJM3VJMjj7OaIuu/QrNh7fr+uV2Hn6hFn1ga3PUctYeyiSmsavrOL4MO1CoJcQdWxSbLstkRMAE3PENwkN8fP1DxUcWx5AxED812IM8VvfX+FraG5GbHcCbiwPeKDR2eYrXuTx/6g1ZOUpOHuo7TalyjxzkFJxkqUeJ0oC7XvHK+37+5GW6N7g62xE6QTm9haP+KYf6PKMEpyPv7QAlGac24rYF+RNBgmOWc3R8zUXA5MV7jUDpgtVIo4zdkYxHTDG0l0nGsut0Omqw6dUcIozUnScbgGxBmc2wzYP+UzW3PZHMSEmaLiSB7Z10RKkzDYCVIWmh6rvRhbCuq+RZgqVnsR0Q7/YqqKLrUCcsySuJbIaAmzD8dx9GPVUQpTpNwPUv7xV84zijOmKg62ZSx7VdfGlpJumKKUYhQroqKI2LaECVqh6BrTpifr2vsA1xGkmdmmbUlyVZRfFwNytjQpiY4UpJlCVsx2pRDEmcJ3JK4tSbMcVXw2S8hJ3P+YCGpMeqHSxsIZJhnnNoc8tFjf8/u18yaJUpqzG0NUEdxyqzm4mmeZQuYizfKV1QGWlJNzb1Coc0mu0MVsX14UPEuuqW6TfSbBFv9/9v48yLLsvu8DP+fc9a2ZL/faq7qqutEAekFjEwCS4AJwMaUZmWNLNkMyJQZHosMjD22HLDNiHGMqJoITM2PZtGVR0sgUQEscWaZMBm2CFHZSALE3Guiturv2Lfd8+da7nnPmj3Pfy8yqrKrMquzuqsb9RvRSmfnuve/edyvP936/v+9XoBFEmZ2Na1V9Ts1UOT3bYLET73ovvLHSpxtl47CWw36Fiif51uU2f/L6Kh882eLQZOUHrp6kJA0Hj9JqX6LEw4VytViixD5RFmrvHfvtu9urrXFYEJdWzb/jdn/+w8cB7ljt8MZK36YIApfWBkSZop/c3rU0ggE2hhmeAFNccs+xSpRjNErbzjOl7CzWZFVyYrrK+iDFcwSr/ZROlOJJyVwjoB64xJlipZ/sIGK7QY8OAMDuEoNBIplr+ASegyMEBkM/UVQ9l0sbfa62rerl3LKg8l3JROjRiVICz6FV9dgcprYPS9pd6V0i7h0HPCnJUON+NCFsgbKrrI3TEZAZQ+C7ZLlmWMyhTVQ8Uk0RzCLwXYHW0KzYeyjJFZnaIjajoI9c56z0ExaaARv9hIuO4MOnbk9T3P6QpBtnbAyScZ3AnWyXovi3J+37qPgO3cj2wp2dq5MoRTfJUEUa46FmyCBT3CxCPIpWgvH2JdAIXIyByZpHruzrTk5XUcbw9LEJvn1Z3/aZvbkZ040ymqHH4/ON8d8px6ZqVH2Hb15qc26pT5wpQs/9gaknKUnDm4PSal+ixMOFkoyVKLFPvJMKtUcpgm9m3PV++u72qzr+lQ8f5/Pn1nfd7smpGs9fa3NypsqJmQonZ2pMhP541mRjkBLnmjeWe1bduct72L6Y18Z+BlzH4BXnKlfSlggbqAUeHzjRYn2Q8hffd4SvX1jnaxfXWe0l9JKM0HU4OVPlvUcmiHPFty+3MRqi9N5x6bIIydAGhAGkwZGSqu9ijGF9YOP9nz46gShCPTxHFsEYW9sxBjTGJjoqxebQWummalY97BWpitstiaELVd+jFlg1T2mDNtY+6kpbaKwSTZbbmPz5RgjGsNIdAhB4kprjcqTlUvcdXlnqcXgixJGCC6sDcmXICpXPd+yMmTGglGZzkFL1JVGqeWyuvuv9dagZMlMPePlmh16cEqV3DuwYnwfseUmVIXQdqp61Fl5ZH3BprY/WmpFQmjmabpwReA4V3yFXmlwZVPH5cIXd3iBRNp0RwXTdw2h46WaXRujyb15fpVX1OTQR7ihsPjZVsXOLdavGNcKthzzT9ZCPnZnmZifmL33wOKdn6xxqhmMbas13x39+p81TlaThzUFptS9R4uFCScZKlLgPvBMKtbenCGZK4zmSk9M1/trH7l0Eu1/ste/ubqqj1poLq31OzdTQRSrEY7N1/sOFydu2+6XXVvi1P3hl1/c2WrStDxJ6cYbSW3azO2HH94Tt1koyZbu5RtY1rXEKO+L6ILUR5r7DchFGUvElmXbIlObqRsQw1Tyx0Cji321vmiNGRGl31DyHSuCw0U/t3JIxZFoRpZKNgZ2tOzVT4+R0jTeWuyil0EYQpTm14nxmShOlmmGaY4BUUZwjAQUJc6VAFkXUgQNGg+c4KGPQ2pKlKCtSFLFkRmC71pLi9QKN77kcnqgAKc8cnaQa+rhScHFtQOjZcu9a4LI+SBkkW3ZUIUAIm6KptE1fXO9nHG1V+PkPHd+1HPlfv7TMizc2efFGh2GidpzD7emHt6pkca5oVnzefajBuaUe55b6u86EKQUrvWQ8W2ij8u01C1zbsxZlmlQZfGC65tKJcjpxzmTV5/3HW4SeLAqbPX7uuSNM1Ww4yJfOLXN+pcdSJ8ZzbSH6mbmttMVq4OJKO7eY5Ip/9KcXx/NTaa5JMk1Q2D/fSfNUJWl4c1Ba7UuUeLhQ3mklStwnHuVC7S+8usyv/9G5cYrgSNl7faXHr//ROYADJ2R76bu7k+q4uBnx0o0umbIhEL/55Qv8UAgXV/s8cbi1Y7vj9xZlNCsu9dAlV5rXl7fe2w+fnuE3v3QBYe4cVDGCKwuFpligOwKqnoNShkxphDPqMjNIqdgYar51eYN3LTT4V9++xvevb+K7kslqyERFFfNhdk7MlZYMZNra5AJXoowhyXenhqnW+NoZlyG7UtAeZCznhSVPCF660eE/+1++h8EqTdqAJ63SFHqSYZpbRWf0frC2S20gLvrLfNd6FfPcUPGs7S707D67sbXTKWO70DKtiYdqbGt0BFQCh9VBhiRnqpgZGyQ5sbLWQ60NgSN5+WaXqu/Qj3NypQldS1aFEASOpBa4ZMoU0faSp49OMFX3ubYxHN9r51d6/NZXLvPGSo/VXgzG9optFxpH9QHcMj8msAres8da5FqzMUjvGM6hsamPrrHEdVSDp40tipbFgwMp7Mzc9673mKg4nJlrcGauMSZWI3vdF8+tYLThy6+v0kty4kwhgEk3YLUX009ynj02yVTNHy+O13oJf/TS0nh+Ks4kz19t0x5mTFY83n9iCt+BP31jha9dWuP/9L6j/IWnDz+y5c4HQRrKFMbbUVrtS5R4uFCSsRIlHgCPYqF2nms+9dXLO1IEARqhpOY7XG1HfPrPLvPxs7MHtojT2nC9PeTi2gCAUzM1jrWquy6KblUdz6/0ubYxxHMl7zs+weHJKnGSgoF/9o2r/MLH3LECMHpv7UFK6Ao2BlkR4iAIXUF7kPIPvnyeP37pJueWepY8SO5pU9z+TSns7NrIlpfmehx6MerIaoQeUab48htrVDxnHBISuJIjk4L1fspmZAuE675jwyAKm1t2ByJm359hKHJaVY8g1zx3vEWqNNfaEevF7FlcvF4CnmvDNjINOlOkSqF1YXPEEicpR6EdZjwHlheEaDRv5TiShWaAATajjPcda9EeJHzj8kYR+S5xhb3OGkOuYL7hE3iSOLaR+toYPnJqiuevbuJKwTPHJji31KMzzOxxZ5q6L4ufBYQgymwEvoMgU4rLa0P+/hfPj9WfT757nn/xrat86/IGG4OEYaqsNdOVSG3G5wIsmRJmK2hDGPA8gTaGV5e63GgPLaFmi5y7xcdz+yVRBnRuxrZEZeznRzq2asF3JFGmiHNNzQ/4wIkWQgi6UTZW/kJX8MVzK+PzfXKqyo3NiG6co0yyI7BksjLJYifmvYcneOHq5nh+CuDcYo9cGY63KrSHGc9f3WCQ5HSGGYnSvHitw796/jp//WOnDvzhyn5xP6ToQUlDmcK4O95JVvsSJd4JKMlYiRKPEA7iKe/z19pcXh8wXfPHRGwEKSXTNZ9LawOev9bmQ0VX1YPg/EqP3/nGVb5+cZ3OMMMImKz4/LlTU/z8n7vdcgZbquP19pDf+splhICnj0yMj7ceuhBBe5Dy2ZeXOTlVY7Eb842L67y61CVXioG2XVqusF1fg2Kh/tKNDpdWB1Zlg3EP1p1CHrTeWpw3Q5fQlQwSRT1wqfkOm8PMpgIW4RfTjYCPnp6mG2e8dLNLcAuhrfguR1oOjdBjfZjw5589zP/y7esMEkWS3X3OyXMFbsHalJq3RwABAABJREFUGqHHRNVnsRPRjzNbpKzNmNhZUmUIPIlSmlRbq50v7XZmqj79Ik5dF/bD0b5ttLzAkXabE4FD4NlEwarv0qp6XG8Pmar6PHN0Einh8vqQm5tDwEb4DxJly7EbAdDnRjvm868sUwtcHp9v0B5m+K4kKUJUNNBPNRVPkOaabqzH10UW1tDpmk8j9NDa8OL1Tb56fo3zKz3b+6UNlUJlG1UTbMcoGEQUyqY2Bt+VzDYCVvspg1Tf1kdmivnA0Ydk1AsXeg6OhF6UI7VBSkEjtNUBINBYy+LGIOPqxpCVXmorGpRVMwdJTi9VTIYurVqA49jjyLVhmCqWuvH4HLvFA5+nj03we8/fGM9PdaOMjWFKPXSR0iqqV1cjHCmoBQ6BJ0lzw7mlN0/t3ivulxQ9CGkoUxjvjneC1b5EiXcKSjJWosQjgoN6yrs+SMmUpnJLn9IIFd9hY5CyPkgP5Jj/28+/wfeubeIImG74iKIY+HOvLrPST/iVT5zd9fi1Nnz/xiavLnaZrt9uUQIbef781Tb/r3/9Gmv9hEtrfdqDFKeIXR9Z4hB2jinJNLmBiqeRwpKOe5Ubj4jWTN3ngyenWOrGXFkbMkjyMYkIHLsYn66HfPBki+l6QC/JcYS1/qW5JvC2zrcQAt8T+I7ko6dnWO+n/PHLS2Tp7kcjGCl4Bimt8vOBUy2yTLE5TBmkaofCp82WaqO1oeK7NB1BJ854z+EJOlHKdC1ksROjTWbnnVI9VsxsVL1BCEskW1V7/vtxzlwzHKsSh1sVHl9o0ItzXlvqIxA4UmIwDJKcJFN4gd1GqhTnV/r80NkZ2sOMF65tEqU5RycrKGO4sj6glyiGmT0HniNsPL7SZNrG3H/3Wptq4KKUIcpy2oOMTBtqviTTdmYtL978bmey4tpkycCVNCqefR+bMZ043/XnFWBu8TU6UlD1XXJV9KG5AmNEUcpte9LS3BZ195OcP3l9lWboMVUP8EKXQZyzMcyKc1LM6mFJeqvmE2UR7WFKL84QQjBTD/jxd80x2wh2zE+lSpNrjee4aK1Z7yUorWmGHoFry7aVVsw3AtYG6YGr3XvFg5Ki+yENZQrj3vAoW+1LlHgnoSRjJUo8AjjIp7zTNR/PkUSpohHevjCLUjufM13MuNwvtDb88UtLvL7Uw3cE0/VgvCiab0rWBymvL/f44xeX+AvPWmvX9gCOT33VzgG1hym+I3nxRpf3HW9xaqY23keSK15f7hFnisfnG8w1AoyBDGtZHPdAGUiFGatgrpQoc/c4eYDQgYrvcWyqws//uRNMVX2+fbnNROhyaX1IN8owGGbrAUdaVU7PboUutKoeoWef4ufaEGzbrjGGzjBjouJR8R1++r2HuNYe8sK1TW5NuZfCxqX7rmCQKkJX8syxST757gV+5xtX6RfR8VGqtqLcC5nPYDvScp1T8SRa2337rkumNVM1n1RpshycQBDnCq0gx849VT2J50jWBwle7FAPXRqBy/dvdAF4fM7GsKfKBoJEmQa0DbgAlroJRyfs+dDGkCqNIwTnV/pEac5Ubasj7lirxquLXQwQeoJ64KK1DQeR2NLlbmzfx1I3Ic31eL4ryTSZgeQe5DrJDUIYQk8isIRmY5iRqTvrkdu/Y7S1qM427BzXaj/FIBDCWjuHmbLk39gZNcXW/aS1QboSKe2Moeda5SrNdfE5yWkPUqSAwHWYrLg4Rcn4F8+t8NPvXdgxP+U7ElfaOoEk00S5xpGWDIMtARdCjO/lg1S794qDIkX7JQ1lCuPe8Sha7UuUeKehJGMlSjzkuJ8Fzd0i65871uLkdI3XV3rUfGeHVVFrzfog5Yn5Bs8daz3Qcd/YjHjxRgdlDI2Kt2NRJIRVktb7Kb//wg1evNHBcQSh62AwfOfKJkmuaIZuoTLYKPqvvLEGwGPTIQBvLNuZmTOzdRqhR6vuI4uwipHlzBEgiq+NsDbI7mhL3HHuheTUbJVnjkzyzYsbxLkicCRn5hr8pQ8eJ9ea//U7N5iu+xyaqOx4j83QY74ZcnltQDdKcR27MM6UphdlJLlmpu7wP3/zGonS+K7DZMVnmCoypXEdq5z5jkAZYc+DsQvT/8uPn6HiubbTS9mY+e0wu5ASUZCGG5sxhycq9GNLhhaaIev9hHaU2Z+RhqnQY7buk2lDN7Iky5GSfpLzymIX17GzVq8v93AdGwrST3JybfAcqxKhIcoUy70EsKXPviPpxhntYUotcAtCZee02kMbQuIWlsM41aR6y3opgGGiuJZHGCPwHIHOrdV0D60ASGwf2ihsZZgq4sye6zuFdtwKVZzJo60qTpEKmeUG3xX04pwxpxMgJQhtA2BSpVkfJMwIn16c4bsO0zWPTpyzOUyZawQs9xJ6cY7BoLRhM7IPTo61QjYGKd+/1uGxmRovL3apBy6N0GWq6rPSiy351YaKJ3GksA8fck0tsNZJxxEHpnbvBwdJivZDGsoUxhIlSjxKKMlYiXcc3mnpWftd0Nwrst51JX/tYyf59T86x9V2tCNNcX2Q0gw9fuGjJx/YzjRIc4ZpDtiuq1uRK21LkB1JxXc42qoyiHP+4Ps3GaY5p2drVH2XKNUM0pxm6NCNFS9ca3OyZWdflroJhyYr42LoXNl95dquikeWPb3LYlsIu0C/00K85glSbXj5RhcMPHu8NVYkr7UjBqniFz5ykvefiHjpZmfXbUzXA5S2JLcX54zC1XNt1Y9qYU2r+i6DJOf6xpBBqnCl/RwrYcCVVF3JwGhOTlb5u//H9/L4fBOtDadn63z/emccUmJrn2+HATKtmakHOALWBgmugKVORC1wCTyHIFNoRzDfCPnQqSmmarbzKskVbyz36CWK6ZrH4ckKs/WAb1za4PpmRFIoMlIIG26itO1hk5ZIpoXU5zkOZ+ZCOlHGMMnpxYY40yS5IsrUmMhkBlCglbVejiyao0TLVEHgWnK5nXLejVyP+tnA+jDjXIEQRXn23iCw82L1wGWll/DkQp2ZesBKz6p0I4unLI5Zm8LSGLhkCrpRRuA6HJms0qrm9OLMBn64Djc2Y9qDpLCHWott6Nl75vs3upydq3Nhtc/PPXeExW48np86OVNlfZCw0kvHr1PGqm2eI5iq2ocgUZIfiNq9X7xdpKiMbi9RosSjhPJvohLvKLwT07P2s6DZa2T9aJB/RNpWewmOFByfqvA3f+TMgQz613yXqu8Cdu4ncLdmpowxrPVTcm2YqXu0qj6OFHSTjDjNkUKw1k851nKYqnmkyqYE+q6kPUi5tDbgdMMqHU/MN8ck1XckgSt3WNjuJJqIbf+9XUUqEgLRJJnh+mZUdIJBI3Q5O1fnjZU+n391mU++Z27XgIGb7YjQk/z4k7O0C1UizjRVz7Ex77ni2FRl3FVm539sh5UoiE2cKQapjTxv1Xx+/sPHedehJmCVgn/n/cf48uurbEZpcbzWXnjrezEGfM/hyUMNlrsJ19uRjWfPNZ0opx66NumxVeHdhyaYqvkYs7WdKNN0o5Q/d2qKZsWjF+ccmgzZGCRcWR9YQiYMShXqkTZoqciUwhV2O7VA8ol3z/PHLy2x2k9wpSjmqna3i+ZsqZnGbAWtAKSF3XD0pVE8v7kDs3KEVeZybXAdyJX9WpzrPZExT8LCZIWKK0kyzbWNAYEr+dCpKb59eYPVXkymLPkSxb4qriXdjpQsNH06cc5TR5q0aj5r/ZRXbnbIleFd81W+d6NDrikIrWCi4jHfCAk92x93sxMzVfWZaQQ75qeSXHFsqspMzeeVpR7DNC/CTjymqh4V3z1QtXu/eLtIURndXqJEiUcJJRkr8Y7BOzU9a68LmtCR+4qs/4kn5znSCvn0V69wcXUA0nCoEfLaUo+TM9UHPldHJis8dWSCS6sDelGGX5fjRVGSKfpJjuc4zDdDGqHLxiDhxRsd4lzjSNgYaDCGuWaFhWbIxiBjkNp48I1BBg04M1sfKwhg1aZa4NJP8nGMOWyVE++Y/+HOaooButtIwlov5U/fWKUR+kxVfU7P1caK5F945vBtAQMbg5SbmzFJrnjxegdXCg5NVPjzzxyiEXr8f//0IqnSfPPSBq4jaVU9oqK4aqEZcrPoIAuL2HuD/Ry8utjj/EpvfG0eX2jwiz90iv/nZ84R52qsAG3nYxIIfMm7DzVY7aX044x64PLkQpN6KFnuWgtlkis+dHIa15FsDBIurAzYGKZEmWKjb8n6pbU+vVix3IvpF6pZUlgFt8+qAWSFRc8pVOnFzZjPv7LCSjcGIM0Vd+Bht+FW9XJ7CiZYAih2Uz8ZEWtBpm3nGsYqbYNMIYrZru26TJGngStt2IfnCgQ2TEQbO4s1TBXdKEMUhM4t7KfaGCT2NQvNCt04o5/k44cN1zYiXlvukylFP1FUPId+mmO0nWOr+A6ztZBmZYtA1EOX1V7CRMWj5rscm6reNj91qBnyu9+9zj/40nmGqaIZuHiupBdnB6p27xdvFykqo9tLlCjxKKEkYyXeEXgnp2ftdUGz1Iv3FVl/fqXH//S1q2xGGe850qTquwdKXqUU/PR7Fzi31ON71zZZ7sZMVD3Aql5KGxaaPmfmGrSHKS9c22SQ5Egpxp1bw0yz1I1ZaIYcngxpDyW9OOff+/Ax9JU1nj46yYuL/fF5aYQu882Q5Y5d8DtFxPvIOuZg1ZGRfXGvnwSbqCiRAq61hyx1Ix6fb5Dkml6c8e7DE+MF8udfXeKf/JtLRUBFQLPiEmeaq+0h/+NXLjPX8GkPU+abIb4ryZTh5mbExjCjGbhEmUJgODxRIfRdnOJ6R5nixubwts/xX3r/Mc7d6PC5c8ukuSZThmGSE3oOzYqLQXCsVSFKFDc7EbqYw7q0PmC+GXJmrs619pBBYkM4cm2KpENFPXRxpGCjnxBnmq9f2ihi5AFjxqmNsEV8PGnts9pAxZOEcpSOKOknGQZoVX3W+gl7NwneHXdUN8WWVdUVgkwYcg0TFa9Iw7QqpDBm3D82+utBG0PoOLYewLWfLaVhrZ9YpbAov44zBUbgu/bzUfVdlNZsFqXjwzTnZifCkxJhDKHvghG0aj6zdR/XERxtVdAGenG2g4gB4yj8QxPhmLTsNj/1733wOLP1YKx2bwytBfiJ+Qa/8NGTBxprv1cr+NtJisro9hIlSjwqKMlYiXcE3snpWXtd0Lyx0t9zZP1bRV7PzDX4lU+cHfeMrfdtgEAtcKh4FZ4+OkGr6vHty22iVHF4okIvzhkmOZ5r52YypdkYpCw0fbpxzhPzDT7xxDyfvQI/8eQcN7rpjvMyUw8QUiCNoea5xHleFBjbYAnPWDKiRkrJHrHeT+hG1mqYa8P1dsRUzeP3v3sT37WhHoM451NfvcJaP6XqSdpFofFULeB4q8KrSz26UcZs3Rvb2ew8WUY/zukXEesSaA8yDvseQdGJNUitwjL6HB+ZrHBjM+LVxS6L3Zh+bGevpBBIKdHYaPpW1acWurbkWhuElExUbADEai+mn+Scma2x2ku4sDogyzVRqsZJh0bbYIpM6aLguZiNcgR5tvME6qKXy3NskXSUKXDsz9RDl/YgxQgbTLHeT/b9eRqnYxZ/HhGukXI2+v4o5l8VFlDfESAEpijoznI1LoGWEnxhlTOMtTs6QqCM/Yw4UnBkskLgOtxoR2TKMFOzCvX51R7GGGqBS5xrlLZx8yOr7GhOzH7eNMo4KG2Ynwg5PVunVfX43vVN4tzwxHyN86tDNga2O2wU9tIeZFQ8l5948t6k5SeenOfjZ2fvGN5zENivFfztJEVldHuJEiUeBZRkrMQ7Au/09Ky9LGg2BumeI+vfSvJ6Zq7B/+1n38319pCLawMATk5X+d+/t8hLNzvcaEfc7ERUfAchYL4ZcHldkSu7GPYcQTfOGKQ5jdDl33r60HgxFbgOH398lm9fbrPSjejENjRkquaNVSIhBFqD71q7mu9IfNdhquZzYbVfxLHfG8NM4+RbFjmlDJvDnG9fWWeQ5vz4u+b4F9+8ykovpuo7Nkre2LLpVMVMVT0cIciL5MR+nKN8w9WNYZGitwUDdOIc3R5ytFVFSjt71Aw91gcJry52+YMXbvLda21evtGhE9tOs2bokWtNnCmiFCDj8fk6K92EJLdze74rma4FhJ5D4G7NJE3XfBs7vzFksurZlMLc2ukoagE8x9oPR0XWo6ktgVUPBVY1MUVqYa5BFc8G1voJUS6o+g6Za9Mik73GGBa49UqJ4l+mUDkboQ1CAQg9WaRp2lgTTwomGwGLnZgo0+PACwN2lkzaQm3fdQhcQbdINpytB4RFmXQ3zgg9h+l6SK40a72Equ+SaUPFc0hyCF2HTBuU0QwjzWTVwxcCz3GQQlALXB6bqY0rEB6bsUR4Y5jxzNEJLqwOaA9T+kmOKwSBJ/nhMzN87PTMns6R68o3Lb7+fq3gbycpKqPbS5Qo8bCjJGMl3hH4QUjPuteCZj+R9efX+m8peZVScHy6xvHprY6wJw83+dyry9zcjOgnORXPoe1JfCk5PFkhLcIrBkVkejP0mGsEfPPiBucXOzwF/A9fOs8gN6S5ojPM7XySEHhSMt30MQZW+wm9JC+SFu3CO44yenF+136p3aBMEZUvRqTMcH0jouq543k9gSUCQggcAaErGWaK1b5GaYVBMl332RhkW0RsF06ijC1OXu/HhJ7D/EQFR0KSa/7wxUWSTFv7YJGcN5rZWmiGuI5kvZ+QKs2VDduH5khB6Evm6uFYPRVCUA9d1voJZ2brfPxds9zoRChtaA9TXCmZqHr0koxMZShtijANs+OYi9NubYsGstww4rhVxzZuiSLIZZhCrpQN1eDOASu7wRVbZNh1rPolhcCTZpwYOULgWvLquRJXWlV0aTOyxwrkBnRx7nxXoo2hEXr8ucemWB+kVH2Xi6s9HClpD1OUst1gIwW2n9iQmImKR7eYnzPAVN12t7UHhlQZWhWPONfjZM1ulPG96x2ePTbJVM2nGrjM1ANqgcv6IOVdC3VybejFOe1hypHJCv/+h4+/7WrOg6rpJSkqUaJEid3x6K5MS5TYhh+U9Ky7LWj2E1n/VpPXW2dMoizni+dWaFY82ym1PiDTmizWmMDlw8enOTFV5fXlHt+/sUmaa3708VkOTVa5uTnkS6+t8NTjAIbJisfzV/u0hxmTFY/njrfIc20td6qwjilrSUyi3EaUO0VR7/64GBJLOmyEuaARuAwzxUo/IUoVp+dqRZiDnTPKlCZKNamyZcBKg5QKo+H0bI0LK/1xnPmopHl7EEamDe1hxrEpj8dmqix2EpJM40rFQjPk9eUeABXPqi5RpuinisMTHu5ESC+yc02TFY9cGXpxtiPwBLZmkg5PVvjY6Rm+dXHDdpy5Dr4jSXLFUidGYmPnDbY8eURqRnCkwC0IlxRboSlesb9Bau2Oudb04p3zZnuFkNAMXHqJGsfI+47AcRzqvkvoSRY7McoYPnBykvlmlWGa88Zyn26UkirDVD1gsuJyczMeq6KeIwg9B88RbEYZJ6Zr/PR7F/hfv3N9fC6STPHijQ5ukfBhNEXAh2ShGbLSi+nFOTfbEdoYkoLoSykRwqq8gevg13w2BikXVvu0qi2iVDFTD/i5547wvWudcUpi4Dp8+NT0QzPf9E62gpcoUaLE24mSjJV4R6BMz7K4NbJ+ZF28dYj/rSSvt86YBI5krZgde9/xSYyBr15YY7WX0Kp6DFLFWj/hxFSFbpShDTw+3+BIyy7wljqJnQEClroxuU7JleF4q0J7mHFlY1jY1TJybYmNw9as0UjVyvdpkbM9UzZcRBkIHGnnerShH2dkyjBfD5mseKwPUgSWgGi91TulsYv4711vM90IUcaMo+ehUN2wP6dhTNCm6z5r/YzAk+TaKodJrsdK0EiZ8l1rU01zjefa4S5HCpqhx0TFqhe3zySlVDyHH3tiDgFMVHwurfd5+sgEUkqubqQM0hxjjLVLFsdri51NkTAIQtkzbAwkypK1wJUkRc+Y1obQc23gBfsnYvbc2Lh4V0KUGXwJruMWRd+WuBpAa3j+SocfOeux1E3oxRkGm444W6hQzdDjxmaMNtYKa22ZhpPTNf7qR07w2Eyd71/r8NLNDmcn7H1wczNmpRfjVQWJ0kxWPNJMUa85ti/Pcwg9W6+w1I3tLFmmGCYKpQwLBZGphy4bg5RulLHcS3jqyAQfPT3DR0/PPLTzTe90K3iJEiVKvF0oyViJdwzK9CyLvQzxv1XkdbcZk5VuzIXVPo3QpT3MmKr5vOdwkxeubTJMFYErWevbMIkrG0MmqzZxUQhBN8rYGKY0QvtX11ovJdGCZsVFSkk9dFnvJ/SiDFdaE1yuraIChc3NWCK2H1FMYAmAEAKNVZNC30FjyY4qCn41hmePT/Jv3lhjM8rGsepJZvfnSQg9G+iw1IlJC0IoizAPzxEYY5P8lDIobInypdUBZ+YkHzk9xzcubVDxHLpRhtGgijAS1xE4QpAajTKmiDwUTFV9TkzXuNYe8szRCS6uDtkYJGzmKRir3Dx7bILvX9/k91+4wVo/4drGkMVOzHsONbnZiQBwHIkcvU9j0Lekn+TGvj/fEaTKFKR3SyGq+Q6D3L7ufjIUhbDn3e5764tCGOJUMSjmxkLPoVWRdOOcP3ljDaUN9cBhvhHgOmKsbEkpaYYua337wEJpXYR9yOL7t98jo5Llq+2IyarPuxYanF/pc3UjQhlDxZNM1QM2Brb3ba4RUvUdch2TZNYq3CgSKuNMcX61z4np2o577WFVlX4QrOAlSpQo8Xag/FuzxDsKZXqWxb2G+HVhmRqFX6z2Ypa7+kDJ651mTDxXUvEluTJjq9ZULeDZY5NcWBmwNkjoRhnr/YRG6PL+461x2EGqdFGObP/qyrQm0wKvWEB7jmQ1SejEOaEvGcS2s8z3HMgUnivJck26DzbgFqqTlDYWP3RtH5QrJVGmCFxb1Htk0iZBPj7fYJAqvnZ+nUxp4swWCweO4PhUlYrvsNJLdqYJGqu6OVKgtCHJ7QG6Ek7N1Hn6aJN+onj+yibtQcpyJ2aQ2LCSOFOkStMI7JzgqDi4G1mVaGEy5IfOTvPHL2WsDzLmmwHDLGeQ5ES5JnANr9zsstZLOTtf5/BkhZm6z0s3unzrSps0VzRDj7SwHxoDUZoTm63wDs8VdrHuWbWwG2UYY+x7L269KNfERfriflIsR6qfwCY6+kIy3wzt+ROC9nCnEpPkOXFm0xzjTKOxhNUpwjP6cY5fk8SZYn1gY+qn6h5KSSZrHtfaQ/7pVy+Pwyh2K1meyzRBYb88NlWlGaZca0c4jiTJNbNj4mdnB6dqPp0oY6LiMUwVcWYtm+85PMG/+4Gje77X9hop/2bgB8UKXqJEiRJvNUoyVuIdh3JQ/O7YzTY4XfdpVX0mqh5n5uqcnKrde0PcfXF4pxkT35FFshxsDFJ6cU6z4jFVC2id9FnsxGwMEv7t547whVdWdsw4+Y7ElXIcvOFJiS7mlALXGX891xqTCbLCIpjmdlE+stTtB/+H9x3i1Zt9bnaicZ+VNjBMc6QQZAqOtQL+5scf40uvrfLGSp9G4LIw4aMULPcSfFdyfKpC1XfpxTmBYwMlKtKQKnuMqmAo6bZBtqrv8sGTLWYaIcYYvnt1k0trA7SxPWSHJ0Oub0T0U8VmlBNISb3isNKLGaSKRuByaXXA70c3max6VDzFd69uEmWKWuByuFUdFwN7xaybIwXHpmocmazwtYvrrPYTfuTMLAa4sDpgY5BgAFdqHEeQZIoPnmxxtFUj04alTsTXLqyT5DaxcASJTTXcz5yeFDYMpea7SAHDVNnZNAdSZXYEdoxggLggs54EacCTgo1hRjfOmaxaG+kwyUkzjedIkkzTrPi8+5CtWtgeRrHbA55DzZDFwpJX8106ccr/51+/xkKzQsVzqAcO376yyWovxq/5eI4NEXnXQgPfkZxf7fPuw03+9k8+sefY+f1Gyh80Sit4iRIlSrw5KMlYiRI/QNjNNvjaUpc/fWONOFNUPEnFdzk5XeOvfezuRbH3WhzeacakEbpMVX2WuxFCCNJtiYbGGFZ6Madmarz38ASXV4e8vNjdUeo8VfVp94cAzDR8ci1Z7Sd4VUE/zqn4jrX4CWuVc0TRO5WLsUq1V3gOtKoBv/LJQ/yDL13g5mZEpjRJZkmB4wgOT1T49z58nKNTVX7mvQu8cHWTF292ipALQTVwODxRIVWaq0s94kxZa6GB0LPEwpOSXBuSXO8gi6Enubg2REpJq+oxTHOUsQl9/SSnHrocnaqy2InYHGYkRuFlAoOgVfF5/4lJDk/aEIubmzGLnYjpus/j8w0C18EYw9cvbbDQDBgkaqxUiqKr7NRMneVuQpwrDk9W6UQp51d6tIcpWm/NfV1cG3JosoYQ8NKNLgYbiqG0GYd85Fqzn/BK37HWRlP0wzlC4Dq20Hopt11v98KI+CljaIYO3ViRKE2r6rHSjcm1IZAUVtmJsQJ7axjFbg94dvx5A6aqAVXfGVv4zszV6Sc5G4MU37UKWaYM7WHCiakaP3x2lvNr/T0pXPcbKX/QKK3gJUqUKHHwKMlYiRJvMd4uq9FutsFLa32+faU9Jhe+K6kHDq+v9Pj1PzoHsCshu9fi8K9++ATn13qs91IwPU7P1sdR+0IITs/VWB8k9OKcNFfkWnOzHfHCtU1SpRmmit/4/Bu0aj6OFDuexM9PBNxs9wGbrNeshWwMUzvHU/EIXIlTlA47wqYmOlIihdq3KtYIPD778jKOkPytHz/LNy+tc36lxzDTVD2H6bpP3Xf55sUN/uS1VbQxzDdDfvLd8yw0Qs4td2kPbADG4mZclAgDUmC0Ic0MjiOYrHp0ooxkm+POk9Z2eWNzyHo/5mirysYwpeo5HJ2qst5P6UU5QsBsPeDQhI20P9SsMEhyTs1UyQ0MEtvPttAM+P71TQ5NhrYYWwjW+gm51jRcW/C8XakEmG0EVHyHxU5MnCn+5PW1sSLouZbs5NpwZX2I0qtUA4dBmtMMPQw2ml/rrcCO/Zx+RwjmmxX6iS2zTnXxX2Uwe7yQo5/KlCbOJb4rGcQ5ohmijJ1Bq/qSYaq4sDoYWwr3G0axm4Vvqubz7LFJzq/0uLJuQ2VypTk0EYKB33v+xp4UrreqoH2vKK3gJUqUKHGwKMlYiRJvId5Oq9GttkGtDS9ctbHxk1UPZWxkeeA6HG+5XG1HfPrPLvPxs7M7rFT3Whx+9cIaf/OffQelNZvDDGUML97o8L7jU5yasfbHyYrHRMWzFq9hxsXVARdWByitaYQu3SjjqjasDVImKh6HmiGbw4zzK33W+gkVz/ZknVvu47rWIjXXCNEYLq8NaFV9Nou5JTvjtH8iNlPzODFTY72f8spih0Ga8wsfOUnFt4RjrZfwmRcXWeolVDxJe5Cy2k/43rVN/s3rq7zv+CTTtYDlbsyNzQit7FyYEaIoGLZKmNaG9UGKNAbfsQRHY/+73I1xpA31uLkZk2uNEIIkt/Y6Iey5PD1X59BEhVcXu7SHKZnSfONym1xrXCmZqvpM1X08R9AepFzZGDJV9fGkGNs+PUfST3JSpTFmq+dqthEwWfH46vk1BklezM9Zq6bnSjyjSXLDUjcidCWySHAE8F2HiusAEc4or3+PUEXQx8JEwDCx9QF5ko/j//dzOZPcIITCc+y5u7I+xBEw1wiYqgdkyrDai+knOc8em8RzxL7CKO5k4fMcwUTF44OnpvjZpw5R9R0+8+Ii7WG2Z4XrYYyUL63gB4e3cw6wRIkSDwdKMlaixFuE/VqN9vpLOs/1XZMTR7jVNrjYjdiMsqIAWGC0tr1YmcJ3PaZrPpfWBjx/rb0jDOTKxoBvXFzHcQQ3NyMOTYRj1evy+oDzy33iXHOsVeH4tMfNzYiVXsKfvL5CrmcIXclLN7pkynC0VWGQKi6v2zmohYmAiuciBHSijDhTxJliuubzsTPTfP7VZYQIODNdAbp86OQUVzcTqr7Dzz13hH6i+P0XrnN6pkF7mNhwkn6ybyJW9QSHJ0JyZQg9hzOzdZZ7CZ9/dZlf/vhpAL7wygrtYcZ0zeN71ztEqaIRurSqHqu9lO9c3SRwBINEUaS5kxb9YxVPjmeqcs2472o7yZDY742sfplSxfcMSZZQ8W0PWD/OiTLbuxWliqvrAyq+Q6Pi4TkumdKs9GJudiI6w4xMG7IrbWqBPdbQtduoBS6ulAyTnEurA9YHCZ0oY6oWIIFenNvgjSLt0ZOC0JW4joOKMrLcYIyi4jmkSqO0wXMkh5o+EJFqzc5msjvDEdCoeGTKsBllOEKQFScxKFRPtY/rabvRNA6WCB9r2dmutaKCwHcENd9hY5jy8o1NZhshzxyb3FcYxZ0sfE8fneQn3zPPYzN1fvPLF2gPs30pXGWk/DsXb/ccYIkSJR4OlGSsRIm3APu1Gu31l/QXXl0ed4qN1I07zXvdGk0dpWocGtGLM1Kl0QaWuwmDJKdZ9ciUjePevr+//6U3OLfYQwqb/jdR8Xjf8RYnpqq8cHWTTGmqnk0crPoux6cE6/2E9UHGn51fZyJ0CHyX9x2f4NBEhc++ssTmMMORkuVuiufkxeyatccZ4EZ7yFfPryGl4EMnp2hUXIjA9yRaG16+2eXqxpAT01Xag5x+I+PUTJ21XooQgtVeTLaPeSUhJNc3YxBwfKpKs+IV16XP9faQpW7M81fbtKoeF1YGRKliquaPr2vFkyx2YzxH2gj/fooo1KRMaWQGBqtK5dtCKLZzRr3ta7dySY0NszCewXUky92ENN9ktuGTaU3D8awNUqtx/P5yNyZVGkcIJqsujnRY7SXFMRuWujHTNZ8Xb2wySBWOEEzXAw5NBHz3asfG9ws7C0aRqhjnmrrj0AhcNnVWvD9DpnNaFY/pesioRGA/CYrN0GGq5nNmtoZB0I5SLq/1qfqWqA+TfF/zZ6P9R7kh9GyUv0YwuLbJUjcmyzWJ0mS5Zq1vExb/0geP7VuhuFvYx5++scr3r29yeHJ/Ctd+IuVLleXRwcMyB1iiRIm3HyUZK1HiLcB+rEZJrvb0S/oLry7z6390jl6cMV3MuUSpsvNenznHaj/h2WOT40XZrXMtVhGDfmwLfREQupLAFQxSxaDo/JouQg1G+9scpviOtJY77JzRV95YY+1Qnc0oI/AcS9RGxMR3OdJyqAYpi5sxrVqFHz47WxQKD1jqxPY8YDDG4EroxjlrgxRX2JLlXAoGSY7vSr53vcNzx5qcEvDi9Q7dpLBZakMz9MjVkG9dbtOLM661hyS52leCX8N3qAYuca4x2jBIFO1hRrPicn6lz2995TLX2gNevtml6jt045yZ+hYRG1n8cmVoVSzhUTBmVxqgsBnuv/p4C7akWKONNe6tDxK0siEZVzeG458blTtrbRBCEHgO7UFGswITFc8WcAuYCD0WOzFRqnAdQeg5TEvBai+laA6whKqYwdNao5RmkJhxIbPriLFFcZhp6rmiHSe3HfvdUPMdHl+YIFeal272SHM1DjaZqLikuWaYiCKbcf/wXIFBMlXzOTVT4xsXNxikOY60PW+OFFQ8hy+eW+HEdPW2BfG9CM92C9/5lR7/6E8vcmG1z2o/5sLqgE6UcXa+MQ4LGeFOCtdeI+WjLOc3v3yhVFkeATxsc4AlSpR4e1GSsRIl3gLs1WrUizO+dG71nr+kj09W+dRXL9OLM463KmObYCO0MzuX14f8vc++znPHJ6j63nhRtn2uZa4e4Ajb/+S5VqWp+A6uI5FCszHMmKhUePbIJHmux/s7NV1lsZMwSK2C5YWCbpzz+lKfNMsJfY+KLzHGMExzHGGDQQLXlh23agFS2u9fXB2Qa4PnCISwPV4Gu1jJlUELW2icKoOUdj6qE6VcXO3x3ByFIhVggPYwJfAcnlio86XXVvniudU72hNHfVmwkw452ILoXBsahY0vymzK4HzD59rGECFgvhEyUfHIC1vnej/FdxwqvkOaawZpjgBW+wnxNknOkbaLOTOgtB6b9kTxzz7FHnIDJje4LiSZZsNYQtqPM5QGxxEYY0mTxpYwV3EYZopunOMW9jzfcZiqeWxGKY1mQOBK3EJR3Bhk9voACogzgyOtSVBrq4SNCq1PTtUQEjaHOcNUcbMTk2XZvt5T1ZcErqRV9ZmtB9zYjLjZjVAaFjsxNd8pCKHYU6LidjQCl8CRdOOMyarHWi+lHrosTIRoYz9zSa44OlXhenvIv35pmcd+dGtBvB9b2a3KRz1wi0RLWzvw7LHJHYTsTqXJt86jLTQDcr0103dkssITCw0+/WdXSpXlEcHDOAdYokSJtw8lGXsEUVpRHj3s1WrUT/I9/ZL+7LklLq8PmK75YyJmt5Oz0ksQ2B6squcxWfV2LMpGcy3fv7GJ60gcqdAaPF/iSBtwEKV2oXloImS5n7DYiXbsb6rmkSpVzJdJQs+GWtguL0OmNNc3Y7Sx8e4Vb5SkCK2KXYD24px+khO6tt8qUzacIi/6o4wxZNoSmHrgkmvNIFE4UnN1XcGcDZAAa/0bzTudW+qT3hIRfyt2W8NP1zzmGiH9JGeq6hF4DkLY+Pr1fsLiZoTnSp4+MoEQguvtgBubQwLHxvNvDFIOe/b1g1RhjO3UGpUi57lhey3WduI1Vp72y8awxHJUEq1STZxZJcoSMUOidipIw0wxVfHQjiWEvmMLkJe7CXGmyJWmh42lj9OczICUkkbgsBnbubVc2/1ufx+B53J2oUmz4vLKzS7r/YSVXrIv9cp3BVGqeX25xwdPTnFuqW8VP23GM3T9xBaz7dem6Aio+IKK77IxsGrfYiei4jsEriRKc5Z7MVIIXr7ZAQSrvZs8c2yCHzo7uy9b2W7KhzGG+UbIcjdimOY7agTuVZo8mkf7na9f5euXNuhEKRiYrHo8NlPnq2+slSrLI4RyDrBEiRLbUZKxRwzlwO+jib1ajeqhu6df0kudhEzpsdVwtJ2NQUamDLXAoRcrYqVohNUdi7Jf/vhp/sMfrfOnb6wySHN8KXhjuU8nzulG1q41Xfd56sgEYBcO64N0x/4qvstCM2RjkBFlCqUVxljSOcwUUghCTyKFQBu7gI4zRdV3aFbsNlJllaFqYIuQhbZ9UKpQKEaEyZOShYmAzWFON0oZpIoks99c7cU4jo1aP9KqsNiJWO8n5PtM7PAdwSefnMdzJS9cszNTQgo8R6KNTTsMHIf3HW+Oye/puRrdOLPBFlozTHPWRgTEWOVNUJAWbfBca+3bbpmUwu7bGBvucT/Itr3MdSBTNu3QGHsOb00ejDPNzYKwSWCtn9kQC1eQFSqlROzoPIszjR+4+I7tyhoVX4/Q8CWtmsfVjQEV12FYZPSnuWaPncYAVFyJMhBlim9eXmeY2MqFwHVQgaGfFKmY+zxVjoDAleRacHauwWIn4tWlru2l8yRSSqLMzskdngxohB5JrljpJvzON68y1wj53Ct7t5XtpnyMKh16SUY3yljuxrSHtmx7r6XJca6Zbfg8MV+nEXo4UnBxrc/V9SHvOz5ZqiyPCPYzB1iiRIl3Pso7/RFCOfD78GIvcyS7RV9HqdqxEAtcZ0+/pBcmAjxHFgl+drWb5nqsVOXa4EhBtYiA321Rdnq2zlw9ZLLq8Z7Dkyx2I6JUUfEd21WV5mwOM2q+y3TNx5WCztCmLzpC2Hmyuk+cKfs6T3N6tsZ3r3dIczt35DnWSpbmCscRLDRDlroJzYqP70hcR9JwBGmuyJQgdGzkvjZ2ve0IWJgIqQUeqTKs9S1Rc90iV9BAe5gRuA5V3+Hy+tBGs4/OO3fut5LFjFyr5nOsVaEauDRCj2ePTXJhZcDGMLU9WQaaoctMPeDwZHU8E6YNnJ2v40rb1zZI88JyKcFg1bHiGBWAMgSuJHCttS9VhoorCTyHXhHZ/qAYz4cZxufwbtgREmIMviOIM4MQ9sWusFZIbaCXWFvjbN0n04YkU2Nl8uysLTi+vDZgouLRqvpkypK5/fySGST28yuA9V6K44DQgm6U77unbARHQtVzSJWhEXq4jmCi4qMNxOmATBmSxBLSw1NVJgrlVgrBZMVjkOT87vPXWO0me7aV3Un5mKoFPHtskjeW+1xrD7m8PmC2Ht6zNHmktLWHKc8c3Um6jkxWeG2px81N20V36/GVKsvDh70+nNtPmmeJEiUeXZRk7BFBOfD78GKvauWdoq+3L8S0Nnv6Jf2T71rgf/7mdV5f6VHzHaSUKGPQxowjzqfrvi2YLXDromz7guDsXJ0jk9Vd93VkssIgznGk5NrGEMcRjFLKfWmJZpwZpmseviv56GPTvLbUYzPKiFJLCmcaAU/MNzBA4Dnj2ZfJisdiJyL0XKSQVH2HOFcMU4UQgumax2wjsPNnSY4jQZstrSfJFZMVH8eRrPVT0lyhtR53UcliGGtETrbDEfDeIxP8jR85zWtLvfE5n6oFtE769OKcOMu5tDbkSKtCL8q40R6w3E1ZHyT0C/VnsurxniMTXN+IiDLbZZVuk7+ELObBtCHODI2Kx0zDRv6nSiMLm9pBIMk1ntzqKtsPMgVB8XEbH44AaSjsp2D0SM2TpErTqvpFPL8lqJky+K69Fp0ovdOu7ojcgFEakxVdazk8SMiJBAJpyW+r6vHMkSaxMrzv+CTGGL56XrLYiZDCkr0o0+Nr0Y9z5pohj83UuLDSRxnDkdbuytKt99bdlI+pWsCThwQTVY9//0PHOT1bv+3hza0Pd4wxd7QvB65DLXBZ7Sc7CrtHKFWWhw97fThX/i4vUeIHA+Xfzo8IyoHfhxP7VSt3i77evhDb6y9p33f4ax87ya//0TmutiM7y1UUOXciayd89ljrlnmynYuyve7r4lqf/+kbV9DF/NH2YawYcCXUAo9m1eP86oAfOjPLuxaatylto0Lmn33qEG8s97mw2sd3rZUx8CQfONGiEXosdWO+nW+glC2gTpW1AK72E5S2M2ljc6axC+iW79CLM6uqYZP2wM6oCSFsUXGhuAlh1ZKzcw3+73/+Pbzn6AQnZ6q3nYdOlI770DxHcrMTsdZL8BxBnOtxkuFSJ8Z1bFx64Eo2hxmuI6mlOevDDFMQVyFGap/BEYKZuk8nykiKuPmD0MZybUnmfojYiNpqIM2tTVEVPV5KF+cLqPoOUWZTNl1HUvEcnj06yUov4cbmsEgkhI1BijY2YON+lpL7nQW7GyouVEKP2UbIf/CRE3zrUptDda/4TAjec6RJN8noxjmh5xBlOb0kJ8s1Fd/l9GydauDa9yMkwzSnXthqU2Xn7Rqhe9u9dS/lY6mb8MzRSX7k7OxtC+7dHu40Q4+1fsLhXZSSRugyWw+4vD4gyRWwRcZKleXhxV4ezpUoUeIHAyUZe0RQDvw+fLhftXJ79PVu2Osv6VGP2PaeMYNdNH/09DSnZmrjbd5pUXavfY2Kar97rc1SJ0Jy+0I/13BsMuQDJ6f47CvLvLbc5WOnZ3YobQCDOCdwHZ481OQTT86PCelaL+GFq5tcXLNFwzXf4T2HJhimNsp+qRuz1InJ8i2CFXoSsJa2WJmCJDk0Ky4136BUSq4ZK2QYO+ckClI0Uw84O9+gWfV2PQ/nV/pc2xjiuXLch7beT4gyRS8241AO19kKH3nlZo/Tc1UGReeYrvhkekg/zovrbhWnKNMEmeLJhSYbw3QcdPEg2D4Xtt/Rs+0/rgC1bQMGS8RqoctCM+DmZozvCmq+y+FJa3HNjeH6pu1ac12JUJrQc8el1m8XBHB8ps6zx1t8/IlZQtchylY5vO3v0KlawFNHJtgcZuRKkylDlCoOF2RqqubTizMmK5bQvbrYJdea9iAlzuz7m6x61AKPj56eHt9b96t83OnhzoVV+3mcqfscm6rteI0QgsOTIcvdmBubEaHnlCrLI4J7PZwrUaLEDwZKMvaIoBz4ffjwZqqVe/0l/RNPzvPxs7M8f63N+iAlThXfvLTOZpTTi7M9Lcrutq9rG0NeX+5xdW2A0kXIQ75FbExhYbuyMeTjj89waCJkcTOmG2VMVLdiu28lgzsI6QJ89PTMjv1HWc6n/+wKV9YGxdyWHpNAT9hAB8jItSkSISX1wOU/+rEzfPHcCl+/sM76MCvSDC15wnYVU/UcDk1WeHy+cRsxfexH61xvD/mtr1xGCHj6yARSSrpRhjK2Tytji1gZY0MnPEfSTxU3N2Mw1hLnuJKjkxVubEb04oxM2RksVwjefahBI/B46UaHeMQa94jQFQSOYJBthYEcjMlxd+TGliwvdgy5NmSJIclt3P3GcJ0kV0XCoSBXttOtE6s38YjuDgHUfIlGMF3ziZKcP3jhJkobrm1EVDxnB6E51qpydq7O1fUBnuvwgRMtDk9Wbks5PDtf54vnllkbpAgD2mhU8f1a4PJTt9xb+1U+7vZw5+kjEyx2Yl660S3uny3F2xhDlGl+7F1zTFV9Lq4N9rSvW+/3Em8P7vVwrkSJEu98lCv3RwTlwO/DhzdbrdzrL2nXlXzo1PT4z+850uR3v32DC6t9tNFMVvx7Wl/utK9ekvHSjU36qU0+TAoiJsXWPJbRMEwVF9eGPLHQYLWfcH61z+PzjT0/od9t/z/+rjn+3//6NXpxjisdMkYLfEOvmNcapIpY2cS+XBlmGgE/99xRljoxg5tdW9yMJSuugamGz7GpKu9aaO56LFJa+1onSplvhGwMM3xHkihFP8lRxhJSsHH7rtwqOU6VJss1gStZ7aVICWu9hChVKOz8Uui7HJ4IqfoONztDe3zGUHGFtYDeBaMjjXNDpswdFbBb0xMPApkGkygmqz4TFZelXsJiN2Gy4tEIXaanAl5b7jHY/5jYgWAU1CIEuFJYS22ueXWpx8lpzRMLTQJXcml1wLcut6n6LtP1AChSDmdrXG9H+K61HSpjiJJ8/Ln9xJPz/ItvXWWYKoZJjtK2ssF1BLXAmmZ/9zvX+fBjUzw+3xwf136Uj7s93JFS8t7DTb57dZPv3+hwerZ+27318x8+zmMzd9+X1oY/u7DG519ZsbNyEiqetWN+4l3Ttx5SiRIlSpR4C1CSsUcE5cDvw4eHUa08v9Ljcy+vsNqLCyVHMNsI+MST+59BOL/S459+5TLX2hGwzfLHVkKgZKtAuZfmY8XpsZk6a/3kvucgtDacW+wxVXXpRi5SOhiTWCuZBikKy+K2YxqkOf/9F86zMBEy2wj580/XuNYecml1QJTZ2bWnjkzw/hNTdz2WVxe7vHyzixA2at+VNljEphQaAkfaQmVpbYrAOEVRSsGThyZ4bbnLyqadcRsFiUhgkORcXBvQiaxqGWdqHBV/L7jSKnJJfm8r4m520gdFbuCpw3XWhzlTRfDIZNXn1HSVF67bOoB74c0gimBnAIWws4K5Nihti8aPTIR0oowXb3R49tgkHzrV4k9eX+Oblzf42OlpqoGd91ofZDxzbJK5esBmlLHSS3Z8bpc6MV88t8Iwyal4DoEnUUUxuRSCqZrPai/hX33nBn/npxv7siWPcK+HO4cmK6z1U07N1NgcZne8t+60r/MrPX7nG1f50rkVhpmiHthZs8qkw0s3Oyx1BnxgHzUEJUqUKFHiYFCSsUcI5cDvw4W7qZVaay6s9jk1U0MbY0tr32SifOu8yZFWlWGac60d8emvXd5X9cH5lR6/9ZXLvHBtE1eK2zqwTPEvRUGIBNQ9l8VOzHPHW/yNH36MxUIVvJ85iBubEc9f3WCtn9GJFJCPZ+JuXcw7Euq+S6Y151f6rPVjTk1XuVIEGjQqLvXARRmYqgb8zFMLJLnm2sbwtuM6v9LjD19cpJ/kTFY9moFHpjSdyPa3GWOJlxRiGzE1pLnGcwS+I/m3njrE929sWsImwHVsgIhNI7SR9uuDlBNBdRzqcS/UfVtXkClrlbybKiaEtU5Gud613PpB8L0i0MR1JIErWe8nDJOcqxvRnl5vgIpn0ze3BTaOv3e/cKQ9x3nBB2VRiVAJPELfsDFIubDa5wMnWnzwZItzRRS864jx36GfePccoetwcW0AwKmZGseK9MR/9rWr9JMcKcFzHVwp8Bwwru1E6yc5viseKERpLw93ZuoBf/1jp5BC7OveGt3P3768gTGGY60KuYa1fsIgVTxzdIL2IIaGfRByr6qOEiVKlChxcCjJ2COGM3MNTv5IbTwjNF3zee5YC3c/zaolDgR3UisXN6Mihc+mAP7d/+0VTs/W+Xc+cGSHhekgcZDVB6Nt3dgcIoV90v7GSn/cWzVSN7Yvnmu+gzaa2VqFn3zPPK4rH2gO4ovnlvn25TZKm6Kvyu5cjYqUi59zJLjSAWEjvrtRRj/OuFaQA8+Rtveq5tGNMj736jI3OxETVW9cQfDJd89TKdIYf/+7N4nTnBPTVVZ7CfXAbtevSdJc04sz0txQ9S0ZSzJdxNNbC+eJ6SoLkz5xZsmZI8U4Jt53BLGxbCFThjS327oXfGl7zoaZphbY7W1G2a5Ea0SSrf3xztuUgOdYa6QL7NVImyuDW5DOUb9c6Dn7In02aZEd8277XeYLoOJJHCnICpUuKTZY8R3qgcPMNhtiPXTZGKT0YqvexpnmL33wmO2w86069rmXd6+nCFyHxY6dNetGmnDbQxchwHclg0TRqnloo+/blrxXK/qxVnVfxGj7/SwETNZ8HClxJPg1n41BysW1AU/O2fv1G5fWefHm4J5VHSVKlChR4mBQkrFHDLvFHn/rUrv8Rfk24U4pfNpALXDoRjmrvZRXF7t849I6//FPnB2nIB4kDjJMZLStqarPjc2IVtVnoRmy2Il3VaakgMdm6zx7/O72vxHu9dT99aUe/+Kb14gzVQRlGPS2jItRDPv4/7VVixKlGXEbV9pFstLQHqbEmUIIG3TQHqY8e2ySKFN8/dI6n31lidlGQK4NF1b6zDUCjrSq9BPFxiClHrp4RYR5J3aJUxtrv6GyQvW0x2H7xQyf/upVMqVphg6OlGhjiDPNMFVjRcsA1zfTO6pBbqF+jc53NfCI8tRG/d8j8MOwUzlzBFQ9SVwoZSPCNlI790MdHEdijEFpewVybUjV/sI6ktzssJfO1D1qgcvl9Wj89TsVPDtAq+YV11PQCD2OtSp4juTFmx2mqj5PH5ngtZU+mdJF0Isl5f3ExtGLFELPEoxjU1XOr/T49NfuXE/x8SdmkRKm6z6bw5Rca1vsXUACmdaErsNkxafqOVzbGO5bVXqzrOi33s/bj307Uc1NBQT8L9+5Tm7knqo6SpQoUaLEg6MkY48Q9ttpVeKtwa0pfFGqGKY5Sa6phx7NiiDLNYvdmP/uC29wrFXl8YWDvU4HGSYy2tZMLcCVkkxpZuo+gzSnG+1swwpcwV/+wDH+zz9yes92qbsVZGtt+N3vXGN9kGIwJPmW9W43pSfXdiGcqa3iZIFdfDtCIB1bZjxIcxwBFd8dEyMbUZ6w2k9xHcGZ2TqX1/psDjNSNeDUTI3VXkJ7mFqLmhAcaoa87/gkn391hU6UUnASqr6kEViScGVjgDKGXAukhF6iiLPbJ7juNvelt71nKYSdRxMCZYwt977rWd6CxAZauI5EZQ9uW8yyjEwXttWCNSXZ/jZ6qy3RztWJHSRsZO8EyPKt9zvfcKlXA1wpGCSq6KizUe5HJqu8a6HO0VaV1X7KSi/Gr0mEsOqZKyWeFDvCjkaq0Xo/ZaEZkOQaY3IaocvZuTpvrPT59uUNAkcy3wi4thHZYuXQw5H2GsaZwpM2yKNV8/mDF25ycW1wX6rSm2FFv/V+TnOFQIxnSl1HkGtNL8qgCsM05z1Hph5IXS9RokSJEntHScYeERykDa3EwWN7Ct8oyW2q5o+vU+A5LDQDVnsJv/v8Nf6Ln37yQK/TQYaJjLblSMFU1ef65pAotQvfuUZAnOYkypYDn5qp8Vc+cuI2tW039eviWv+eDxMC1+H8ap8oy8fEwYz/dTscAUYyDsEYL/S1Rgk5frEq2E3gOQhhSHLF5bUhcaZZaIYMEoXShtBzCVzBIMlZ6yd84MQk/USRKk2aK7Jc0wx9njs2yfV2xPowZariUQ+trWxjkNIIXSTQizN8R5DswYp4K7aTJlcKar4tWR6k+e6s9A6wM1GSXpI/MBGT2FQ/o7b8hQZrOdT7SAu59TA2hhlJpnZYF5UBVShoBnsOHp+v0yjO80Iz5Oxcg6ePTTDbCKh6Dn/wwk1eXuwCcHquRi/J2Bik1AKHfqyYrNlC8el6MFaYrm0M+e61NhuDlDeWe6Ra40vJXDPgzFydQxMhF1f7dIZ5oSrZ0vH2MMV3Jb4jAcFE1WO+GbLSS1jsxA/0sOygu6e238+hK7m6MRzPMEoh8FxBxXVY7sVQhZNTtQOv6ihRokSJEndGScYeEbyZnVYlDgaDNKcdWRWlHnq3XSffdfBdwYU34TodZPXB9m2dmqlyYbXPMLXpa7KIBqw61sY0UfH5/CsrnJndSpA7v9Ljj19a4sUbHYZpTtV3ee/hCdqDdPwwAaAXW9vYfCNgqZvw2ZeX+dF3zTJMcuKC/LlSkOb6jkqQNlZZ2W5hBEgUW6Rh9LNYJcBzrNVvY7hlQRwUBdNTVZ+Vnu2N2hik9BNFs+JhjOGNlT7HpiqsdKzVa5jZcufGtvNdD+380aGJkGvtmDjfGVQx/n9hLXd74WmBK9iMcuqBQ5LnttNrHxBwIEEeQkAvsefUJjtaopkfQGxjkmvmmgEbg5R420kZqWSN0GWy4tmibekw1wj55Hvmdsxg/vRTCyx247HF76kjE7y21GOxY4M6Jisex6erfODkFIHroLXh1cUuL93okOSjKBqLdpSy1k95fL7O68t9ZmoBjdAlV4aq77DWS1HaYCS0Kh4//sQcAIvd+EAelh1k99Tofv76xXUGaU6uLckNPGtX7AxzIldxasrO2NWC3ZcFD1rVUaJEiRIldkdJxh4RvNmdViUeHDXfxRGSJNc0K7cvuDKl8V0bdnDQ12mv8ybAPedZtm/renuI7woaOMS5JtMaT0qOT1d56sgknrMzQe78So//9vNv8PpSz4ZuFHrV60s9UqX58Kkp2sOUCysDNor5G1dKar7D81c1z52YLKxiQBFTLgRIs3tU+63zUQCetL1Yu/1wN8qYawb4rixmf9yxhS1wnbGi0o8zlIEoyxGC8Tk8Mlnhy6+tkuSatV5C6El6nsNULaDiO3Y2yeQ8NltnqZugtNkxJya2/XOveHqBJT0KyXTNoxMrKr5LN9r7ZydVdqZL8mCx8g5FyXXx50yzg+FVPYHShr3yxFuPRRnoDDMqnkOr6tBLMuLMdraZIgjn3FKPs3N1jrQCrrWHfPrPruxQm261+CW54vhUlfefbHFkssL1dsTltQGvLnbHDwheur5JN8rwHEnoW2urKtIxl7sxnaG1sD59dAJl4PxKn/YwZa4p6cYZR1sV/q+feJyT0zV+4/NvPJQPy6QUfPI9c3z2lSW6cc6hiYB+ohimijTX+I6gVfGZm7C/W4apola5fWnwdlR1lChRosQPAsq/VR8RPIydViV2YvQE+tXFri3/9Zzx94wx9OOciarHZMV7U67TveZNAH7zyxf2lJI22tY/+/oV3ljpUws9asYqP4/N1Dg2VUUIO2syegigteGff/0K37m8gSMFjYpHzXfItWGtl7AxSHn5ZhfPEcSZLlQpS4Y2hyk3OxH/v29cZb2f2vCKYrV+NxLhS4HvOjvCMUZr4Vtnk7bPniWZIleGfpyR5pr5icrYAvfssUleudllpWd70lrVgKeOTPDEQoM/eOEm/TinFjgErp1HGqSKVMUsNEOkxM4mOZLJqkcjcLm0Phx3jTlFU3Z8DzlJAkdbIZ4rWeokGARPHWmy2ktY7yfk2myFcewB+xWvXGHPldL2tffiWNm9mOUt2O2n41xTCVykFFQ8hySzdt+Ka9MRM2VY6sYMM80zRydYH6S3qU27WfyiLOe/+8L5XR8QrA1SpLD9cE7xnl0hcDybzLkxzHjXQp1mxSrdHzzZGiu6aW4/Q4/N1B/6h2UVz2W2UczapYqKZ0NM6oHLY7M1JisevWECHlxa7zM/YQhcZ3xP7FddvxVlVH6JEiVK3Bnlyv0RwUHa0Eq8OZBS8O984AjfuLTOYjdmoRngu7YsuB/nhJ6k6rucnW+8adfpTvMme5nX2p2QnWJxM6biO7Sq/nhxNsL2hwBfOb/K//a9mwzSHM9x6CeKmi+ZrodM1wM2hilXN4bM1n0WJipb83SuQ+QoOp2Y79/oMFXzuNre6q3abeE+OgIpBI4jEULhYBWWVFkysz2RTwKNiovrCC6vD1jrxXRjG7LSqvq8px6Mj6dV9ZlthDx3osVHTk8jheDkVJX//fuLJLnmxFSVlX5C1XcYpIrQtUmFG4ME35VMVjzWBwnN0Ofdh2qs9JJxIbJNMLwzcZECAlcSOIKpWoDjCDrDnEPNCrkyXFobkmuYqLi0h2/ewj4vDnOvhRm7KpHcObJ+eyn1+GdGmSAGhqlmZPD0PIkrBbky1AOXblHifHauzhvLvdvUpu0WP60N/48/fIXvXdvEd+wDAs+xoTRLnYhhYh9uuVIQZRrflVs9bsL+3Tq97bMhhKBZsQ/Dcq25vDYY32cP88OykQ33zz02bRUxpfGLhNDRQ5Uraz2owPWNiJcWB9QDl5m6VYOjTN93muO9QntKlChR4gcdb2s51Z/+6Z/yF/7CX+Dw4cMIIfj93//9e77my1/+Ms899xxBEHDmzBk+9alPvenH+TBgZB2bqvm8sdKnF2c2ASvOeGOlf9+/KEscLB6fb/If/8RZFpohq72U1V7MMFVMVD1atYDjU9U3/TqNFqPvWmiOF6Xbw18aoWeVq9Dj7FydjUJh0LsMFh1rVXn6qLUO3krERg8BzszVibKc//6L52kPM5SGNFfEmWJ9mHG9PURrQ9VzSHJdFPTuLMhe7Sd4rmSYZJxfGdzzL6YiaA9DEbNurOq09fXiXGAj50Pf4UirwjBR9OKc9YENWnGlIM4VL93Y5PXlLjc3h7y+3MN1BEoZ/vfvLfIvv32NX//jc3zmpSWqvuTMfJ2q7yClQAqbpgewMUhpDzOutSPWeilJrviT19cJXJvil2t7YLvNb40j3Y21s2oDyhiiROG5gh86O81PvHuOwxMBU1VbRL0XPOjS/0HHwe5EO2/drixUKQPkyna3OcU94kqB0vbry92EdlHg/J2rbV5e7PJqEdqxG663h3z94jqOgOl6QOA6NoHRdWhWfIyxpc1TVd+quMrWEOTKEHrOOABlN2wnWKOHZYudeJzqOT4H2+6Tt+th2YgsRpmdgZypB2O1D2BxM+JG8QDk6aMTnJquAXBlfch3r25yeCK8r7TeUQLwSzc7TFY9HpupM1n1eOlmh3/61cucX+kd7BstUaJEiUcQb6syNhgMeOaZZ/jFX/xFfu7nfu6eP3/p0iV+9md/ll/+5V/mn//zf84XvvAFfumXfolDhw7xUz/1U2/BEb+9eDNij0scPH7iyXmOtar87neucWHVliVPVjzOzjfeluv0IOEve5lF+8ST8/yLb1zl8toA2CJFBlDa0E8VKz2rJG0MM6JUk+RqrFC0BxmZMvhSsNrLbGdXkax3JzIwynjItSHNFNpYe9lEzSXNNULYwmVX2l6sfqK4tDpAG6uuzDcDPClpD1O6sU3KW+klTFZsKl49dFHajFXEG+0hG4OE15bhfccmOTNX5+LqAGNgkOTEmVUbAldyfLrG43MNvndtk7V+gkHSqnmsdtPb7H6esBZAXahCUthkwkRp4jRnsZtQ9V2+cG6ZtKhHSDIblT8Kt7hXRL4UBxPgcdDYHmUvsYEScZZjzIiESaQwZLliWBCkYarGZD7LNUmm+cMXF3lstjauRtiuCp9f7dMZZkw3/Ns++xXPwXMEubIq3OHJCmluC8Yltp9O4BGnis4wJdNmrCYBO9wIb1ZH2EHhbs4KrTUv3eiO+8eOtKocatXpxTlJrrixGTFVC3hspr6vfZYJwCVKlCixN7ytZOxnfuZn+Jmf+Zk9//w//If/kFOnTvFf/9f/NQBPPvkkX/nKV/hv/pv/5geCjMHBxx6XeHPw+EKD/+JnnnwortODzrPc6yGA50i+fmnDKkCOsCXMrrShERIybejGGc3Apeo7TNftAnczzxDYaPRcKeLU9kkJCrIlCjvbLUTClVvK2GhuKvDsnNaRySpr/ZRBmo8Lf6NMgzAkmabiOzRDO7fXS3KiTI0JWi1wee/hJm+sDFjpJXz88VkaoYfWhihXaK250R6y3k+ouJLcWDXnaKtCJ8oYpoofOTvLkVaFXpyjgeNTFVb7KcNE7Tr8lhl2qHmj96q04crGENdxeGymiu+6XNvocXMzHsf4w71DQDRF11hByA4g+HDPEIDv2H3vBlcU82jGXm+pjU0oLOYFtTS4UtJLFMaYwsLpFB1uhs1hxum5OkmmrLJrDJ97eWWHHU4ISLVGYOeeRmTLEVbxqocu7WFGN8qoBi6eK0HZzi2D4Jljk6x0Yz77yrKNsncljcCl6rscn96pcj/MD8vuRhYvrPbJlOGZIw2gA2y3Y3qEnsOF1f2Hj5QJwCVKlCixNzxSM2Nf+9rX+MQnPrHjaz/1Uz/Fr/zKr9zxNUmSkCTJ+M/drrW0ZFlGlmVvynHeitF+DnJ/Cw37ixJAqRy1v7TrEnfAQV+rh+E6hRJqriBObJT7rUiSnKorCOWd3/eJVsgvfew4i514TC4PTYRIKfjKG6sMk4SFuo8wNoxDGBtNLwRIaci1xpEO712o4buCTqRIUgVYoma0tott5/Z9234roFi0h45gInQBxZOzNSYaAev9jMXNIVEc06q4GL31Xnwh0EZjpKHmwkQgWO9FbAxScm2sOpUbpC8IHUEgDThwdb1HP4r57tVNNgZWGTFAlGb0BFR9F0cKFuOENDecnKlxdNJHoMlVhlIZNd9jruay1Inx5Z3Lmm+9KpbICKZrLmu9iEsrPYwx+EIjnJ0zV/eCFJb4BI4kyvWe4vQPCgLwhd1hRZrbQlUcRncHYAwNzxZUp8qgtAKtCaU977b4Wttr5oDvGHypOdL0+f7Vdc4vd0hz2xtX9X2GqeLSeh/HaNa6Q3zHzvYZYxDCdm5VXJChpBlIkiQjKcI9QkdwarpCzbPXoOpS9M3lrPcyRN3nx84e5UQr3HHP3O0+eat+39wJJ1oh/8GHj/KFV1e4tDZgrWttlqenKzhoDjd9SEGYnX9J1TxYyzO6w5iscfs83J3QHcZkeUbd82/b5oNst8Sbs6YocfAor9Ojg7f7Gglzq8H9bYIQgt/7vd/jL/7Fv3jHn3n88cf563/9r/Orv/qr46995jOf4Wd/9mcZDodUKrc/+f+v/qv/il/7tV+77eu/8zu/Q7VaPo0rUaJEiRIlSpQoUeIHFcPhkJ//+Z+n0+nQbDbv/YIDxiOljN0PfvVXf5X/9D/9T8d/7na7HDt2jJ/8yZ98y054lmV87nOf45Of/CSeVz4BfJhxUNfq4mp//AR6ZJk6NVPjJ56c47HZ/c1eHAQurvb5Z9+4SnuQstAMqfiSKNUsdWNaNZ+/8uHj931c1zeG/Mr//AJRasuub25GRKm1lhlsz5YjBE8dbdKNFKu9hEwpMmXtZntReEaKymzd599+3xF6ccqz4ir/48UGRkp6ccZaPwUMoecyVfOJM2W7xKSw3VwCUqWRCGqBLWd2HYE2hkzZgJGTM1Wi1KbqXVjtk2n78waza2KgYGu+LXAlHz7VYrWfEaWKYZrTizOi7M6l1dvhCJhrhMVrFHXfQQrJMMvtMd6nx1AWqthUPUAAZ+fqrPYSrrcjNuM372mgAHwJUhh+7f2a/+FcQDs2RLlGG7PDYjlKvxzVD4xso+v9BEcIEHaGLPQdJkOPRtGD1R5mnJqu8dpyjw+ebLEwsfOBnDGGL7+2yuW1gU1KvMUm7LuSn3z3Av/ZJx9nuZeM1SxtDL/55QtMVLxd1eR+nNOJMv6jHzvDkdajnWCrteF//MolXlvc5McbS1wOT2OElaiNMVxYHfCew01+8WOn9mWzHm33lcUup2drt4X/3O92S5RrikcF5XV6dLC+vv627v+RImMLCwssLy/v+Nry8jLNZnNXVQwgCAKCILjt657nveU3x9uxzxL3hwe5VudXevz2N66PY+TnfZdhmvPiYp8b3fS+UskeFE8cbvELH3O3CnF7KYHr8O4jrQeeZzkx2+T9p2b47MtLLK0O0QYqgYdWpiA/8NhMnZudjJV+TOBIkC6BK0jjjGQfvrlUCzYizdW1iGfnwPVcrncSkkwjHQdHCLqJYn0YjYMhRqmHoWe7qjQClWiUBlGUMvuOQ6sR0k0M1cDj+mZELzUILBHQRuwaguEIaFR8+klGNzF8/XKXiYrHwkSIEpKb3ZRM722hKYEbnQQEBI4LjkOqDL0URga/vRQ3O8XPbOduShsmEbz38CRzjYBBbjiEoL/SL2LkGW9fcHCzZdKRhNIezdJAMcxtwEua73wfo/clsJbKbqJpVl20yMkNzNYDMIa5RoCUEgUkucIgWRlkuK7LdKOKETuTD7txRqSgXg2Yrvn0EzUuGp9vBhyaCNmIFGuR4uTc1sO5c0tdBrlhPvAx4vbrFwSCYS8l1rwj/k7/yacOs9iNAeglhiAQ28JHQj753sMEgX9f273RTXl9Ndol1OT+t1vColxTPBoor9PDj7f7+jxSZOwjH/kIn/nMZ3Z87XOf+xwf+chH3qYjKlFiJx7mBLE3K/xFSsHHzszw5ddWGBYx70mukFISepK5Rsj8RMBSNybNNY4QNIq0QmGjFXaQAbidcFQ9gRSSTBteudkhzWzYyObQljZLKaj5Ho6ETpRvbU+C59jwiihTCCGKmHkbh59rimMMcB2HQZJzei7gyvpwHKgh7pZWaOzRVjyHNM9tcIgnUVrTjTIcKVFG3zHOfvuXdfHGPSGo+JJMmXEq5Qh7oa0KSxLFtlLoTEPVd/jY2Wm+8OoK1zYiurE9PldahXKUbLj9Wrjyzh1i94IAlNakhRM+Uwal7dUeEa/Rvrbv03EEytgOudCVdOMcT9rwjvYwox66uFLQHmQEnuTwZIVhqogyRcPZScZSZZM764HLc8dbCCF2dGwpY8ZdYdvxsPeGHTTOzDX4Kx8+zrlvXbZhNMXDmgcNH3mYQ01KlChR4mHB2/qbpN/vc/78+fGfL126xAsvvMDU1BTHjx/nV3/1V7lx4wa//du/DcAv//Iv8/f//t/nP//P/3N+8Rd/kS9+8Yv8y3/5L/nDP/zDt+stlCixAw97gtj2QtyDwvmVHl88t8Jk1WdjkGIKC5ox1lrmCHhjuc/mMCXXlqh5mY0nN8bYNMViwT9WR2yoHQZohi4np6v0khwBXGtH1IuH6YPEEi/fkbSqHlc2hlBsw3PsOR+V+q4PMrQ2+BIybJJemhu00bSHKcvdmExpNocZ03WfXpxSdDXfsbwYLCFT2gZ6GKOJUsVSNykKhS3p7Cf5jhTE0XsdYRTYEbqSQRFd7zmS+D6Z0K0pi46AK+sRv/nlC/TjnDRXeK5DxXcIXMkgyYmyLYXMLSLz75eIgX1/SY6V6oCqJ0m0Qd+lIFpKe82M1qwPEpuEaQzX2zFHWxVqvksvzhkkORXP5YfPzPCXP3icz72yvGtsuycFWW6Yqbs7erVGiJJ8V1J1tyj4UW/YKNb+nYLHZuucA/6jHztDrDmwhzVlAnCJEiVK3B33Rca+8IUv8IUvfIGVlRX0Lb9Zf+u3fmvP2/n2t7/Nj/3Yj43/PJrt+oVf+AU+9alPsbi4yNWrV8ffP3XqFH/4h3/If/Kf/Cf8xm/8BkePHuWf/JN/8gMTa1/i4ceDxsg/atiuBD51uMnmMAVs8p3RmqVewkovYb4Z4BSlWKmCzWGOI+28liN3pgMaLJGTwlraDjVDhqni0ESFE1MVvn5pgzy35y/XmnrgM10LyLQmzhSeI8i0QYqR6a4gZYFLN87wXIdW6PH4XJ2La32Wugn9IooeYDPK2IyyHSrdnZaNAhgmOY4jOdaqkitFlGnmmyH9JEdpvYNo3glWkTJ4rsTJbadWNZAIYJCqPSlid0NuIE8VUTsqOtmg4luFCSkAlyRPxyTOdUAaQbqN1Y3OphTgu4IkN/eM1t+Oqu8Qa0OUKRtfv227I0VOsFV63U9yQs9hth7SieyM1iBVzDcCzs7X+aEzM/zw2VmOtapIya6x7UvdhNlGQNW7/Vfd3UjVw94b9mbiSKty4JadN+MhUIkSJUq8U7BvMvZrv/Zr/N2/+3f5wAc+wKFDh2570rgf/OiP/ih3C3P81Kc+tetrvvvd7973PkuUeDPxg2ZvGimBFU/y+kqfbpwTpYrQk2S5sTY/x84s5Wor2lxjiRwwjvsflROPFv2uI6iHHrnWVHyXuUbA+iBjoRkyV3OBIbONgMC3XUjDQY7SZlw6bf/f7idDIyRjS6TnSNb6Cf0kJ0rUrjNSt1kId4HG9qi5rsB3LXnajHM2BglKGzzPoe5JXAkbw7sT8FRBe5DZGH8BvSjj0ESFfpqT5eY2S9/9YGSXzIuyaiFcQDBI8h1WylyBJ81thdGuA9XAw5MCIXIG6d6ls0Gq8BwHrQVx8X4ktmcu0/b626LwrdcYA51IgRA0i06wy+tDVnsxF1cHfPm1Vd53rMVPvXd+Vzvc00cn+Hc/cJQvnlvZN6kqLXYlSpQoUeKtwL5XhP/wH/5DPvWpT/FX/+pffTOOp0SJRxqPor1Ja3PfFqJeknG9PWR9kJIrzXTNYwNDnGniYj6MzCpkniMBRXaHrjVjrJUtV9omMEo719OoeMSZ4t+8scogUThSMF9z+PF3gVK2/LceGjb6qS2B1nbWShn7/W6cI4s/GwPHpqqcnavz9YsbtIc5D1L9JoBW1WO6HtCPrXJjNAwSO6cUZzZVspfsbS8G8F0HgU14jDNF4EoypRDGlijnZsvWud9j3U7kklwjEgXG7LAoQrGPWw55pFjGqWKo9Z4tjKPS5yTXZEVRtucw/hxoYwmZI7ZKvEcfP601OQKlNEu57a4zBiq+j1KGaxtDkkxzYzPiZ55a4MeenOWDp1rUA5dG6I0/yyemq/dFqrZb7HpJRj/OqQcugeugtUFK8UD3T4kSJUqUKLFvMpamKR/96EffjGMpUeKRx6Nmbzq/0hsvUkcR/Kdn6/zUe+/95P/8So/fe/4G55Z6ZEpT9R2UdqiHHtpkDFOFwaC1oOo4HG5VWO0nbA6zsdribJsNk8IqVlM1n06UEbiSwxMhi52YlV5Cro0tkRY20hygm+RkWrDSS3bMmlmZxe5kNMNmwzocDk9U+Il3z/PGSp+VbvTA5zDNLAFD2Dm4ii+Zrfu0o4xenNNPcvba5jj6sdBzAE0tsIrg6yt9kkyNCeX9YLeXJbnaF7HLNGiji0LvLa/h9lj60RfGmy2+Vg9chpn9WUcKGqHAlQKloeJJ1gYpukjfDF2BQZAoY8uuHZtmmWtNxbOzbhXPYWOQ0oszvnVpnReubXJiukLFc8ef4dF99iBzS1IKklzxpVdXx/dJ4EhmGwFHWhVutGNWezGJ0vu6f0qUKFGiRAm4DzL2S7/0S/zO7/wO/+V/+V++GcdTosQjj0fF3nR+pcc//erlcQR/1a8wTHNeutnhZie6awT/6LXX20Pb3WTsonZ9YNUpr4iTB9vl1AgcfFda9ct3SHJdpClaRcR1JDN1H8+RvP9Ei8AVfPPyJm+s9OlH2Xhh70hpF+KOA2RkuUYLyWTFpVJUCKwPMrttYw8rL8ieK+F4K6SX5Dx/pY3viNtS/fYLg41hzzaHnJ1rcHK6yqtLPd5zeAJHCr52cd2mSGaKaA8R/p5jtzlMFb4rGaY5Z+br3OhEeI5VhbSxitmDhGuAVQrvlhR5JxgDzYpLnCuUMqTaYIztW3NdaesAMGMLoyetIjrXCGnHmmGa0U8UnhYcm6zQqHisDzKaFY9hkhNnukhTtMEsSa4AgdLavn9t7Y1CWDJ3eX1AzXcIgdl6iOuIXT/D9zu3dOt9EmeS15Z6fPXCOsMkp+I7HJ+q8sRCk9CTe7p/SpQoUaJEiRH2RMa2lyZrrfnH//gf8/nPf56nn376tkHfv/f3/t7BHmGJEo8gHvYEsQeJ4N/+2iOTFS6tDejFOb04B2NsGh5WJcqLYudUwVo/oRNnNrzBbPVZhZ4k9Bymaj7DTBF4DtM1nzNzNb7yRoQyNoHPik+GOFX4oY0wd6RgkCqOtCp88MQUqdK8ttTje9c2yWHMshwBjdAlyjQrXdt1NtesIOhg7pOKjYqKK54lIFGmqAUeAuglOa2qjxCCk9M1ljoxUS+55zbrviRRNlzjAydbxJlGCkOmDVNVHykFgSu5tD4g28e81q24U4XAXlHxHJQxKK3HUl2uwUMghI2xB3uOxu8tdJCui+4ZUmXwHcl7Dk/STzOubUS2bgCbnplpq4YpbUhzYcn76GDznKVuXBRk25TKiapPqjTKGFqhf2A1ErfeJ+1hyos3OgxThSw+OY4UbBZff/bYJGfn6m9JhUVpjyxRokSJdwb2RMZuDcx49tlnAXjppZcO/IBKlHin4K1MENvvwmwvEfxvLPf49pUNmhVvxza3v9bOeTkME4WUtjVMa0OaK1xXFv+v2RgkYyVHYlUPUahWUaYJPRchbBT+IMn57tU2l9cGDLfJP3b2yJAWM1kWdoU+iG3a3nI3Yakbjxfuo33VQhetKZL8DFfbQ/7Kh4/ztQtrJIPsvs65KP5V8R2UNkSp4np7QCNwubzWZy106cUpbsUSBQfuOZ+mcWhUJBXPoR64XNvo8q3LQ4apojPIcB2B60iSB5XFsOd/v5bHEQFd7Vvb6PY0RYOdJxPFfJ4U0Kq4VD0JZGxGOQaJKwWtikduDF+9uEYvzokzNVYotWeVtjgzaGNus1EaDRvDzM4CAr7nFMqnxC96xg6qRmL7Zx3gwsqAKLXzgJvDjIpvi8Trgcsgzbmw2ucDJ1pveoXFg9iLS5QoUaLEw4U9kbEvfelLb/ZxlCjx0CLPNc9fa7M+SJmu+Tx3rIXrynu/8C3C/SzM7hXBH2eKlxe7/KM/uUjgyR3bzLUZv1YKqAYu8WbERGiT+dJc0U8VLuD6DtpY290IGpDbZp/s93N6UYbvufzp6yt04/y2RXhuwOSGwN1K+LNdZlaVeulmB23sscNWXL42Rfy8lCRKk+aCTpzx+VdWWJgI2YyyHQl+e4UG/JEdU0rqgcvltSGuI+jHeUFWDBuDjEzpexIxV8BkxWWmEbDSS/jiuRU7X1d834BVGtXu6Y/7gSysoaOwlL1itN9EGVxxeyXBqLjalYKq73BiusZ83QOGnJyqUgk8Xl7sEaU5a70UVwqrsmkNCOJcM0g1vgOe4xQWxS0IIPCs3TXJbQR+NXBIM8X8RIVGuPUr7SBqJLbfJ704Z2OYUi+647QxhI60xwHUQ7eYYcupBm9ehcWD2IsPEqUyV6JEiRIHg33PjP3iL/4iv/Ebv0GjsfMv+8FgwN/6W39rXz1jJUo87PjCq8t86quXubw+IFO2iPfkdI2/9rGT/MST82/34d33wuxuEfwbg4TvXGnTj3Omah7zzZ3b/On3LhC6DoMkAwT1wAUDSaYJPIdUWeuakA6h51D1Ha5tDPEcKML70FjroCz+P8o0g1TRifJx8uBus1zKQJwb/KL0WQpBM3ToxTm+awlRlKlxb9UIuQZH2nj9JLM9WYEneerIJJMVj29ebo+tdXuFjcgXxJkh9AUbg5hunFELXA5NhkSpYr2fEt+SVLgbRkvYfqrINyNW+um442u7pfBBSdioWBkDjhDUKu49I/fvBCkFrmB8nKZIRZyoeBxrVVnrJ1xYHXBtTfPTz8K3r7RxXBeMoRPnYCz5FEKSKU2S6zG5yxXUfchuOTQpbA+ZI+U4IXOQauabNrRju8p7EDUS2++TVGlyrfEcF4oQk0xbW64jBJ4j6Sf250TKm1Jh8SD24oNEqcyVKFGixMFh34/3P/3pTxNFtyeQRVHEb//2bx/IQZUo8TDgC68u8+t/dI7XV3o0QpcjLfvk/fWVHr/+R+f4wqvLb+vx5bnmX37rOlfWB8w3AuqBW6TUeZydq7MxSPnsy8vjPq/tGEXwL3biHV1/xhjOL/fZjDJOTFc5NFG5bZvfv9ZhInT56oV1vnZhjavrQ6vaGDMOYHAcSSNwWWiGjGiRlBJPgu8IQlfiOgJHbiMiiWKQ5hhtxhHnu0EbSIowjEbFY6oeYLAdXZfXBwx3maUyQJpvbdcYw/mVPt++ssH6IOOxmeodi53vBIklkVGWM0wU7UGOAE5MVZiphxxtVTk5U9vTdg2WWGz0U252kl2J2P3AkxAU2fIONqXQc+w/Susdpc57hcRG7Nd8F4S1TU5WPCYqHoFnCchUzYZyDNIcXXy+PEfSiTJW+ylJpqmFLlJK8uJ659qMyaYGBpkiN3Z/gSuoeJaACewsmRQCVwLGcGauzlTNHx/jqEbizFz9gWoktt8nnhS40hJH35WEriRKFRVP4rv2666UeFIcyL53w17sxSN75JuF0QOgl252mKx6PDZTZ7Lq8dLNDv/0q5c5v9J70/ZdokSJEu9E7PmxXbfbxRgbM9zr9QjDcPw9pRSf+cxnmJube1MOskSJtxp5rvnUVy/TizOOtypIaZ9bNEJJzXe42o749J9d5uNnZ98Wy+L5lR7/8lvX+KOXlnCkYK2f0qr640Xpvea+7hTBv9JNuLIxZLLqc2ausWPBN9rmd6+10QXxypQm9GxSYpTmSGHLj4+1KkxW7eJ4fWCLmPNc4zoSbWyYhhS2gjnJFMNUEadqz51fo0V7s+LSjhSZMraT6i7cYtSTRfHf0JPUQ49MadqDrS6yPUPYsInpekCqFNfbcZEYKcbny55rmwB4LzjSvkbfwkTvl4jZqH9JLZAkue1TS5WdxxJFp5c2eofV8G6Q2LTHXFtibYxNw6x4kkwZMq3Jc82aTtgYpGhjo/lrvp0Z08ZQcSVpYevzpe1S6yc5WhtcaYuvt7+D0JUgDBOFejtMFbONAM+RqOIzqLRhrZ8wVfMPvEZi+32y1E2o+Q6bw5R66OE4Vl2Vwkbf92JF1Xd4Y6XHTCPkE08efIXFvezFB2HNvBseFmWuRIkSJd5J2DMZm5ycRBQ9Oo8//vht3xdC8Gu/9msHenAlSrxd+N6NTS6vD5iu+WMiNoKUkumaz6W1Ac9fa/OhU9Nv6bGNnkxfWR/gSJiu+ygNq72YfpLz7LFJpmr+bXNfo26kD5ya4smFJo/N1PnrHzvJH7+0NE6IU9pQDx3ef7y1Q2kYIfQcrm4McaUg14b2MEPpFBjFxxsqnkvgSVKl6cc2VTDJFO1hhoO1ddmZJYHWdnFfDVw60f4XkBJBlpux9e5OzGUU5JEXKY6+IwurmyBwHZqhhzH7UxMqnsPRqQqOlCx1LJnzpKRdBDvYNElLc/YSn6+0PX+OtPbNTN8/EaPYX5Rrom3Dd7ogYqNTlRcF2buIp7dhtuGjjQ1BmakHBK7k5mZEltsUQ4ElnqNofs+xO5quB8CQw5MVNJKVXszNTkIvUUhhUErjOAKjBI40Y7vGZMVDSkE3skRupMLVAxfflWwMUuYnQiYrHqdnG6z1k3vWSNzPnNP2qorvXtOs9hNWewmHJkOeOjLBUifmWjsiyRXD1CFTmorv8rlXlpGSAzmGEe5mL4aDsWbeDftR5t6q8KISJUqUeNSx57+xv/SlL2GM4cd//Mf5V//qXzE1NTX+nu/7nDhxgsOHD78pB1mixFuNjWFWLKqcXb9f8W3h7PogfUuPa/uT6TOzddb6KUobAtfBr/lsDFIurPYxprpj7stzbDfSNy5t8EcvLXF8qsrZuQZPHm5gCiXGYHClwBGSOMuB4Lb9r/as6pFkCm2gGXoIYUhyMw7OyJRmsZMwU/OZa4Y8NlPjYsXjGxfXiXND6NomqiTXREWfltZ2ER54gqSwE94J25eAzYpDL9V0YkmsFI7Ymknbcd7YSThSZVjqxkxXrbXuZmd/RMwWVAtLOqShWXHpRBlSQJTlpLmdn3MdWUT935vtjJQ7Twqy+212vgeEYEy+BFsEdS8YJDnPHJ3keifGKSL2c23n8ITAzkoViZf2fBubIllcsIrvkBvJwkSFlV6C0gaFKmyH4DgCoW0sfs13mG8W0fWeoRfnuK61vhoMG4PUziN6Lu8/McXf+OHHWCwUoTsRnAeZc9peVfHqYpdvX26z2otJlaZV8ximitCTHJ6oUA9djIEXb9w+t/mgs1Yj2+RLNzvUA3cHIRpZM586MnHg9sgR3m5lrkSJEiXeidgzGfv4xz8OwKVLlzh+/PhtT8VKlHgnYapqCUyUKhrh7TbEKFV4jlXI3kpsfzJdD1ymqj4rvRi/Zhf99dBlo58QJTmbUcZjMzUCV/K9653ivTis9lJeXezy6mKX331eM10LeP+JSc7ONxgkOUudmG9dblP13ULVsDDGcHNzyCCxs1H1wCnSCXUxF2RQ2i7yj02GNKs+U1WP8yt9VnsxnmPVslxpOnFuz1/d58hkyAvXOoS+xBGCjDunBQrA9wQVKQBFxXVJVIpTzPOkSt/RFuhIxqmJ2hjag5T2MMURYs+zU560Sp4rBe861KDqu7QHKYPELj5tkIjtPgs8h0bgEjhiRzjI3VSy3IDQ5oELne8EPZ7BkkX/295JX6YNZ+cbBL7D60s94swqqXnBckVR0mznp3Ibb78LqYwzxWTVR2CVVUda+3uWbUX/O0XZc641x1oVzq/1yQuLZZRpJqoeVc/l+HSVT7x7bk9E7EETCEdVFcemqnziyXlubEb04ozf/+5NW1StDBfWBuTazo61Kh6DNB/b9i6u9Q/kGHazFx+kNfNueLuVuRIlSpR4J2Lff2N2Oh1efPHF274uhCAMQ44fP04Q3P5EvUSJhxG3WobmavaWeObIJCena7y+0qPmOzusilpr1gcpT8w3eO5Y6y093u1PpoUQnJ6r0UsyNgY2ctuRgn6Ssz5ImaoHnJ6tc3HVdiPZp9bJOPzAdwVRZuglGa8v96kFHlM1nw+davEnr6/xzcsbfOz0NNXApR/lvHB9k+VeTFQwhe0dYCOVRQq7aEcIpms+3726WZQhuzyx0GBzmLIZZfiO5OxcnbNzNb5/ww78T9d8NgbZHQuwHGFnxNLc0Kg4QIbvOWNbWyO06lSmzA7CI4p/XLGlmAlhCZtV0bbCMrb3n+2GkbomBFxeGxJnCikEc82Ao60KV9YGpLlhuRvjudam5zoOrtwiLfeiP3uZL3sQ5AaE0mPCtxcLJdgAlH/9yhLvPtRkvhmy3I1R2mp+I4JXD+ws4CDJ7bkyoLZdy9G98+5DTZ47PsFv/smlsZXTsHUNulFGL8qQ0haHn52rM1sPi7APzWTF5+x8gycWGnzu5ZW7Kk1vxpzTiJhd2xhyca3PWj8hV4Z66OI5LpmydkZHCp6/2uZ6e3hgx7DdNnlhtX9Pa+ZB4u1W5kqUKFHinYh9k7Fnn332rqqY53n85b/8l/lH/+gf7Qj5KFHiYcNulqEzMxWOAK4r+WsfO8mv/9E5rrYjpreFA6wPUpqhxy989ORbHt5x65PpqVrAs8cmubAyYGOYEme236oRurz/eAvPkbYbKXBZ66dkSlP1HRuYkRtqgYvW1gZ2YbVPq9piuh7ywZMtzi31uLkZc30z4vxyj+QuKsooDVAV9rfOMOXSmp0zOj1bJ/RcMqV46WaXfpLTi3NeutGhPcw4NVvj2saAfqJwpCD0JHGmbiNEykB7aIt+TfG8J8kU1cBhpadxpcB1xDid79YkQoPAd7BhItqghUGYnaSt4tnrGWW3929Zx6pAFOQizRXKyj92fqkRMF0PGCY5Sa64uj5ksuLx9NEJnjk6wb/45lVWbymY3jW+/y7X/yAggVbNZ62XonfZ/x1fV5RyT9V8PMch9B36qaLiCoyx1s9cG6SAyapPZ5iOAzoA+nHOUj+jGXr8lQ+f4FuXN5hr+AxTRZopDDZdM841qhjuq3gOTx1pIqXDVM3nZ55aYLYRUPNdolTx6a/dW2l6M+ecenHG1fUhSmum68F4+9Y2LFnvJ1zbGHJ+tX+gx7DdNvlW9ny93cpciRIlSrwTsW8y9nu/93v8nb/zd/jbf/tv86EPfQj+/+z9eZhk51nfjX+e52y19949PT37on2zJCwkGWQsbxhMCEsITrBNCAQMhmC/xHZA2FzghQCOIXZsjLEDIX7jBK4f8Hq35QUseZdlaxvNrtl6X6prO+vz/P44VTW9Tlf3dI9mRs/nuqSZqa4651Sdqurne+77/n6Bb3zjG/zJn/wJb33rW4njmDe/+c38zu/8Dn/8x3+86QdsMGwGq7UtPTk6z0gRjk9W2zlirZyxmVqIY0muHSrymnuenZyxla5M9+Y9eva4zDcijk5W2dmboxHEZJw0kDZWCqUljag5n8V5Nz3HEvhKk3FkO7C2lHUY7s7iR4q+gssXn55YVzubBs6UG5yd8xnqymBJi4FianjSCBN29uTwI0UtjCllbUqujWtbTNcCenMOQqTzSLO1aMV2RQVMNrOx/vnoJAOlPErDXD3CsgROU2y1CjICUjdJT7ZF6XwjxrUkAk2s0mpea67MtWSaI0X6+iidCpFCxiaIEvw4nWuarcc4lsAVktCPKNcjHFuyreSxrTtDGGteffduXn7DMF8+Msk/H51iul5eNLsm2XrxtRRNWqFa71SaZ6WPDmPNwcE8j5yawxJpaHN/MUPYNPKwmo6ap2ag3Ijbs4TVIObaoSIvuWGIbz0zw6efGCNRaaRBolQ6g+eft7dHQyNOODRW5QcO9jFTD3nsTJlfvm8/AO//0rGOKk1bOedUDWIaUUIxY68osjwnzcCbroabfgyt6tyl5tmszBkMBsPVyLrF2Nvf/nb+9E//lJe97GXt226++WZ27NjBAw88wDe+8Q3y+TxvfOMbjRgzXJZcqG2p6ObBhy8cmuDgtm7uv36I+w4O8MjpWaZrIX15l9t39jwrdvZw4SvT45WA3X15XnP3Hj735DiPnyszVPSwZTp/o7RGIvDj1I4+jBVRopuOgpJ6lKSBzZyfifv0E2MbyqISOhU2ni2ZmPd54lyZME7nSYIoZrCUIdaSff15TkzVSbTGEYJyIybn2mkAcAeW8JGCc+UGlkhFk45TMwnLEuRdm0QpGpEi50pcS1DKpo6A1aYlerIg2wrS1suF7Zdh05wi59mEcUKQaAQaz5YkSVpXqgbn5VSQJBydrHN0sk5Xxsa1LL58ZJJ3fvIQc42Q3rzLVPW86culFmKQirF5P163GNNCMFuPeOxsmclKQDFrp46JQrTbZDN26iY4UwvpyrrcuL2LH79tG+qZ7/D2f3kT3YUM//Orp9pOoF1Zl3IjJErAj/SiKiWkrW9TtYBvPTPHjdtLizK0Oq00beWcUyFjk3UtgkhR8PSytr0gSivRfQX3qpq1erYqcwaDwXA1su5v/scee4zdu3cvu3337t3tWbLbbruN0dHRiz86g2ELWKttCeD4ZK3dMmTbsmP7+ouxre6UPb157tzdw5cOTXJ0vErek2RdZ9GVaaU1j56e5dHTcyilqYcRWmvqkcKzJQMFj9l6yGw9oqdZjbKlxLVke/bDljBdWb9bpCXAs23qUcxsLWS6FrUX2X4cU/ZjTs8FdGVtvne2zFQlNdLozjkEkaIexqkYE51NM6UB0Lq9gG/NiFWDCBAkiWa0HODYqVNjPVLt0Oi10KRhyWGsiGKFlIKCZ6ctmVJQD1aXU2U/5u0ff4J8xmFsvoFriWar5MqGIc0RswsGXl+IZrZzR+6InVjZL0QAlpR0ZR2KGYuJis9cQ5JxLLpzLp4lmW1E1IIYS6YRCrYluWN3Ly+9fhuffgaet7OHDz10apETaJSo1NJfQEw6w2fRHBsUTVGv0hmyIxNV+vIeFT+dJeu00nTNYHHL5pyKnsOu5uxYS5A6VhoAXW06QO7syXJgoHDVzVo9W5U5g8FguNpYtxi77rrreNe73sUHP/hBXDd1kouiiHe9611cd911AJw9e5ahoUvfwmUwdMLStiWt05mpMFG0jBODOFl329LF2lZ3woNPjbfbJsNEIQVs68rwM983xL+6YydSivZ9jkxUqAZx04VOI2SaqTVQdLGsNJDYsyWCtMVvW1cG0ByZqNKbd1G6E0P2xQjS/LCWGcPUkhmphZQbMTW/QsaRJEoTxSrN+yK1yXdtybly0PG+Nc1Q4gTitiI5/wzCWK9rey26shZ+3AyEVppa07RDKbVmWPIzsz7gU3Aljm1jNRfhUT1a9touP+LOkXQWWC1JXSUdS6L18rm41dCAJQS9OZeMY+PZFmdn60gpydoSDewbyFHMOCiVukr2FRbPD42W/WVOoM/M1NKKrZSLXFNa+wPdzqsr+xFTlYC//845fuCa/o4rTVs55zTSneV5O3sIorQdeLYeUQ1i7JYglZLbd/WwoydnZq0MBoPBsCLrFmPve9/7+LEf+zF27NjBLbfcAqTVsiRJ+PjHPw7A8ePHed3rXre5R2owbBIL25aiRLXNL2KlyFqCW/aklZD1tAxthnX2Wjz41Djv/NQhKn60yFDk3JzPh/75BANNG/qF9xnpzjLvR0xWQhKtcSVMV0Pyns327ixFz+aZ6TpRkrbelRtxu8L2uSfG1i0MWmtJ2xIkHeie1KdBY0lBI0qwLYljSRBiJUPFNQm3oO9vpp5gN+PmlAad6HUL1YxrYQlBotIst9SkZPHc1ga6Qdt0Z20QqQjx4wsfm2unLZuN1XXyikRJwmQ1oBgn1IOEmXpEojT1MAYEjiUoZdNK0e27enjx9UN4tsXh8dQtsxJGy5xAJ6p+av7SdGUUpDOBlhAIoYkTQKcCUilBd87l1EyNTz0W0511GC37HVWatmrOaaHQm64G7OjJYsn0PKeC1GuLLDNrZTAYDIaVWLcYu+eeezhx4gT/63/9Lw4fPgzAT//0T/OqV72KYjH9ZfJzP/dzm3uUBsMm0jLB+NqJaWZrAX6k2pbUOkmrYVPVgEbUWWVMKc2nvjfK0YkKffnUSCPvWhdlnb2UOFb8j4dOUvEjdvVk21b7xYwk71qcmm3wkYdOoJVedp/evEd31uHUTIOBksftO7sYr6T5WhnH4l/cNsItO7vaLnUj3Vm++PQE/9/31t9qLKWgO+ukboUdPqYS6rSFT2vKjZC856CVJr5MigQaaHpQpCJnA6IpiBRBpImVSu30NzHUWZC+7p5jkXFsZmpBuw0zrTClf1HNOyudOhau9wjCWDNVDZisBs0YA9Gc+3IQpMHWBc8i79kcHCrwuSdT0RHFES8uwCcePUcYq0VOoDePdDFdDak2Z9ja8QKkQkxrsKxUqDqW5LptRXb25trVpZ6c03GlaavmnJaKrHoY49kWt+zoXiayzKyVwWAwGJayoWnhYrHIL//yL2/2sRgMlwQpBS+5YYjPPjnGZDVkWynTnvMImjNAxYzD55+c4MBAcc2F0v/59mn++munaERxuniUgq6sw/N29bC3P39R1tktHjk9y8npGn15d1HmWfp80vDpw+MVtIaBorfyfQou5XrEj9yyne3duVUXgw8+Nc47P3mI0fkGEjoSVQXXwnMkloC8ZzPvr6/FU2mNUum+onrUbqXrdP+XO5UgwRbpe0ND6va4CdsVpGKr4qfOk60pO3tB158U6fCVa6XviTg5n3nWKQvz13RrHzbkXJtSxsG1UzdOz7aYrga89wtHGe7KsL07S8FxIYAzsz6TlYAgUjxvVzdCCHb25LhuW5ETU1Vm6xFK6WYgNSSJQjTt9B1LsqsvDVxuGXTM1SN+4vYRvnu63HGlaavmnNYjssyslcFgMBgWsiExduTIEb74xS8yMTGBWmJ39ru/+7ubcmAGw1aSda3mTIegFqbzYbaUDJbSVr/9A4WOBNSDT43z3794lHk/pOg5OJYgUmnu1FeOTAGwszfbsW31agYg07XU7CDrWqs+n7BZ7bjQfWZqIVPzIUKItjvkcCnTXjSGYcIHvnSMqaqPLaA7lwqr1UKQ9/fn2DdQQACNKOHMbANLpiYg60Hr86G/uvlvS6YW6f5qO7/CiHUqhDYTKdI5uUQL5mpRu/K1kLQ1Mp0XK2UdZutRGsy9DhaZozT3kei05TJWCuJUhM/WQmxLMFOLeN7ObgqeTa2RmsAMljzKYcJ8I+LweIXt3VmyrsVwV4Yzsw16cgJbtuxXFJOVAM+xKXhWs4rW3W5HbBl09Bc9fuWF+y+LSpMRWQaDwWDYCOsWY3/xF3/Br/zKr9Df38+2bdsW9eoLIYwYM1wR1MIY15Z8/76+NHQ2UbiWpOQJ8CfJupKgEl5QQLVaB+thQt61zptiyDTrat6PefT0LL05uyPb6gsZgPTlXRxL0ggTipnltvqNMDW80JoL3idWmj//52PpgjxROJZkT1+e1967h529Wf7swaM8dnYOIdIsLduS7daxlmACcAV05V1+6+XX8dIbtrUXw6nBwln+8bvn1nM6ljkIJhr8MEGY9q21EZLurMVsPSZaQexp0giAWCvierghQZg057Za24O0dbMeKs7O+UghyDSNPBwrFdFTtYDD41UqjYBb9sA3T87iOjY512Jnb45TM3XqYULOtXjxDYMILTg1W+f0TJ15X+HaNl1Zh529OfYPFOjNu+3jWWrQcalEUKduqZfCVdVgMBgMVwfrFmN/8Ad/wNvf/nbe9KY3bcXxGAyXhJaJRyNKKGXPu7EJnbYpNkK1poBqtQ4OFjzm/ZhaGGM5FkKkV8mzrsVcLeSpsQr3XTN4Qdvqx8/N8ta/f4Lx+YCenMPN20t4rt02APm5u3azpy/P4YkKedda1IaolGK6FnLNUBGtNEenaive59ycTxAnjJYbDBTPz9gcnqjwO3//eNPAIyJMNJaARJFWPWhZm6eiTGkY7s4SJZpHTs3y0hu2tRfDR2WlKWDXWRlb4bZYc3GuFlcprdpR2wZfa2ar0ZqW9kqnc1/rfUXt5g5bp6JV9NSAbUHWsUi0TrPbtCbnWuRcmyPjVRKl6cmm78OMI5iup8HiGdtqmnYo0BZ9OY+X3riNrGtRCSIqjYhPfm+MkzM1bhnpWvRefras4Dt1S70UrqoGg8FguHpYtxibnZ3lp3/6p7fiWAyGS0bLxGOl3B+AsXmfG0Z6LrjYa7cOeha2JQiThEbTkt0SqaVBkCgcW17QtvpPPvM0f/5Px9rZU2fmfJ44V2FbV4YXXTfIdC3kC09P8Op7dvOHn36aU7ONRW6K07WQUsbh5+/dC6RuiovuEyRMVAL8KMGxJbt7c1hW2spYzKRzWYfGqwgBO7pc5uupEFq4aE/nnNK/2xLiRDHcnWVyPmi3crbCtGtBsiEnxE55rtcXWjNbLfw1VNjS87iR/blSogApF5t/SCHSkG3SCxBoUjMOpVGuxVApQ6trtpUXNluP+NrJaYZLGfrzLmEc8vHvjfK149P851dczw0jXQD0FTw+/JUTfO9smZ6cSzFjY0vB2Hxwya3gO3VLvRSuqgaDwWC4uljey7QGP/3TP81nP/vZrTgWg+GS0bKk7s27HJmoUvEjYpXmGQH0dLDYW9g6mHVttpUy5F2bOElzssJYk7EtfvJ5O1ZdgP3JZ5/m/V8+tiwEWAHnyj6feWKMrCM5OlHlum0l3vLD13HNYJGKH3N2tkHFj7l2qMibf/g67r9+iPuvH1p0n2em6pyZaxArTaIVAhibD2g0PeC11kzVQrROs8gqgVq22F9KotLXb7CYYa4RUfFTj/RWmHbBszfFnOJCPNcF2aUk0RAlCrRGNI08Wq2rQZQQxIp6pNBakySaKFHMNSLm/ZjRss98vfX+qFP2YywpyFiSWhDzyOk5vnlylsPjFR4+Ps3P/sXX+euHT7T3nXEsJisB3zwxwxcOTfD1E7Ns78pcUlHTusgwUws5OFigmHGwpKCYcTg4WGCmFvLZJ8aJY9XR/dR6E7cNBoPBcFWz7srYgQMHeOCBB/ja177GzTffjOMsDtz89V//9U07OINhK1kp9ydnC8jAv71r15qLvdt39ixqHcy6Ntud1EgjShTjlYDrt5V45S3bV3y878f89cMn2852C3Vfa702VQ15ZqrKUFeWWhhz//VD3HdwgEdOz7YNOG4b6Wa8GnBobJ68a/ND1w5y38EB/r/vnePvvnOGKFZkHck3TsyScSS1MCFMfLaVMkgBfpQgSEVWLUyamU4Xfu3mGzFPnJtDa8Hff+ccri2JlcaPE7TWqYPfFkmytcSiYXNY6GQZaxAacrZFos8LMltKwjh1PVRK49gC13bwo3Q+caISMFfTsBfm/RilBQXXwo8V5UbcPo/NaDnmg4j/8pnDTFZDZmrpf3ft7WvmdkXM1EMa0aU1dGldZBjuyiyroLecHY9OVHnk9GxH91uPq6qZPTMYDIarn3WLsQ9+8IMUCgW+/OUv8+Uvf3nRz4QQRowZriiWWlJnJHz3q6fZN1BY87G2LXntvXuWtQWGSTrD1ZNzee29e7DtlQvQH3vkFJUgPl/ladkJcn42SwMnZxr0F7Pt+TXbljx/bx+Qtk/9xVdOLJtPeckNQ5yb8yl6Dgd3FjhXbmBbEqUh60gakWKmFtKVs0mUJmnuy5GgtEBqvcyVT5Iumts5WVowWPI4NVPjIw+d5OU3bSNjW/hxgmtJ4iTZElt6wQZK+oYNYYumINOQcSQ9eQfZAM+22NaV4dqhAmGiOTJeodyI6M65VP2YciNirhESqzQzDJqzZs2Ms9bsmi3Pz785lkSgCOKEv/7qM9y1p5vrhrvawqYn77Yzxi42t2891MK4HVa9Ei1nx+la2NH9OnFVBTN7ZjAYDM8V1i3GTpw4sfadDIYriIVubFEU8d11PPb+64cA+B8PneTkdI2ZWohjSa4dKvKae/a0f74SZ2f99myVaLoVrrS0rIcJ27uzy+bXLjSfcng8NdLY1Xxe+aaLXbkR4WRtXFtSDSL8OKEeJu0KRT1UbRHmyLRa1sqvsmV6oEKkOVVSCIa7svTnXcbmA753usy+/jyPny3TnXPSKllTjW1mJUtzdWSPXe4o0gsCAsi4kjt29zBQ9Hj0dBk/SrhhuERfwWO+ERHGilwzOqHg2dSCKBX+tsQRaUtsy5EzTPSCgGfRbJFN9yWlxJWCqp8ayWxWheliaJn9tMKql9JyduzLux3dby1XVeh8Rs1gMBgMVz4byhkDCMOQEydOsH//fmx7w5sxGK54VmodvH1nz6oVsRYjPZm2CJNNt7qWIFsoXjK25P7rBxdVAZbOsbQWrcWMQ8GzeeTULJOVgIGCx1OjFWbrYTO0VzNVjcg4giDWSJEsqoAt9IJQ6nyosGxXSHTTnCS1Sj80No8tJXnX4junFa+9Zw+HxitNl7+tbyc0FbKtRwB9OYdYaeb9mBcc7GOyEjJdC3Ftydi8z+i837bMn62HRErjWGlNrPXebEeINd8UC4tarTZHz7ZwrFSYRcnKknu9FaaL5UJmPwudHW/f2cM3T8yueb+1HCDX+mxf6sqgwWAwGLaWda9l6vU6v/ALv0Aul+PGG2/k1KlTALz+9a/nXe9616YfoMFwJdBqHfzhm4Z5/t6+NYUYwM/cvoti0+wiUc25GVLRs1DE7OrN0F/wOD1T57HTc/zVw8f5488e4stPTzBYcFapHmQpNyK+fmKayYpPxrHY0ZNjR08W2xLUAkWYaOJEt/OjVkIDni3JOBaWFGSbf2actBLQk3PJOJK5esjTYxW+cGiC0bkGUkJf3mmG+G4drdZKxxK4C/ZlQzr/t8U8F5bCtgVDpWxbSPXlPP7l80a4aXsXp2bqfOvkDLUgJk7Sd64fJs22V0HTYBFI39eeLdsirGXL32rHtZtxEIlqhVmv/MZcT4VpM1jN7KfiRxyZqLadHW1bdnS/tQRUpzNqZ+caW/m0DQaDwXCJWPdvs7e85S1897vf5Utf+hIvf/nL27e/+MUv5m1vextvfvObN/UADYbN4nIZhl94HD/+vBH+5mvPkOjz1vEL6ck52LbNm/7ue/hRzDPTdYJm+UoDh8bmuWNPL7fs6F70uIGCR5xo5hoR+/pyqblGpOjKOOQdydMTNVwh6M5YVIKYZEF5bGk1qxEpcq4kY6X25rYlGenOknHSrw/PtijrkPF5n7/56kkQ6W2FjE3GElSVXlbt2yw0YElBzrVpRAkOmkhBAgSJboulrarQXU5GIkuDuVtc7GsfJanYvXWkm8lKwNdOTHNkosp/+MF9nJyuIqUg51gonYaEh7FCqzT+wLYlXvPCRNGzacQgSGcWW3EJUkDGtsh7NpZInUgLGQfXSlsYN1ph2kxWMvvxbIubR7p46Y3nZ7g6vd+F6HRG7VJVBg0Gg8GwtaxbjP393/89H/vYx/j+7//+Rb8kb7zxRo4dO7apB2cwbBaXyzD8SsfxfXt7+d7pOeoLXOIkMNyd4Y7dPRyfrHJiqk6taUe/kPkg4aGjUwCLBNlkNcC2BLYlOT5VTx0Im8YbSmuE0Egp8DybmUaMZwtipdszbAud9jUQRAplSzSwuyeDJQX1MMYSgloQcWbORzVFVyljI6Vkth7hRwoLsCxY4fA3hVhpGmFMkGgsKXBkOpOUbwo0DSSJvmLmzDYiniyabX8yFU8Arp2qs2gDr/tCJ0WAQ2NVGmFCkGiiJOH4ZI1zc3WmqwGWEGRdm7lGhB/HKNV8fNOsoyuT/poZ6c5xdj4kbET05h3m6hGaVFzkm8Y35TAm41i8+u7dzNRCjkykFaJWpt5o2b/kGWMtlpr9rHZBp9P7rUanM2qXqjJoMBgMhq1l3d/mk5OTDA4OLru9Vqsta6kwGC4Hjk5U+PBXTnB2rkFPzqU/72FJVhyGb2UAHR6vUMplNrV69vi5Wd72908yVQ0Y6srwvB1dhAoaUcIPXT/IkdF5tBR0eQ7XbyvQnff49jNzlBvxIiG2dLEeJppvnpzhxuEilmU1qweNtLVQQFUnRElClKhm5USgNCSxwg9jtE7bLGUzzDlaoMSanh30FVzqoaIexpyd87Et2T6KapCg0RQzNrUgwZIS15aEEfikVSq1RUIMUpEZxKnYsrWmkLGbx5RWzYJItYVFq/HtchRmtkwrResVYhLIZ2z6cg7DPVkeP1smiJM0701DuRGRrGOjYsnfXQsqfsTxKcVwV5ql51qKY5M1qmFM1pZIKSl4NmHTEKa1P60h66Spz635yD19eX7jJQc5PFbh7751hslqwFwjwmq21/7CC/byc3fvWXThYiMVpq1godnPZtxvJTqdUbuUlUGDwWAwbB3rFmN33nknn/jEJ3j9618PnB/O/tCHPsTdd9+9uUdnMFwkSmk++rVTfOuZWSRwdja1eO/JuewfyDPdDGLd11/g+FSVzz52jhHgA18+hmM7m1Y9+5PPPM0H/+kYQXOVenKmwaOn5rh1Zzffv6+PR07NIqTkJdcPNYUOzDciZmoB881QZUgXx62Mp4XGG9Ug4enxCjt7883qgccz03Xm/Bit0/kw1WwJk6RW9gqYqUVoDYlK28G01svEgBTQm/foyiqOTsY0ooSCTJ3vokSRtMwaNGh0Wo3SelHrY6dYpOJtXSxozQtVmmdlSYklwFfLn8/lKMSA9vnZSCZwI4zxXclAwWOkO8do2acRJhQyqXNmlKgV22BXYmGOm2OL5ntNUw8Tzsw2cG1J1knfo3GsaShFb97CstKWRNdOA53DZjutaobWTVVTZ8DX33+Q+68f4uU3DvPLP7Cfzx4aY6wcsK3L46XXbcN1U/F2sRWmK5XWjNq5cuOyqgwaDAaDYWtYtxh7xzvewQ//8A/z5JNPEscxf/qnf8qTTz7Jww8/vCx3zGB4tnno2BRffHoCpdOcIscSRIlmsuJTDWIODuY5OlHl4WNTfOrxMco1n5Ei7O3LU430plhJ/8lnn+a/f+nosupEkGi+9cwsALv78jwzXWei4rO9O72iHiaKRqwIVukzW1ohOz5Vo5hxuXmki568wz8dniSIE6Q4X+1IVCrmLJE6J0ZNx8QkUsuEQMtMxEIghaYSJthN18eSZxFqSJL0GOJEM5+kIb7VIKEeLM4YW3icS4+76ArqUdpiaEsIIr3MxORCJJyfl2o9R6UUFaUWOVVC+twvq0GvBbTyvNaNSM/jTC3iyESFm3d0019wm1XVqK2u1vPUJWlrqSNluyqb6HR+0I8V8/7590eoNJUgJu/ZOFZq9iJFGgyutKa/mAEavPymIX7ijj3s68/zjRPTbefRl98wvKrhzcVUmK5kNmP2zGAwGAxXBusWYy94wQt49NFHede73sXNN9/MZz/7WW6//Xa++tWvcvPNN2/FMRoMG0IpzYNPjdOIEnb0ZLFkuuDzbIGbd5mphZyd88nYkv/7zTPM+SG3bi9AkC4Cixn7oq2kfT/mL//5+KptYkrDo6fnuG1HiaxrMVr2Ge7KIoTAtWRz9mb1JXRrgS2AF147yGvv2ctwKcMffOKppuuhpBYk7W1IuSA7yhYkKjW8gHSxLRZsF9JFuW0Jzsz5hFGSCjcNp8vh4ufR/HNhNtlqLBVmiRZYMnXTS7RGLB1YWgNBOh8VRLpd1dGklabWz88HCwt0fOXMj3VC6+0RJJqTU3Ucy8KSkPMk5XrSbn2UIg1xbglwSMVp0bMRTfHUijAYKroEsWKmvtgkYmFFdqF8CmKF0jEFz0JKSazAdSxKGZvXvmAvyclZfvPF1/KV47P8/sef5OR0jShROJZkW8njR2/dzouuG3pOVL465blaGTQYDIbnGhuaAN6/fz9/8Rd/sei2iYkJ3vGOd/Cf//N/3pQDMxgulrNzDUbLPnnPJlaLLdyFENhScGS8gmUJJFDIOKgkYX9zJFIpzeh8gyBK+NrxaV5x0zb2DBTWdQx/9qUji4w5ViJMNN89U2ZXb458U/y1WpPyno1YUNNouwMu0WcZR/Bv7trFzt4cp2fqjJYbdOccEqWph+fNNVo5ZokGoVITD6lScSKbO2g58tnNsbBGpGis8RwWYkmBXqE9cCmS1Oo8SlJTESnBlZJEasK487Y6SA06Vttf67m0Zstg4+2AlyPtlkKZmmE8M10nShKklPTmHZROK5eeLenK2hyfqmNLQd5z6Mu7dOUcGlFqytFoVsGqfoy/5ARIFgtpLUA030+iuY9KkJCx00DwvrzLgcECNw138d2T8M9HJnnXZ49S8SP68i4AU5WAx87O89RYhU8/PsYLDgxcclOdy5nnamXQYDAYnktsWmbq6OgoDzzwwGZtzmC4aGphjBSCgYJH1Y/RCxRMI4yZqgbUwpiia5P3LAqezVQlAOCJs3P8w6Nn+ewT43zt+DTfPDnDG/7Pd3nwqfGO96+U5itHpjq679k5n9t39fCrP7Sfm7Z3MVePeGa6xrZSJm2vbH5SFedFRKsCJIB79vexp69w/nnL1N5eKY3TzC/TOhVhSVNsReq88QWk80HXDhXoyzlpG6NaHAK9Ekuv0UcKIqVZ6OUjSUODPTvNnbIl9GYdhrsz7B3Is63kMlD0yNg2sVKpeFhn6UqtdX9NW4yL5r+vpvqCIwU5z0ZpqAYRkmYlzLLobQqfeT+hGiSpwJeCoVIqxMLmi92VtdvvqVjpZWK19TPZbHNdaKNvWaKdH1bMOFwzVGBnb47bd/Uw3JUB4H99/RQVP2JXTxZbCqaqAZHSlDIWWsMz0zW+d2aWjzx0kqMTlS1+xQwGg8FguDww3riGq5a8a5N1LLLdGWphzEwtpJCxsaVkshJQCxMyjsWBwQKnZhsIAT351Er6GydniVS6wM04Ej9SnJqt885PHQLg/uuH1tz/2bkG5UZnWUDFjNOeBTkwUFzUmnRobJ4//szTHJ+sETVXyO1FsITrthV5yytuaLcvpc/bJsoogjital3ITc9qzlSFsebkdJ3+vMN0vaPDXrUatXAhr0jn31zLIu8J4kSRz9gMFD1qfkQx61IPY6p+3BSH6ytZadY2/Yg1iKRpYNKcl7tcZ8fWS1rp1ESxImmq0oxrI6WgFsT4zZlDS6bi+8bhEo+eLXN0sk7etdCk4d/1MMGS0JtzEVIwWwtIkvT9oUirX5CK64Xvp6xrpS2mzWrozp4spaxLX2Gx0cSpmTp9eRchBDO1iCjRZB0LISCLoBokFDyHmQWmOqYlz2AwGAxXO0aMGa5aFlpE37qji+OTdWbqIX4UUQ1iPNtiT3+Oa7cVqQYJExWfXD79SESJopD1sKWgESlKGYdtJZfTcz5/9fBJ7js4sKrpQItKECFEZyv+N77sYLs1a2lr0s7eHLv7cvzFPx3nWydnmK5FaK3pyjq8+Poh/u3duxe1dY10Z+nOOnzz5Ayig3Y8pcGVqZOiHylOzwUdHfNaLBz9Si3vBVKmdus516aYsTk5lc4ONcLU8GMrZ7k0zapg0249ihOiK1iQuZYgbg76aQ1BkoYtO80KpIQ0500Kcq6FlJpGFNNfzPB9uyVfPT7NvB/hSNG26LSkwI8Vec9KQ711AgIcAVGi29VVveAYdnRnqIWKapDmyk1UQu490M/LbtrGgcEiUZS6gUaJotu1CGNFI0pwbdmuoDpS0FCaRpww3JXh6ESVs3MN06JnMBgMhqseI8YMVy0LLaKnayHXbiuQKDgzW6caxAyVMtw80o2Ukv2DeSpBxOi8D8MgRRqCHCXp/EvWTU0J+nIuJ6ZqPHJ6lufv7bvg/qt+TKLO50etxkDB5YUHL1xpu2aoxB/+5K2cma1zfKoGwN7+PDt7citXD5o3lRthRwWgjCuJYkW0Vl/iOlBL/q6VpupHbO/OcM1QnsfOzlMNYhKl15WDtRnH1QqDvpIJmy+a0E3h2zTqsIRohnInhInC1oKKr9Gk8Qbn5uokGoaKHiDY1pXh7Fw9rRx7NpFKxZ0l0rkwNCg0dtOWs2VZbwnoybl05VxKWc1ERTDcZbGzN8srb93Orr78ouN1LEkjTEW50hpLnL+YEanUTTPnWGRdi/F5n1rYWVXZYDAYDIYrmY7F2Bve8IYL/nxycvKiD8Zg2GyWWkQHcYJjSwaLGa4dKrTnaXrzHrft7OaRk9PNR6ZtXwKBkmlG0oyI8GxBGGuma+HqO22Sc9MAZksKlFrZwU8K2NefZ3TeX7MKIKVgV19+2SJ3KWfnGszVI3b2Zjk721jzOFtzZ8kFXBs3A026yB/pznJ4vNqcz7u0QmzhsVzpyLZQWtymGcVppbFlSZ/mc2vCOG0jfGJ0HoGg6Fm4jkUQK2wpybk2Uko8mVbBBksZwtkGYaLagqxl4iGAnGfTX3Sp+jGVICbn2ty6s5uKH1FfIY5hV2+OJ8drDBU9pEidM22RfjYaYUJfwWW4K0MtTPBsi7xrrhUaDAaD4eqn49923/nOd9a8zw/+4A9e1MEYLj+U0le8tfJSi+icY/GPj57jidF5tNbt4PLevMcNw0WgTNaxiLUgShQWEikktoSKH6M0+OGFp5SOTlT4x0fP4ceKOEmdAi3SikBrMevYgr68R9a1ODZZ3bTXuBamwcwz1fOCse3CuOpjkkviLqiAb56cTY9HpFWcSy2NVtrjZh+FDWxVXUcArpVWW1cS+AlQ9uM0K6zZpho13SY9W2AJQRAlzCYJIKgHEdu7siQqfe9kbInWGteW7OzNMjbnE6m0smYLgZSavGvhOVb7Z7YlsK3UnbQn764opP7NXbt412ePMlb2QWvqfoxtWQRxQsa1uW1nD0IIRss+N490MdKd3aJX0GAwGAyGy4eOxdgXv/jFrTwOw2XI0YlKu6LkxwkZ22L/QOGKtJ5eOof18pu3MTrvL7KRb4QJjSCBTDprU2sFMoWqKRzS7RQ8h7OzdVTTGn4hSmn+6cgE7//yMSr1mIJrUWmkj4tVKj48W5JzLVzbopixGZ/3+ejXniFUCktI9g8U+Kk7R7hmqLSh55p3bZTWzPlRmivWwSBWrFJr9EshyFqVMKlBdzhTt5ksFV5bIQczjiRB09iCoTQBzQsIGkukf9eA0Gn11ZaCsHkBQAjRbj1tve+qQUTYfk9oglpMPawxUMzgWJJ6mCClaOa3WdiWpCdv05V1sC3BXC0iTBKESA1uChmbvGsRJYozcw1ilc6mLeW+awcZrUR86J9PMD7vpxW3SJF3LW7aXqK/4HJkokpvfrHxh8FgMBgMVzOmD8SwIkcnKnzkoZPM1EKGuzLk3Cz1MObxc2XOlRv8/L17LmtBtlZFb2n74vi8j2db3LijCyqjqbU3AqnPZ1JFGqTW7OjJcHyqvsxg4OhEhfd94SifeXIMP1QIkc6eaQANJc8mVIqsneaHWVIwUwvxbKtps58QxIqnRuf5+olpfv3+gx25Ni5lpDvLcFeGbz+Tzvms1iK5kIXh0e1cLtIA55VomXNYzT83IjkUix94KWtkjoR1RKetm2qkcKTAs0U72+xiWVjdDJoth46ErCPxHEkQp5EC1w4VeXqsQqLS6ta8HyFFGgBeDWIWFnVbr3kjUozONxguZoiVQiIoNyKCWBEmir6Cyy07usm5Nmdn6zz49ARRrNjVm0vnzBJFLUgYKHiUMg6ff3KCAwPFRZ+545NVDo1VuH5bkRtHSsw3IiYrAZVGxMnpGq4tuX1XT9tV1GAwGAyG5wJGjBmWoZTmM4+PM1MLOThYaLfxFTMOhWYo8eVsPd1pRW9p+2Leten1JJ///KE0gJhmK1hTpbhSIARMVyO2d0WLDAaOTlT4/Y8/yTdPzhJECtdO75sk6UyUSjS1ME5NDKKEgZJH1U/bxBxLMO/HFDIOpawgihWj8z5/9uARdvbkuGbb+hamUgruv36ILz09SRAlxMnaLYiWANeWDBQ8Ts00mlU8sMV59zwBFFxJ1DQlqTct85eGAW+USyXEFIurhVux3zTnS7PC6NSGcaz0vRInqv2+lEJgW6m5jGNJSlmbXX055uohteYc1ulpkBJqQdw2/YBWhe18gHgUa8YrPiPdGVzbphHGqZAjrbalZjZppljBtahqzXQ1JFYKx7IYLGXYP1DAscSKbogPPjXBTC3kmm3F9neK1pr5RsTRySr7BvL8+3v3Ml4NODQ2f8naoq+GVmyDwWAwXLkYMWZYxtm5Bscm0/Y9IRYvSoQQl7X19HorekvbF792NA11zjs2Wkq0BqVTR0XHEkQK5hohtUC152KU0nzqe6M8fna+adgBtiURNM0T4gSlBY4l6cnaNGJNKeOgFeS91Oq7t5m/BKko6s05nCs3+MjDJ/j9H7tpTRv9pdy7v58XXTvIp58YJYgVS10yBGkr3fXDRcbLARlHIoTgxu1d+JFith6254wgFV/dOZfBokc9TPDDmFoUIthaO/qVsK6AdbIirbxtZtvncMkjSDTlRoQrU6OORKfOkL05B0tKhruyDJeyfEfPMlkJmKkFhM2KmVpShYTFAeKQzpb5UUKs0qqoY0n68y5T1ZDp2jS2JZivR8zWI1xLkmjN7r48u3vzFDM2QghipVZ0QzwxVVv2nSKEoCvncs1QkeOTNf74c4eZqgaXrC36amrFvpIwAthgMBjOY8SYYRm1MMaPE3LuygP0l6v19GZU9GbqaSZSzrMoB+dDaVvYKKJE0ZN32wYDZ+caaUWsuZjz47Ta0IxuwrHSeRqtYd9gEUsKXn7TMB//3lnGygGFjNM+1kYYM1OLqEcxjTDhi4cm+C/e0/yr79vR8eIwDBM+/cQYJ6aqlBsRaE3eEYvmlxxLcNfeXm7Z0c23Ts5ydq5O1pH05Bz2DxQYn/fRKGbqMVppihmL4a4ss/WI4a4M09WAqVqIEKLZjplangvWDmC+WBJ9+X9xCS5OiNkCPCcV9NVQYTfLWFlXNtsTU+v6WpB+BpXW9GRt9vXneXK0zJlZn0TptFXSkQSRuuDxCNJzqDVUgoTtXS6eYyEl9BY85uohp6ZraNJssURpQp2AEJyeaTDSnVvwHl7ZDdGPE4ZWcUj0o4TD4xX8KOGaoeIlaYu+0luxr1SMADYYDIbFrO9yu+E5Qd61ydgW9VXE1mqLrWeb9VT0VqM35wBpKLBjCRpRQqzSsNtYaWpBgi0lL7x2oC3oamHMfBCSKI2UaRUtTlS72pAeiibRaVXjjt29PH9vL7ZMbcUd67wQG2uKXCkEWUdiS8GTo2U+8tBJjk5U1nwN/urhE3z/ux7k1z/2KF88PEUtVIQKalHaYubYgoFiWuFqtaztHcgRJZpGlFANInb3ZUm0ZqISEieKKEmo+AnHpmoIIRgqZfBjRdaxyLlpLtTe/gIDRQ/bFlzs9W2rKWIXVsCulGvmFqlYudiL/CrNck6dCiXsHyxw74F+XnjNIM/f00OiNJUgJkg0jUgxXY+oBAlfPTbFlw9PEcYqdU6UEkuIZRcf2u9Nzs+NJU2b/O6sy/XDJZ63M50RqzQizs2l4k4IQdazcSxJlGiU0tT8iGOTVbTWaK0ZLfscGCwsc0Nc7TtFa83TYxXiRHNgoEAx42BJQTHjcHCwwEwt5LNPjKM2scy49MLNpdin4bwAfvxcme6cw77+At05h8fPdf4dZzAYDFcb6xZjn/70p/nKV77S/vf73vc+brvtNl71qlcxOzu7qQdneHYY6c6yf6DAaNlHL8meutBi69nmfEVvZZGYdVMb7QtV9G4d6QagGiYMFj3yrk3cbN2K4jQo+LrhIq+8ZXv7MZOVgLlaTJgoKn5CrBRKa8I4rUYoTZrTpDX9BY+X3jjEzp4c+wcKhLEiihVaa2ZqEVGiyToyNV9wLAqezYGBzhaHf/LZp/mDjz/Vru4tJdapm6NrSYpZh6nmbM7DR2eIlSZONF87PsNXj89QD2M8O91/Wv0SoCFsGozM1NI2xloYE0SKWGmGSh45124v8DeCRdoSuXCWyWpW3lxLXHZXjyTnn6sAhEwX+hebnaaAWpjGInh2GqTcX/CYa4R890yZih/j2TLNCrPSF+vUdJ1jU/X04gGpyUeQKCwpGCi4y9o79YL/WghAojk6WSNWmp6cw9i8Txgn6Rxk8z45VyKlSI1tlGKy4jNablzQDXFvf37F75T5RsRo2We4O0Mp6yz6WacXUdbLZly4MawPI4ANBoNhZda9tvmt3/ot5ufnAXjsscd44xvfyCte8QpOnDixZjC04cpASsHLbhqiN59aTVf8iFgpKn60pdbTSmlOz9Q5NDbP6Zn6un8pb0ZFrzWbVfAcJqshpYzNcFeG7pyDbM7kvO6FB9r3OzpR4VOPjeHYAqfpXGgJkbooaoiVIogSEi3YVsrwxpddw4HB1GXup+4cYaDoMTrvN4NyYywpaEQKW6aiqbfgUco6ay4OHz8zx1/+83GiNV6zsCn8ojhhrOzzlSPTTFQaqYGHI8k4FvUgPY6X3TDICw70M1DMMNydYXuXx2w9ZGzex5aCvGdhyTSLbbIS4EeKvGe1q0L2Bt4eCRAlqRBTNKs2zackRDqDdzlVyWyZhns7TffJWKWid93bEYu/jCVgW4LevEtfweXxs/N8+ekJ/vnIFKNzfjoH2MzI68m7aL1YVFnNP6NEUwtigliRcdb+uheAtCSNMOb4VI2hkkfSFHca0Z49ixUUMjZdWbs5YxgxU4u4eaRr1fa++68fXPE75ehkFdsSXDtUWiaMoLOLKOtlMy7cGNaHEcAGg8GwMuvuMztx4gQ33HADAH/3d3/Hj/7oj/KOd7yDRx55hFe84hWbfoCGZ4fVrN9vHunaEuvpzZgjaFX0Hj9Xbld0WrQqep2Gyb7xJQf5q6+d4eR0jShROJbkhuESr7lnT9tuvnWld7YectfeXsJYcW7OJ0zS1jLRvI8lob/o8cCP3sh127ra+7hmqMSv33+QP3vwCOfKDRph0rQpt3AtSVfWZV9/noqfhjjP1kMq/vKq1+GxCm/82+9S78CrXTXbLcNEUw/jppGHRS2IKTciYqVJlCbjSL5zpsyt27twpGCi7JNoTaLS18KSaXCwLSVSaGpBxMkwTp+3FMjmDFM1SPBjvS7HwoXPol250ZBskkX8ZtFq7wsT1exF3djxZW2BlBKJJlKagufQm08NObTWjPRk+NrxWeYbMVJqhEhFWJBoLKWQTcfLVtVKNQ+uFcmgNFT9GNcSWGKZl0v7ubTiDKarIbv7cszUQgaKHsWMQ5Sk1c9WVELetenNu7i2YKzsM9Kd5T/ct487d/euepFm30Bhxe+UG7aXyDjWqmJxK9qiF164KWacZT+/XFuxr2Su1Flkg8Fg2GrW/ZvGdV3q9ToAn//853n1q18NQG9vb7tiZrg6WMn6fStcrzZrkL5V0TvXbJdaGOY8WvbXVdG779pBXnjdMI+cnmW6FtKXd7l9Z88iV8OFV3qLGYcfvGaAb56Y4dRMgzBJUCqt5FyzrchvvvjaFTPD7r8+bVn88EMn+NLTE9hSUPBsegse/QWX45M1ZuohjShGKfj775zDtWX79Tg6UeF9XzzK6Jzf0WutgXIjQjdSIVbwLGpBQqQWS4laqDg0WuHoeIVYLW1lU1icN+pIg4fBkoJCJm3rnK1HTNbidhvfemXKwu1f1ghB3LR8b4mf9dKINYK0BTbnWvQXXEpZBw3M1kKmqhFdWZt6qAjiBK3T19q10gy7epje1n5bNwWYlAKJRmlItMayLFSosARkbfDj1PK+dX4c20JqnQaG10OklCiVts1mHItYabaVMhQ8G9dO3Tf9KI1NuG1XzwWFWIuVvlOGSxn+/J+OX/Aiyk3bu1Bab5rl/WZeuDF0hhHABoPBsDLr/tZ7wQtewBve8AbuvfdevvGNb/Cxj30MgMOHD7Njx451H8D73vc+/uiP/oixsTFuvfVW/tt/+288//nPX/X+73nPe3j/+9/PqVOn6O/v56d+6qd45zvfSSaTWfe+DWuz1Pp9s7kYB8SV7JE3s6Jn25Ln7+1b9edLr/T25j1eeuM2yo2Ic3MNwlgRxIoHfuSGNEx6Fa7ZVuQP/sVN/JfPPM2To2UODBSIleK7Z8o0woS8ZxHFku6Sw6mZGh956CQ/f+8e9vUX+Mzj40zXApwOF6aatHXNcwS2tPBjTdgsRS0MFW7fVy02eWjdHgOOBUnSzCFrtmQKIkAsuu96aUUCrBY4fTnQHNMibtr/K73RulhK67H1MOHkdI3unEtX1kndDf2Y/qJHuR4RRIJKkOBYaRtrrFLjFVggqpqvXZKklvbtyqLSOJZAaY3nOsQ6RjRDyS0hsISgmE3nePKuxVwjYrTcQApJV9ZpG83Q3GYQxYzNB2wrZfjJO0Y6Fkcrfadc6CKKJQXT1YA//fyRTXPf28wLN4bOMALYYDAYVmbdYuy9730vr3vd6/jbv/1b3v/+9zMyMgLApz71KV7+8peva1sf+9jHeMMb3sAHPvAB7rrrLt7znvfwspe9jKeffprBwcFl9//oRz/Km9/8Zj784Q9zzz33cPjwYV772tcihODd7373ep+K4TJgo5lma7U1XoqKXutKby1IBUiYqGZ7oUN3zqXiR8zVI0q55VeBl2Lbkn/1fTv4yEPpAney4lMP0iDoWhCT82xuGO6iJ+e0BeqP3CLbr91jZ+Y6Pu7urI1jWzSihFojXci3bM1XEhSrVXyEXt5SWI80GUsjSX+mSatcUqbCrhNkczbMFWJRSPHlggVNZ0pJo/mkNnKUrddoKX6sGZsPmKmFbO/Opll1pHOIQqQzekGssaRMZW9z50mzOpaxJbYtqQVJ+/WTwLVDBW4c6eYfHj1HI0orcUmicO109i/jWBQ9hyBOaESKgmfjOZLBkkfFj3CafYyVICaMQ8JYM1zK8Pr7D3LNUGndz3/pxZTX3LObzz0xsegiynBXholKwOi8v+n285e6Ffu5jhHABoPBsDLrFmO7du3i4x//+LLb/+t//a/r3vm73/1ufvEXf5Gf//mfB+ADH/gAn/jEJ/jwhz/Mm9/85mX3f/jhh7n33nt51ateBcCePXv42Z/9Wb7+9a+ve9+Gy4NO5wgqfsTpmTq1MGaqEvDJx0bbmVerLdC2OpB6pDtLd9bhK8emkKSzWLYl6cm57B/IM10L13Wlt7U4/D/fPM0T58rpXFasGCxl2D9QoDfvArQF6vGpKjP1gJofU/E7a+orZWzuOTDA4fFK2t7G2oYYq7XehauIKz9ZvM0E0B0KMUukoddK6WWue5cDArAs0Y46uNhtXYgo0UxXA4qexWwtJNHpfJlrCeqRJonVkvbRdMHrOhZSCGyp2rEMpazNvsEiP3PnTqSALz09SRAnzDdiNJq8Z9Obc5mtR9SCmGLG5vZdvWzvzlEPY45MVJlvRO0WSilSu/2fun0n12xbXbQopTk7mxoynJ1tsKvfRkqx6sWUl9wwxI+526mFMTnH4h8fPcdo2d9wbuBaXKoLN4YUI4ANBoNhOesWY6dOnbrgz3ft2tXRdsIw5Nvf/jZvectb2rdJKXnxi1/MV7/61RUfc8899/A3f/M3fOMb3+D5z38+x48f55Of/CQ/93M/t+p+giAgCIL2v1tzbVEUEUUrW4BvNq39XKr9XUlkJORtgR+EFDLL345BEJPEMf/4yGmmayGNKOH0TGrffcfuHkpeWl8oeZLiQJZjkzU+9/g5dt67d0MLqvWcq+OTVaarDZI4BgFdWQcBTM3XmSjXuGmki/uv7SNJYpIOB6B292R45a1DHJsoU/QcpBR0Zx2KGYnQ6UbyDpysNfi7bzzDU2dmKfsxjrXGhoGerENPzqU/bzNXcJir+fiWXmz88CxjARmpSJrVOCk0rkyF38JWSU/qRX9eKhyZBmZHSZobJzp43S/EWl/AYRwzHaeGBhLQSWovn7M1iVp8ziTgWqDiGD9JYxXc1kxYEvPZx87y0OFxXnTdILftKFFuBDjSYqYeUPVjKo0AlSgGiw537+triv/0s3X7jiLHJmrs6M3wI7dup+imDp9SilU/K8cnqzz41ASnpircnYEPfPEwu/qLXDNU4MtHppithWwrZci5LvUw4alzs4yVa/zbu3axf6DA2dkGz0xVGCm5SBYPLgpgpORyYmKeU1MVRnourrVtW9EB0gr2ej6vVxOX6vfU7p4M//7eXYyW/fNzg2u8lwyLMWuKKwNznq4cnu1zJPQ6Lz9LKVe0H26RdPhb7Ny5c4yMjPDwww9z9913t2//T//pP/HlL3951WrXn/3Zn/H//D//D1pr4jjml3/5l3n/+9+/6n7e9ra38Xu/93vLbv/oRz9KLre1lRODwWAwGAwGg8Fw+VKv13nVq15FuVymVFp/2/3Fsu7K2He+851F/46iiO985zu8+93v5u1vf/umHdhKfOlLX+Id73gH//2//3fuuusujh49ym/8xm/w+7//+zzwwAMrPuYtb3nLovyz+fl5du7cyUtf+tJL9oJHUcTnPvc5XvKSl+A4a88PPdc4Plnlb75+qn2lPOtKGqFirOwzNt+gkHHY158nUmlm0lPn5unO2czVYwZKHs/b2d2+QJAoxTPTdf7Dffu5Zmj9LS+dnquzsw3e98WjdGUdChkbrTVVPyFUCldKQDPvx/zqDx1YdtW+VTE4MVVrt2jt7c9z//XpnOTffO0UjzwzS5Qk9BVcYpVak2ddi509Wb5ydIp608VuLVpmGHv7Crzw2n6eHK2Q92wmKz6nZxpM1cJF95ekTn0L88ou5Ia4cUP382QtgW1Jgjh1dZQiNZTQ6FXnzDyp+f07FQ98SxKoS9NSJoCCIxFSpnbySlMJE1wJxYxNLVT48dbUFy0BriXxF7Qm2hK6Mg5KaypBjCNlM+dNMFcPiRR4lsSzJWGS5stpnRq2uJagmLHxHJvn7ezmX9y2nZ6Cywe/fJy9ffkVq8qdfraU0vzlV07w5Og8+wfySBR7/GOczOyn7Cu+cGiCbV0ed+3tW3Zhr+qnEQu/+kMHABZ9xpay8L4XWxkzmN9TVxLmXF0ZmPN05TA9Pf2s7n/dYuzWW29ddtudd97J9u3b+aM/+iN+4id+oqPt9Pf3Y1kW4+Pji24fHx9n27ZtKz7mgQce4Od+7uf49//+3wNw8803U6vV+KVf+iV++7d/GymX59R4nofnectudxznkn84no19Xglcu72H19xrt+cIgkqIZ1ts78sz3YipBIqHT8wRK4XWUG7EaCnJeA4T1Zj5QFPKpm/lWqSwbYdSLnNRr/Va58pXDWqxZshz0UKAgELu/McpVoqxaoSvWLSdoxMV/vrrZ9o2/kOuTT2MeWy0yplySMaWTNVjnrenl++eKTNZSyhkbPJZl8lKwPHpWSq+ItGdCxCRwHgt4nvnavTmM+wbyPPQ8TlqQYIQEn9JfpelQSnRkchKZefGXRM1YEnJrp48fqKZrYUEcUIQKYIOiuyBEgTJpRFjtoRsNgNoakFCJYiIlCBKIEYRRppkiyKpbQFaCEKVzqsJQWqrj6QWJoSJQEqLapS2KjaS9H6h0syHSfP4BUmz2y/WMJz18CPNY6NVPHeSH755GMd2qEaa4grip9PP1umZOkenGgx25UDa6GZ7rRYWgdJoKZltqEWf2xaeJ6hXQnwF1wwW2TNQ4vFzZQ5m3GXue2fn05nMXf1FM+O1iZjfU1cO5lxdGZjzdPnzbJ+fTQv0uPbaa/nmN7/Z8f1d1+WOO+7gwQcf5Md//McBUErx4IMP8mu/9msrPqZery8TXJaVDm1cjsP+hs5ZaZD+iXNlPv3YGI6VWm47lk0UK2ZrIefmfHb2ZomVSkN3ubT2yBvJzFnLxv+7Z+aYrITctbeHUtbltp2CYxNpzlii0ucYNnOm1lOR0sBkJWS2Ns1IV4anx+axJWwruUxVQiyhFwUBa5Uu6CO13GFRAo4tCBYIONsCpVYOE74Qri2IYk09UlSCCCktso5F0bMYK3eWm3YpSRSMzzfagqaFAhrR1n3/WAJsK3VRZEGemNYQx+n733UsXFsQRIqoeaxSnJ8FtERqOKJJz2Eri6wn7+CHCWfnGjx6ao6+vMtTY/McGChQyjqp9b3WzDcijk5WuXF7F8OlC8eIXMiUx7Uknm0RxOc/twtZ+Lkx7nsGg8FgeC6wbjG2NNhZa83o6Chve9vbOHjw4Lq29YY3vIHXvOY13HnnnTz/+c/nPe95D7Vare2u+OpXv5qRkRHe+c53AvDKV76Sd7/73Tzvec9rtyk+8MADvPKVr2yLMsOVy8L8IaU0//OrzxArTW/exbPT8+s5FiM9WZ6ZrnNmtkF/3kUKqPjRJV2gbSQzZ6GNP8B8I2rb4RczNj05lyMT1Xa+Vm/eo2ePS8WPCRNFuRHypUOTGzLasJoL86laSFBOyLs2c40IpTSuLdtukGGi29v3bIFjWWilsSxBxpY4dhpKPF0NOD3rIyUUXId6GJNswIbebYYPnysHDBY8Eq3xY009vvwurqQZbef/fimQpEIs59pU/NT5sC3GtcZPFEJA1pHESXoutdYrHt/C7DchwJYSx5JUdYwtBZ96fJSenMvpmTrHJ2tp5bYrw3jZZ7TsYzft7//8n45fMOPrQhcqihmbomcz6vvLsvFW+twY9z2DwWAwXO2sW4x1d3cv6/PXWrNz507+9//+3+va1s/8zM8wOTnJ7/7u7zI2NsZtt93Gpz/9aYaGhoDUuXFhJex3fud3EELwO7/zO5w9e5aBgQFe+cpXbvmsmuHSc3auwWQlzRYqNyJc+7xxTM61Ge7yODfnI5uBsBnH3tACbWnW0WC+s4/ERq7atyoGfmTx1Ogss/WQOFFtO/yBoocA5v2InqaNvRCCUtZhphZwcqq+YjVhLSyRLr4dSzQrJFD2U4c+R563RLcEiGaIsUYgtE5FVtPJsCLSebLZesiO7ixdWRulFI043lAeWBCneWQtYTHnx/hhQnKRlvFbyaU8smYnIq4lsS1B1rWoBzFxs1qpFYhEAQI/Uni2Rc610FpRCc6fN0iraK1tasCzLQqeRZQoEqU5NVOn4sdcM1Rkd1+Op8cqnJ5t8PR4haxjsasvx7VDRTKOtWbG17ILFUt+nvNsBooeY/Pp53etz42xnzcYDAbD1cy6xdgXvvCFRWJMSsnAwAAHDhzAttff9fhrv/Zrq7YlfulLX1r0b9u2eetb38pb3/rWde/HcGVRC2OCRHHtthKPnS0zU0ut7x1LEiWKOIGenMvP37uX23f3bGiBtlLW0YH+LCMdPn69V+3zrk0YK779zAyJ0hQyDk7GJko0kxWfmVpAxpbM1kN29eYQQqCU5onROb55YoZ6qNbVCiiAjC0QAsJEEymFEHLRz5VO86zgfBtb6+/xghZFBaAhSTRhknBovIoUkLUllpBYMm2fXM/xLQyTVgoyjsQP40sqeC5HBKnBhhTpbJdWGj9McGwLIQUy0VgWZGwLAfixIowTip5Nb96lGkRs785yZrZx/vVtbluTvu59BQ8hBBU/Ikk0SaLobkYflLIOfXmPrxyd5NRMnZ09We7Z19e+MLZWxtfSCxUjpfTCQtWPOTufvrdfdN0gh0YrHVe7FlbNDQaDwWC4mli3enrhC1+4BYdhMCym1eqUcSS37ezm6ESV2XpINYixpaQ7ny4cf+DgwIYWaUcnKnzkoZNtI41WcPSTo/OMFFPHw2u396y5nfVctR8uZQgixVwjYldPtr249WyBk3M4NdNgsOSRdSTfPTOHIwUPH53acMte1pFYUpAojdIaWwpKGYdGGJDWU1qCTBMlLKpIKb2gqrLK9pVOTR1yjqQn5xDEutlK1xkLC2COLSl6FtPVS1t9utQ4Mq1MrvQc5YJBwFhrdvfkEWgmKkEqjqMExxKUPBvPkWQcq3l+FaPlgHqUMFT0aEQJni0YKnqUGxGJ0sQqnQuUAnKuRc6zmKmF2FKSSI3Wgt6C1zbuqAYxjUgxVMpQjxTVIKGUTd+vQoh28PjZucaKn7+FFypOTs5DBsqNaJHg+qFrB021y2AwGAzPedYtxt75zncyNDTEv/t3/27R7R/+8IeZnJzkTW9606YdnOG5y8JWp4ODBb5vT097dsqRgrF5n1t2dG/IqONCRhpFNw8+fOHQBAe3dXe0OOz0qv3ovI/XFC4ztQghaTvjBVHaLjZZCcg6FqNlnzOzjXULEynAs1Jrek0qsMIkDXYuuBaJ1kiZVqIU50WXas4ZtVoaY9V5EHQQqWaVS1PyJOVg/a2UQawYLfsd2fVfyTiWRAhFmJwXw7Jp0OHaEteyAEXFT8g4gm2lHHfu6aWUsfnmiVmKGYu5RsTofMC8n4bZZxyL7d2ZRQpvrh6xpz/Pvv48QayYqAScna1zbq4BQBAlDBQzFDyLJ87N01/w2D9w/rMQJopYKbqyDuXmbONCsq7F+Hwa2rsarQsVp6YqfPerp/nVHzpgnA8NBoPBYFjCusXYn//5n/PRj3502e033ngj//pf/2sjxgybwkozWTnPQoQwWvbpK3gbNupYaKSxdP6x9e/jk7VVr/pvlFoY49qSoVKGR0/NUQvj9iyPlIJSxibj2Ozty3N0fL5jIdZa0PcXXPoKaUvYsYkqfqSwZCoApJBYUlJpRMvcGBfuxxLQcpRfj6RKZ8b0hmbHIBWFW+lI2AmOgK08BAHUI7Wo4qhJn7ulU+EcC00pYxPEmoxtUQ1iRss+tSBmtp5mwtmWZLDo4dmSINb4UYxnW/TnPV71/bsJY8UnHhsliBI8x6I7n7Ye5lyb3f0FSp5NI0qwZNpW2pv3uGaoQG9zThGac2pS0ggTbClxrcUutiu5ha6ElIKRnizfBUZ6zle+VmoR3j9QuKAxiMFgMBgMVyPrFmNjY2MMDw8vu31gYIDR0dFNOSiDAbbOSe1C1tstgji54FX/hSw1AVmt3Srv2szWQp48N0+kFMWMgyUEtSCdj6v6MVnH5shkhZlGByFbpDNhrm1hS8G/vH0HT5yd5+R0Dc+xiVWMAPKeRRgp5hsRkdLYlqTLtZitR20h1qrShOq8dXqnJLAhJ8XLDSE5r0Q3GUfSnN1buUUxSFIha0tNLYwoZVx29WZ5/FyFqUpAkCj8ZgK2aysmK7CjJ0d3zkZrm/H5AAjZ259nd1+efQP5ZZ+bW3akn5t9/efbanOOxT8+eo4nRufRWi+oEtv0ZB2OT9fY159flDt2sRESq7UIr2UMYjAYDAbD1ci6xdjOnTt56KGH2Lt376LbH3roIbZv375pB2YwwNY4qa2VEQZ0dNUf1neFf6iQOkD6cUJvzkHK1I6cZmthmGhm6gGT842On0uiNBlHIkirYXnP5u59fUgpeHq8wqFzZWZq0aL2P0tAI0qwZWoQsrAC5tmCJNEIsf7csCsdtZHMgA4pNuMP5hrRqq+rhlQsC/j+vT2cnGkwUQkAvciuPog1URwhRIP9A/n2owW6XXVb63OzsOL78pu3MTrvL3MFtW1JKeNgS0k1iDcl42utrL0LGYMYDAaDwXA1sm4x9ou/+Iv8x//4H4miiBe96EUAPPjgg/yn//SfeOMb37jpB2gwbLaT2loZYQD7BvJrXvXv9Ap/q3L29ePT1MKYrGPhxxrX1iitUCqtSDiWwA/VuipTUqbzVgXXRqC5Zihd4M7UAmaqAUqftzVvEcYKSdqGqAVYpEHOUkhKGYupasgGHPS3vM1vq9mqaLO8I5kPEkB3JHB7czYZx+KZ6Xrbej5e8kAFzNZCprIWUkgKGZu+vEc9Ol/a6/Rzs1oF+u59fVy7rbgu18O1WKtFeDVjkE6rzwaDwWAwXGmsW4z91m/9FtPT07zuda8jDNMZhkwmw5ve9Cbe8pa3bPoBGgybzYUywibKdfYV4UXXDV5wsdfpFX6lNZ97YoJjk1VOTteo+jHFrI3QmkaYECeKRGtcS+BIgR9D1rFIwqSjmbEgBktqgjhhuhYxW4/oyTl888QM5+b8NCR4yWMSfb4bzxLgOhIbqMUJSUPhWGBZEqVSo4lOuQxzmp91BKnj5HqohIpvn5pj3o/QTaOVld6JChifD7llR1czSFx0VM1diQtV0lquh5UgourHFDwbz7ZQSq9bEK3VIrySMYiZLzMYDAbD1cy6f3MLIfjDP/xDHnjgAZ566imy2SwHDx7E87ytOD6DYUtYrRpw4/YSVM6xb6Bwwcd3coX/kVOzPD1eIYwVw10Z9pDj8HiFqh8TJ6pdsUo0+JFCWel2LCkWGWxciMGiy7VDJU7P1JisBnz1+DR7+3I8M11HLSmJLd2mRRoEHUSKeutYVKvVTeHaAldqwg61xNWgxaxNbs/cyKYazfk+9MomKvYCN0wBHBzIM1mLNjzD1WK1SpqUgiBO+OJTkxctiNZqEV5qDGLmywwGg8FwtbOxy6hAoVBoG3kYIWa4ElmpGjCYt/n0pw+hlOb0TH3Vtqi1rvBnHItTM3UGix637+pBiLRqkXHSNkABWDIN91U6nQPym6WloIPgYwEMd3ncd80Afqx4amyeOFFESchYuUEjVljiwmIgAZIVylntoGel29b3V4PQ6oTNEmIWF+cFYlupkUqil1fFEpWagVhAojVPjlW4dltpw+6ia7GZgmitFuGFxiBmvsxgMBgMzwXWLcaUUvzBH/wBf/Inf0K1WgWgWCzyxje+kd/+7d9uB9kaDFcCS6sBURQB8F8/d5gjUw0SrejJuhwYLC6qAqx1hX+yEtAIk5UrZ5y3NE9tF/Sin60V0yWAvGuRcWz8SHFkoopSGq1T58SKn7Z4JRoWfho16xNWq3XXtebNDKtzMZou70A9VHi2JApV+7zBgvOp03lBrWFPf2HLKkSbLYgu1CK81Bjk9Ex9Q/NlBoPBYDBcSaxbjP32b/82f/mXf8m73vUu7r33XgC+8pWv8La3vQ3f93n729++6QdpuPyJY8Ujp2eZroX05V1u39mDbV95wvzLT08A8OknxkBaeLak0oiZqoaLqgBrX+FvkHMtBouZ9u2j8w3CWFHMpIvPSKUtaQtZaxFvN6tdiUrnzJ4anafciOgvuMzWo9ScY+GxLHisFMvNPNaD1cHxGToPy14JCeQ9lyBWZDybWhgsih+ANCA661q4lqQ75/BrL9zPnjXaai/EhcwxNmq4cSE6jazYyHyZwWAwGAxXGusWY3/1V3/Fhz70IX7sx36sfdstt9zCyMgIr3vd64wYew7y4FPj/I+HTnJyukaUKBxLsqcvz2vv3cP91w8924fXMYfHKnzgy8f4uR0wUHDBsokSTbkREcTp8nphFeBCV/j7Ch4Zx6IRJRSbgbmNMCFRmlLWRiCYb1awloYAr4ZrpWIqVhAlijOzDfw4QQBzjYicYyGaUqDVJrdwe+oilZQinVeKTVlsRWwp6C84jM2HG3p8wZU4dvqekVJwy0gXR5wqZ2cbKJ3GDQiglHXI2mlw2Q8cHGBXX37F7XXiQLiWOcaFBJHWqcvjZDXg2GR1XQ6HnURWrHe+7GrDOEgaDAbDc4N1/xabmZnhuuuuW3b7ddddx8zMzKYclOHK4cGnxnnnpw5R8SP68m5bkByeqPDOTx0CuCIEmVKav/32aaaq6ULadSxiLfBsgZt3mamF1KOYI+OVdhXgQlf4X3z9EJ97cnxR5SzrWlhSEEaKWpiKKClSkSPFhUWOIJ0VWmj6oXRqg29bkijRzDZNH4TYmuxiSdpmpi9W1V1lSCDnWdy2o5vTs/V1z9h5lqC/4LK9O8u5OZ+5WOEIQTWIecGBPr5+YoaJ+YAwSU1VSp6FbVlcs63Iq+7ateICvRMHwk5mwVYTRDO1gGMTNcYrPo0o4f/9+imeODu/LkOPtaz31zNftpQrXcgYB0mDwWB47rBuMXbrrbfy3ve+lz/7sz9bdPt73/tebr311k07MMPlTxwr/sdDJ6n4Ebt6su15wWJGknctTs02+KuHT3LfwYHLvmWx1Y7l2ssXbEIIChmbih8z1wgXtUVd6Aq/lCyqnA0WMhQ8i8lqiFIaa0GV6UK28AtfOUsCOjX+cCyLpJlTliQLwpu3SCspIE70c8rQYy1cS9Cbd+jNeUgBU9UQS3Ru8+9KKGQcevIekdJYlsBzJBlbMlEJODBY4OaRLh5jnkaUMFTy6C943DLSverCvBORta+/0NEs2C/9wL5lgmimFvDo6TnqQUysYFdPju3dmU13OFzPfNnS538lCxnjIGkwGAzPLdYtxv7Lf/kv/MiP/Aif//znufvuuwH46le/yunTp/nkJz+56QdouHx55PQsJ6dr9OXdZcYtUkr68i4npmo8cnqW5+/t2/B+LsVV7loYk2hwLWvFnzuWJIwjpJDL2qIWXuFfeqyvuWc3n3l8nG+enKEaxPTkXcqNiFqi0erCoqZllKEW/FuKdH8DRQ+lNEGs2i6MW41mc23fr2RabpiWFPTkPSwpODReQWuN50iI1JoCO+da9ORcbFvgxwm2kuzoydFfcJmYDzg9W+fkdI2BQoYfv22EW3Z2MVD0LvgZ6NRw40dukR3Ngo3O+4sE0baSx5HxKvONCNuSlLI2B4eKlLIuxYyz6Q6Hnc6XtbjShYxxkDQYDIbnHusWY/fddx+HDx/mfe97H4cOpW1oP/ETP8HrXvc6tm/fvukHaLh8ma6FRIki664sYLKuxUwtZLq2sRkauHRXufOuTU/WwffT56KXOF2EsSKMFQcGC6tmOa10rBrNM1M1Rst+2mZmSfoKLvUZf83qkmWBIyRZRxIlikaUhjBLoak0QjzXQYrnlvX85YRGYElBtREy14hBCDKOJFGa4AKPG+n2+Mk7dvL0aIXhLg8hZPu9Ucyk1ae+vEtXzuFnn7+L/QOFji9AdGq4cWKq1rE5xnXbSm1B9L2zc5yerZNxLIZKGfYPFOjNu8u2v5kOh53Ml8HVIWS2wjDFYDAYDJc3G5p83r59+zKjjjNnzvBLv/RLfPCDH9yUAzNc/vTlXRxL0ggTipnlbYiNMMGx0grZRrhUV7njWHFuro5SEDVLP7O1CM9rVcQSxuYDtpUy/OQdI+2FXBgmfPbQGGPlAAEcGZ+n7CftY316bJ6Hj0+jlGZ7V4bt+SyNMGFiPkA0nQ1by62VHPiSBFxPkCSK2oLk5URDLVTUogDoPCDasLnYIjXtUDp1t7SEJlKCWpS0z+3C8yKA79vdzd/8wvdj25L3f+kYj58rLxIOkF4IGJsPuHVHNz94cGBdwqFTB0JgXeYYLUH0T0cm+dBXjrOvr0B3zlkmGLbK4XCt+TK4OoSMcZA0GAyG5x6bZkM1PT3NX/7lXxox9hzi9p097OnLc3iiQt61FrUqKqWYroVcO1Tk9p096972pbrKvdAJshEmqCSGnQCaepgQxiFhrBkuZXj9/Qe5ZqgEwP/86kk+9M8nmKz4JFqTKI1jSe7a20sx46CU5umxClppPNsiiDWWEBQzDgLNTD2tFgpoC7OluLZAKUUtSn8oAdeGMD4/ayaFXpeNuhFum4MUkHEkQZzmgCk0Yazb50VAO3Q7zZODrCO5caQL25YbnodailKaM7N1jk/VgPSYPEuuKbL29efXbY4hpWD/QIHBQgbbEssEz8LtPxsOh1eDkHmuO0gaDAbDcxHzjW7YMLYtee29e3jnpw5xaraxyE1xuhZSyji85p49GzLvuBRXuZc6QQ6WPOqNAAiZqIRs78mzsyfL/sECP3X7Tq7Zllbh/udXT/JHn3maIE7IuTaWgPmm/f1Xj8+kbWYFN7Wb92wsKWhECWGs8BwLhWi3F7q2IIz1MoEkSIXnvJ+GUNsSso5FxpHM+zFBcyBpvTNcRohtHrFKRbgU4EhBvORk6AX/tSzpz841ODNbZ1dfft3zUEs5OlHho18/xdeOT1OuR2gB3RmHrGsxVQ153q7uVUXWjp7chsTgxTgcbjVXg5C5nF9fg8FgMGwNl+9vJcMVQcu2vlVdmqmFOJbk2qEir7ln4zljW32VezUnyN6CB1TwHIljC37nR29gd29+UWviX/zTcfwoppRJhZbSGiklGZEaajxyapa79/Y0q2VpG2GkNUmz/GVJgSUgVGllY2m+mNMUXnv6cnzvbBkpwLUtHEvit6pkYuO5YS1jEMPGabWKSlKHyTDWJCoNxpZWKsxaFTFI/5yqBnz75Cwf/spJ/u3duzgwWOx4HmopRycqvOfzR/ju6TksAX1FF4Fgrh4x04hwm9l2B4cKq4qstcTgvv4Cp2fqy45rMyp6W8HVIGQu59fXYDAYDFuDEWOGi+b+64e47+AAj5yeZboW0pd3uX1nz0XZ2W/1Ve4LOUECDBQ8Jishk5WAvf2F9u1//fWTjJYbIATVQCGEQgqBRiOExLYUtSBmthFjSUGUaCyZtnRZzcWhLQQ0HxOsEAgWKbASRb05e+TZAsdKHfeUAltKHAvqQbLuFsWMI8k4FpVG1LH9umF1BBAnCiEFNOMFJGlA81KxHCso+xHfemaaSKn2zGMn81ALUUrz6cfHODxWwbUEfQWvLTyGSpLpWkisNFprZmsh4/Nq1YrbamLw+FSV93/p2KrGORdT0dsqrhYhc7m+vgaDwWDYGjpeyf7ET/zEBX8+Nzd3scdiuIKxbXlR9vVLuZir3HGs1hSGaztBSqJqtMgJ8uhEhU8+NkasIWOdnwlKlE7NP7TClmnGlCMF3VmHqWqAa1sUPBu3eQy2hHANJeTHmv19eWaq6XFWgwTQ2M2Kh9aptbpqzY5x4WqX3QyXtoTAsyW+LYkjUx+7WCw7Pd8WkHHSltPoAonbsYJTMw26Ms66Zx5bsQnHJqt848QMsVKUsotNNIQQFJuZeDnX4mfv2kUp61yw4rZUDHZqnLORit5Wc7UImcv19TUYDAbD5tOxGOvq6lrz569+9asv+oAMBtj4Ve6FhhxRonAsyZ6+PK+9d3HL5NpOkGqRE2TLUERpjQS0FgiZtiAKqdEalNaEMSAg59pcu63I9PEQP04oZWyqQUwYK6aqQUezW187Mc2BgQJPjldRSoEQRIkiUWlL3MJtKJpmIKT/W1qVaf07UoogViuaLxjWTxyDJdMWVNnhazrvxzw1Nk/GtTg7t72jqtjC2ITJqs+hsQpxosm5Nt6Sb3GnKdgbcUIp63DdttKa228JvYof8fffOcd0NeCaoeKaxjmXoyvh1SJkLtfX12AwGAybS8di7CMf+chWHofBsIz1XuVeasjREm+HJyq881NpJl5LkF3ICRJgph6yd6DUdoJsVSRuG+nmxGSNahBjS4kQaQuibUGUpFWyrGMhhSbnuXz/3j4eOzPHRMVnbD51VHTtlatxS5muRfzE7T2cKfvU/Bil9AUNO1pibOF9BDRnziRxokgSTT2IESafbFNQgFZgW4KcZ1MLIpJVKmMWqXNmolNB9uS5eZ4am19zwb20UlXwbE5N15kKQkbLPiPd2UUV3ihJK545x+6ojXeh0JuphxybqDJY9BgoZtoZYnDl2MODETIGg8FguHLY+FCPwXAJODBY5FdeuJ/ffMk1vP7+g/zmS67hl+/bv0yILTXkKGYcbCkpZhx29WSp+BF/9fBJ4qb3eMsJsphxODWbVgRipaj6qSFI0VvsBNkyFClkHW7f3dN0SFREiUZpTZxookSTcy3+w337+I8vvY679vUyWfGxpaA759Jf8NjZl6fTopTW0F/0+Kk7diClWFGIWQs+wQpYqgOkSM1O+vJpO1usIUg0cayxrqxCwWWLJjXxEEB2FaFtCbAsgRDpOdHN8/CtkzOoCzixLI14KGYcunMO27uzuJbAjxJmakE7pFxrTcVP5xVv2bG2WUVL6D1+rkx3zmFbKYMlYa4e8ejpOWaWBLZnXYsgTqiF6cWB0zN1Do3Nc3qmfsHnYTAYDAaDYWWMgYfhsqeTq9wXMuSQMm03PDFV45HTs+3ZtpWcIPNOqlDe8JKDi9oaFxqK3LKjO93nM7PUwrg9I5RzLX7pvn38+v3XcHgstR0fm/fpy3vEiaIWRExXAuYbnTlAWgKGSh7PTCdsK7qcmfVBnK9+WTJd1K80L9ZqV9RAkiRMVTXhAjUXgymLbSIaqPoRrmORcyT1SLUrj7ZI38Napw6LUkCioC/nMDkfXLDKtDDiAdIIhTBRbOvKMFUNGC37zNRDChkb17Yo1yOU1ty6s5uX3bTtgq15K2X5aQ0Zx8azBbUg5thklZ5cT7tdsWWcM1UJePDJiVUNPgwGg8FgMHSGEWOGq4K1DTksZmrhIkMOWO4E2ZORjD/xNe67dnDR/ZYaityyo5sbh0scm6pS8WOqQcyLrh3k137oIEpp/vbbpzk310BrzbHJ6iIh1CndeQfPkTx2psz2nixny0FzIa9TIcbqOWO6+T8NpNrPmHVsJZZIRf9gMcOe/iwPHZlun3PVTH7WpG2KSoFjS67bXiJM1AXjGVoVWT+SHBqtMFMPiZXClpK8Z7O9O8PonN+OlOjKuty9r5efvWvXmqJopSy/YsamN+cyUfHJezYztZCKH1PKOm3jnOGuDJ98bJTZenRBgw+DwWAwGAxrY8SY4bKiZSSw3sH7tQ05kkWGHAtZ6AQZRRGffGL59lczFBnuygI+u/vyvOKWYaQUnJ6p870zc9TCNOg53mD7VtVP+NPPHWamHlHK2AihzwswU9W6ZKw0W7f0NtWsVO7py3HjcIlnpus8M10naTqrtAxWtE7ny/b25+nPu5Qb8QXnuvKuTdjMrosTTSFj41h26rDpx0gpuGVHNz/+vBEGih57+/Ps7Ml19JlZKctPCMH+wTyVIKLqRyQaGlE6Yzha9unNuaBhth61q2mwusGHwWAwGAyGC2PEmOGyYaGRwHpbny5kyKGUYroWcu1QsW3IsRE6NRSpBBHj8wFRcl6ItZal69FQYaI4OZ1W16YqAcaJ/tnBlqklvW7+3ZJpO59oVimVTsVYrBQnp2vM1kNc22JnT47pakCYKOym86ZlWQwUPe7c3cPYfLBmCPFwKUMQKWbri8PJPdvCyQlOzTbYVsrwL28bWXeu32pZfr15j9t2dvPkuXkmKgHj8z49OY+bR7q4eUcX/79Hzi6qprW4kgw+DAaDwWC4XDBi7DlEJ/lbzxaHx+d53xePMV0NGO7KsLcvTyNKOmp9UkozOu/z4hsGOTVb55mZOv0Fr+2mOF0LKWUWG3J0ykLL74ofUQsTrt9WZGdfBktKBgpe+3VUSnNmts4/H5lkrh6iFvQQrreQJQBbChKl8WOjwp5NFsYIxArQzXBn0fw36fnKNcO0z8352JZg/0CBnrzL2dkGsVLkPZvhriwj3Rmma2FHIcSj8z6eI+nOOszWo2ZlTLYrY905F9eWjM776xY/F8ry68m5DBQz3LGnhx9/3ghFz2GkO8vhicqyatpCsq7F+Lx/wdZLg8FgMBgM5zFi7DlCp/lbzwaHxyr8/sef4thklZxrMVUN6cn5HBgscHCwcMHWp6XVtO1dGc41Z2iopZlL1w4Vec0963+erW1/5/QsRyeqzNRCEqXQOt1ud97l4GCB5+3s4brhIg8dneJrx6eZrASU/XjDU1otO3oNBEaIPevYViqKW9o61ufbFFt/aqAeKRwLunM2jmVhW4L+vEd3zqHkOTSipOl+KToOIa6FMa4tuWN3Lyem0qpbK1ZhsJRhd1+O+Ua0IfGzVpZfX8HlX925c9ExrlZNa9Ey+OjEUt9gMBgMBoMRY88J1pO/dak5OlHhfV88yrHJKt05h7xnEyWayYpPNYi5bWf3qq1PS/OXcm6WeimmK+OQaM3dB/q4aXvXhiqAxyer/PXXz3Bqps7pmTrT1YBEp/b1qRxUzNRCnjhX5vhklVqQoLUi69hkXYlVXx68vB6UhmQDph+GzSV91+h2hlvrjLRm9yxBW2B5lmRPf56MY6XGHEHCzdszjFcCDg4V+dFbh2lEybpmIVviJ+NIvm9PDxU/JkwUriUpNoPEg0htWPysN8vvQtW0lsHHWq2XBoPBYDAYzmPE2FXO0vyt1sxJMSPJuxanZhv81cMnue/gwCVvWWxZa0/XArJu6g4nhcCzBU7OYaIS8r0zc9wy0oUfJYuu/q9ky50+L4drtqVGAn6ouHN374aMBB58aoLpakgUJ8w3IiyZujAkaIQQKK1p+DEV//wxSQGujEi0uKj5LiPBLh8Wiq9WJcyWTVkmwJWCTNNkAyEIYoUUAtsSxEoRKc1wV4Zjk1WkEFy3rbSu/S8UP2nOmN0WZPONiLH5oKM8sQtxYLDIvhcWOjLOWaua1knrpcFgMBgMhvMYMXaVs5H8rUtFy1p7e1eWqWpqTe/ZFo0wZqYWUQ1ipmsBs/WQgmczVQlg2+LHXqyRwFL3xsF8+pE4MVWjlLE5MlFJjRssSRDHzT8TVuoeVBr8BESzkmJE1ZVNK78tXJCkrYFoQclTADkhCBOF0qnjoGNJHFuQdSxcS17UHNVC8fOd03PUg5hKEBPECVGsGSh6/PSdOy5a/HSS5ddivdU0g8FgMBgMq2PE2FXORvO3LgUta+29fXl6cy6j5Tq1IKHsRwig4EqEFESxJnY0n3xslG1dGQ4MFle05V5IJwvgldwbD/RnGQH8OCGfSS3E0za11EEv0WpFIbYQI8KuDtp29Cv8zBLpf7HSTNdChAbLEmQciUBQacRoDVGiaIRc1BzVgcEiL7pukD978AiTlQDXlmRsi/6CTc6x+cKhCXb35S6pCFpPNc1gMBgMBsPqGDF2lXMx+VtbTWsephElTFYDTkw3Fv3cjxNsCYOlLN+3p4fpWtg28tiokUCrEvbU6DyfeGyUIErY3p1tB9c+OTrPSBHmGxFBki4stW61qWmC2Eit5xKrne3WOF+rSCYAq/lGCZUi51p4tuTYZJVSxmF3f45KEHF6pr5u0aKU5tBoheGuDM/b2U2kdHtmDHjWsr3WU00zGAwGg8GwMkaMXeVcivytjdKah/nf3zzF6dnGiveJFSRJQl/Bw7Vlu/VwI0YCrUrY0YkKT5ybZ64RMtyVJetYFDybYsYhjlNhd2yySpiks2F+rLBiRWiEmGEBC/1VzjsqJhQzNn15D6U1Ryer9Oc9Eq157xeOris7r0W7nbc7u+KFB5PtZTAYDAbDlcvlETJl2DJsW/Lae/dQzDicmk3zsmKlqPgRp2YbG87f2gykFPzg/j7OrCLEWpyYrhNFEVnXIohTI4/WLE1v3uXIRHXR8zoyUV1mJNByXnz8XJlGlDBdCwgixdGJKl98epIvH57kxFSVx8/OA2lbWVfOwXUsJIJGrC5Z++Fm1DZMs9ilR0rJYNGjK+MQxAn1MCaMFFnHYldvjn39BbpzDo+fK/ORh05ydKLS0XbPt+SufO1s4efCYDAYDAbDlYWpjD0HaNnWt3LGZmrhReVvbSb/99HTa4qcRMO3T5W5YXuJWGnGyj45x8KxJPddM8C3Ts4yWfEZn1crGgksdF7syzt87cQMfqQoeDZSpPlQp2fqjM41KHmpKHVtyf6hIjPViGeocm4uudAhbpiWSQQszqy6WEwN79LSbGglSjQ/cKCXSGm+d6ZMGCtu2dHVrmgVMw4Fz15Xa6HJ9jIYDAaD4erF/PZ+jnD/9UPcd3CAR07PMl0L6cu7G8rf2kyU0jx8ZKaj+05UfGaPRtiW5EP/fIzxckiiNX0Fh5GuLIOlDHfu7eX6baVlMzmtNq9tpQxPj1WIYkXGkSBS50Up0vm0RGkydrrYtaVkoJChO+syWw+ZkMFF2dW3aB2VLSHvSGzHZrYWojWIphrbGtlnWA+WWNyGuOb9JeRdi3IjohYmFDw7zb/rzlLKLhZQ63H7BJPtZTAYDAbD1YwRY88hbFtecvv6C3F6ts6cH3V036lKSHfeZUfB5fBYlWoYgxZM1wJqQcJ0LV0E7+vPL6s0tNq8Cspmph7Sk3NJFMw1QsJYESW6XUmargYA9OQdoiThu2fK1MMYx5JE6uLVmCbNI/NsiZ+AiqPzi36dijRLr08IGDafnCOpRgrd4XlwLIkl05yx6VrI2LyPbQmuHSoti16Aztw+W5hsL4PBYDAYrl6MGDM8a5yYquF0uIDsL9jcONLFN0/OUgsTip7TbjEcK/vtitNKrV+tNq/WXJlj29iWoB4maUWKtCqlNLQ8Oo6MVTg2Wce1BEOlLNUgoR5dvP2/LSHr2jSCuC3MFrYqrmWbb7g0OLakIOWiUO/VyLmSnqxLNYhRWpMkmhu2l8g4VlqBXYGVWguXZt4trPCabC+DwWAwGK5OjBgztLnQYnCrkELQm7OZqa++6O3L2dx37Ta+d7ZMLYwpeBa2lR5XxpHEiaIaxGRciyPjlWWtX602r2+cnMYSgihWzNTC8yKM5YYXM42IIEmPqRKkC+f1tq6thAU0gpi4KQKVNvNdlyODpQy37+zh84cmmKoErKSRW++fgmcz3OVxckaxfzDP7/34jezszvHn/3S849bClTLvlroubkW217PxmTcYDAaDwXAeI8YMQGeLwc1mX3+erpyDEwgsKZmqhsuESdGzuGlHN0rDbC3Ekul9W1gCIg0Zx6Lix8w1wmWtX602r7NzDUbnfE7P1tsVDyHOi6LVmKpF9OTgwGCBIxPVC953LYIFq3ojwi5PsrbgxuESs42Im0a6OHRujiDRxEoTRDGtYpkUkPcs/EhxcqZBT87lV3/oIHv7CwAdtxa2nD5naiHDXZl25t3j58qcKzf4+Xv3tD+Dm5nt9Wx85g0Gg8FgMCzGWNsbFtm+d+ecDVtwr5cdPTm+f18fiYZSxubm7SW2d3n05By6szY7urO8/OZhenMuFT9CAbYUJAsGeRKdGiJ4tiSMFVLIFV3lDgwW+Xcv2MONIyWqzRZBSD8AncwFzdUjthVtPGtrqgYCY0d/uSClZK4RcfNIF//6+Ts5MFTi4GCR3rxLxrHxbIHVNFuphwlBnLC7N8ebf/i6Rc6krdbCm7Z3MVePODlVY66ebrclsBY6fR4cLFDMOFhSUMw4HBwsMNMMOlcXcwVgBZ6tz7zBYDAYDIbFmMrYc5yli8FWO9VGLLjXi5SCV921i4lKwOGxCrUoIetaZF0bSwiu2VbkF1+wj889Oc43Tk6TsQShJdMQZscCNGGs2uIrjBUHBgurusrt6y/QnXEoeQ6TcVqF6zTHWQNfP1nGtiTE6/M7bFnWQ1pNUc0WRUumQjAxrYqXBQJwLcHBwRwFz+HF1w+RdS36Cx5aK2brIcWMw3B3lpxjUfYjyvUISwpe/6KDvPC6wWXbXKu1sOX0OdyVaX/2tNZU/JgwSeMXVmq9vRiezc+8wWAwGAyGxRgx9hxn4WJQa825uQb1KCHnWAx3ZdZlwb0RDgwW+Y8vPsinHx/jsbNl6mFCzrW4ZaS73S4lJe0WQyHS1sRaEINI88DynmS8ErCtlOEn7xhZdQH50LEpvnR4kpxnkw0jGtH6JFCsNHrF6aGVydkw3J3l9GyDKEnFF5yvxC20szc8+7i25J79fdw80sWRiSqff2qcX/qBfewbyPOPj54jUWqRaOrNuWgNlhQ8ca7MD14zsOJ770KthecDndMLCDO1gGMTNWbqIbFSyOa+nhqd37TP30oCsMV6bfcNBoPBYDBcHEaMPcdpLQbH5xMeO1NmrhGRKI0lBd1Zh5t3dLXvtxYbNQM4MFjkdStUDwBOz9SJleYVN2/DswVfenqSMNZYMl04OlJQ8ROGSxlef/9BrhkqrXpsDz41TiNK2NGdpRpE+FG0Lh2kVCrIOkakx+ZYklgpRLNG1ppT07qzFknD1tGqUDqW5J59fdy0oxugLUhG531u3dnN3337DEpDmKg05iBRVP2YnGtzcDDPscnahsTLwkDnKFE8enqORphQyNg4lk0tiJmrR3zisVH2DeQ3ZZZrqQBcynps9w0Gg8FgMFwcRow9x8m7aejwU6PzRIkm61o4UhApzXQt5CtHp7hhuLTiHNZCLtYMYGn1YKXt7RvI88sv3M9T5yqcm6sTJgpLCvYPFvip23dyzbbV93N2rsFo2Sfv2dSjtM3QswVBrDsWZOtxnXct0AjKjQhbAhpirVOzkHVsx7A1tJwxHUvQlbHYP1jkxpGu9s8XCpKBosfO3hxhrJhrRFSDGFtKBksZ9g8UKGVtTk7VNiReWk6fj50tU66HNMKE3ryLEAKt0zbc3X05gijZtNbBhQKwmHGW/Xwl232DwWAwGAxbg/lt+xxnqOBxbs6nESX05hxk06nQkwJHwkw9YrTsM1TwVt3GetzgOmG17T1xbp7evMtr7t5D1rXWVYGrhTFSCAYKHmfnGkSJRghB1hXEiSZcw7M+50jCRJE0ldRaAi5KQCtFpCFR5wWYKYRdHrQKnFGi0UJyYLC4qGVvqSDpL3h0ZW1AECYK15IUM6llfcWPNixeWk6fh8crPDNTpzvnoIEwTqj6MVnX5sBgEccSm9Y62BKAndruGwwGg8Fg2DqMm+JznEfPzhHECVnHwo9T+26t03Y8P9ZkHRs/Snj07NyKj99sN7hOtvf5p8YZ6c5y3bYSO3tzHVUK8q5N1rEY7vJwLEEYJ8SJQnTQKtidS48h79pI0Zmg0qSW+9C5SYjh0tJ610jSNsUWLUHSMoNpiZex+YBixqa/4FHKOu3q1cL7boQDg0V+5NZhChmbRGlm6yF+pBgsZbhtZze9eZesaxHEyaa0DrYEYG/e5chEtR2GXvEjjkxUF9nuGwwGg8Fg2FpMZew5znQtBGB7d5b5RkwjSgh1ahyQ92xKGZuZWti+31I22wxgq8wFRrqzdGcdvnJsqi2+IgWJViidtq15jqTbFUCCJcAWsLM3Q7mRUAkTLHnxoc+GZx9XAFLg2YJGpKmGMTO1gJy3cg4YdJ4ZtlGu31bixuEStiVwbWtR5Q02v3WwZbvfagUen/fxbIubR7p46Y0mZ8xgMBgMhkuFEWPPcfrybrsqsL07QxgrEq2xhMC1JdUgxrEkfXl3xcdvxAwgjhWPnJ5luhbSl3e5fWcPti03vL1OODpZ4eRMLZ3hErCzJ8vpmQZBks5xSQGWEO12xe6sw6yvODnttythyfoc7Q2XIY4E2xJoBEJIihlBohSztYhY1VYVJFstXka6sxwYLPL4uTIHu7KXpHVwLdt9g8FgMBgMW48RY89xbt/Zw56+PIcnKuRdC8+x2j9TSjFdC7l2qMjtO3tWfPx6zADiWPEXXznOP37nHFO1AIHGc2z29OV57b17uP/6oS0xFzg8VuH3P/4UxyareJakHiUEjZisZxPUU0fFSEEUJCROKr2CSBHGysx4XcFIQEqImwN7UqRCLGlGCriWIOtYZD2P175gD9u7sxcUJFspXlqtg1tZfVttv8a+3mAwGAyGZ49nfWbsfe97H3v27CGTyXDXXXfxjW9844L3n5ub41d/9VcZHh7G8zyuueYaPvnJT16io736sG3Ja+/dQzHjcGq2sWh+5NRsg1LG4TX37GlXrpbSmqcZLfvoJcNXC+dpDo3N82Pv+wp//NmnOTReYbYe0ogUaM3hiQrv/NQhHmzOgnWyvU4rBEcnKrzvi0c5NlmlO+cw1JVhR3cWt2lP7tqiPTtki/NzRI04MS2JVzB2s+3UkufPLzo1VgFBwbPIuTY5z2ZXb46Dg8WOZhBb4mU984qd0qq+3bS9i7l6xMmpGnP1iJtHutZtgmMwGAwGg+HK4FmtjH3sYx/jDW94Ax/4wAe46667eM973sPLXvYynn76aQYHB5fdPwxDXvKSlzA4OMjf/u3fMjIywjPPPEN3d/elP/hnAaU0Z2brHJ+qAbC3P8/OnotfEN5//RAA/+Ohk5ycrjFTC3EsybVDRV5zz572z1eikyv6xYzNH37qEM/M1EFDzhEoBH6smKyF7OjOUPEj/urhk9x3cGDTKgQtM5DpWkDWleQ9GwEEsaIWRDTCBEsKenMW80HqkJezNWCE2NXA9q4Mec/mmek6jSgm49hIIci5klLGoSfvYluS23f1XDbOgaZ10GAwGAyG5xbPqhh797vfzS/+4i/y8z//8wB84AMf4BOf+AQf/vCHefOb37zs/h/+8IeZmZnh4YcfxnHSFrY9e/ZccB9BEBAEQfvf8/PzAERRRBRFm/RMLkxrPxezv+OTVf7vt87wzZMzzDcitICujMv37e7hp79vB/sGChd1jD94oJd79nTz3bNzzNQjenMOt450Y9tyzePe3ZPh1Xft4MGnJjgxVWNqPm0lvGV7gR88OMAff/Zpqo0ATypsW2I3F5atEN1yNWBbl8fZmSrfOjnJHbt7V93ei64bZHdPpqPX8vRMnSdOT+MIhUoSpudrzNUiGklq2pEW+zRhpOhyLVxH0vDT94onjRq7nGmdn9XOkwDCKOIHD/RScAXzjZiBostgMYNtSRKlqfoxPQWX+6/tI0niy2omcFvRAdLvuMvt2NbLZnz/GbYec56uHMy5ujIw5+nK4dk+R0Iv7QW7RIRhSC6X42//9m/58R//8fbtr3nNa5ibm+Mf/uEflj3mFa94Bb29veRyOf7hH/6BgYEBXvWqV/GmN70Jy7KW3R/gbW97G7/3e7+37PaPfvSj5HJmVsJgMBgMBoPBYHiuUq/XedWrXkW5XKZUKl3y/T9rlbGpqSmSJGFoaHEL3NDQEIcOHVrxMcePH+cLX/gC/+bf/Bs++clPcvToUV73utcRRRFvfetbV3zMW97yFt7whje0/z0/P8/OnTt56Utfesle8CiK+NznPsdLXvKSdkWvU5TSfOgrx/nk98ZQWtGTd9tOa1prZmsRUgp+5OZt/MIL9l127Uyfe2qcd33yKUqZtF3MkqJdGQNQOg1cHix6CCF4+7+8iTt2917UPo9PVvnvXzrGd0/NUfZDMrZF2Y8u2HooSe3tpdD8/p2KB74lCdTl9VoazuPJlc+TIM14k6SVz5t3dPPAj97AgcEiSmm+fmKaLz09xXi5ASgakaY76/ID1/Tz8hu3rTobuRCl0tnFVhvhcFfmsvvcLeX4ZLVdafbjhIxtsbc/z/3XD150VX0tLub7z3DpMOfpysGcqysDc56uHKanp5/V/V9RbopKKQYHB/ngBz+IZVnccccdnD17lj/6oz9aVYx5nofnectudxznkn84NrLP0zN1vneuiq+gmHFJsBalDnseVPyY756tMlGLLztntP5iFi0sFBbCsqmFCZ5z3lQhVpAomPUVN490ceeegY4WxKuhlOZzh6Z4aqyGtC3yGY9yI6IRi46cEb1mgTVQgiDZ2AJbNhWB2tCjDeth6XmyAGkJHFuyqzfHYClHIZvBcRyOTlT4zFNTzNRCIg1Pj9aYbUREieIzhyb5m2+c4XU/dGDFGUmlNGfnGjw1Os+3Ts4yWfEJEkXGttg/UOBlN12+2VxHJyr89dfPMFMLGe7KMOTa1MOYx0arnJ0PL5k5yLPxnWtYP+Y8XTmYc3VlYM7T5c+zfX6eNTHW39+PZVmMj48vun18fJxt27at+Jjh4WEcx1nUknj99dczNjZGGIa47spZWFcytTCmHsaAbueBLaR1Wz2K1529dSlYaJ0/VHQ5PesTRArbEgg0YayRUtCbu7BrY6ecnWvw2NkyidaUsg71MGGyGlwyi3pJOgv3rNuUXuWsJpOFFHiWZLgryy07u5lvRNTCuG3mMlMLsaXg68fLBHFC1rUoeBa1IOHp8Qrv/GRalV8oyI5OVPjM4+N85/Qsh8cqxEoz3JXh2m0lMo7k8XNlzpUbl6Xj4cLnfXCw0K6qFzMOBc/myESVzz4xzr7+wmVf3TMYDAaD4WrkWVszuq7LHXfcwYMPPti+TSnFgw8+yN13373iY+69916OHj2KUudrDocPH2Z4ePiqFGKQ5njlXBsQRMnyWkvrtpxjryt761Kx0Dp/PkgYLLpk7PS5NGKNEIJrhgr85x+54YKujZ2yULzGiWauHmJdwkVm6wyZZe3WstopzbuSA0MFvn9fH1nHamfSnZ1rcGyyylDR5dHTcwRxQilj49kSS0pyno1rCeYaIX/18EniZjjZ0YkKH3noJI+dLTNbC3EswWAxrbY+drZMlGgODhaYqYV89olxlFq/7FdKc3qmzqGxeU7P1De0jdVoPe/hrsyiIGkAIQTDXRmOTlQ5O9fYtH0aDAaDwWDonGd19f6GN7yB17zmNdx55508//nP5z3veQ+1Wq3trvjqV7+akZER3vnOdwLwK7/yK7z3ve/lN37jN3j961/PkSNHeMc73sGv//qvP5tPY0sZ6c5y80gXJyZrVBoRbkEumhmr+DGWFNyyo+uysedeylLr/HzGIas1fXmPH7ttO7/4gn0XXRFr0RavGqarAVGSzgTFSUC4RX71ArAkKHVejF3B5neXPU4zsBnSubA4SV/3gmvxggN9DBSzFDM2Rydr3DySfi4OT1Tw4wQaUG5EZF1rUSXIEoIIQSljc2KqxiOnZ7lzd2+7qrSt5HFyukYx6+DZFq4tmamFHJuscufunkWiZj2twq2q27HJanuWazPbHmthjB8n5NyVvxuyrsX4vH9ZVtUNBoPBYHgu8KyKsZ/5mZ9hcnKS3/3d32VsbIzbbruNT3/6021Tj1OnTiHl+UX6zp07+cxnPsNv/uZvcssttzAyMsJv/MZv8KY3venZegpbjpSCl9+0jUNjFb57eo7xeZ+unAMIyvUIpTW37uzmZTdtu2zajFrzNQtzku6/foj7Dg7wyOlZpmshfXmX23f2IKXYtEwlpTRaa7aVMjxxtky5EVLMOAgBhYzNbC3aknZFKSHjWNTDBBuIjSv+lhLpdM4QUiHcEr5hkvDw8VkKXoWsa3HNULGdSZd3bTK2xWw9JFEaZ8l7LNFplTbn2kxVA6Zr4aKqUhArYqVwrPQrUwhBIWMzUwup+DE5b/2iplV1a81y5dws9TDe1LbH1vP+/7f353FyndWB//957lZ7V+/d6lZrly1bko0XvGBDIDYYwgCZyUACjjGELBB7gJiw/RK2GQgEEgIhBDJkgMw3GCdkCJMJxMYWtgFjbGws27ItWbJ29b7VXnd9fn/c7lK31Fot9SKf9+ulOKq6t+699VSJe+o8zzlVLyCXPHpOfM0LG9lDIYQQQsy/Bf9f4FtvvZVbb711zufuu+++ox67+uqr+fnPf36Wz2pxWdeZ473Xr+f2h/bz891jjJU9APIph6vXtPLmK1cs6FqVmcHXaMnlsf0TbOsvUvUC0o7F5t48r97UzbrOHFesbmvs9+xgiX959ADPjZQJNbSkbNZ15k4rKzAzwzBadvHCCC/UVOoh6STYhkHSNqj5z6+shiKuujgdcClA6/imNpKiHWedCZimYvqdDnQ8ZTFhKhzLxAsiCpGPccSUvN7mFGs7svx45zCmAj/SOEoRRjqu6BlE5JI2URSvzWzLOLOySloHWIaBH0YkrHjNqm0alN0AL4xQHqcU1MzXWq7p697WXyCbsGZNVdQ6rgo5nT0UQgghxPxb8GBMnJx1nTn+9LUXcnCiyu7RCgCr2zP0taQXNCN2ZBD03EiZuh+RdkwcSwGKPSMVtg+WeO/16xtB1pZnhvjrLTsZKbk4liJhmZRqPqMV75SzAkdmGHqaU6Qdk5/sHMWfau5rGAqlIJ+00GiK9dObSKiZnfmafuvP0gxIMUPWMbBNAzfQOCZASHvGAWXS05zCm8peleohPfkkQRjNCmhu2NTFwYkKu4YrlOsBphFn2MIoLiKTCAKGSiEbe5q4tK+FgWJ9RlbJojXtMFyq42TiqcJ+GGEZBrahTjmoOZW1XM+nQur0dfcXauwcjo+XckxqXshAoU5rxmlkD4UQQggx/yQYW0IMQ7GiLcOKtsyCnsfMMt/ff3IA1w9Zlk+xa6REoeYz3UY8n0pimYpSzefxA5Pc/tB+/vS1F7JrpMRfb9nJYLFOd1MCxzLxw4hCzccN4iDpZLMCx8ownNeVY7LqsWu4Qkc2QW9LkudGKjiWYmCyfsbeCwnC5kfKUqzpyJGwFAcmavi+D0BzysGy44xPwjZJYGKZBhM1n+WtKXYNlzk4UUUpRRBpXntRD8OlOj9+dgw31NgKbFNhKJisBSRtk1de2IVlGbOySus7s6ztzFByfcYrHpmESbke0pyxGSzWacsmTimomc+1XOs6c7z9mlWNH02GinUSlsnm3jyv2rh4S/ILIYQQLwQSjIlTMp0J2zVc4qn+ImU3YGVbmqRt0j9Zx1SKdMKkHkRMVn16mpO0ZRMMFes8tHuM/WMV/uWRQ4yUXJY1JUnY8ZSvhGXiZOKiCFUvYOdQ6aSyAsfKMCilWNeVY7jkMlpxacs6KDSTtZBaIJMJl5qObIJUnA6jKWUzVI+n6oZakzqi5cP09EHTUAwV63z9p3sp1n3qQUjCNHB9zcq2FJNVn0I9wA00KE3CNMgm4gIe0VS27Mis0ubePDsGSwwU6limoiXtcNHy5lMOauZ7Lde6zhxrXp49Y+szhRBCCHFmSDAmTtrM6YC5hIVS0Jy2GSm5DBTqVN2AbNLCMBSOZVDzQ7wgImGb5NM2Y2WPR/ZN8NxIGccysI+ooDhdFKFUD5ic6g91IsfKMIxXXHYPV4i0puaFbB8qUvPi83mey8bEAii6Ic1e3BfMUDAddx+5jgtoTB+cqHgcGK+iFKztyJJ2UgwX6+werZCwDJpTNgkrnvqYtONptYVawL3bh/nVDZ1cu77jqKySG4SsaE1z2aoWLl/VygXdTacV1CzEWi7DUIuuKbwQQgjxQifB2DlirgqGZ/JX7yOnA45VvLixcsImm4CDEzWCSDNdrtBU4GtNOD1ncarzVj0ICXVEwjLwQ03Cmn2OtmngBR6G4qSyAnNlGMYrLlsPTFLzQtKORU+LSXcuyS8PTEggtkR5QRivCbQS1LyQTMICfJpTFgMlv7GOa7rdQ1PS4pmBEoah2NzT1GgUb1sGKdtgohpPc1zbkZlVsdWxTA5O1NjyzDAvWduOYaizklWStVxCCCGEAAnGzglnu1cRHD0d0DGNWVmJfMpmtOxS8QLSWGgdZy/MqRvkQtUnn3JY15nl0b0TlGoBhZqPk3FmZQW8IMQLNGs7syeVFTgywwDw3HCFmhfSkraZqPpxCfKqi2MaSAewpSkII4p1D0NpNIqXrG0HDmBZBqahGCu7JGyTUj2g5odMVDzcIKI14/Do/gLrOrO0Zpz4MzBVRdEwVPyDwIwEbRBpMgmL/snarGmyZyOrJGu5hBBCCCHB2BJ3tnsVTWfctvUXGK+6LMsnAY6qLmfE97jU/QjX91CGImUZ1PyAkguR1ly9ppXLV7Ty6N5JRsvxzfJ4xSObtKYyYhGDxXgt2X+9tA/DUCfM+B2ZYcgmLEYrLo4VZz+Stgk6Pq/WjMP4VEbkTFFwVnqXidmCCGpeRHNKcXFfM7/70tVs/8UBXryylV8eLLJ/vMp4xaPmhzimQXdTkpLr05pxGCnVKbsBL+prpiUdl44fmKyRUMaMzG08PbBcD2jPJjAN5qURsqzlEkIIIV7YJBhbws52r6KZGbfxqsdzwxVKtYALe/K0ZpxGdbnBYp1izcdUCstWeKFGEfdyGii4tGQcLu5r5s1XrsCyjEbwBFD1AkpugBf4eEFEd1OS/3bdes7rzp10xm9mhuGX+8cp1nzyKZvOpiRduQTPDJbIJi3cIMLg1HqBnSjY0iexjXh+FODYcZuEa9a1846XrmZlS5LtwDuuXc3rKgHFqs8/PrSPfWNlluXT+GHEtv4ioOMgvOLx3EiZy1e2sKYjw56RMm6oCSJNGEVU3ZCSG/fF65nK/s5XI2RZyyWEEEK8cEkwtoSdzV5FR2bcluWTlGo+BydruEHEJStaaM0kuHh5M/fvGG70FmtKWYQRU1GKxg00K1pSvPu6dY0AambwtGu4xGTNw1AG6zqz/MZlvZzX1XTKGb/pDMMj+1r4u/t305qxWZZPMVbxCKII27CIDH3SQVPajte0nShwO7IJtDjzHEvRmnJIOCY3XhU3OJ8ubT8dyBygykjZxQ00Tw0Up6Y1+kxWPXqbU/FU1YpHqR6wvDlFSyZB2Q2ouQHDhTp+pLFMhWkonuovcu36dmmELIQQQoizToKxJexs9So6Vsbtwp4m3CBkpOzy9ECBK1e34gYRoYae5hQX9jTRkU2QTZiU3RAvjOJGvGFEyp79UZs5PatU9ylPVWJM2RZBEJ1Wxs8wFJevbOUXKybY1l8AwDENwlCzd6xCxQ1OGIxNv9qVq1rZsnOc6ASNxI5sAi3OPC+I13et7ciSTzlzbvPMYJFnh0rYhkEuZWMnLSxT0T9ZZ994le58gjCCiarHYDFi8/I8xZrPzqESjmXQkbaxTYNiLV5zNlxy2T1alnVbQgghhDirJBhbws5Wr6JjZdxaMwkuWdHC0/1FhosuzwwUMZQil7S4bGUrHblEY9umVFwVIYgi9o5W5gwIDUPhBiH3bh+ZNRWxPeuwe7TCitb0KWf8jlxD5gURA4UabqBRJ5ipOfPpfeNV0BJlLQYaGKt4NKdsljUlj3o+ijSP7BknCDUtaZPEVMuEfMrBNhSHCnVGSx5J26DmhVzc18z1F3Rxx8P7GSzWMYgLd4CmtyXFmvYMYxXvlKb4Hrm2cVlTkoGpH0JkHZgQQgghjkWCsSXsbPUqOl7GrTWT4Mo1bTwzUORNL+6jLePw7Yf2k7SNOV7p+AHhsaYiPj0QF2TozCXJHX3vfcKM3/Q0yC//aBf3bh/GDeLpiceLrUw1+/m9Y1WCSG6eF4uaH/HvTw4QhhG3XLeelS2HPxiHJmtxE/F8kkLNJ2GZje9COmHT12IwUKhx9dp23n3devpa0hyarDFZ87lmbRug8MIIxzTIJePvkWMZJz3F98i1jV4Q4foRCdvAsYyzUt1UCCGEEOeGue+gxZIwnQVqzTjsHC5TqvsEUUSp7rNzuHzavYpmZtzmUvdDWtIOm3ryXL6ylXWdOQYKdfQR0c50QLhujjL1R06FzCVtTEORS9qs68gShJodQ8WjXhNOLuMXRfDMQJEgik7qQx7quLDH9NEiwJJYbNEwFXhBxJ1PD/E//v1pdo+UG89VvAA3jDi/O0fKMRmveLh+SM0LmKx6TFRcEpbJDRu7WdmWwTBU4weHTMKmKWXTnk3QlLIbQVzKMXGD8IRTfKd/UNjWX6A5bdOcsjk4UeXZ4RIHxqs0pxya0zbb+gt844G97BoundX3SQghhBBLiwRjS9x0FmhTT57Jqs/e0QqTVZ/NvfnTLms/nXE7mQDrdAPC4xUfaUrZLMsnGZiMqzQe7/gzRZHmwHiVp/sLfOOB3Rwq1AiiuLPY6cRVvsxSXBQsIGkpbFOBhm2Hitzz9GDj+ekfD5K2yYv6mskmLA5O1tgzWqF/skbZDXEsg7RjHrXPsX5wOLmAf/YPCtmExd7RKkEYF60Jo3itYjZhsb4zy/jU1Mcokg+WEEIIIWIyTfEccKZ7FR257mpZPknKMal5IQOF+qwAK4o0jmmwqaeJR/ZOcHC8imUqkrZ13Oa1x5sKqZTi/O4cI2WXXSNlzuvKHfP4044sw/9Mf5Gqe7jBs9z+Ll2WpUApDCBpxxmrR/dNsrw9fn7mdN22jB03bnZM2jNOXJSjHmAaih88OUB3Psm6ztwZmeJ75A8KxZrPeDXum2cYxqwKjtM/MJxudVMhhBBCnJskGDtHnOleRTPLzz83UmaoWCdhmbMCrF3DJW5/aD8/3z1GoeqjgUzCZGNPnv98aS/XrG0/ZkB4ouIjSdvkvK4ca9qzjJbdOY8/7ci1Z7alePxAXOVRLG0KGi0GkqZBwlR4AVS8wxnT6R8PDk3WeHjPOHU/IJ+28QJNse6TS9q8qK/5qKIcJ/uDw7Ec+YOCF0ZxGwUz/mfVNg3KboAXxg0STre6qRBCCCHOXRKMiWM6XsZt13CJL9yzk8cPTGIqaMs5KBSTVZ9H900QRJplU1mIuZxMZuLSFS38/kvXHLcq3ZFTxSaqHjuHytS8cK7DikXIAFBwrNl7oQYVahJJg0CDUpBxZgfw6zpzvGZzNw/tHqPkhoxXfbSOA6LpqYZHZqZO5geHuUxXThws1AlDTcX1aUo5OKaBZRj4YUTCMvHDCMswcMx4NvjpVjcVQgghxLlL7grEcc2VcYsizZ3bBnl2sIRjKtqyiUYw1dVkMFbxeHaoxF3bBlnz8rlLg59sZsKyjONm/GZOFZuoemw9MEnVC5Eq4ouLAiwjrlg53ZfNBLSKn5vOYipmTynVMx7TGmp+SNI2uWxlM1SGZx2j5se97ZKWiaEUQRihdcSBiSpjFY/LVrWgYFZmak17ltddbLB7tALA6vYMfS3pY2bEZk6HrfkhByaq7BmrcMWqVlozDq1ph+FSHTutKNcDOpuS5JLW86puKoQQQohzlwRj4pQdmqzx5KECodbkZlSgg3i9Vy5pUaoHPHGwcNz1MaebmZhpeqpYyk6yfaBEzQtpyzgUqh5VPzpj1yyeHw34EViGwkRjqjggT9oWacdgqORiKoVhgKEMvCAkjA4XXok0FOsBtmmwqbeJ6y/sZvsvnuXQRI16VCNtm/xi9xhuEBGEIRpF0jExlSKIIspuwMO7x7m4L9/ITB1Zkv5EJeiPnA7b46RI2Qa/2DvB/c+O8OJVLaxqTzNWcdk/UaM57bCyLU3ZDU566qMQQgghXlgkGBOnrOIFU1XoNEkEbTIAAGM2SURBVLZ5dEHO6ceqfnDC9TGnW3zkyKliw8V6o3gCQMI2Af+4ryHmh6XAUHEwFkQaBbRmHFK2iWkqXD9CEX9u0o5JGGk6sg5jZY+qHzamL6Yck+s3dPKuV6wjDOLP1Zfv3UUl0ISRZv9YFa01bqDJpw73GrMMg6Qdrx8bKdXpyiaO2eNuW3+B/kLtqEqkR06HnX7tvtYMacfk4T0TbB8ss6otRV9rms6pPmPFmo/rR6f0A4MQQgghXjgkGBOnLONYpB0LUI31MTP5UwUL0rZ1UutjjjUV8lgB2syMRsWNb6Ar9QDDgK5cglE3YqLinZmLFactDrBUY9ph0gZF/PfOXIJXnN9BxYsYr7j8eOcoURRhKEWkoCXt0NWUpFT3GSy6pGyDz73xYq5e087u0TL/+NB+Ljcgn7LpSjgcmqgyUnap+yGWqaj5EY5lEEWamhdSD0K0hkOTdT539w7CUDNWduluSuIGEVoH5JJxCfqdw+VZhT7g+K0Y2rJJrlnXRn+hzptevIK1HVmWNSWPu9ZRCCGEEAIkGFvUjheQLOS5pG2TTT1N7BmpUKr5OFkDpVSclfDj4gmmoeZcH3My1/TsUJF/eeQQz42UCXVES8phXWeOGzZ1ATQyGpNVj6cOFSi7IdMTEserAZY6vC5JzC8FWKbCVmBbBl1NSZhav2UZCtMwGCzWGSm7lN2QfNohl7RYOV7lueEyZTcgl7KwTIUXRnhBRDZh8coLu7h6TVzL/q5tQ3GwnYNs0kIrRXPaIeuYVN34c2VNNXaueiEacCxjKkNm8sv9EwwW6uRTNnvHqvG5mQYtaYe1HRmyCYtH943zyL4WLl/ZOqtJ9FytGADSifiY3flk44cFKV8vhBBCiBORYGyROtX1LGfT9sEC//DAPnaPVMDQLMslac0mWNacZPdIJV7rZRsUagHlekCkNa3pBOMVj92j5cb5nsw1bXlmiL/espORkotjGSQsg1ItYLTscWiyRtIyGK941LyAR/dNEEYaZ6oyRH2qCoQEYgsn4xj4kcaLNDrU+GGEH8bFNSIdT1GMIk1kMKuH3Jr2DIOFOjUvxDYMJqoeEAdvF/fkeMuVKzAMxYHxKs+NlOluSs6q9JFLWrRmEwyXXdwgpLUphRtEWGZEwjQIgbRtkk1YNCUtnu73qHkhfa1pckkLP9Qcmqyye6RM0jFx/ZC/u383v1gxwQ2buk7YikEqJQohhBDidMidwyJ0qutZzqb/78G9fPneXRRqPgowDcWBZJVl+RTLmlO8eFULjx8scHC8RqQh7Zj0taRZ25lhoFjnGw/s5e3XrAI44TVFEfz1lp0MFussa0piWwZ+qCnUfNwgouYHVL2Iy/vy/OuzIwShJmkrDAUaAxWG0tx5AbWmLbqakvRP1qh4EWGk6S/ERVlSjompDLwwigNxZbGsKclk1W8Ubvm1zcvQOt6n6oWkHZOLeptnBeuHM1QOuIePrZTiwmVN7B0tU6gFuEGZuh9/GuoqzsopoHvqmErRCA4NpYiikJoXf740muaUTWvGbnw+b7561fNuEi2EEEIIcSQJxhaZYxUKyCVtsglrzvUsZ8s9Tw/xhXt2UnZ9cgkb21T4kaZQC6j5cSnwl5/fSUvK5uF9E7RlHNoyDj3NKQzDQGvNzuEyd20bQmt93Gu6a9sQk1WXkZJLd1NiqgAHJCyFk3EYr3iEkWa0XOfHu3xKXogBeKGeKmOvJRBbYGnHwrFMTNPANDRRFKF1PH3VnBqjMNIkLZOmlM3Ktgyve1EPNT9sTFkFjjuN9XCG6ug+ckpByjYp1APqfvx5MJgqja8hCDWTUz8qNCUsSm5IEGkcrRmv+AQRZBMmFS9keUuaZfn4fHYOl7nnmSFeubHzeTWJFkIIIYQ4kgRji8zxCgUopY5qXHu2BEHE392/i4obkE9a2FZcITFhKGxDUawHDBRq/Oy5EUZKPhpNzasxWHTpL7is68zSmnFYlk/yxKFJ0NDbkjrmNT1xaDJef2YpnCMKgiilyCYtRksupXqAOzUP0ZjuURXpYzYMFvNnouqRsuN1YqMll/GKh0JPrf3S+FGE1tDVlGRzbxO7RysYSrGhu2nW6xzvcz3dLPyZ/gk2z0gOa63ZNVQmiKA941BxA+pB1PiMGIYim7AIwoiqH7c/qAcRpbpPpDVVP8A0FG4QFxHpaT78WZ3+zr3u4p7n3YpBCCGEEGImCcYWmRMVCkg5JkNTVdrOpl8emODARA3bUljm7ODIMBQpx6RQC9g+WMZQsLwljTM1rXCkVKfsBryor5mmlDVVREFPVWCc+5qqXogXaRKWOWeFRstQlN0AQylsUzUaASuliCLJii0UA4im/htGmsl6QNaJp7MaKu4P5geaigrIJCyWt6TY3Bt/LvaOVk75czzdLHywEGdmy/WAREIxXHTZN14lm7CI0HTnUwwV4+mOKTvOjwWRJpewKNR8qm7IqvYMKctksFjH9SOStkHSMUnZJh3ZROOYM79zG7qbTqsVgxBCCCHEXCQYW2QWS6GAsYpHEGlsQxFqjXVERssywA1CTANasgmUitfezJxW+NxImfO7sqQdEzTHvaa0Y5KyDHQUrxFzMsasLFrFDXGDiN7mFI4ZFwsJIo2SlNiCiogzlCnbwAs15VpAFEFbxqbuh/hTRVUuWp7n/K4cTVNNwkt1/7Q/x+s6c/z2lSvY/ou9cWBV8qj7IbmkxZqOLDuHSziWQWcuwWCxjhdqbHNqjZgxNWVRazb15GnNOPQXajy6d4Lk1DV0NSXJJQ+f15HfublaMQghhBBCnA4JxhaZ6WlYC10ooG2qKa/rgxdEmLbJzHjM9eOpgV1NSdozCUbKbiOAmp5WOF522W0qrljVhtaabf0Fups0fqRxTKNxwztQqHNRbzNaax7aO44bhIxX4gbOtmngBSFDpTqWoVjXmSVlx8HqvvFao3LidKZMzK+sY5KwDcpunOHKJi2CSFP1QjKOyUTVJ+nEWc7pQOx0PsdHtkRY1ZZhO3DLK9ZRj6BY8/n2Q/uxzbiEvR9GpByL7qYk4xWfshsQRhFuENGVT7KyLc1YxZsK2pK0ZhwOTtboyCZY23F4XaMU5xBCCCHE2STB2CIzPQ1roQsFXNrXwqq2DE8PFDFVXJrcsQxMpQjCkLIXYJuKy1a0YFsGZS+YFUBFOi6WsKYzLl2/b6zK3c8M8cTBAo5l4FgGuUTcPHpFW7rRQ2ygWAeg6gaU3AAv8Kh6EaZSGJbBtkMFbNOgJePQlLLZNVym6keNQGx62pw4+1KWYlV7Bj8MKdaCqWmJcYXCYj0g48R9vZKWwXDJZaLqYZsG/ZNxK4R1XfF0vxNN85urJcK69hS9xOsQbdsmijS/2DPBk4cKtKTsxo8DKcdimWUwXFI0p23yKYsrV7fzyo2d3P3UMM+NlHGDOi0ZhyDSNCXjQjVBFElxDiGEEEKcdRKMLULrOnMLXijAsgzeds0qPv0f25mouCig5gaEWhNGkElYrGxNk05Y5JI2L+pr5rnhCuMVl8nAJwwjckmL37p8BQA/2j5MU8purP1yg5CBekBHLsGvbuhsXNP0de8aLjFZ86l5IYWaT8o2GCzGN/SWYTBadnEsk+XNSQ5O1qgHmqRtkLFgpBpJpmwe+KGm6gb4kca2FEpDqR4QRRoUpJ0EF/c1UfMiDkxU2TtWIWGZuH5EEBl877FD3GkNHrd/3rHaPDw9UKQ3B7tHypzf0zLrR4yKFxfjGCu7JOz4eEnHpClp09eabhxrXUduVrat5geNAE2KcwghhBBiPkgwtkit68wteKGA6y7oon+yxt//ZA8jpTpBpDGUoi1j8/svW0vZDRvTKVszCXQn1PtD6r5LLYjIJW0ePzjBfTt8xisel/Q1A/ENuxdG2IZisOiyfaDEus5so8T5H7xsDQPFOqW6z/ce6+fpgQITFRfQWKYR3+xrzUTVY6LiYZlxwQitNZUgfn+suIFUY82SMRWdSdbszAk0HJys0dWUiDOXhiLlxFnRYKoZ92jZZ11Hhnza5lfO6+ChPeNYRkhPc4q0Yx3Va25N++HPfNo2ufPJwTlbIuScDNTjIH99dzOGoWb9iPHYgQn2j1cp1YOp3ncpLl3RMiuwmmvt15EBmhTnEEIIIcTZJMHYIrbQhQJ2DZfYPlhiQ3eWjT05Ih0HNWGkeXa4zK9uONx3KWUb7BgqUa4HgKK7Kcn6ziwP7BrjwESVTT1x+XKlFE2pw0U8inWf7z/ZzxMHJzEMRaQ1y/JJrrugixWtaUZKdcYrHoMFF6XADyNcPyKckfbyQliWMdCmTdn1AfA1JNBTjarj7QJJlZ1RlhEHweMVH1PFnw3bVNQDTVPSIp+0GC3VGS/Xec3mbsZKLl4QcV5Xbs5ec7c/tJ/WtMPu0Qr1ICSMNAfGa2zozs7ZEgFg90hlVpuHmT9ilOrxWrFs0iKXsE8qsFro75wQQgghXlgkGBNzmtl8+vzupqMKiewcLrNjsMTNL1nJD58a4gdPDjBe8cinbDIJi1zSYt9YlbFyndGyy6P7JinUAtZ35WjNOACMV1x2DJUaU9AqtZCRssvjBya5f8cIF/c1N3qqRVGcbXH9aM7s1kAlJGNr1nVm2TNepVQL8MN4qmIUSUbsTDMV5JMmbqCp+SG5lNVYK2abiqoXMlr28IIIpeA/nhwkaVtc3JefM7BK2Qb3bh9mRVuatR1Z0k6KQxPVqc8IZBJ243MzkxuER5XHnxlQzSz8cTLr04QQQggh5pMEY2JOJ9t8+nUX9/C6i3t48mCBZfm4ct14xWXXcJlIa1K2iWMaeGHEQKFGxQu5eHkey1Q8cbDAZCVuFHxwokYQaRKWQcJyKNYCth6YZLTs4oURJuBF+rhBVcWP2DVcprc1jY5qWAZM1EIJxM6ClG3Slk0yWfOpeh6uH9GWdXBsTbHq44Xxur2kbWAoRc2PGK3EY5x2LNqyCbTWU028Q3aPVqj6Ib3NqUb7g+a0Qz5lU64H7BoucX5XrlGJsykRfyaPVx5/rsIfx1ufJoQQQggx3yQYE3M61ebTVS9gsOhS80PqfohCk3EsvDCeUqijiGzColDz+PGzI1imYrhYR6OwDEXKCbEMg8mqT6Q1WtOYlhgEmugkkxkVP2LfcBlMxfLmNBEuhdrZbZD9QuOYYFsGVS+iLeNQqQdkkhaX9bUwVKqz3SthGoq0YxKEmqofxuMYRvRP1rhvxzCXrGhmrOwzXvWo+SFjZRfHNKh5h0PnXNKiLZNg71iZncNlhoouhgLLNOjImKzphDUdmTlLzh+r8MfM9WkSkAkhhBBioRkLfQJicZrZfHouMxvhDhXrPN1fZN94hbGSy2TFwwsjNJqUbWBOlTwfr7gUa3ExjyCM0Chs08ANIyaqhx+P1x5B3Q/RWqOBUDNrndjx+HF9D4bLHglLPuJnmtbxPxw1P6DiheTTcZVMyzQYKXsopUgnLCKtKbsBmjiTlrQNNJrRssuPnx3l4EQ1roDpmHFRFmDncDxtFeIMbHvOoeqFlOo+oMmnbQwFe8eqAKzvzB417XDmFNv1nVlySRvTUOSSNus7s4xXPH741FDjmEIIIYQQC0XuVMWcpptPDxTqaD37pnW6EW5cATHgyz/ayUTNxws09SAi0FD34z5jfhhXYEzbFug406WBSCtSjklz2iYIItxAU/UjCvWAiarPZNXHUKpRn/5Ubpsj4pv/1W1par5MUjzTgiguvFJxAxxTsaw5RUcuyUChSqnuE4QhYRhPQdRKkUtY2JZB2jExlCII9VSBjiiugOmGOJZJR86h7oc8N1JGa00URRwcr2Gb8edH67i5c6RhVVu8JmzncPmooOpkp9gemqzN23smhBBCCDEXmaYo5nQyzaevv6CLr967iycPFeN9OBw0acALNJM1j3zSxrFMHFPRk7IJQs2lK1ron6zx9GDxqCqHU5XrifwQrU+vX1gQRjwzWKbihc/jXRBz0UAc42qSjsmG7iY2dOf4t62HKNYD/CCi5sfZrUzCxJnKThpG3Ozb9UMcw6BQD0jYFj3NSVrSNmU3IJOwGK94HBivsW+8ws7hEkGkySQsmtM2vS1p2rMOho6AUbYdKnBwosqKtkzj/E51iq0QQgghxEKRzJg4pum+TZt68kxWffaOVpis+mzuzfP2a1ZhW4qf7BoDwDYUCdvANhUzcxFBCNmERcIyiNBEESxrTtHbkqItl5gqhT+38Hn0Bav4kQRiZ5htTPVrm6KBhGnw8vM72D5Yoi2TYF1HloxjNj4HfhBR9UKKVZ/JajwNNWUpVrSlac04bO7N8+JVrWxeniflmJTrPqW6zxOHJhksxL3tMo5JezZBqR6wY7DE1v2T/GLvBABPDxT5+k/3smu41DivU5liK4QQQgixkORuRBzX8ZpPf+eRA5Rdn4xjUffDuOqhoeLCG4FuZLTKbkh3PslY2SWVNljbkQVg72h5zqzXkbU6bGM6EyMWkh/FwZgBGAY0pxzGKj4/fGqIshtwXneOjqYEbhAxMFnD1SGBH1E9YvA8YLTs0pJJ0JpxUErRmknwor5mnuovMDJcwQ0impIWmYRFezauqlh1ffaN17AMxZq2JABJy2TPWJlvPLC3UZRjeortdEPyI9syDBTqbO7Nz1n4QwghhBBiPkkwJk7oWI1wq15AGGm8MCTUEUGoCUKNUnGj5XCqv1cYRXQ1JcinLMbKLntGS+xXBqPFeuPmPpyxNuzIAE3KLCwe0VSVS9s06GxyGC55/HLfBC87r70RVF21ppVf7Blnx9DcwXYEDJU8TMMgmzAp1uJS+LahyCYsupoSbFzWRHPGYcdgiZGSi9aaiWqAIj7+9At3NCW4qDfPrpEKP3xqiDXt2ZOaYvuqjV3Sb0wIIYQQC06CMXFadg2XeGagSBhpSvUwvkk2QE2t8Qqn/msb8DsvXY3W8O2H9jFc8tgxVMGYrs2hwTQUBjq+0SfOvugZUxRDyYrNq+nMVzDjfTenxmu6kqKhFONVn6SpKLv+rDFqSTvkUw5qahynzYihABgo1PnhUwNoZeAFEV4QkUta5FM2y1szmIZiXWeWshs01ng5lsILNRM1H4DV7VkMw5hVlKOvNd2YYjvdZ2yoWCdhmWzuzfOqjdJnTAghhBCLgwRjYpYo0nNOSZxpuofTRMUnYcf9piAOxFAKy4AwjHuDdeQSZByTL9yzCzcIySZMgkjjBVFj6qGO9KziH+FxbuDF2aOA9qxNa8ZhvOJTrAdoHeFPLb0zFDM+C5pyPaCvNU2h6lOs+7RkHABK9YADE1X0HAN3eO/4z97xKt1NSZK2RVvWwVCK0ZJL/2SVvtZMY/riEwcLjFU8okihgfZsfKyWtB2Xzp+jKMfxptgKIYQQQiwGEowtEScTJD1fu4ZLjUxCPQhJWiZrO7LcsOlwJmFmD6dl+SStaQc/dAkjPZXN0ugwnkqWsU36WtP8r5/sxQ1CWtM2hmGgNYSRpljzqE2tLQuJMy5KTVVTnDonCcTmh6niwGZ1e4bmtEMQVrBNg6xjsHesSqTjQMxUAAo3iEjaJsuakihgouqxojWNUgovjLNc02MXZ9IABQqFRjeybhnH4kUrWmlNO+SSFlpr7npqiG39xanPuEFrJsElK5op1XzqQUR3PsmVq5vBHW+c/7GKchxriq0QQgghxGIgwdgScDJB0pk4xjce2NsIstJOiqoXsK2/QH+h1iiOMLOHkxtEJB2TVW1phoouNT+Mez4p6MwmuGRlXL5+rOKSdiwMIy7eGa8pixsD1wN/VsB1so2dxZmTsg3a0g5epMkmba67oIu6f4ihogdoTMvA9yLCQOMDhqExFeRTNqHWXLWmjbofNtZnmUphzvihQDUCMYDZvQps0yCbsGhK2Y3HVrVnePzAJPc9O8z5XTk6pwI+yzQwI82Fy5oanyWQohxCCCGEWLokGFvkTjZIej5mZrvWd2Yb1edySZtswmLncLlRHGFmDyetAyzDIGkbbOh2KLkBXhBS9yNetr6DlGOyf7xKpDUJ6/DNuR9G1Lyo0QAa4uyJaUIk1ejnVcJSWIYiiCLKbsAv9ozjBxFjZZ+qGzBccgm1bkwXNVQ8HTUiXhDW25ziLVeuADj8g4Ef0ppxGC27hDoOsNUcQbZlQFPSwjHjwGq84vLkoQIHxquU6gGlus/+sRotGYd1nVmuXd/OcMllrOKRNOPXKNcDDhU9KcohhBBCiCVJgrFF7FSCpOdzEzoz2zWzDDiAUmpWcYSZPZxySYvWtMNwKa5Q15S0cQMD24xIWAYDhTqr29PsGirhBpq0Ewdi5XpchXF6AZECErbCDeK1Y1KvY35YKi6OUo9CDAUp22xMP6x4AQPFuIqhZSgsC4JQEwJoMNA0pW1u2NTNiuY0Ww9Nsqo9zcr2FKvaMzx1qMjn7tzOaCUutDFXwjOXtOloSpFLWoxVXH66c5SRkgto0o7JsqYUJTegPpVx/a0Xr8Aw4qBv70gRklCo+VKUQwghhBBLlgRji9ipBEnPZ13MzGzXXGYWRzivM9fo4bS+M8vazgwl12e84pFJmJTqIWnHZOdwifZckt+/ZjWPHygyWKyRtBQVN8QNIxQQhtPXAvmExZDvyxqxeaSnytRrIGGbhJEm0hq0JmUbaK0xFJimQuu4XYGONFpBwjaYrHh84e5n+WjFxw3iwbRNg5VtaTqzCVa2ZfCCEkV3drpTASnHIOOYrGnPMF7xuP/ZEYaKdaJIowyFqTSWqehpTjJW8Tg4WePupwd518vX8a6XZ9k/WuLxBw9wyyvWsaI9t2AZsflYyymEEEKIc5cEY4vYqQRJz8fsbJd91PMziyPM1cNpc2+eHYMlDkzUcIOQqmfihREoxXceO8jLz+/gu788yGjFJ5haFDZ9u6qIb/KrgZbKifNMGWAojUZRqgUEUdwjbvtgiZIbYlsKhcIxDTRx4GFEUwGaoaj7ETuGSoShJp2wWNacBB3v/0tvkuaUTUcuQXsORksu9amALWGZNKcd1ndl2Tde5dBEldGyC1rHbQ4MBUoxVHLpbkqSS1qU6gFPHCw0fnjobUnxONDbsnDBz3ys5RRCCCHEuU2CsUXsVIKk56O3OdXIdmUT1qws3FzFEY7s4eQGIS0Zm6oXknIM2rMJhop19o9W2DFYIpuw2NiT54mDk/jh4aDLMRVtWQc/jCi5IRopZT+fHBPcACKtidCYpkFz2iKdMBmt+GgNlqHoakpimwajZZeqFxJFEVUvJIzi8Uo7RlwdsxrQ05xEodk+WGZCa3qW5TBNk/ZsAi+ICKKIYj0gZZu88bI+bn9oP6V6/GOCVpCwDFKOiWUoan7EeMWjO58AoOoHz/uHhzNlPtZyCiGEEOLcJ8HYInaqQdLpmivblXJMal7IQKE+Z3GEmT2cSnWf7z3Wj2UY2Kbi4T0TVLwAc6oU+mTVxw9CmtM2ST8iaRmkHIuWtIVpmtS8ALPkMuy7sl5sHtX8w4FvBGQsRXdTamr9mKLighdGJMw4W1X3Q/wwIgyjRvsByyAOsHVcAMQLIiIUSsXrAyteRFPKRClFwjZJYBLpuBdZqCPasw5XrGrl8UMFijWfpG1gTxX0cCyDmh9S8eKMWtq2nvcPD2fCfK3lFEIIIcS5zzjxJmKhTAdJrRmHncNlSnWfIIoo1X12DpfPaAW56WzXpp48k1WfvaMVJqtxcYS3X7OKNe1ZDoxX2T5Y5MB4NZ6yNtXDKZe0GS27pGyTh/dMMF52qbohxVrAZDWg7voUagFVLyTjWKQck7asg2maU+uSFK0Zm6RtILeu88NUzHqvlQI/0tT9EMcySDtWXI5ewWTNp+qH1Lyw0ax7uqFzRByUhWFE3Q8JIh2Xto+LLeKHs8NrrTWuH68rVErhhhGr2jP0taSwDIUfRI3XNlWctSvV48D+ouWLo3T9qazlFEIIIYQ4noX/mRn48pe/zOc+9zkGBwe5+OKL+dKXvsQVV1xxwv3uuOMO3vzmN/OGN7yB733ve2f/RBfAkVMCh4p1EpZ5VirIzcx2zSxIsHu0zFfue+6Ya2MqXkDVC9g3XmWo5M56TQ3UI8ALyTomGo1pxGvdDKWoeiFuEFLzQ/ypBtDi7ItmvNEGgAYviDg4WUWpeB1W2jbj7JdpMFio4c5oAmeb4IfxfqGeqowZRYSRJmEZ2JZB6EfUvAA3sLBNo1FJ0zIN+lrTdGQTJC2Tmh+yrjPLaNmL10C6AQnbIIyIqztaEed1NXPDpu5FkWmar7WcQgghhDj3LXgw9k//9E/cdtttfPWrX+XKK6/kC1/4AjfccAM7duygs7PzmPvt3buXP/7jP+alL33pPJ7twjhWkHQ2bkyns13TTmZtzEjJ5bmRMjuHK8d97bIXYihFOmFSnOojNR0UaC1rxeaLCaDiwilKKRRxViyKoO5HDJc8NnTnyHbl2D1aoe7H4zb9aXNMUMogVPF0xTiDFa/5MpTGNuMuz5mETW9zkrFqgB9G2KZBZzaBZRlcuqKFS/ta+MWeiUZlzqvWtPLkoQIHJ2pU3YBAQ1PS5jWbunnLVSsXzRqs+VrLKYQQQohz34LfLXz+85/n937v93j7298OwFe/+lW+//3v8/Wvf50PfehDc+4ThiE33ngjn/jEJ/jJT37C5OTkPJ7xwjgySDobjizTvawpecK1Mbc/tJ+aF1I9ySxA0Q2wS3Gj4YRp4IYRYSSB2HxLWAaRBkMpoqlS9p4fglJkHJPzOrMMlTx68kmUitdvPbBrjDCKUMpoVFQMQk0wlRhTCspuyGjFpy2ToCPnMFELCIKICE0QRIxWPM7vzvGqjV1YlnHUWsWXrG1npFRnz2iFXNLmbdes4qXrOhZFRmzafK3lFEIIIcS5b0GDMc/zePTRR/nwhz/ceMwwDK6//noefPDBY+733//7f6ezs5N3vOMd/OQnPznuMVzXxXUPT50rFosA+L6P7/vP8wpOzvRx5ut4p2P3SJktzwyzZ7TSmIrYlrHZO1ZleUsag9kRkwJ6cjaP7BmlPefgez4J8+RCqt68w8BkDYMIS2lM8+xc0+lIGHrWf88ljXYCCiwVB14p28T1I6IIEqZGo1E6ZN9YidZMAiLF8pY0bhCSTxiEYfwxCCKNhSY04kbdQdzJgCgM2Nid4xXnd/LIvglqro9lq8bRDUNjEhEGAb7vs7IlyVuvXN747I0GcVbpuvPb+dUNnazpyBKGQaMn3bSF/k5dv6GNwUKF3cNFupuSpByDmhcxWKzTnnG47vw2fN9noFA//ONGPrmogsr5stBjJU6OjNPSIWO1NMg4LR0LPUZKa71gd539/f309vbys5/9jKuvvrrx+Ac+8AHuv/9+HnrooaP2+elPf8pv/dZvsXXrVtrb23nb297G5OTkMdeMffzjH+cTn/jEUY/ffvvtpNNnN9MkhBBCCCGEWLyq1SpvectbKBQKNDU1zfvxF3ya4qkolUrcdNNNfO1rX6O9vf2k9vnwhz/Mbbfd1vh7sVikr6+PV73qVfP2hvu+z913380rX/lKbPvoNSYLKYo0/+une3h6oMjajsysKVfFms+Ptg/TnU9w5eq2oyrHHRiv8uj+CV5+Xif3PD3ASOXEvyxYwObeJp7sLxIswuRTwtD8j8sjPvKIgRudO1kMBRhTFQ6n6xvaCsKptXpx822FoaA9m+Ala9t51cYu/t/jA+RTNpmEyWP7J+kv1IgiTc2PS9xrYHV7mkzS5opVrfzONasZKNT58r27yKdsssmj/4kp1wMKNZ9bXrGO3pbTm8q3WL5TUaSPyn7tHavwjw/tZ6Li0d2UJO2YVL2QwWKdlozDb1+5gjUd2QU75/m2WMZKHJ+M09IhY7U0yDgtHWNjYwt6/AUNxtrb2zFNk6GhoVmPDw0N0d3dfdT2zz33HHv37uV1r3td47Eoim8tLctix44drF27dtY+iUSCRCJx1GvZtj3vX46FOOaJHBivsmu0Rmc+DYY1a+1WNmXQlkuxf6LOhmUR+bTTeE5rzWg1IJ1IcHCyjlYmbnjidWMu8PP9JVjkRezdSOGGi/scT5bJ4RL001dkEI/FNAUYEbRlHa5e18lY1efJ/gor23M8NVBkfWeWlR05JuohVS+k2VGU6nHvuJZsivZcgldu6iGRcKhHdSqBpivhoNXR72EioaiWPOoRz/v7sBi+U6s6D38vokhzz/YxRisB6zubGj9gZFIWa5Jxi4otO8ZY3938gpuyuBjGSpyYjNPSIWO1NMg4LX4LPT4L2mfMcRwuu+wytmzZ0ngsiiK2bNkya9ritA0bNvDkk0+ydevWxp/Xv/71vOIVr2Dr1q309fXN5+mfdVGkj+rtdaYdLtM9Oy7XU/2dOpuSAOwcLjX6nBVrHo8fnCTjWDSnLX62e4yJqr/Iw6sXrunlVoq48qGpji6Yoqf+rOnI0p5Lsiyf5LmRMi9a0dzoc2ebBpt78zSnbAq1AMOA7nySi/uaefs1qxrVDmdWG5zLYqw2eKa+a9KDTAghhBCnYsHvhm677TZuvvlmLr/8cq644gq+8IUvUKlUGtUV3/rWt9Lb28unP/1pkskkmzZtmrV/c3MzwFGPL3W7hkuN3mJz9fZ6vqYrJw4W6oShpuL6NKXiX/hHy3UeP1BgouIRaA1a4wWa/eNVvCBitOwCiiij2T5QwgsiUrZFZ5PNcNGVyoiLkGWAH3HMqaGWAtNU1LwQrXWjV1Z7LjGrz50bhKxoTXPZqhYuX9XKBd1NR7VZWGrVBs/kd016kAkhhBDiVCx4MPabv/mbjIyM8NGPfpTBwUFe9KIXceedd9LV1QXA/v37MYwFTeDNu5Pp7fV8ArKZN581P+TARJU9YxWuWNXKockaD+8Zxw1Cpku7pB2TIIqIph7oyCVY056hUPPxwoiEZRJpTd2PaEnbaKBc9/GjY5+DmD+WEbdG4DjZnkCD0jBW9ijVA5Sikb3qa02fUp87w1BHlaxPOSY1L2SgUKc14/CqjV2LYpremf6uSQ8yIYQQQpyKRXFHcOutt3LrrbfO+dx999133H2/+c1vnvkTWkBRpE/Y2+uHTw2xpj17WjezR9589jgpUrbBL/ZOcOdTgxRqHmEIthW/tkIRRJq9Y1WGii7ZpMUNF3ZhGAbDJRetIZc0cQNNwjJozzpYhoFjGXG/qDGZjjVfLCMuL++H8fzjiHhKYjZhUqyFJ9qdYCpDWvcDJmvBrOzVqfa5W9eZm5VRGyrWSVgmm3vzvGrjmcnuPl9n47u21LKCQgghhFhYiyIYE4edypqTU20Cfaybz77WDEnL5LuPHcQPwTbiZsC2oUg6JqZSTNZ8qm6AIr6h7GlOkXLMuPFvFDcF9kONZRgkbJOaFzBUck9wRuJMOdzJSwGaiDggMxS4QXRSU0cNwA0jdo9WWNeZe97Zq3WduVPKqM23s/FdW0pZQSGEEEIsPAnGFpmzuebkeDefXhShpoo75JI2tqkwDYVSCj+Mpyi6oWa04vHIvgmWTdZZ056hOWUzVvFoSpporQm1puYF7B+vUvVknuJ8cUxAqUbhCTXj/xgqDtDi/3tsIaAjzfKWFDdfvYo17VkOjFcp1X3KbkA2aZFL2KcUUJ1qRm0+na3v2lLICgohhBBicZBgbJE5m2tOjnfzGRduiDMpKLDMeJ2eH0aU3aBxk28qRcoxGSnVKbsBazoyFOo+41Uf2zQII81IyaVQkwIF88E2IetY+FEcbBlWHDz7oUYpWJZPYpkG+8YqBCcRGydsk1It4I5f7AcN+yeq7B+rUvNDUo7JitY0l/S1nLFCMgvpbH7XFntWUAghhBCLgwRji8zZXHNyvJvPlGNimQZaRwShRk99MmpeRBSBZcZrx0ylyDomKmExWKxTqHpkbIOqF1LzQ54dLC3KZs7nqgu6m7hoeTNPDxSZqHhxLzEFExWPqheSciyyCZOhokHZPX40ZhtwXmeWTMLk7qeH8CNNyjYwgFzSwvUjDoxXcf3ojBSSWWhne33XYs4KCiGEEGJxkGBskZm55uTZoRK5pIVpKMIo7vvVlk2c9pqT4918dueSJCyTMNLYBtT8ENNQ+FHcLtgLNEnboLPJYaLqY5mKcj3OtGUTFi1pm7ofUapLRuxsU4BjKiKtWdeRoy2b4Np17ZTqAV4Y4ZgGo2WX+3aMUHYDgigim7CpuMduO2AqSNomPS1phooutqmouAGeH7K2I4NhGGQTmvGKRxBFjJXd51VIZjGQ9V1CCCGEWGgSjC1C6zpz/OqGTr75wF6e6i/ihxG2abCqPcMbN3SedjZi+ubz0GSVxw9O0pJ2yCUtLEMxWHTZ3Jtn92iFihtgK6j7If7U3DbHMrhqTRvLW1LsGi6zc7hM3Y8r9AWRJmNbVL0TV+wTz589FYiZpkGk4/FRStGUmpnt1PS1pMilLNZ2ZKl4IQ/tHqVUD6h6swt62IaiJWOTtE20hvGqR9I2ibQ/VZ1RkzDiY2STFhNVv/E5OJ1CMouJrO8SQgghxEKSYGwR2jVc4kfbh8kkLK5e04ZhxIUZivWAH20fZmVb+nndJCYsg0MTNZ7pL6IUtGYSvGRtG2++cgX7xqp884G97B2rEEQa29TkUzZXrG5lTUcWgPO7FcNFl6apG/OMY+JYCrcoBTvmgxfG2cumpMXTgyX6WtOzevFprRksuly1to26HzJR9ckmLJpSDq3pBIW6j9aQT1lMVD06c3FBFzeIQEEQxb3j4nIfilAfDt1s06DsBpiGouoF50TzYlnfJYQQQoiFIsHYIjOz/Px5XdnZUwm1fl59xnYNl/jCPTt5dqiE1vE6sUjHUxIHi3EZ+usu6OJX1nfwywMTjJRcfrpzlPGKy+r2TON1/DDuEByEGq3jQgdjFQ//OE2FxZllmwYp26TiBjxxqMDajuxRU+zecuUKIq35l0cOsWu4hB9GlLyQVe0Z1nXmsAzFg7vHUAoqbkBnU5KWlI1lGGgdB2IQF22Z5ocRlhEXajmXmhfL+i4hhBBCLATjxJuI+XQqvY9ORRRpbv/5fh4/MEkYaXIpm86mJG3ZBKaheOLgJN9+aD9RpLEsgytWt/Hai3p4x0tX055LsnO4TKnuE0QRXhBR8yLqfkjF9SnUAnyp2nFWJSxF0jJIWIqEFTfVjnRcMTGftDg0WWPPSIXJqs/m3jxvv2YVAHc/NcxIqU4EdOWS5NMOpqGwzbgqZsYxGSy6JG2TtR1ZmlI2rWmHuh9iqDgcs834c6i1plwPaEnblOoB6zqz0rxYCCGEEOJ5kGBskTlcfn7ujEPKMXGD8JSnhx2YqPLzPeMYStGWcUhYBoaKb+zbMg6GUjy4e5wDE9VZ+02vqdnUk2ey6rN3tEIQRnTnk5TrAeFUpcWEZSCTus4OxwTHNLCm1m05ZlzQpVALGC66bB8qUa0HdGQT/JdLe3nnr6wF4BsP7GVbf4HmtMOKljTL8kmakhaletwHbt9YhZaMQ3dTkpa0g23GUxK78wn8UOPYJk0pm/GKR6nuM1b2ME0DyzCeVyEZIYQQQggROzfmGJ1Dzlbvoz2jFSZrHh3ZxJwZt3zaZqzssme0wsq2zKznj1xTk7ZN/nrLs2wfLMXFJCKNYcYV/txQMmRnkqVATa3bijQYU42dq/7hIhz7x6qMljz2T9QYm1oDdvfT8VTXtozNjsES49W4CqKpFJGGlozD269ZRS5hU/MD7n5qeFYBi1de2HW4z9h4lVI9IO2Y9LWkuHRFixS3EEIIIYQ4AyQYW2TOZu8jpUEfs7j5yQdRg8U64xWP5pRFGMFkzcMLNIahcMy4wIR4/hIGmKbCjyAKNZahCMMQd0bRSgMaLQkmqh6P7J3gaz99jiCIe4Q9frBAzQvJJi1s08IPIyYqHo/sGecNF/dw4bI8AOs6ckcVsIB42myp7lN2A7JJi1zCluIWQgghhBBniARji8zZ6H0UTTXvTdgGYyWXnmbjqOp7hapPc8pmTXvmqP13DZcapb/rQYjrh+wZq+JYJvlU3GNsourjBhEKjRNGlD2prPh8+REkHZNMQhFFUKz7BDPeVkXc4NkLI7KJONCq+yGP7p1geUsKL9DUvJDWjNMI6hOWSUcuwcGJGlueGeYla9sxDHXMAhZS1EIIIYQQ4uyRYGwROpO9j6YDqV3DJSINE1Wfqh/R1ZQgl7TjCns1n0jDFavb0MD2wWIjO7J7tMw3HtjLeMVjWT5J2kkxXKzzzEAJL4zwgpDWTILufBKASGtqXsChiTpNKYvhkncKOTcxUwSU6nFGKoz0VEA1+91UxMG264ckHRM3iCjWA8puQKEWkEtaR01LDSJNJmHRP1nj0GSN3uaUlHUXQgghhFgAEowtUmei99Gu4dKsQOola9v42XNjjJZd+ifr5FMBjmViGgZrW1OgNX/2/Weo+AEZ22JTbxMTFZ/xisf6zsNl9rvzSdqzNjsGy4SRZrTskrJNskmbbMJkourj2AaXrGjh8YOTTFQ83ODYEyTF3BRxQOaHEfmkSaEeMd1XWwGmAq3i4IowIomJ1hpF3Duuf7JOS3r2usPpiojt2QSmAc8MFPm3rf2NrGfSiqsq3rBJ1oQJIYQQQpxtEowtYs+n99HMfmXTgVQuafPS9e3sHCqxe7SKYRis7cjQ25Ji90iFB3aPEc7oFbZjqIQfRFy5pnVWduXJQwV2DlcaxTpUCGEUUvVDJiom3c1JunIJmpI2+ZRD0jLpL9Rwpfz9KTEVhBrqfkTSMsg6JoaKqHpRPEXRUCitCYEw1ARBRBBputIOr97UzXPDZUZKHi0ZG9s08MOIcj0g5Vj0Nicp1gO+/+QAXhA1sp5VL2Bbf4H+Qo23X7NKAjIhhBBCiLNIStufo47Vr6w1k+CK1W38ynkdrOvI8I5rV0MEu0cqcf+xpE1rxiGXtAkjzXjV47nhylQTYNg9Uubnu8fwggjHjAMGc+pTpLUikzB52bp2rlnbTrEe0JyyKNR8DMmLnTYNFOsB9WC6omL8WBTFjZkVEGkoewGWaXDt+jZ+/eJeXnF+JwnboO6FTFQ96n5EZ1OSi5fnqXoRrh/h+iHrO7PkkjamEQfs6zuzjFc8fvjU0NQxhBBCCCHE2SCZsXPU4X5lR1ddVErR2ZSg6gVM1Dy+/+QAFTdeX5QywTHjPmSt6bjH1IGJKsWaTy5p8+i+cbwgImEp4lAA0o6FoTQVP64ucWiyyq9e0MlAsc5YxWWi6ksodhoiDq8Qs0wwlcKxDYJIoyON1hDqePqnBmzT4NK+Fm68ciWWZfCWq1ZQD0IOTdZoSTvkkhaWoRgsuiRsgyAy6GlOnbC5uBTxEEIIIYQ4OyQzdo6a2a9Ma02x5jNadinWfLSOq+ztGi7z7m9vZbjsUfEjBkse2wYrPN1fjPuZ2SbZpEXVCxmruOwaKTFeiQtyuL6mHmiCSFPxfEpuSBhGjFc9Hts/yY+eGeFXN3Sya7gkgdhpMIizXQCOAZ0ZBxT4kSZtG1iGYjqGMhSkbYPXbFrGn/6nCxpTC9d15vida1dzxao2DKUYr3gUagGbe/O89qJlOJZxxpuLCyGEEEKIkyeZsXPUdL+yn+8ZIwgiJmo+QRRhGQYtKZuDkzUOTtTmDJTKXsiu4RLrOnPkUxaFqs8v901SD0LqM9d9TaXGghBQmulif6ZpsGeszKGHq0xU5Wb+dExXsDeA87pzFGsBXhAQ6bhipQIcy2BZPkXKMbhmbTsfuGEDlmUQRXpW4Zc/eNkaBor1WYVgDk3WuNMaPOPNxYUQQgghxMmTO60l7sgb7+mKi4ah2LAsx79uPUSp7tOWccinbGpeyHOjFUbLbmOa4VwBWdWPGC5UUIaBbRpo4mzakUIdv0Yjk6MhlzDpbU7yL48eOqvX/kKwpiMdTyNUcbYqjDSGUnhBRIQmn7K4sCfPm17ch2UZR/WEm1kdcUN3U+N1z2ZzcSGEEEIIcXIkGFvCjnfjvaY9y/aBEsuaknRkHSaqPoWaj2UYpB2jMQXOVHEQNVeL5tFKQNIxacsk6M45KMAtuBwZkmnioGxazQ340fYRvFAmKJ6IQfz+OabCMRVuqAkjjWUo0o5J1QvRGrqbktT9kPGKT80PMQ0Iw3id2M0vWcm6ztxRrQyOVx3xbDQXF0IIIYQQp0aCsSXqRDfer97UzXMjZdZ3ZckmLEr1AC+McEyDrQcm2DtWi19ITVXni47OkAU6Lpne25zgwEQdrcG2FZEfbzlXqJWyDZRhMlKondXrP1dExAGxG2q8MJ5+qFRcmCMCxiseq9szKKVIORY9tonrh4xXfdKOQSZhMln1CYLoqFYGALmkTTZhsXO4zA+fGmJNe7YRYB3ZXHywUCfUmmX5JNddEAf0QgghhBDi7JFgbAmaq4cYzL7x3vLMEDU/oGeOaopNyRnDPj1X8Rj8MOLR/ZP4ocZQEEZx8KaIg7WZsraBMhTDxRqSFDt50++VASgjzlTqCGpTxTNK9ZCEHTZ6hY3X4uxYGEVsO1Tkq/c9x7rOLLtHK6xoTZ9SdcTp5uI/e26Ue54eZqBQY6hY519/eYgnDhSk+bMQQgghxFkkwdgSdKweYnD4xvvQZA009E9WGSi4TFQ9gjDCMg3ySQtbga/jgGp6qtyRMhZUAgimoi6T2VX+jlT255rsKE6GAowZtU3VVOBrm4p8yqLuxw2by25Aoeaj0dhTOwyX6kzWPEbLHp25JLnk0a+fckyGpop4HGn3aJn/2DbIeMWjtyVF2rGk+bMQQgghxDyQ0vZL0OEeYscuS24qRco2+cXeCYaLNepT+9S9gNGySypxeN+5gqukpXCPiK18TaOnlSS+ziwFaD09bVFhTU0lTFomacdgWT5BGGnGyi6uH6GjuMx9wo7XeZXdkJoXsmOo2GjQPdOxqiMemWWV5s9CCCGEEPNHMmNL0MweYscqS24bqjHlbGYhDUU8zTCXtLl4eZ5nh4rU/Nk32mnbABRBdHT1RMl9nR3TAa6pFIZSBGGEYSgsU7FvvEapXsIPo6lsGTBdeCXScSbLD7FNRf9EjWLNJ592Dr/2caojnkyWVZo/CyGEEEKcHZIZW4Kmy5IPFOpHZUG01vx8zxj3bB/mob0Tc1Y0jDSUXR+A//nWy9nQlSGbMOnI2mzsStOStvHDOOySWnpnj2WAbUDSViSnGjlD3EfMNOPsmGEomhI2tqka6chQg6UU+aSJBiaqPtmEiWOZKAW7RsqU6nFfuVLdZ+dw+ZjVEU8myyrNn4UQQgghzg7JjC1BxytL/vM9Yzw7WCY4zrSylK2o+5qdQyVylsVLz+vkh08NorXGtCyqvt+Iwqbre5gqXtN0ZKsxSx1dyEOcmG0qkpZJFEWYpsI2DYIorqaYsAxqfojrxyUuJ6ouLSmLKNJ4YQTEQZptGhgG1PwQreMM6YrWDBcuyzNadhkq1klYJpt787xq49yFOE4myyrNn4UQQgghzg65w1qijixLPlSsYxkGhyZqRJGOC23MsZ8GXF9jGVD3I750/y6UUrhBRLHmM1718cOQMJy9j1JMTWObHXlZpiIMtKwhO0mKOBBzLAPTUDiWSRBqEqaiNeNgKkV/oUaxHg/AcNkDYLwaYBrgmAZhpAmiuB+ZaSh8rakHEV4QcXFfM+9/1fkMTBXrmNkIfC7S/FkIIYQQYuFIMLaETZclPzRZo+IFPLR7lDufGsAyQCtFdIz68iFxUBABB8ervGRdBxnH5MlDBfona7hTM9Jmhl7h1PqkmUzANAyUihsTi+ObnhMcRBoVRmituXBZM0MlFwVU3JDRsjvn1FINBBFEUYRtQhDGBTxAEWkdV0JsTvEbl/ViWcZJr++S5s9CCCGEEAtH1owtcYah6GtNs6G7CT+cqoyo4mmFxxNEcbDVkUuwY7DEjqEyhlIkbRNTxWuZMraiJWXhmIpIx6XWZwqBihces9S9mC2a/qPBDTSuH2FbBud35XjrS1ZiKOYMxI58jSCMi7AEYbwmLIw0vfkk775uPed1NZ3yeU1nWTf15Jms+uwdrTBZ9dncm5ey9kIIIYQQZ5Fkxs4h3fkEphFnxEzTQBEed/qgoeDQRJWIOAizpvpWJWwDP4gIUZgaHMvAC4+urCiev+eGy5iG4sfPjlA+ckHecSRtE8tU5JImL1nXxu9du5bzuk8/aDoyy3qi6Y1CCCGEEOL5k2DsHPKqDd105XZwcKIGQYhjKtxjZFoU8XqvwZJHyjYo1gP01NqjrGNS0ZBOmBBBoXq4kp6pIJOw0FpTdo8f7InjMw3on6yfcrsAZcDqjgwv6mvmugu6uGZt+xkJmqazrEIIIYQQYn7INMVziOOY/O5L15ByLAIN4THmD6Ztg/xUdb64n5VBaiozFkWakhtgm4p80mZdVxZDgW0oklZceCJlG+SStgRiz5Mbnl7ftpVtGT78mg28/ZrVdOQSHJqsSVNmIYQQQoglSDJj55ibrl4FwFfu28VQ0W08bijIpyw29eTZ3NPEd7f2U6wF2JbCUHG1RMcycExFzY9ImAAaP9RTFQAhQmEbCtNQVKXv1IKwFFy7tpVf7Jlg9+hB6kFI0jJZ25Hlhk1zl68XQgghhBCLkwRjS0gU6ZNa03PT1av4zcv6+NYv9nH7Q/tJ2QYrWtO0Z5M0pWxK9QDbNDCN+DUjHZcxDzUYhoFlghdFBBFkHBMAPwLHVCQdE1DUfFlDthDWdqQYqwYMl4ssyydJOymqXsC2/gL9hZoU3BBCCCGEWEIkGFsidg2XuPPJQZ48VKDiB2Rsi829eV69uXvWzffMgG1te46uXJLdoxWqXhnLrNKSdmjLOjimIuVY+GFEFEVUgjg7lnZMOrIOAwWXaKriomMZeEFEKmnEzYlDfcwpkOLsWdWa4pp1XQwU66zvzDZ6guWSNtmExc7hMj98aog17VkpvCGEEEIIsQRIMLYE7Bou8YV7dvLsUGlWELRnrML2oRLvvX496zpz7BouNZpAj5ZdDoxXiYirI2qtMRQMF+sMFeuU6gFtGYcw0hTqPhrQGipuwETVw1CK1oyNbRlcuqKFx/ZPUHIDwgg0cdZMzA9TwZuv7OP3XrqWL96zk2X55KzmzBA35F6WT7JruMyhyZoU4hBCCCGEWAIkGFvkokhz+8/38/iBSRwrLpxhmwo/1JTqPo8fmOTbD+3nN6/o4x9+to/xikd3U5L+yRpaayzTwFCKjGNSDyKU0tS8iLRj0ZKxKdYCTKXQCsIoou7HfcNySYuNPXlSjslAoc6FPXl2j5Qp1HxO0ApLnEGv2djBX73xUpJJi+2DRepBSNpJzbltyjEZKtapyHo+IYQQQoglQYKxRe7ARJWf7xnHUIq2jNPIiCQshZNxGCq6PPjcGIZSjFc81ndmKdUDxisufqSp+T5hBK3pNC/qa8WPNF4QMV5x6Z+sU3ID+lrTRFozMFnHNzXZhEXKNtk3XuXylS20ZWye7i8Sao1jKWq+RGPz4Q9ftpoP/NqFjb9nHIukZVL1AnJJ+6jta15IwjLJOPK1FkIIIYRYCuSubRHzvJA7Ht7PwYkKzSmHKIowTbPxvFKKfNpmqFDnqf4iG5blUErxi71j7ByuzCo9P17xqPsRL9/QRRBFjJZd8imbtGNS8ULqfogXRuTTNp3ZJIYR77N/vMrTA0VGSnW8IEKWip08y4BNPTl2DlepnEJDZ4A3XbpsViAG0NucYm1Hlm39BbIJa9ZURa01A4U6m3vz9DbPnTkTQgghhBCLiwRji9T/9+Be/v4nexgo1PBCTaleY6hYpzufojufnLGlRmuNF4WkHYsfbR9iW3/pqNeLgCcOFUnYJpt68xgKko7BZctaqHohQ6U6T/UX6MgmMFRcLXGs7HL/jhpVLzxm82gxt6RtsHFZjua0w0DRO6Vg7GXr2vnsmy496nHDUNywqYv+Qo2dw2WW5ZOkHJOaFzJQqNOacXjVxi4p3iGEEEIIsURIMLYI/cPP9vC5O3fghiFJ08QP4xt5L9QcnKwC0J1PorWmUPXJp21aUw4Hxys81V885utq4PEDk+STJms7c4wUXWp+SFMqnvK2265QdgMmqj6TFU8CsBkMFff4Mk0DBQRRRKjjcv9hqAmm3qq0Y7K5N88f/MoauvMpijWfv7p7B6Ml96TW2r3rZav54BEZsZnWdeZ4+zWrGoVahop1ElZ8zFdtlD5jQgghhBBLiQRji8zThwp8/oc7qXohtqUItMYyFMHU/MAogsFCjaakQdWLpw1eu66D1ozN//75vsY0QgXMde/vhprBostvXL6CX+6bZP94hfO6LHJJi6RtsHOohOvHgcaxXuOFRAFpx2BTT57u5hTNSYutBybZP1HF9SMs08A2wTIV+WRcffLCZU28bH0nhqGIIs2m3maeOFikNlUc5VjH+dpvX8r1m5ad8JzWdeZY8/LsSfWcE0IIIYQQi5cEY4vIruESf/Yfz1B2fWxTYRsKTZyVMVRcel4TB1RDJY/mlMPFPTluvGoFA4U6f/+TPSd1nEI94N8e78cLIkZKLhU3ZF1nhqobUPMipGr9YY6luHptOxt78gAUaz5uqFnWlMINIjb2NuGYBo5lkLBMQDNR9Rvl5Q1D8cbL+vjxsyPsHasS6YgwpPEeKyBlG7x6Uze/emH3SZ+XYSgpXy+EEEIIscRJMLZIRJHmrm1DjJY9tI4zLUopFGBP1ezQgI7iKXHNaZs3XNzLDZviqWlBpGnPOhTqh8uaK+JGzgYQ6cMBwLJ8kjXtWapegBtEFGs+Ww9Osn+iBjO2fyFLmIpswqY167ChK0ux5uOFEWU3wAsCFAZd+SSr2jKzCmkEUcRwyaVU9zkwXm1krv74hvP5i7t20D9ZIzA0GrAMRVPS4tIVrfzhK9ZJZksIIYQQ4gVGgrFF4tBkjedGynTnE+waLhFGYEwFYUopLDMOkCzTwI80N165gpuuWt24gc84Fpt68uwfq+LruFFwI0ZQimhqwZJjwOUrmjENRS5pc0lfMzsGiuwYKhGFESYSiAE0pWzOW9ZMGGl++Mxwo9m2H0ZMVDzacgnWdmSPar5c80LcIOJ7j/UzWnapByFJy2RtR5b333A+D+0e56n+An4U0ZJyuLivmRs2dctaLyGEEEKIFyAJxhaJihdQD0Iu6GrisX2TlN0AyzAaN/sKiLSmHkX0Nqd58+UrZ2VSeptTnNfdxLaBIrtHKgQaTOKALJxROeKi5XksKx52rTXb+gs8tHuMiieTE2da3pzkzVes4P9u7Wdgsg6AQmMbCscyqXsRWs+OWrXW7BwuU6z5WIaipzlF2klR9QK29RfoL9S4+epVvNVZJWu9hBBCCCGEBGOLxXRDXzeMuHRlCw/sGqXmR9imgWlAEGr8UJNxTN5x7Wocx5y1/8yy5wAHxqp4kZ5VgaMpaWFbFuMVD9D8aPswh6YCDREzpv57YU8zOwZKhJHmho1dlN24D5tjGnhhyI+fHeXhveNcs7aNdMKi5oX0T9Yp1nyakjbndeUagXQuaZNNWOwcLnPPM0O881fWSgAmhBBCCCEkGFssZjb03dwbF4v45b4JKl6AF8QZrqaUzR+9cj03Xb1qzteYLnvek0/xyP4xtu6bxAsjckkbW2ly6QQjpTqjZZey6zNQcOfxCpeGjGMCIUPFOocKHr0tKQzDoCllzNjK5sWrWtg+WKJ/so5lKhKWyYq2FEEUsaI1fdT0RaUUy/JJdg2XG8U9hBBCCCHEC5sEYwsoivSs8uSv3NjZaOi7uj3Dhq4czwwWGSy6tGcd/n+vuYALpwK1Y1nXmWPVyzIU7vLxA826jiy5pMWj+yYZLtVpSds8N1phsurP01UuLR1ZG/Co+iG+jkg7c39FljWnqPsRb3pxH935JBnHouT6/M2Pdh1zn5RjMlSsU/GCOZ8XQgghhBAvLBKMLZBdw6VG496ZRR5+dUMn2wdKPDdSxg1CWjMJrljddkoNfQeKcfbrvK4cuWTc0HltZ4aS6zNccqkfp9/VC1l7xm5UTUnbJoE2qHpB4z2cqeaFJO14zKazXAfGqyQt87j7JCyTzDGCNSGEEEII8cIid4ULYNdwiW88sJfxiseyfHLOIg+vd3qOWeThyIxaVzbB1kOTjFU8WtM2JTdguFwnm7DQWqOUojWT4EV9zTxxcJL+ydoCXv3ilLYNeltSREEIwMaePBEGTw0UySasWdMOtdYMFOps7s3T25xqPD5zqunJ7iOEEEIIIV64FkUw9uUvf5nPfe5zDA4OcvHFF/OlL32JK664Ys5tv/a1r/G///f/Ztu2bQBcdtll/Nmf/dkxt19spvuJjVc81ndmT7nIw5EZtYmKR/9kHTcICUKNF0bYpkJrGJis05lLsq4zS2vGAcA0DCQpNlvWMVjZnmGyGpB14vf8ugs6MS2LgWKdncNlluWTpByTmhcyUKjTmnF41cauWWM0s4jKye4jhBBCCCFeuIwTb3J2/dM//RO33XYbH/vYx/jlL3/JxRdfzA033MDw8PCc29933328+c1v5t577+XBBx+kr6+PV73qVRw6dGiez/z0TPcTW5ZPnrDIw5GmM2rb+gs0p20M4On+IoPFGlUvJIjicutVL6LqhxRrHsOlOlsPTLJntMzWA5OMFOvEraTPfceLeWwTMrZB0jLIJG3Gyh6GUrxkTRsAazqyjYIom3ryTFZ99k6ttdvcm+ft16yac9ro6ewjhBBCCCFemBY8M/b5z3+e3/u93+Ptb387AF/96lf5/ve/z9e//nU+9KEPHbX9t771rVl///u//3v+z//5P2zZsoW3vvWt83LOz8d0P7G0M/dUtWMVeTgyo6Y1PHGwQBBpWtM2k7UADbSk4rVKkzWfqh+RdUKKtYjH9nkopal4IY5l4Hvh2b7UBWMb0Jx2iCJN0Q0wFZiGIog0CcvkilXNjJR9JisefhSxrjPHmo4M113QxRUr8tx55+7Ga63rzLHm5dlZ00JP1BvsdPYRQgghhBAvPAsajHmex6OPPsqHP/zhxmOGYXD99dfz4IMPntRrVKtVfN+ntbV1zudd18V1D5dwLxaLAPi+j+/PT0XB6eP4vk/SgIylqLse2eTRb7/rBqQtRdJg1vkdmqixd6RIb5ODQcRAsUbN9cgnDUwFtooAhaUiLNOgJWVS90LySYuKFzBScWlJ2yQt6Mo6DBTq1IJzp9GzpaAjl8CxDCYqPqaOC2zoCLwwImmaKMtgVXuKjctyaK15aqDIytYMv33VykawNHOsZurO2UAc6IZhQHgSsezp7CNOzrHGSSw+MlZLg4zT0iFjtTTIOC0dCz1GSmu9YEuI+vv76e3t5Wc/+xlXX3114/EPfOAD3H///Tz00EMnfI0//MM/5K677uKpp54imUwe9fzHP/5xPvGJTxz1+O233046Lb2ehBBCCCGEeKGqVqu85S1voVAo0NTUNO/HX/Bpis/HZz7zGe644w7uu+++OQMxgA9/+MPcdtttjb8Xi8XGOrP5esN93+fuu+/mla98JbZts3ukzD8+tJ+Jikd3U5KUY1DzIgaLdVoyDr995QrWdGRnvcahiRpfvncX+ZRNNmkxUKjxo2eGsS0DUykKNQ9Q5FMWlmngBhF+EPGrGzpRSvGLveNsXNbEnrEqhoLhUp2aFy7J7JgCljcn+S+XLmdTb57/9/hA430BmKh67B4pM1ryqPkBfqhZ2ZqiKeXgWAYJy2RNR4Zf3dB51Pt85FiJxUnGaemQsVoaZJyWDhmrpUHGaekYGxtb0OMvaDDW3t6OaZoMDQ3NenxoaIju7u7j7vsXf/EXfOYzn+Gee+7hoosuOuZ2iUSCRCJx1OO2bc/7l2P6mOf3tHDzNVajKqJb8khYJhf2thyzn9iKdotVHU1s6y+wPunQ2ZQhlXAYq3g0JU18HVdJDLRBEECxHtGWdehoSrFrpEpPSxY3UmSTDsNlF9O0iBREWuMvonhMwZzVHk3AMOM1Vz3NKT7yho28dF0HAE/2Vxrvi1KK5kyKS9JJijWfXSNlLuxp4o+vP5+hsnvSa7gW4vMhTp2M09IhY7U0yDgtHTJWS4OM0+K30OOzoMGY4zhcdtllbNmyhV//9V8HIIoitmzZwq233nrM/T772c/yqU99irvuuovLL798ns72zDrVIg9zlU3fvDzPT3eOMl71SVgmhoKyGxBEkLQNzuvK8txolbaswxsvX86Ptg9T9UMsQ+GpuNqgZRpoIs52gsyauiytAQW2adCUNEknbCxTMVnxCDXkkxZ+GDFSchtBomXE52kZip7mFB949QZ+5bzOxmsfq5z8UMllZVuGN13eh+OYjebMQgghhBBCLAYLPk3xtttu4+abb+byyy/niiuu4Atf+AKVSqVRXfGtb30rvb29fPrTnwbgz//8z/noRz/K7bffzqpVqxgcHAQgm82SzWaPeZzFyDDUKQUI02XTpzNqABf2NM3qMxbpiFzSZEVriqakw7rObCPbtrItzV3bhnjswAT7x6v4ocY0jLgvGVCq+XhhBBEYBiRskyCKqPmnv6zQUpBJWLRnE7RkbArVgEhr2rI2vc1p1nfleNXGLvaNVfnmA3vZO1Yh1NCaTZCwDFrSDralsA2TTb1N/NfLl3Ne1+zppUe+L0PFOgnLZHNv/piZRiGEEEIIIRbaggdjv/mbv8nIyAgf/ehHGRwc5EUvehF33nknXV1dAOzfvx/DONwO7Stf+Qqe5/Ff/+t/nfU6H/vYx/j4xz8+n6e+IObKqHVlE2w9NMlYxaM1bdPZlMQNoqOybTP3LdV9ym5A2jGpeiHZpEXaMukv1nhuuELSNnnxqhZ6mlI8vGecf3viECMlF6U0Kcsk1JCyDUxTkbEtvCgin7LpzCVJOAajZY+EabKuK8u6jri5dc0PSdsmGqj54azzW9eZ41fWd/DLAxOMVTzaMg4v6m0+6amFUk5eCCGEEEIsNQsejAHceuutx5yWeN999836+969e8/+CS1yc2XUrljddtr7zrSqI8tL1nbMeuza8zu49vyOY+xx5liWcdR1nErm8FQzjUIIIYQQQiwk48SbCCGEEEIIIYQ40yQYE0IIIYQQQogFIMGYEEIIIYQQQiwACcaEEEIIIYQQYgFIMCaEEEIIIYQQC0CCMSGEEEIIIYRYABKMCSGEEEIIIcQCkGBMCCGEEEIIIRaABGNCCCGEEEIIsQAkGBNCCCGEEEKIBSDBmBBCCCGEEEIsAAnGhBBCCCGEEGIBSDAmhBBCCCGEEAvAWugTmG9aawCKxeK8HdP3farVKsViEdu25+244tTJWC0NMk5Lh4zV0iDjtHTIWC0NMk5LR6lUAg7HCPPtBReMTb/hfX19C3wmQgghhBBCiMVgbGyMfD4/78dVeqHCwAUSRRH9/f3kcjmUUvNyzGKxSF9fHwcOHKCpqWlejilOj4zV0iDjtHTIWC0NMk5Lh4zV0iDjtHQUCgVWrFjBxMQEzc3N8378F1xmzDAMli9fviDHbmpqki/kEiFjtTTIOC0dMlZLg4zT0iFjtTTIOC0dhrEwpTSkgIcQQgghhBBCLAAJxoQQQgghhBBiAUgwNg8SiQQf+9jHSCQSC30q4gRkrJYGGaelQ8ZqaZBxWjpkrJYGGaelY6HH6gVXwEMIIYQQQgghFgPJjAkhhBBCCCHEApBgTAghhBBCCCEWgARjQgghhBBCCLEAJBgTQgghhBBCiAUgwdg8+PKXv8yqVatIJpNceeWVPPzwwwt9SuesT3/607z4xS8ml8vR2dnJr//6r7Njx45Z29TrdW655Rba2trIZrP8xm/8BkNDQ7O22b9/P6997WtJp9N0dnby/ve/nyAIZm1z3333cemll5JIJFi3bh3f/OY3z/blnbM+85nPoJTive99b+MxGafF49ChQ/z2b/82bW1tpFIpNm/ezCOPPNJ4XmvNRz/6UZYtW0YqleL6669n586ds15jfHycG2+8kaamJpqbm3nHO95BuVyetc0TTzzBS1/6UpLJJH19fXz2s5+dl+s7V4RhyEc+8hFWr15NKpVi7dq1/I//8T+YWadLxmr+/fjHP+Z1r3sdPT09KKX43ve+N+v5+RyT73znO2zYsIFkMsnmzZv5wQ9+cMavdyk73lj5vs8HP/hBNm/eTCaToaenh7e+9a309/fPeg0Zq7PvRN+pmd75zneilOILX/jCrMcX1ThpcVbdcccd2nEc/fWvf10/9dRT+vd+7/d0c3OzHhoaWuhTOyfdcMMN+hvf+Ibetm2b3rp1q/61X/s1vWLFCl0ulxvbvPOd79R9fX16y5Yt+pFHHtFXXXWVfslLXtJ4PggCvWnTJn399dfrxx57TP/gBz/Q7e3t+sMf/nBjm927d+t0Oq1vu+02/fTTT+svfelL2jRNfeedd87r9Z4LHn74Yb1q1Sp90UUX6fe85z2Nx2WcFofx8XG9cuVK/ba3vU0/9NBDevfu3fquu+7Su3btamzzmc98Rufzef29731PP/744/r1r3+9Xr16ta7Vao1tXv3qV+uLL75Y//znP9c/+clP9Lp16/Sb3/zmxvOFQkF3dXXpG2+8UW/btk1/+9vf1qlUSv/d3/3dvF7vUvapT31Kt7W16X//93/Xe/bs0d/5znd0NpvVX/ziFxvbyFjNvx/84Af6T/7kT/R3v/tdDeh//dd/nfX8fI3JAw88oE3T1J/97Gf1008/rf/0T/9U27atn3zyybP+HiwVxxuryclJff311+t/+qd/0tu3b9cPPvigvuKKK/Rll1026zVkrM6+E32npn33u9/VF198se7p6dF/9Vd/Neu5xTROEoydZVdccYW+5ZZbGn8Pw1D39PToT3/60wt4Vi8cw8PDGtD333+/1jr+x9S2bf2d73ynsc0zzzyjAf3ggw9qreMvuWEYenBwsLHNV77yFd3U1KRd19Vaa/2BD3xAb9y4cdaxfvM3f1PfcMMNZ/uSzimlUkmvX79e33333fpXfuVXGsGYjNPi8cEPflBfe+21x3w+iiLd3d2tP/e5zzUem5yc1IlEQn/729/WWmv99NNPa0D/4he/aGzzH//xH1oppQ8dOqS11vpv//ZvdUtLS2Pspo99/vnnn+lLOme99rWv1b/zO78z67H/8l/+i77xxhu11jJWi8GRN47zOSZvetOb9Gtf+9pZ53PllVfqP/iDPzij13iuON5N/rSHH35YA3rfvn1aaxmrhXCscTp48KDu7e3V27Zt0ytXrpwVjC22cZJpimeR53k8+uijXH/99Y3HDMPg+uuv58EHH1zAM3vhKBQKALS2tgLw6KOP4vv+rDHZsGEDK1asaIzJgw8+yObNm+nq6mpsc8MNN1AsFnnqqaca28x8jeltZFxPzS233MJrX/vao95LGafF49/+7d+4/PLLeeMb30hnZyeXXHIJX/va1xrP79mzh8HBwVnvcz6f58orr5w1Vs3NzVx++eWNba6//noMw+Chhx5qbPOyl70Mx3Ea29xwww3s2LGDiYmJs32Z54SXvOQlbNmyhWeffRaAxx9/nJ/+9Ke85jWvAWSsFqP5HBP59/DMKxQKKKVobm4GZKwWiyiKuOmmm3j/+9/Pxo0bj3p+sY2TBGNn0ejoKGEYzrpZBOjq6mJwcHCBzuqFI4oi3vve93LNNdewadMmAAYHB3Ecp/EP57SZYzI4ODjnmE0/d7xtisUitVrtbFzOOeeOO+7gl7/8JZ/+9KePek7GafHYvXs3X/nKV1i/fj133XUX73rXu3j3u9/NP/zDPwCH3+vj/Ts3ODhIZ2fnrOcty6K1tfWUxlMc34c+9CF+67d+iw0bNmDbNpdccgnvfe97ufHGGwEZq8VoPsfkWNvImJ2eer3OBz/4Qd785jfT1NQEyFgtFn/+53+OZVm8+93vnvP5xTZO1iltLcQScsstt7Bt2zZ++tOfLvSpiCMcOHCA97znPdx9990kk8mFPh1xHFEUcfnll/Nnf/ZnAFxyySVs27aNr371q9x8880LfHZipn/+53/mW9/6FrfffjsbN25k69atvPe976Wnp0fGSogzyPd93vSmN6G15itf+cpCn46Y4dFHH+WLX/wiv/zlL1FKLfTpnBTJjJ1F7e3tmKZ5VAW4oaEhuru7F+isXhhuvfVW/v3f/517772X5cuXNx7v7u7G8zwmJydnbT9zTLq7u+ccs+nnjrdNU1MTqVTqTF/OOefRRx9leHiYSy+9FMuysCyL+++/n7/+67/Gsiy6urpknBaJZcuWceGFF8567IILLmD//v3A4ff6eP/OdXd3Mzw8POv5IAgYHx8/pfEUx/f+97+/kR3bvHkzN910E3/0R3/UyD7LWC0+8zkmx9pGxuzUTAdi+/bt4+67725kxUDGajH4yU9+wvDwMCtWrGjcX+zbt4/3ve99rFq1Clh84yTB2FnkOA6XXXYZW7ZsaTwWRRFbtmzh6quvXsAzO3dprbn11lv513/9V370ox+xevXqWc9fdtll2LY9a0x27NjB/v37G2Ny9dVX8+STT876ok7/gzt9U3r11VfPeo3pbWRcT851113Hk08+ydatWxt/Lr/8cm688cbG/y/jtDhcc801R7WHePbZZ1m5ciUAq1evpru7e9b7XCwWeeihh2aN1eTkJI8++mhjmx/96EdEUcSVV17Z2ObHP/4xvu83trn77rs5//zzaWlpOWvXdy6pVqsYxuz/WTdNkyiKABmrxWg+x0T+PXz+pgOxnTt3cs8999DW1jbreRmrhXfTTTfxxBNPzLq/6Onp4f3vfz933XUXsAjH6ZTKfYhTdscdd+hEIqG/+c1v6qefflr//u//vm5ubp5VAU6cOe9617t0Pp/X9913nx4YGGj8qVarjW3e+c536hUrVugf/ehH+pFHHtFXX321vvrqqxvPT5dMf9WrXqW3bt2q77zzTt3R0TFnyfT3v//9+plnntFf/vKXpWT68zSzmqLWMk6LxcMPP6wty9Kf+tSn9M6dO/W3vvUtnU6n9T/+4z82tvnMZz6jm5ub9f/9v/9XP/HEE/oNb3jDnKW5L7nkEv3QQw/pn/70p3r9+vWzyghPTk7qrq4ufdNNN+lt27bpO+64Q6fTaSmXfgpuvvlm3dvb2yht/93vfle3t7frD3zgA41tZKzmX6lU0o899ph+7LHHNKA///nP68cee6xRgW++xuSBBx7QlmXpv/iLv9DPPPOM/tjHPibl0o9wvLHyPE+//vWv18uXL9dbt26ddY8xs+KejNXZd6Lv1JGOrKao9eIaJwnG5sGXvvQlvWLFCu04jr7iiiv0z3/+84U+pXMWMOefb3zjG41tarWa/sM//EPd0tKi0+m0/s//+T/rgYGBWa+zd+9e/ZrXvEanUind3t6u3/e+92nf92dtc++99+oXvehF2nEcvWbNmlnHEKfuyGBMxmnx+H//7//pTZs26UQioTds2KD/5//8n7Oej6JIf+QjH9FdXV06kUjo6667Tu/YsWPWNmNjY/rNb36zzmazuqmpSb/97W/XpVJp1jaPP/64vvbaa3UikdC9vb36M5/5zFm/tnNJsVjU73nPe/SKFSt0MpnUa9as0X/yJ38y60ZRxmr+3XvvvXP+79LNN9+stZ7fMfnnf/5nfd5552nHcfTGjRv197///bN23UvR8cZqz549x7zHuPfeexuvIWN19p3oO3WkuYKxxTROSmutTy2XJoQQQgghhBDi+ZI1Y0IIIYQQQgixACQYE0IIIYQQQogFIMGYEEIIIYQQQiwACcaEEEIIIYQQYgFIMCaEEEIIIYQQC0CCMSGEEEIIIYRYABKMCSGEEEIIIcQCkGBMCCGEEEIIIRaABGNCCCHE87B3716UUmzdunWhT0UIIcQSI8GYEEKIefW2t72NX//1X1/o0zhpe/bs4S1veQs9PT0kk0mWL1/OG97wBrZv3w5AX18fAwMDbNq0aYHPVAghxFJjLfQJCCGEEIuV7/u88pWv5Pzzz+e73/0uy5Yt4+DBg/zHf/wHk5OTAJimSXd398KeqBBCiCVJMmNCCCEWlfvvv58rrriCRCLBsmXL+NCHPkQQBI3noyjis5/9LOvWrSORSLBixQo+9alPAXDfffehlGoESgBbt25FKcXevXsB2LdvH6973etoaWkhk8mwceNGfvCDH8x5Lk899RTPPfccf/u3f8tVV13FypUrueaaa/jkJz/JVVddBRw9TfFtb3sbSqmj/tx3330AuK7LH//xH9Pb20smk+HKK69sPCeEEOKFRYIxIYQQi8ahQ4f4tV/7NV784hfz+OOP85WvfIX/9b/+F5/85Ccb23z4wx/mM5/5DB/5yEd4+umnuf322+nq6jrpY9xyyy24rsuPf/xjnnzySf78z/+cbDY757YdHR0YhsG//Mu/EIbhSb3+F7/4RQYGBhp/3vOe99DZ2cmGDRsAuPXWW3nwwQe54447eOKJJ3jjG9/Iq1/9anbu3HnS1yCEEOLcINMUhRBCLBp/+7d/S19fH3/zN3+DUooNGzbQ39/PBz/4QT760Y9SqVT44he/yN/8zd9w8803A7B27Vquvfbakz7G/v37+Y3f+A02b94MwJo1a465bW9vL3/913/NBz7wAT7xiU9w+eWX84pXvIIbb7zxmPvl83ny+TwA3/3ud/m7v/s77rnnHrq7u9m/fz/f+MY32L9/Pz09PQD88R//MXfeeSff+MY3+LM/+7OTvg4hhBBLn2TGhBBCLBrPPPMMV199NUqpxmPXXHMN5XKZgwcP8swzz+C6Ltddd91pH+Pd7343n/zkJ7nmmmv42Mc+xhNPPHHc7W+55RYGBwf51re+xdVXX813vvMdNm7cyN13333c/R577DFuuukm/uZv/oZrrrkGgCeffJIwDDnvvPPIZrONP/fffz/PPffcaV+TEEKIpUmCMSGEEEtGKpU67vOGEf/Pmta68Zjv+7O2+d3f/V12797NTTfdxJNPPsnll1/Ol770peO+bi6X43Wvex2f+tSnePzxx3npS186a+rkkQYHB3n961/P7/7u7/KOd7yj8Xi5XMY0TR599FG2bt3a+PPMM8/wxS9+8bjnIIQQ4twjwZgQQohF44ILLuDBBx+cFUw98MAD5HI5li9fzvr160mlUmzZsmXO/Ts6OgAYGBhoPDZX/6++vj7e+c538t3vfpf3ve99fO1rXzvpc5yePlmpVOZ8vl6v84Y3vIENGzbw+c9/ftZzl1xyCWEYMjw8zLp162b9kYqMQgjxwiNrxoQQQsy7QqFwVJDU1tbGH/7hH/KFL3yB//bf/hu33norO3bs4GMf+xi33XYbhmGQTCb54Ac/yAc+8AEcx+Gaa65hZGSEp556ine84x2sW7eOvr4+Pv7xj/OpT32KZ599lr/8y7+cdZz3vve9vOY1r+G8885jYmKCe++9lwsuuGDO89y6dSsf+9jHuOmmm7jwwgtxHIf777+fr3/963zwgx+cc58/+IM/4MCBA2zZsoWRkZHG462trZx33nnceOONvPWtb+Uv//IvueSSSxgZGWHLli1cdNFFvPa1r31+b6wQQoglRYIxIYQQ8+6+++7jkksumfXYO97xDv7+7/+eH/zgB7z//e/n4osvprW1lXe84x386Z/+aWO7j3zkI1iWxUc/+lH6+/tZtmwZ73znOwGwbZtvf/vbvOtd7+Kiiy7ixS9+MZ/85Cd54xvf2Ng/DENuueUWDh48SFNTE69+9av5q7/6qznPc/ny5axatYpPfOITjRL203//oz/6ozn3uf/++xkYGODCCy+c9fi9997Ly1/+cr7xjW/wyU9+kve9730cOnSI9vZ2rrrqKv7Tf/pPp/VeCiGEWLqUnjkXRAghhBBCCCHEvJA1Y0IIIYQQQgixACQYE0IIIYQQQogFIMGYEEIIIYQQQiwACcaEEEIIIYQQYgFIMCaEEEIIIYQQC0CCMSGEEEIIIYRYABKMCSGEEEIIIcQCkGBMCCGEEEIIIRaABGNCCCGEEEIIsQAkGBNCCCGEEEKIBSDBmBBCCCGEEEIsgP8/2kIbanaDmocAAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plt.figure(figsize=(10, 6))\n", + "plt.scatter(panda_df[\"locusSize\"], panda_df[\"locusLength\"], alpha=0.5)\n", + "plt.title(\"Scatter Plot of Locus Size vs Locus Length\")\n", + "plt.xlabel(\"Locus Size\")\n", + "plt.ylabel(\"Locus Length\")\n", + "plt.grid(True)\n", + "plt.show()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "gentropy-iQynFIia-py3.10", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.14" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From 5b5b408e0c5ac30e361f344de52d317ef02234d2 Mon Sep 17 00:00:00 2001 From: Daniel-Considine <113430683+Daniel-Considine@users.noreply.github.com> Date: Thu, 8 Aug 2024 15:37:52 +0100 Subject: [PATCH 007/188] fix: updating config paths and fine-mapping methods (#725) * fix: updating config paths and fine-mapping methods * Update ot_locus_to_gene_train.yaml --- config/step/ot_locus_to_gene_predict.yaml | 2 +- config/step/ot_locus_to_gene_train.yaml | 2 +- src/gentropy/colocalisation.py | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/config/step/ot_locus_to_gene_predict.yaml b/config/step/ot_locus_to_gene_predict.yaml index a98e3cf2a..c3cb88b59 100644 --- a/config/step/ot_locus_to_gene_predict.yaml +++ b/config/step/ot_locus_to_gene_predict.yaml @@ -6,6 +6,6 @@ model_path: null predictions_path: ${datasets.l2g_predictions} feature_matrix_path: ${datasets.l2g_feature_matrix} credible_set_path: ${datasets.credible_set} -variant_gene_path: ${datasets.v2g} +variant_gene_path: ${datasets.variant_to_gene} colocalisation_path: ${datasets.colocalisation} study_index_path: ${datasets.study_index} diff --git a/config/step/ot_locus_to_gene_train.yaml b/config/step/ot_locus_to_gene_train.yaml index 25f3710c5..b59a24dae 100644 --- a/config/step/ot_locus_to_gene_train.yaml +++ b/config/step/ot_locus_to_gene_train.yaml @@ -7,7 +7,7 @@ hf_hub_repo_id: opentargets/locus_to_gene model_path: ${datasets.l2g_model} predictions_path: ${datasets.l2g_predictions} credible_set_path: ${datasets.credible_set} -variant_gene_path: ${datasets.v2g} +variant_gene_path: ${datasets.variant_to_gene} colocalisation_path: ${datasets.colocalisation} study_index_path: ${datasets.study_index} gold_standard_curation_path: ${datasets.l2g_gold_standard_curation} diff --git a/src/gentropy/colocalisation.py b/src/gentropy/colocalisation.py index 1d71ed447..6b370d426 100644 --- a/src/gentropy/colocalisation.py +++ b/src/gentropy/colocalisation.py @@ -1,4 +1,5 @@ """Step to generate colocalisation results.""" + from __future__ import annotations import inspect @@ -40,7 +41,7 @@ def __init__( credible_set = ( StudyLocus.from_parquet( session, credible_set_path, recursiveFileLookup=True - ).filter(col("finemappingMethod") == "SuSie") + ).filter(col("finemappingMethod").isin("SuSie", "SuSiE-inf")) if colocalisation_class is Coloc else StudyLocus.from_parquet( session, credible_set_path, recursiveFileLookup=True From e45f2950c0339dec0eaae31ffac920f0c20980cd Mon Sep 17 00:00:00 2001 From: Daniel-Considine <113430683+Daniel-Considine@users.noreply.github.com> Date: Thu, 15 Aug 2024 09:51:33 +0100 Subject: [PATCH 008/188] docs: macos fix for some functions (#729) * docs: macos fix for some functions * docs: formatting --- docs/development/troubleshooting.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/development/troubleshooting.md b/docs/development/troubleshooting.md index b9f7385da..a30f72be0 100644 --- a/docs/development/troubleshooting.md +++ b/docs/development/troubleshooting.md @@ -39,3 +39,13 @@ Another solution which helps is to remove Node, NodeJS, and npm from your system On Ubuntu, this can be done using `sudo apt remove node nodejs npm`, followed by `sudo apt autoremove`. But in some cases, depending on your existing installation, you may need to also manually remove some files. See [this StackOverflow answer](https://stackoverflow.com/a/41057802) for guidance. After running these commands, you are advised to open a fresh shell, and then also reinstall Pyenv and Poetry to make sure they pick up the changes (see relevant section above). + +## MacOS + +Some functions on MacOS may throw a java error: + +`python3.10/site-packages/py4j/protocol.py:326: Py4JJavaError` + +This can be resolved by adding the follow line to your `~/.zshrc`: + +`export OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES` From f49a5c52c6773450b2aa736b8d57e287e171a620 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 22 Aug 2024 09:35:11 +0100 Subject: [PATCH 009/188] build(deps-dev): bump ruff from 0.5.1 to 0.6.1 (#732) * build(deps-dev): bump ruff from 0.5.1 to 0.6.1 Bumps [ruff](https://github.com/astral-sh/ruff) from 0.5.1 to 0.6.1. - [Release notes](https://github.com/astral-sh/ruff/releases) - [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md) - [Commits](https://github.com/astral-sh/ruff/compare/0.5.1...0.6.1) --- updated-dependencies: - dependency-name: ruff dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * fix: linting issues associated with ruff 0.6 * chore: fixing imports for notebooks * chore: removing old notebook --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: David Ochoa Co-authored-by: Daniel Considine --- notebooks/FineMappingSimmuations.ipynb | 32 +- notebooks/FineMapping_AlzheimierDisease.ipynb | 51 +- notebooks/Finngen_PICS_run.ipynb | 2459 ++++++++--------- notebooks/Mapping_EFO_finngen.ipynb | 24 +- notebooks/Productionizing_LD_matrix.ipynb | 1504 ---------- notebooks/Release_QC_metrics.ipynb | 70 +- notebooks/gwas_cat_benchmark.ipynb | 273 +- notebooks/l2g_benchmark.ipynb | 603 ---- notebooks/pics_benchmark.ipynb | 1678 ++++++----- notebooks/susie_inf_benchmark.ipynb | 23 +- notebooks/ukb_ppp_benchmark.ipynb | 271 +- poetry.lock | 40 +- pyproject.toml | 2 +- 13 files changed, 2393 insertions(+), 4637 deletions(-) delete mode 100644 notebooks/Productionizing_LD_matrix.ipynb delete mode 100644 notebooks/l2g_benchmark.ipynb diff --git a/notebooks/FineMappingSimmuations.ipynb b/notebooks/FineMappingSimmuations.ipynb index d81b268e3..fcec9bbe9 100644 --- a/notebooks/FineMappingSimmuations.ipynb +++ b/notebooks/FineMappingSimmuations.ipynb @@ -82,7 +82,7 @@ "metadata": {}, "outputs": [], "source": [ - "ld_matrix = np.load('/Users/yt4/Projects/ot_data/tmp/ld_matrix.npy')\n", + "ld_matrix = np.load(\"/Users/yt4/Projects/ot_data/tmp/ld_matrix.npy\")\n", "ld_index=session.spark.read.parquet(\"/Users/yt4/Projects/ot_data/tmp/ld_index\")\n", "ld_matrix_for_sim=ld_matrix[0:500,:][:,0:500]\n", "ld_index_for_sim=ld_index.limit(500)" @@ -129,11 +129,8 @@ } ], "source": [ - "print(FineMappingSimulations.ProvideSummary(cred_sets=x1,n_causal=n_causal))\n", "x2=x1[(x1[\"pValueExponent\"]<=-6) | (x1[\"credibleSetIndex\"]==1)]\n", - "print(FineMappingSimulations.ProvideSummary(cred_sets=x2,n_causal=n_causal))\n", - "x3=x2[(x2[\"purityMinR2\"]>=0.25) | (x2[\"credibleSetIndex\"]==1)]\n", - "print(FineMappingSimulations.ProvideSummary(cred_sets=x3,n_causal=n_causal))" + "x3=x2[(x2[\"purityMinR2\"]>=0.25) | (x2[\"credibleSetIndex\"]==1)]" ] }, { @@ -177,11 +174,8 @@ } ], "source": [ - "print(FineMappingSimulations.ProvideSummary(cred_sets=x1,n_causal=n_causal))\n", "x2=x1[(x1[\"pValueExponent\"]<=-6) | (x1[\"credibleSetIndex\"]==1)]\n", - "print(FineMappingSimulations.ProvideSummary(cred_sets=x2,n_causal=n_causal))\n", - "x3=x2[(x2[\"purityMinR2\"]>=0.25) | (x2[\"credibleSetIndex\"]==1)]\n", - "print(FineMappingSimulations.ProvideSummary(cred_sets=x3,n_causal=n_causal))" + "x3=x2[(x2[\"purityMinR2\"]>=0.25) | (x2[\"credibleSetIndex\"]==1)]" ] }, { @@ -227,11 +221,8 @@ } ], "source": [ - "print(FineMappingSimulations.ProvideSummary(cred_sets=x1,n_causal=n_causal))\n", "x2=x1[(x1[\"pValueExponent\"]<=-6) | (x1[\"credibleSetIndex\"]==1)]\n", - "print(FineMappingSimulations.ProvideSummary(cred_sets=x2,n_causal=n_causal))\n", - "x3=x2[(x2[\"purityMinR2\"]>=0.25) | (x2[\"credibleSetIndex\"]==1)]\n", - "print(FineMappingSimulations.ProvideSummary(cred_sets=x3,n_causal=n_causal))" + "x3=x2[(x2[\"purityMinR2\"]>=0.25) | (x2[\"credibleSetIndex\"]==1)]" ] }, { @@ -277,11 +268,8 @@ } ], "source": [ - "print(FineMappingSimulations.ProvideSummary(cred_sets=x1,n_causal=n_causal))\n", "x2=x1[(x1[\"pValueExponent\"]<=-6) | (x1[\"credibleSetIndex\"]==1)]\n", - "print(FineMappingSimulations.ProvideSummary(cred_sets=x2,n_causal=n_causal))\n", - "x3=x2[(x2[\"purityMinR2\"]>=0.25) | (x2[\"credibleSetIndex\"]==1)]\n", - "print(FineMappingSimulations.ProvideSummary(cred_sets=x3,n_causal=n_causal))" + "x3=x2[(x2[\"purityMinR2\"]>=0.25) | (x2[\"credibleSetIndex\"]==1)]" ] }, { @@ -335,11 +323,8 @@ } ], "source": [ - "print(FineMappingSimulations.ProvideSummary(cred_sets=x1,n_causal=n_causal))\n", "x2=x1[(x1[\"pValueExponent\"]<=-6) | (x1[\"credibleSetIndex\"]==1)]\n", - "print(FineMappingSimulations.ProvideSummary(cred_sets=x2,n_causal=n_causal))\n", - "x3=x2[(x2[\"purityMinR2\"]>=0.25) | (x2[\"credibleSetIndex\"]==1)]\n", - "print(FineMappingSimulations.ProvideSummary(cred_sets=x3,n_causal=n_causal))" + "x3=x2[(x2[\"purityMinR2\"]>=0.25) | (x2[\"credibleSetIndex\"]==1)]" ] }, { @@ -386,11 +371,8 @@ } ], "source": [ - "print(FineMappingSimulations.ProvideSummary(cred_sets=x1,n_causal=n_causal))\n", "x2=x1[(x1[\"pValueExponent\"]<=-6) | (x1[\"credibleSetIndex\"]==1)]\n", - "print(FineMappingSimulations.ProvideSummary(cred_sets=x2,n_causal=n_causal))\n", - "x3=x2[(x2[\"purityMinR2\"]>=0.25) | (x2[\"credibleSetIndex\"]==1)]\n", - "print(FineMappingSimulations.ProvideSummary(cred_sets=x3,n_causal=n_causal))" + "x3=x2[(x2[\"purityMinR2\"]>=0.25) | (x2[\"credibleSetIndex\"]==1)]" ] }, { diff --git a/notebooks/FineMapping_AlzheimierDisease.ipynb b/notebooks/FineMapping_AlzheimierDisease.ipynb index 2934080f0..bdb37e354 100644 --- a/notebooks/FineMapping_AlzheimierDisease.ipynb +++ b/notebooks/FineMapping_AlzheimierDisease.ipynb @@ -121,19 +121,20 @@ ], "source": [ "import os\n", + "\n", "import hail as hl\n", - "import pyspark.sql.functions as f\n", "import pandas as pd\n", - "pd.set_option('display.max_colwidth', None)\n", - "pd.set_option('display.expand_frame_repr', False)\n", + "import pyspark.sql.functions as f\n", "\n", "from gentropy.common.session import Session\n", "from gentropy.dataset.study_index import StudyIndex\n", "from gentropy.dataset.summary_statistics import SummaryStatistics\n", - "from gentropy.dataset.study_index import StudyIndex\n", "from gentropy.method.window_based_clumping import WindowBasedClumping\n", "from gentropy.susie_finemapper import SusieFineMapperStep\n", "\n", + "pd.set_option(\"display.max_colwidth\", None)\n", + "pd.set_option(\"display.expand_frame_repr\", False)\n", + "\n", "hail_dir = os.path.dirname(hl.__file__)\n", "session = Session(hail_home=hail_dir, start_hail=True, extended_spark_conf={\"spark.driver.memory\": \"12g\",\n", " \"spark.kryoserializer.buffer.max\": \"500m\",\"spark.driver.maxResultSize\":\"3g\"})" @@ -195,10 +196,7 @@ "study_index = StudyIndex.from_parquet(session, path_si)\n", "\n", "slt=WindowBasedClumping.clump(gwas1,gwas_significance=5e-8,distance=1e6)\n", - "slt_df=slt._df\n", - "\n", - "print(\"Number of SNPs in GWAS: \",gwas1._df.count())\n", - "print(\"Number of clumps: \",slt_df.count())" + "slt_df=slt._df\n" ] }, { @@ -254,9 +252,7 @@ ] } ], - "source": [ - "print(slt_df.show())" - ] + "source": [] }, { "cell_type": "markdown", @@ -1071,7 +1067,7 @@ "source": [ "df = slt_df.withColumn(\"row_index\", f.monotonically_increasing_id())\n", "\n", - "columns = ['N_gwas', 'N_ld', 'N_overlap', 'N_outliers', 'N_imputed', 'N_final_to_fm', 'eleapsed_time']\n", + "columns = [\"N_gwas\", \"N_ld\", \"N_overlap\", \"N_outliers\", \"N_imputed\", \"N_final_to_fm\", \"eleapsed_time\"]\n", "logs = pd.DataFrame(columns=columns)\n", "\n", "for i in range(0,df.count()):\n", @@ -1095,7 +1091,6 @@ "\n", " sl=res[\"study_locus\"]\n", " #print(sl._df.withColumn(\"size\", f.size(sl._df[\"locus\"])).show())\n", - " print(\"Region: \",sl._df.collect()[0]['region'], \"; number of CSs: \",sl._df.count(), \"; log:\")\n", " #print(res[\"log\"])\n", " logs=pd.concat([logs,res[\"log\"]])" ] @@ -1146,8 +1141,7 @@ } ], "source": [ - "pd.set_option('display.max_rows', None)\n", - "print(logs)" + "pd.set_option(\"display.max_rows\", None)" ] }, { @@ -1164,8 +1158,7 @@ } ], "source": [ - "summary = logs['N_overlap'].mean()\n", - "print(summary)" + "summary = logs[\"N_overlap\"].mean()" ] }, { @@ -1318,9 +1311,7 @@ " imputed_r2_threshold=0.8,\n", " ld_score_threshold=4\n", ")\n", - "sl=res[\"study_locus\"]\n", - "print(sl._df.withColumn(\"size\", f.size(sl._df[\"locus\"])).show())\n", - "print(res[\"log\"])" + "sl=res[\"study_locus\"]" ] }, { @@ -1382,9 +1373,7 @@ " imputed_r2_threshold=0.8,\n", " ld_score_threshold=4\n", ")\n", - "sl=res[\"study_locus\"]\n", - "print(sl._df.withColumn(\"size\", f.size(sl._df[\"locus\"])).show())\n", - "print(res[\"log\"])" + "sl=res[\"study_locus\"]" ] }, { @@ -1482,9 +1471,7 @@ " imputed_r2_threshold=0.8,\n", " ld_score_threshold=4\n", ")\n", - "sl=res[\"study_locus\"]\n", - "print(sl._df.withColumn(\"size\", f.size(sl._df[\"locus\"])).show())\n", - "print(res[\"log\"])" + "sl=res[\"study_locus\"]" ] }, { @@ -1546,9 +1533,7 @@ " imputed_r2_threshold=0.8,\n", " ld_score_threshold=4\n", ")\n", - "sl=res[\"study_locus\"]\n", - "print(sl._df.withColumn(\"size\", f.size(sl._df[\"locus\"])).show())\n", - "print(res[\"log\"])" + "sl=res[\"study_locus\"]" ] }, { @@ -1610,9 +1595,7 @@ " imputed_r2_threshold=0.8,\n", " ld_score_threshold=4\n", ")\n", - "sl=res[\"study_locus\"]\n", - "print(sl._df.withColumn(\"size\", f.size(sl._df[\"locus\"])).show())\n", - "print(res[\"log\"])" + "sl=res[\"study_locus\"]" ] }, { @@ -1703,9 +1686,7 @@ " imputed_r2_threshold=0.8,\n", " ld_score_threshold=4\n", ")\n", - "sl=res[\"study_locus\"]\n", - "print(sl._df.withColumn(\"size\", f.size(sl._df[\"locus\"])).show())\n", - "print(res[\"log\"])" + "sl=res[\"study_locus\"]" ] } ], diff --git a/notebooks/Finngen_PICS_run.ipynb b/notebooks/Finngen_PICS_run.ipynb index 21f29db2f..614f07ba5 100644 --- a/notebooks/Finngen_PICS_run.ipynb +++ b/notebooks/Finngen_PICS_run.ipynb @@ -1,1293 +1,1284 @@ { - "cells": [ + "cells": [ + { + "cell_type": "markdown", + "id": "2dd3bf11", + "metadata": {}, + "source": [ + "# Running PICS finemapping on Finngen summary statistics\n", + "\n", + "1. Read summary stats.\n", + "2. Apply window based clumping.\n", + "3. LD expansion.\n", + "4. lD clumping.\n", + "5. PICS." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "0deeb686", + "metadata": { + "ExecuteTime": { + "end_time": "2023-10-13T09:53:43.429135Z", + "start_time": "2023-10-13T09:53:23.566141Z" + } + }, + "outputs": [ { - "cell_type": "markdown", - "id": "2dd3bf11", - "metadata": {}, - "source": [ - "# Running PICS finemapping on Finngen summary statistics\n", - "\n", - "1. Read summary stats.\n", - "2. Apply window based clumping.\n", - "3. LD expansion.\n", - "4. lD clumping.\n", - "5. PICS." + "data": { + "text/html": [ + "\n", + "
\n", + " \n", + " Loading BokehJS ...\n", + "
\n" ] + }, + "metadata": {}, + "output_type": "display_data" }, { - "cell_type": "code", - "execution_count": 1, - "id": "0deeb686", - "metadata": { - "ExecuteTime": { - "end_time": "2023-10-13T09:53:43.429135Z", - "start_time": "2023-10-13T09:53:23.566141Z" - } - }, - "outputs": [ - { - "data": { - "text/html": [ - "\n", - "
\n", - " \n", - " Loading BokehJS ...\n", - "
\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/javascript": "(function(root) {\n function now() {\n return new Date();\n }\n\n const force = true;\n\n if (typeof root._bokeh_onload_callbacks === \"undefined\" || force === true) {\n root._bokeh_onload_callbacks = [];\n root._bokeh_is_loading = undefined;\n }\n\nconst JS_MIME_TYPE = 'application/javascript';\n const HTML_MIME_TYPE = 'text/html';\n const EXEC_MIME_TYPE = 'application/vnd.bokehjs_exec.v0+json';\n const CLASS_NAME = 'output_bokeh rendered_html';\n\n /**\n * Render data to the DOM node\n */\n function render(props, node) {\n const script = document.createElement(\"script\");\n node.appendChild(script);\n }\n\n /**\n * Handle when an output is cleared or removed\n */\n function handleClearOutput(event, handle) {\n const cell = handle.cell;\n\n const id = cell.output_area._bokeh_element_id;\n const server_id = cell.output_area._bokeh_server_id;\n // Clean up Bokeh references\n if (id != null && id in Bokeh.index) {\n Bokeh.index[id].model.document.clear();\n delete Bokeh.index[id];\n }\n\n if (server_id !== undefined) {\n // Clean up Bokeh references\n const cmd_clean = \"from bokeh.io.state import curstate; print(curstate().uuid_to_server['\" + server_id + \"'].get_sessions()[0].document.roots[0]._id)\";\n cell.notebook.kernel.execute(cmd_clean, {\n iopub: {\n output: function(msg) {\n const id = msg.content.text.trim();\n if (id in Bokeh.index) {\n Bokeh.index[id].model.document.clear();\n delete Bokeh.index[id];\n }\n }\n }\n });\n // Destroy server and session\n const cmd_destroy = \"import bokeh.io.notebook as ion; ion.destroy_server('\" + server_id + \"')\";\n cell.notebook.kernel.execute(cmd_destroy);\n }\n }\n\n /**\n * Handle when a new output is added\n */\n function handleAddOutput(event, handle) {\n const output_area = handle.output_area;\n const output = handle.output;\n\n // limit handleAddOutput to display_data with EXEC_MIME_TYPE content only\n if ((output.output_type != \"display_data\") || (!Object.prototype.hasOwnProperty.call(output.data, EXEC_MIME_TYPE))) {\n return\n }\n\n const toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n\n if (output.metadata[EXEC_MIME_TYPE][\"id\"] !== undefined) {\n toinsert[toinsert.length - 1].firstChild.textContent = output.data[JS_MIME_TYPE];\n // store reference to embed id on output_area\n output_area._bokeh_element_id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n }\n if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n const bk_div = document.createElement(\"div\");\n bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n const script_attrs = bk_div.children[0].attributes;\n for (let i = 0; i < script_attrs.length; i++) {\n toinsert[toinsert.length - 1].firstChild.setAttribute(script_attrs[i].name, script_attrs[i].value);\n toinsert[toinsert.length - 1].firstChild.textContent = bk_div.children[0].textContent\n }\n // store reference to server id on output_area\n output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n }\n }\n\n function register_renderer(events, OutputArea) {\n\n function append_mime(data, metadata, element) {\n // create a DOM node to render to\n const toinsert = this.create_output_subarea(\n metadata,\n CLASS_NAME,\n EXEC_MIME_TYPE\n );\n this.keyboard_manager.register_events(toinsert);\n // Render to node\n const props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n render(props, toinsert[toinsert.length - 1]);\n element.append(toinsert);\n return toinsert\n }\n\n /* Handle when an output is cleared or removed */\n events.on('clear_output.CodeCell', handleClearOutput);\n events.on('delete.Cell', handleClearOutput);\n\n /* Handle when a new output is added */\n events.on('output_added.OutputArea', handleAddOutput);\n\n /**\n * Register the mime type and append_mime function with output_area\n */\n OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n /* Is output safe? */\n safe: true,\n /* Index of renderer in `output_area.display_order` */\n index: 0\n });\n }\n\n // register the mime type if in Jupyter Notebook environment and previously unregistered\n if (root.Jupyter !== undefined) {\n const events = require('base/js/events');\n const OutputArea = require('notebook/js/outputarea').OutputArea;\n\n if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n register_renderer(events, OutputArea);\n }\n }\n if (typeof (root._bokeh_timeout) === \"undefined\" || force === true) {\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_failed_load = false;\n }\n\n const NB_LOAD_WARNING = {'data': {'text/html':\n \"
\\n\"+\n \"

\\n\"+\n \"BokehJS does not appear to have successfully loaded. If loading BokehJS from CDN, this \\n\"+\n \"may be due to a slow or bad network connection. Possible fixes:\\n\"+\n \"

\\n\"+\n \"
    \\n\"+\n \"
  • re-rerun `output_notebook()` to attempt to load from CDN again, or
  • \\n\"+\n \"
  • use INLINE resources instead, as so:
  • \\n\"+\n \"
\\n\"+\n \"\\n\"+\n \"from bokeh.resources import INLINE\\n\"+\n \"output_notebook(resources=INLINE)\\n\"+\n \"\\n\"+\n \"
\"}};\n\n function display_loaded() {\n const el = document.getElementById(\"cb01f13c-6396-4b85-99db-68f8056c07dd\");\n if (el != null) {\n el.textContent = \"BokehJS is loading...\";\n }\n if (root.Bokeh !== undefined) {\n if (el != null) {\n el.textContent = \"BokehJS \" + root.Bokeh.version + \" successfully loaded.\";\n }\n } else if (Date.now() < root._bokeh_timeout) {\n setTimeout(display_loaded, 100)\n }\n }\n\n function run_callbacks() {\n try {\n root._bokeh_onload_callbacks.forEach(function(callback) {\n if (callback != null)\n callback();\n });\n } finally {\n delete root._bokeh_onload_callbacks\n }\n console.debug(\"Bokeh: all callbacks have finished\");\n }\n\n function load_libs(css_urls, js_urls, callback) {\n if (css_urls == null) css_urls = [];\n if (js_urls == null) js_urls = [];\n\n root._bokeh_onload_callbacks.push(callback);\n if (root._bokeh_is_loading > 0) {\n console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n return null;\n }\n if (js_urls == null || js_urls.length === 0) {\n run_callbacks();\n return null;\n }\n console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n root._bokeh_is_loading = css_urls.length + js_urls.length;\n\n function on_load() {\n root._bokeh_is_loading--;\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n run_callbacks()\n }\n }\n\n function on_error(url) {\n console.error(\"failed to load \" + url);\n }\n\n for (let i = 0; i < css_urls.length; i++) {\n const url = css_urls[i];\n const element = document.createElement(\"link\");\n element.onload = on_load;\n element.onerror = on_error.bind(null, url);\n element.rel = \"stylesheet\";\n element.type = \"text/css\";\n element.href = url;\n console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n document.body.appendChild(element);\n }\n\n for (let i = 0; i < js_urls.length; i++) {\n const url = js_urls[i];\n const element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error.bind(null, url);\n element.async = false;\n element.src = url;\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n };\n\n function inject_raw_css(css) {\n const element = document.createElement(\"style\");\n element.appendChild(document.createTextNode(css));\n document.body.appendChild(element);\n }\n\n const js_urls = [\"https://cdn.bokeh.org/bokeh/release/bokeh-3.2.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.2.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.2.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.2.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-mathjax-3.2.2.min.js\"];\n const css_urls = [];\n\n const inline_js = [ function(Bokeh) {\n Bokeh.set_log_level(\"info\");\n },\nfunction(Bokeh) {\n }\n ];\n\n function run_inline_js() {\n if (root.Bokeh !== undefined || force === true) {\n for (let i = 0; i < inline_js.length; i++) {\n inline_js[i].call(root, root.Bokeh);\n }\nif (force === true) {\n display_loaded();\n }} else if (Date.now() < root._bokeh_timeout) {\n setTimeout(run_inline_js, 100);\n } else if (!root._bokeh_failed_load) {\n console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n root._bokeh_failed_load = true;\n } else if (force !== true) {\n const cell = $(document.getElementById(\"cb01f13c-6396-4b85-99db-68f8056c07dd\")).parents('.cell').data().cell;\n cell.output_area.append_execute_result(NB_LOAD_WARNING)\n }\n }\n\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: BokehJS loaded, going straight to plotting\");\n run_inline_js();\n } else {\n load_libs(css_urls, js_urls, function() {\n console.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n run_inline_js();\n });\n }\n}(window));", - "application/vnd.bokehjs_load.v0+json": "" - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Setting default log level to \"WARN\".\n", - "To adjust logging level use sc.setLogLevel(newLevel). For SparkR, use setLogLevel(newLevel).\n", - "23/10/13 09:53:40 INFO SparkEnv: Registering MapOutputTracker\n", - "23/10/13 09:53:40 INFO SparkEnv: Registering BlockManagerMaster\n", - "23/10/13 09:53:40 INFO SparkEnv: Registering BlockManagerMasterHeartbeat\n", - "23/10/13 09:53:40 INFO SparkEnv: Registering OutputCommitCoordinator\n", - "23/10/13 09:53:42 WARN GhfsStorageStatistics: Detected potential high latency for operation op_get_file_status. latencyMs=198; previousMaxLatencyMs=0; operationCount=1; context=gs://dataproc-temp-europe-west1-426265110888-ymkbpaze/64dcfdf8-46d3-4b5c-aad4-0a12ee0ba91a/spark-job-history\n", - "23/10/13 09:53:42 WARN GhfsStorageStatistics: Detected potential high latency for operation op_mkdirs. latencyMs=166; previousMaxLatencyMs=0; operationCount=1; context=gs://dataproc-temp-europe-west1-426265110888-ymkbpaze/64dcfdf8-46d3-4b5c-aad4-0a12ee0ba91a/spark-job-history\n" - ] - } - ], - "source": [ - "# Import:\n", - "from pyspark.sql import functions as f, types as t\n", - "\n", - "from gentropy.common.session import Session\n", - "\n", - "from gentropy.dataset.summary_statistics import SummaryStatistics\n", - "from gentropy.dataset.study_locus import StudyLocus\n", - "from gentropy.dataset.study_index import StudyIndex\n", - "from gentropy.dataset.ld_index import LDIndex\n", - "from gentropy.method.ld import LDAnnotator\n", - "\n", - "from gentropy.method.pics import PICS\n", - "\n", - "# Initialize session:\n", - "session = Session()\n", - "\n", - "# Input:\n", - "sumstats = 'gs://genetics_etl_python_playground/output/python_etl/parquet/XX.XX/preprocess/finngen/summary_stats/*'\n", - "ld_index_path = 'gs://genetics_etl_python_playground/output/python_etl/parquet/XX.XX/ld_index/'\n", - "\n", - "# Parameters:\n", - "clump_window_length = 500_000 # Distance between semi-indices.\n", - "locus_window_length = 250_000 # Distance around semi-indices from where the tags are collected.\n", - "\n", - "# Output:\n", - "window_based_clumped_output = 'gs://ot-team/dsuveges/finngen/2023.10.13_window_clumped_w_locus'\n", - "ld_clumped_output = 'gs://ot-team/dsuveges/finngen/2023.10.13_ld_clumped_w_locus'\n", - "picsed_output = 'gs://ot-team/dsuveges/finngen/2023.10.06_PICSed'\n" - ] + "data": { + "application/javascript": "(function(root) {\n function now() {\n return new Date();\n }\n\n const force = true;\n\n if (typeof root._bokeh_onload_callbacks === \"undefined\" || force === true) {\n root._bokeh_onload_callbacks = [];\n root._bokeh_is_loading = undefined;\n }\n\nconst JS_MIME_TYPE = 'application/javascript';\n const HTML_MIME_TYPE = 'text/html';\n const EXEC_MIME_TYPE = 'application/vnd.bokehjs_exec.v0+json';\n const CLASS_NAME = 'output_bokeh rendered_html';\n\n /**\n * Render data to the DOM node\n */\n function render(props, node) {\n const script = document.createElement(\"script\");\n node.appendChild(script);\n }\n\n /**\n * Handle when an output is cleared or removed\n */\n function handleClearOutput(event, handle) {\n const cell = handle.cell;\n\n const id = cell.output_area._bokeh_element_id;\n const server_id = cell.output_area._bokeh_server_id;\n // Clean up Bokeh references\n if (id != null && id in Bokeh.index) {\n Bokeh.index[id].model.document.clear();\n delete Bokeh.index[id];\n }\n\n if (server_id !== undefined) {\n // Clean up Bokeh references\n const cmd_clean = \"from bokeh.io.state import curstate; print(curstate().uuid_to_server['\" + server_id + \"'].get_sessions()[0].document.roots[0]._id)\";\n cell.notebook.kernel.execute(cmd_clean, {\n iopub: {\n output: function(msg) {\n const id = msg.content.text.trim();\n if (id in Bokeh.index) {\n Bokeh.index[id].model.document.clear();\n delete Bokeh.index[id];\n }\n }\n }\n });\n // Destroy server and session\n const cmd_destroy = \"import bokeh.io.notebook as ion; ion.destroy_server('\" + server_id + \"')\";\n cell.notebook.kernel.execute(cmd_destroy);\n }\n }\n\n /**\n * Handle when a new output is added\n */\n function handleAddOutput(event, handle) {\n const output_area = handle.output_area;\n const output = handle.output;\n\n // limit handleAddOutput to display_data with EXEC_MIME_TYPE content only\n if ((output.output_type != \"display_data\") || (!Object.prototype.hasOwnProperty.call(output.data, EXEC_MIME_TYPE))) {\n return\n }\n\n const toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n\n if (output.metadata[EXEC_MIME_TYPE][\"id\"] !== undefined) {\n toinsert[toinsert.length - 1].firstChild.textContent = output.data[JS_MIME_TYPE];\n // store reference to embed id on output_area\n output_area._bokeh_element_id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n }\n if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n const bk_div = document.createElement(\"div\");\n bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n const script_attrs = bk_div.children[0].attributes;\n for (let i = 0; i < script_attrs.length; i++) {\n toinsert[toinsert.length - 1].firstChild.setAttribute(script_attrs[i].name, script_attrs[i].value);\n toinsert[toinsert.length - 1].firstChild.textContent = bk_div.children[0].textContent\n }\n // store reference to server id on output_area\n output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n }\n }\n\n function register_renderer(events, OutputArea) {\n\n function append_mime(data, metadata, element) {\n // create a DOM node to render to\n const toinsert = this.create_output_subarea(\n metadata,\n CLASS_NAME,\n EXEC_MIME_TYPE\n );\n this.keyboard_manager.register_events(toinsert);\n // Render to node\n const props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n render(props, toinsert[toinsert.length - 1]);\n element.append(toinsert);\n return toinsert\n }\n\n /* Handle when an output is cleared or removed */\n events.on('clear_output.CodeCell', handleClearOutput);\n events.on('delete.Cell', handleClearOutput);\n\n /* Handle when a new output is added */\n events.on('output_added.OutputArea', handleAddOutput);\n\n /**\n * Register the mime type and append_mime function with output_area\n */\n OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n /* Is output safe? */\n safe: true,\n /* Index of renderer in `output_area.display_order` */\n index: 0\n });\n }\n\n // register the mime type if in Jupyter Notebook environment and previously unregistered\n if (root.Jupyter !== undefined) {\n const events = require('base/js/events');\n const OutputArea = require('notebook/js/outputarea').OutputArea;\n\n if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n register_renderer(events, OutputArea);\n }\n }\n if (typeof (root._bokeh_timeout) === \"undefined\" || force === true) {\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_failed_load = false;\n }\n\n const NB_LOAD_WARNING = {'data': {'text/html':\n \"
\\n\"+\n \"

\\n\"+\n \"BokehJS does not appear to have successfully loaded. If loading BokehJS from CDN, this \\n\"+\n \"may be due to a slow or bad network connection. Possible fixes:\\n\"+\n \"

\\n\"+\n \"
    \\n\"+\n \"
  • re-rerun `output_notebook()` to attempt to load from CDN again, or
  • \\n\"+\n \"
  • use INLINE resources instead, as so:
  • \\n\"+\n \"
\\n\"+\n \"\\n\"+\n \"from bokeh.resources import INLINE\\n\"+\n \"output_notebook(resources=INLINE)\\n\"+\n \"\\n\"+\n \"
\"}};\n\n function display_loaded() {\n const el = document.getElementById(\"cb01f13c-6396-4b85-99db-68f8056c07dd\");\n if (el != null) {\n el.textContent = \"BokehJS is loading...\";\n }\n if (root.Bokeh !== undefined) {\n if (el != null) {\n el.textContent = \"BokehJS \" + root.Bokeh.version + \" successfully loaded.\";\n }\n } else if (Date.now() < root._bokeh_timeout) {\n setTimeout(display_loaded, 100)\n }\n }\n\n function run_callbacks() {\n try {\n root._bokeh_onload_callbacks.forEach(function(callback) {\n if (callback != null)\n callback();\n });\n } finally {\n delete root._bokeh_onload_callbacks\n }\n console.debug(\"Bokeh: all callbacks have finished\");\n }\n\n function load_libs(css_urls, js_urls, callback) {\n if (css_urls == null) css_urls = [];\n if (js_urls == null) js_urls = [];\n\n root._bokeh_onload_callbacks.push(callback);\n if (root._bokeh_is_loading > 0) {\n console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n return null;\n }\n if (js_urls == null || js_urls.length === 0) {\n run_callbacks();\n return null;\n }\n console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n root._bokeh_is_loading = css_urls.length + js_urls.length;\n\n function on_load() {\n root._bokeh_is_loading--;\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n run_callbacks()\n }\n }\n\n function on_error(url) {\n console.error(\"failed to load \" + url);\n }\n\n for (let i = 0; i < css_urls.length; i++) {\n const url = css_urls[i];\n const element = document.createElement(\"link\");\n element.onload = on_load;\n element.onerror = on_error.bind(null, url);\n element.rel = \"stylesheet\";\n element.type = \"text/css\";\n element.href = url;\n console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n document.body.appendChild(element);\n }\n\n for (let i = 0; i < js_urls.length; i++) {\n const url = js_urls[i];\n const element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error.bind(null, url);\n element.async = false;\n element.src = url;\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n };\n\n function inject_raw_css(css) {\n const element = document.createElement(\"style\");\n element.appendChild(document.createTextNode(css));\n document.body.appendChild(element);\n }\n\n const js_urls = [\"https://cdn.bokeh.org/bokeh/release/bokeh-3.2.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.2.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.2.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.2.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-mathjax-3.2.2.min.js\"];\n const css_urls = [];\n\n const inline_js = [ function(Bokeh) {\n Bokeh.set_log_level(\"info\");\n },\nfunction(Bokeh) {\n }\n ];\n\n function run_inline_js() {\n if (root.Bokeh !== undefined || force === true) {\n for (let i = 0; i < inline_js.length; i++) {\n inline_js[i].call(root, root.Bokeh);\n }\nif (force === true) {\n display_loaded();\n }} else if (Date.now() < root._bokeh_timeout) {\n setTimeout(run_inline_js, 100);\n } else if (!root._bokeh_failed_load) {\n console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n root._bokeh_failed_load = true;\n } else if (force !== true) {\n const cell = $(document.getElementById(\"cb01f13c-6396-4b85-99db-68f8056c07dd\")).parents('.cell').data().cell;\n cell.output_area.append_execute_result(NB_LOAD_WARNING)\n }\n }\n\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: BokehJS loaded, going straight to plotting\");\n run_inline_js();\n } else {\n load_libs(css_urls, js_urls, function() {\n console.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n run_inline_js();\n });\n }\n}(window));", + "application/vnd.bokehjs_load.v0+json": "" + }, + "metadata": {}, + "output_type": "display_data" }, { - "cell_type": "markdown", - "id": "3bdbcfbf", - "metadata": {}, - "source": [ - "## 1. Read summary statistics" - ] - }, + "name": "stderr", + "output_type": "stream", + "text": [ + "Setting default log level to \"WARN\".\n", + "To adjust logging level use sc.setLogLevel(newLevel). For SparkR, use setLogLevel(newLevel).\n", + "23/10/13 09:53:40 INFO SparkEnv: Registering MapOutputTracker\n", + "23/10/13 09:53:40 INFO SparkEnv: Registering BlockManagerMaster\n", + "23/10/13 09:53:40 INFO SparkEnv: Registering BlockManagerMasterHeartbeat\n", + "23/10/13 09:53:40 INFO SparkEnv: Registering OutputCommitCoordinator\n", + "23/10/13 09:53:42 WARN GhfsStorageStatistics: Detected potential high latency for operation op_get_file_status. latencyMs=198; previousMaxLatencyMs=0; operationCount=1; context=gs://dataproc-temp-europe-west1-426265110888-ymkbpaze/64dcfdf8-46d3-4b5c-aad4-0a12ee0ba91a/spark-job-history\n", + "23/10/13 09:53:42 WARN GhfsStorageStatistics: Detected potential high latency for operation op_mkdirs. latencyMs=166; previousMaxLatencyMs=0; operationCount=1; context=gs://dataproc-temp-europe-west1-426265110888-ymkbpaze/64dcfdf8-46d3-4b5c-aad4-0a12ee0ba91a/spark-job-history\n" + ] + } + ], + "source": [ + "# Import:\n", + "from pyspark.sql import functions as f\n", + "\n", + "from gentropy.common.session import Session\n", + "from gentropy.dataset.ld_index import LDIndex\n", + "from gentropy.dataset.study_index import StudyIndex\n", + "from gentropy.dataset.study_locus import StudyLocus\n", + "from gentropy.dataset.summary_statistics import SummaryStatistics\n", + "from gentropy.method.ld import LDAnnotator\n", + "from gentropy.method.pics import PICS\n", + "\n", + "# Initialize session:\n", + "session = Session()\n", + "\n", + "# Input:\n", + "sumstats = \"gs://genetics_etl_python_playground/output/python_etl/parquet/XX.XX/preprocess/finngen/summary_stats/*\"\n", + "ld_index_path = \"gs://genetics_etl_python_playground/output/python_etl/parquet/XX.XX/ld_index/\"\n", + "\n", + "# Parameters:\n", + "clump_window_length = 500_000 # Distance between semi-indices.\n", + "locus_window_length = 250_000 # Distance around semi-indices from where the tags are collected.\n", + "\n", + "# Output:\n", + "window_based_clumped_output = \"gs://ot-team/dsuveges/finngen/2023.10.13_window_clumped_w_locus\"\n", + "ld_clumped_output = \"gs://ot-team/dsuveges/finngen/2023.10.13_ld_clumped_w_locus\"\n", + "picsed_output = \"gs://ot-team/dsuveges/finngen/2023.10.06_PICSed\"\n" + ] + }, + { + "cell_type": "markdown", + "id": "3bdbcfbf", + "metadata": {}, + "source": [ + "## 1. Read summary statistics" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "c893433c", + "metadata": { + "ExecuteTime": { + "end_time": "2023-10-06T08:46:39.186806Z", + "start_time": "2023-10-06T08:46:04.601886Z" + } + }, + "outputs": [ { - "cell_type": "code", - "execution_count": 16, - "id": "c893433c", - "metadata": { - "ExecuteTime": { - "end_time": "2023-10-06T08:46:39.186806Z", - "start_time": "2023-10-06T08:46:04.601886Z" - } - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "23/10/06 08:46:37 WARN GhfsStorageStatistics: Detected potential high latency for operation stream_read_operations. latencyMs=236; previousMaxLatencyMs=147; operationCount=276; context=gs://genetics_etl_python_playground/output/python_etl/parquet/XX.XX/preprocess/finngen/summary_stats/FINNGEN_R9_AB1_ACTINOMYCOSIS/chromosome=1/part-00011-33e31f88-435f-4200-9adc-3e909d706910.c000.snappy.parquet\n", - "23/10/06 08:46:37 WARN GhfsStorageStatistics: Detected potential high latency for operation stream_read_operations. latencyMs=269; previousMaxLatencyMs=236; operationCount=282; context=gs://genetics_etl_python_playground/output/python_etl/parquet/XX.XX/preprocess/finngen/summary_stats/FINNGEN_R9_HEIGHT_IRN/chromosome=2/part-00020-774f0990-ad3d-46ae-9648-f39c18fae314.c000.snappy.parquet\n", - "23/10/06 08:46:38 WARN GhfsStorageStatistics: Detected potential high latency for operation stream_read_operations. latencyMs=417; previousMaxLatencyMs=269; operationCount=288; context=gs://genetics_etl_python_playground/output/python_etl/parquet/XX.XX/preprocess/finngen/summary_stats/FINNGEN_R9_HEIGHT_IRN/chromosome=2/part-00020-774f0990-ad3d-46ae-9648-f39c18fae314.c000.snappy.parquet\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "+--------------------+-----------+--------+--------------+--------------+-----------+-------------+-------------------------------+---------------------------+---------------------------+----------+\n", - "| studyId| variantId|position|pValueMantissa|pValueExponent| beta|standardError|effectAlleleFrequencyFromSource|betaConfidenceIntervalLower|betaConfidenceIntervalUpper|chromosome|\n", - "+--------------------+-----------+--------+--------------+--------------+-----------+-------------+-------------------------------+---------------------------+---------------------------+----------+\n", - "|FINNGEN_R9_HEIGHT...|2_10603_A_C| 10603| 8.515| -1| 0.0117813| 0.0629271| 2.30629E-4| -0.0511458| 0.0747084| 2|\n", - "|FINNGEN_R9_HEIGHT...|2_10610_G_A| 10610| 8.814| -3| 0.0187529| 0.00715985| 0.0194828| 0.01159305| 0.02591275| 2|\n", - "|FINNGEN_R9_HEIGHT...|2_10659_G_A| 10659| 9.292| -1|-0.00289323| 0.0325443| 8.5694E-4| -0.03543752999999...| 0.029651069999999998| 2|\n", - "|FINNGEN_R9_HEIGHT...|2_10756_T_C| 10756| 2.368| -1| -0.180083| 0.15223| 5.62468E-5| -0.33231299999999997| -0.02785299999999999| 2|\n", - "|FINNGEN_R9_HEIGHT...|2_10797_C_T| 10797| 8.506| -1|-0.00190634| 0.01012| 0.00847354| -0.01202634| 0.008213660000000001| 2|\n", - "|FINNGEN_R9_HEIGHT...|2_10823_G_C| 10823| 6.834| -2| -0.259102| 0.142146| 1.48813E-4| -0.401248| -0.116956| 2|\n", - "|FINNGEN_R9_HEIGHT...|2_10847_C_T| 10847| 5.97| -1| 0.0487634| 0.0922252| 1.03478E-4| -0.04346179999999...| 0.1409886| 2|\n", - "|FINNGEN_R9_HEIGHT...|2_11305_G_C| 11305| 6.992| -1|-0.00333638| 0.00863326| 0.013513| -0.01196964| 0.00529688| 2|\n", - "|FINNGEN_R9_HEIGHT...|2_11311_C_G| 11311| 1.676| -1| 0.112938| 0.0818501| 1.30145E-4| 0.0310879| 0.1947881| 2|\n", - "|FINNGEN_R9_HEIGHT...|2_11320_G_A| 11320| 2.484| -7| -0.0106449| 0.0020634| 0.302909| -0.0127083| -0.0085815| 2|\n", - "|FINNGEN_R9_HEIGHT...|2_11486_A_G| 11486| 6.829| -3| 0.0135765| 0.00501887| 0.035261| 0.00855763| 0.01859537| 2|\n", - "|FINNGEN_R9_HEIGHT...|2_11573_A_C| 11573| 7.428| -1| 0.00483333| 0.0147283| 0.00424829| -0.00989497| 0.01956163| 2|\n", - "|FINNGEN_R9_HEIGHT...|2_11594_G_T| 11594| 5.291| -1|-0.00908649| 0.014438| 0.0045864| -0.02352449| 0.00535151| 2|\n", - "|FINNGEN_R9_HEIGHT...|2_11607_T_C| 11607| 5.666| -3| 0.0139369| 0.00503765| 0.0350636| 0.008899250000000001| 0.01897455| 2|\n", - "|FINNGEN_R9_HEIGHT...|2_11609_T_G| 11609| 8.231| -2| -0.065766| 0.0378528| 7.11595E-4| -0.10361880000000001| -0.02791320000000...| 2|\n", - "|FINNGEN_R9_HEIGHT...|2_11620_G_C| 11620| 5.866| -1| -0.0235368| 0.0432809| 5.48483E-4| -0.0668177| 0.019744099999999997| 2|\n", - "|FINNGEN_R9_HEIGHT...|2_11677_C_G| 11677| 3.944| -1| -0.0888112| 0.104287| 1.01977E-4| -0.1930982| 0.015475799999999998| 2|\n", - "|FINNGEN_R9_HEIGHT...|2_11694_C_T| 11694| 8.855| -2| -0.0468924| 0.0275339| 0.00127759| -0.0744263| -0.0193585| 2|\n", - "|FINNGEN_R9_HEIGHT...|2_11696_C_T| 11696| 2.446| -1| -0.0384871| 0.0330789| 8.17298E-4| -0.071566| -0.00540820000000...| 2|\n", - "|FINNGEN_R9_HEIGHT...|2_11834_A_G| 11834| 5.664| -3| 0.0139372| 0.00503766| 0.0350634| 0.008899540000000001| 0.01897486| 2|\n", - "+--------------------+-----------+--------+--------------+--------------+-----------+-------------+-------------------------------+---------------------------+---------------------------+----------+\n", - "only showing top 20 rows\n", - "\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - } - ], - "source": [ - "finngen_sumstats = SummaryStatistics(\n", - " _df=(\n", - " session.spark.read.parquet(sumstats, recursiveFileLookup=True)\n", - " # We need to add chromosome column as this is a partition column:\n", - " .withColumn('chromosome',f.split(f.col('variantId'), '_')[0])\n", - " ),\n", - " _schema=SummaryStatistics.get_schema()\n", - ")\n", - "finngen_sumstats.df.show()\n", - "print(finngen_sumstats.df.count())" - ] + "name": "stderr", + "output_type": "stream", + "text": [ + "23/10/06 08:46:37 WARN GhfsStorageStatistics: Detected potential high latency for operation stream_read_operations. latencyMs=236; previousMaxLatencyMs=147; operationCount=276; context=gs://genetics_etl_python_playground/output/python_etl/parquet/XX.XX/preprocess/finngen/summary_stats/FINNGEN_R9_AB1_ACTINOMYCOSIS/chromosome=1/part-00011-33e31f88-435f-4200-9adc-3e909d706910.c000.snappy.parquet\n", + "23/10/06 08:46:37 WARN GhfsStorageStatistics: Detected potential high latency for operation stream_read_operations. latencyMs=269; previousMaxLatencyMs=236; operationCount=282; context=gs://genetics_etl_python_playground/output/python_etl/parquet/XX.XX/preprocess/finngen/summary_stats/FINNGEN_R9_HEIGHT_IRN/chromosome=2/part-00020-774f0990-ad3d-46ae-9648-f39c18fae314.c000.snappy.parquet\n", + "23/10/06 08:46:38 WARN GhfsStorageStatistics: Detected potential high latency for operation stream_read_operations. latencyMs=417; previousMaxLatencyMs=269; operationCount=288; context=gs://genetics_etl_python_playground/output/python_etl/parquet/XX.XX/preprocess/finngen/summary_stats/FINNGEN_R9_HEIGHT_IRN/chromosome=2/part-00020-774f0990-ad3d-46ae-9648-f39c18fae314.c000.snappy.parquet\n" + ] }, { - "cell_type": "markdown", - "id": "a76b27ce", - "metadata": {}, - "source": [ - "## 2. Apply window based clumping.\n", - "\n", - "- Clumping distance: +/-500kbp\n", - "- Locus collected: +/-250kbp" - ] + "name": "stdout", + "output_type": "stream", + "text": [ + "+--------------------+-----------+--------+--------------+--------------+-----------+-------------+-------------------------------+---------------------------+---------------------------+----------+\n", + "| studyId| variantId|position|pValueMantissa|pValueExponent| beta|standardError|effectAlleleFrequencyFromSource|betaConfidenceIntervalLower|betaConfidenceIntervalUpper|chromosome|\n", + "+--------------------+-----------+--------+--------------+--------------+-----------+-------------+-------------------------------+---------------------------+---------------------------+----------+\n", + "|FINNGEN_R9_HEIGHT...|2_10603_A_C| 10603| 8.515| -1| 0.0117813| 0.0629271| 2.30629E-4| -0.0511458| 0.0747084| 2|\n", + "|FINNGEN_R9_HEIGHT...|2_10610_G_A| 10610| 8.814| -3| 0.0187529| 0.00715985| 0.0194828| 0.01159305| 0.02591275| 2|\n", + "|FINNGEN_R9_HEIGHT...|2_10659_G_A| 10659| 9.292| -1|-0.00289323| 0.0325443| 8.5694E-4| -0.03543752999999...| 0.029651069999999998| 2|\n", + "|FINNGEN_R9_HEIGHT...|2_10756_T_C| 10756| 2.368| -1| -0.180083| 0.15223| 5.62468E-5| -0.33231299999999997| -0.02785299999999999| 2|\n", + "|FINNGEN_R9_HEIGHT...|2_10797_C_T| 10797| 8.506| -1|-0.00190634| 0.01012| 0.00847354| -0.01202634| 0.008213660000000001| 2|\n", + "|FINNGEN_R9_HEIGHT...|2_10823_G_C| 10823| 6.834| -2| -0.259102| 0.142146| 1.48813E-4| -0.401248| -0.116956| 2|\n", + "|FINNGEN_R9_HEIGHT...|2_10847_C_T| 10847| 5.97| -1| 0.0487634| 0.0922252| 1.03478E-4| -0.04346179999999...| 0.1409886| 2|\n", + "|FINNGEN_R9_HEIGHT...|2_11305_G_C| 11305| 6.992| -1|-0.00333638| 0.00863326| 0.013513| -0.01196964| 0.00529688| 2|\n", + "|FINNGEN_R9_HEIGHT...|2_11311_C_G| 11311| 1.676| -1| 0.112938| 0.0818501| 1.30145E-4| 0.0310879| 0.1947881| 2|\n", + "|FINNGEN_R9_HEIGHT...|2_11320_G_A| 11320| 2.484| -7| -0.0106449| 0.0020634| 0.302909| -0.0127083| -0.0085815| 2|\n", + "|FINNGEN_R9_HEIGHT...|2_11486_A_G| 11486| 6.829| -3| 0.0135765| 0.00501887| 0.035261| 0.00855763| 0.01859537| 2|\n", + "|FINNGEN_R9_HEIGHT...|2_11573_A_C| 11573| 7.428| -1| 0.00483333| 0.0147283| 0.00424829| -0.00989497| 0.01956163| 2|\n", + "|FINNGEN_R9_HEIGHT...|2_11594_G_T| 11594| 5.291| -1|-0.00908649| 0.014438| 0.0045864| -0.02352449| 0.00535151| 2|\n", + "|FINNGEN_R9_HEIGHT...|2_11607_T_C| 11607| 5.666| -3| 0.0139369| 0.00503765| 0.0350636| 0.008899250000000001| 0.01897455| 2|\n", + "|FINNGEN_R9_HEIGHT...|2_11609_T_G| 11609| 8.231| -2| -0.065766| 0.0378528| 7.11595E-4| -0.10361880000000001| -0.02791320000000...| 2|\n", + "|FINNGEN_R9_HEIGHT...|2_11620_G_C| 11620| 5.866| -1| -0.0235368| 0.0432809| 5.48483E-4| -0.0668177| 0.019744099999999997| 2|\n", + "|FINNGEN_R9_HEIGHT...|2_11677_C_G| 11677| 3.944| -1| -0.0888112| 0.104287| 1.01977E-4| -0.1930982| 0.015475799999999998| 2|\n", + "|FINNGEN_R9_HEIGHT...|2_11694_C_T| 11694| 8.855| -2| -0.0468924| 0.0275339| 0.00127759| -0.0744263| -0.0193585| 2|\n", + "|FINNGEN_R9_HEIGHT...|2_11696_C_T| 11696| 2.446| -1| -0.0384871| 0.0330789| 8.17298E-4| -0.071566| -0.00540820000000...| 2|\n", + "|FINNGEN_R9_HEIGHT...|2_11834_A_G| 11834| 5.664| -3| 0.0139372| 0.00503766| 0.0350634| 0.008899540000000001| 0.01897486| 2|\n", + "+--------------------+-----------+--------+--------------+--------------+-----------+-------------+-------------------------------+---------------------------+---------------------------+----------+\n", + "only showing top 20 rows\n", + "\n" + ] }, { - "cell_type": "code", - "execution_count": 34, - "id": "fc0dd4f0", - "metadata": { - "ExecuteTime": { - "end_time": "2023-10-06T10:22:38.264681Z", - "start_time": "2023-10-06T10:10:29.768171Z" - }, - "scrolled": false - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "23/10/06 10:22:32 WARN GhfsStorageStatistics: Detected potential high latency for operation stream_write_close_operations. latencyMs=1812; previousMaxLatencyMs=253; operationCount=415; context=gs://ot-team/dsuveges/finngen/2023.10.06_window_clumped/_temporary/0/_temporary/attempt_202310061022254599137247441201519_0051_m_000011_106753/part-00011-53e48f6d-d432-40c5-9201-d4c8f03e6dee-c000.snappy.parquet\n", - " \r" - ] - } - ], - "source": [ - "# This process takes ~1h on a 32 cores:\n", - "(\n", - " SummaryStatistics(\n", - " _df=(\n", - " session.spark.read.parquet(sumstats, recursiveFileLookup=True)\n", - " .withColumn(\n", - " 'chromosome',\n", - " f.split(f.col('variantId'), '_')[0]\n", - " )\n", - " ),\n", - " _schema=SummaryStatistics.get_schema()\n", - " )\n", - " .window_based_clumping(\n", - " distance=clump_window_length,\n", - " locus_collect_distance=locus_window_length,\n", - " with_locus=True\n", - " )\n", - " .df.write.mode('overwrite')\n", - " .parquet(window_based_clumped_output)\n", - ")" - ] + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + } + ], + "source": [ + "finngen_sumstats = SummaryStatistics(\n", + " _df=(\n", + " session.spark.read.parquet(sumstats, recursiveFileLookup=True)\n", + " # We need to add chromosome column as this is a partition column:\n", + " .withColumn(\"chromosome\",f.split(f.col(\"variantId\"), \"_\")[0])\n", + " ),\n", + " _schema=SummaryStatistics.get_schema()\n", + ")\n", + "finngen_sumstats.df.show()" + ] + }, + { + "cell_type": "markdown", + "id": "a76b27ce", + "metadata": {}, + "source": [ + "## 2. Apply window based clumping.\n", + "\n", + "- Clumping distance: +/-500kbp\n", + "- Locus collected: +/-250kbp" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "id": "fc0dd4f0", + "metadata": { + "ExecuteTime": { + "end_time": "2023-10-06T10:22:38.264681Z", + "start_time": "2023-10-06T10:10:29.768171Z" }, + "scrolled": false + }, + "outputs": [ { - "cell_type": "markdown", - "id": "a1cd0172", - "metadata": {}, - "source": [ - "## 3. LD expansion\n", - "\n", - "- For FINNGEN, study table needs to be mocked." - ] - }, + "name": "stderr", + "output_type": "stream", + "text": [ + "23/10/06 10:22:32 WARN GhfsStorageStatistics: Detected potential high latency for operation stream_write_close_operations. latencyMs=1812; previousMaxLatencyMs=253; operationCount=415; context=gs://ot-team/dsuveges/finngen/2023.10.06_window_clumped/_temporary/0/_temporary/attempt_202310061022254599137247441201519_0051_m_000011_106753/part-00011-53e48f6d-d432-40c5-9201-d4c8f03e6dee-c000.snappy.parquet\n", + " \r" + ] + } + ], + "source": [ + "# This process takes ~1h on a 32 cores:\n", + "(\n", + " SummaryStatistics(\n", + " _df=(\n", + " session.spark.read.parquet(sumstats, recursiveFileLookup=True)\n", + " .withColumn(\n", + " \"chromosome\",\n", + " f.split(f.col(\"variantId\"), \"_\")[0]\n", + " )\n", + " ),\n", + " _schema=SummaryStatistics.get_schema()\n", + " )\n", + " .window_based_clumping(\n", + " distance=clump_window_length,\n", + " locus_collect_distance=locus_window_length,\n", + " with_locus=True\n", + " )\n", + " .df.write.mode(\"overwrite\")\n", + " .parquet(window_based_clumped_output)\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "a1cd0172", + "metadata": {}, + "source": [ + "## 3. LD expansion\n", + "\n", + "- For FINNGEN, study table needs to be mocked." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "1305f6c3", + "metadata": { + "ExecuteTime": { + "end_time": "2023-10-06T08:13:10.050554Z", + "start_time": "2023-10-06T08:13:05.901762Z" + } + }, + "outputs": [ { - "cell_type": "code", - "execution_count": 8, - "id": "1305f6c3", - "metadata": { - "ExecuteTime": { - "end_time": "2023-10-06T08:13:10.050554Z", - "start_time": "2023-10-06T08:13:05.901762Z" - } - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "[Stage 5:===============================================> (15 + 3) / 18]\r" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "+--------------------+---------------------+---------+---------+---------------+\n", - "| studyId|ldPopulationStructure|projectId|studyType|traitFromSource|\n", - "+--------------------+---------------------+---------+---------+---------------+\n", - "|FINNGEN_R9_K11_EN...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", - "|FINNGEN_R9_P16_IN...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", - "| FINNGEN_R9_C_STROKE| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", - "|FINNGEN_R9_G6_HER...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", - "|FINNGEN_R9_RHEUMA...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", - "|FINNGEN_R9_N14_EN...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", - "| FINNGEN_R9_PAIN| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", - "|FINNGEN_R9_D3_COA...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", - "|FINNGEN_R9_F5_UNSORG| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", - "|FINNGEN_R9_HEIGHT...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", - "|FINNGEN_R9_M13_SY...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", - "|FINNGEN_R9_APPEND...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", - "|FINNGEN_R9_ALLERG...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", - "|FINNGEN_R9_M13_FI...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", - "|FINNGEN_R9_E4_DM2...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", - "|FINNGEN_R9_AUTOIM...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", - "|FINNGEN_R9_CD2_BE...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", - "|FINNGEN_R9_F5_DIS...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", - "|FINNGEN_R9_E4_DMN...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", - "|FINNGEN_R9_E4_FH_IHD| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", - "+--------------------+---------------------+---------+---------+---------------+\n", - "only showing top 20 rows\n", - "\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - } - ], - "source": [ - "# Generating a \"fake\" study index, just for providing ld_population structure for each finngen study:\n", - "studies_df = (\n", - " session.spark.read.parquet('gs://ot-team/dsuveges/finngen_semi_indices_250kbp')\n", - " # Generating a list of study identifiers:\n", - " .select('studyId')\n", - " .distinct()\n", - " # Adding fabricated values required to parse as gwas catalog study:\n", - " .select(\n", - " 'studyId',\n", - " StudyIndex.aggregate_and_map_ancestries(\n", - " f.array(\n", - " f.struct(\n", - " f.lit('Finnish').alias('ancestry'),\n", - " f.lit(100).cast('long').alias('sampleSize')\n", - " )\n", - " )\n", - " ).alias('ldPopulationStructure'),\n", - " f.lit('FINNGEN').alias('projectId'),\n", - " f.lit('gwas').alias('studyType'),\n", - " f.lit('cicaful').alias('traitFromSource')\n", - " )\n", - ")\n", - "\n", - "study_index = (\n", - " StudyIndex(\n", - " _df=studies_df,\n", - " _schema=StudyIndex.get_schema()\n", - " )\n", - ")\n", - "\n", - "study_index.df.show()" - ] + "name": "stderr", + "output_type": "stream", + "text": [ + "[Stage 5:===============================================> (15 + 3) / 18]\r" + ] }, { - "cell_type": "code", - "execution_count": 19, - "id": "cb2d5030", - "metadata": { - "ExecuteTime": { - "end_time": "2023-10-06T09:09:22.063715Z", - "start_time": "2023-10-06T09:09:21.359206Z" - } - }, - "outputs": [], - "source": [ - "# Loading ld index:\n", - "ld_index = LDIndex.from_parquet(session, ld_index_path)\n", - "\n" - ] + "name": "stdout", + "output_type": "stream", + "text": [ + "+--------------------+---------------------+---------+---------+---------------+\n", + "| studyId|ldPopulationStructure|projectId|studyType|traitFromSource|\n", + "+--------------------+---------------------+---------+---------+---------------+\n", + "|FINNGEN_R9_K11_EN...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", + "|FINNGEN_R9_P16_IN...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", + "| FINNGEN_R9_C_STROKE| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", + "|FINNGEN_R9_G6_HER...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", + "|FINNGEN_R9_RHEUMA...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", + "|FINNGEN_R9_N14_EN...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", + "| FINNGEN_R9_PAIN| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", + "|FINNGEN_R9_D3_COA...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", + "|FINNGEN_R9_F5_UNSORG| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", + "|FINNGEN_R9_HEIGHT...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", + "|FINNGEN_R9_M13_SY...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", + "|FINNGEN_R9_APPEND...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", + "|FINNGEN_R9_ALLERG...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", + "|FINNGEN_R9_M13_FI...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", + "|FINNGEN_R9_E4_DM2...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", + "|FINNGEN_R9_AUTOIM...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", + "|FINNGEN_R9_CD2_BE...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", + "|FINNGEN_R9_F5_DIS...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", + "|FINNGEN_R9_E4_DMN...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", + "|FINNGEN_R9_E4_FH_IHD| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", + "+--------------------+---------------------+---------+---------+---------------+\n", + "only showing top 20 rows\n", + "\n" + ] }, { - "cell_type": "markdown", - "id": "3d13ae41", - "metadata": {}, - "source": [ - "## 4. LD based clumping.\n", - "\n", - "- Persist resulting dataset.\n", - "- Save dataset." - ] + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + } + ], + "source": [ + "# Generating a \"fake\" study index, just for providing ld_population structure for each finngen study:\n", + "studies_df = (\n", + " session.spark.read.parquet(\"gs://ot-team/dsuveges/finngen_semi_indices_250kbp\")\n", + " # Generating a list of study identifiers:\n", + " .select(\"studyId\")\n", + " .distinct()\n", + " # Adding fabricated values required to parse as gwas catalog study:\n", + " .select(\n", + " \"studyId\",\n", + " StudyIndex.aggregate_and_map_ancestries(\n", + " f.array(\n", + " f.struct(\n", + " f.lit(\"Finnish\").alias(\"ancestry\"),\n", + " f.lit(100).cast(\"long\").alias(\"sampleSize\")\n", + " )\n", + " )\n", + " ).alias(\"ldPopulationStructure\"),\n", + " f.lit(\"FINNGEN\").alias(\"projectId\"),\n", + " f.lit(\"gwas\").alias(\"studyType\"),\n", + " f.lit(\"cicaful\").alias(\"traitFromSource\")\n", + " )\n", + ")\n", + "\n", + "study_index = (\n", + " StudyIndex(\n", + " _df=studies_df,\n", + " _schema=StudyIndex.get_schema()\n", + " )\n", + ")\n", + "\n", + "study_index.df.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "cb2d5030", + "metadata": { + "ExecuteTime": { + "end_time": "2023-10-06T09:09:22.063715Z", + "start_time": "2023-10-06T09:09:21.359206Z" + } + }, + "outputs": [], + "source": [ + "# Loading ld index:\n", + "ld_index = LDIndex.from_parquet(session, ld_index_path)\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "id": "3d13ae41", + "metadata": {}, + "source": [ + "## 4. LD based clumping.\n", + "\n", + "- Persist resulting dataset.\n", + "- Save dataset." + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "20449e76", + "metadata": { + "ExecuteTime": { + "end_time": "2023-10-06T09:42:11.040193Z", + "start_time": "2023-10-06T09:09:52.968139Z" }, + "scrolled": false + }, + "outputs": [ { - "cell_type": "code", - "execution_count": 20, - "id": "20449e76", - "metadata": { - "ExecuteTime": { - "end_time": "2023-10-06T09:42:11.040193Z", - "start_time": "2023-10-06T09:09:52.968139Z" - }, - "scrolled": false - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "23/10/06 09:11:42 WARN GhfsStorageStatistics: Detected potential high latency for operation stream_read_operations. latencyMs=1312; previousMaxLatencyMs=1306; operationCount=59583672; context=gs://genetics_etl_python_playground/output/python_etl/parquet/XX.XX/preprocess/finngen/summary_stats/FINNGEN_R9_RX_N05C/chromosome=1/part-00012-a13aba14-79f4-45c0-9af0-937d599fa3f0.c000.snappy.parquet\n", - "23/10/06 09:11:43 WARN GhfsStorageStatistics: Detected potential high latency for operation stream_read_operations. latencyMs=1316; previousMaxLatencyMs=1312; operationCount=59631953; context=gs://genetics_etl_python_playground/output/python_etl/parquet/XX.XX/preprocess/finngen/summary_stats/FINNGEN_R9_RX_CODEINE_TRAMADOL/chromosome=1/part-00012-36e099c5-3f60-4091-bf73-6fa15d48af6c.c000.snappy.parquet\n", - "23/10/06 09:16:19 WARN GhfsStorageStatistics: Detected potential high latency for operation stream_read_operations. latencyMs=1489; previousMaxLatencyMs=1316; operationCount=76331604; context=gs://genetics_etl_python_playground/output/python_etl/parquet/XX.XX/ld_index/chromosome=7/part-00010-ff42773a-494c-46d2-bc22-322062b5e715.c000.snappy.parquet\n", - "23/10/06 09:16:21 WARN GhfsStorageStatistics: Detected potential high latency for operation stream_read_operations. latencyMs=1735; previousMaxLatencyMs=1489; operationCount=76482674; context=gs://genetics_etl_python_playground/output/python_etl/parquet/XX.XX/ld_index/chromosome=7/part-00010-ff42773a-494c-46d2-bc22-322062b5e715.c000.snappy.parquet\n", - "23/10/06 09:16:23 WARN GhfsStorageStatistics: Detected potential high latency for operation stream_write_operations. latencyMs=460; previousMaxLatencyMs=337; operationCount=17471; context=gs://dataproc-temp-europe-west1-426265110888-ymkbpaze/64dcfdf8-46d3-4b5c-aad4-0a12ee0ba91a/spark-job-history/local-1696579691428.inprogress\n", - "23/10/06 09:27:35 WARN GhfsStorageStatistics: Detected potential high latency for operation op_open. latencyMs=1041; previousMaxLatencyMs=1034; operationCount=215062; context=gs://genetics_etl_python_playground/output/python_etl/parquet/XX.XX/preprocess/finngen/summary_stats/FINNGEN_R9_M13_DORSOPATHYNAS/chromosome=19/part-00009-09e75b10-c64d-4b79-9c84-6b0ca039c439.c000.snappy.parquet\n", - "23/10/06 09:41:56 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=126; previousMaxLatencyMs=93; operationCount=32; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909552056325521918358154_0027_m_000008_57347/part-00008-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", - "23/10/06 09:41:56 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=134; previousMaxLatencyMs=126; operationCount=32; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909555844252084106444775_0027_m_000028_57367/part-00028-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", - "23/10/06 09:41:56 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=134; previousMaxLatencyMs=126; operationCount=32; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909556216099889261123757_0027_m_000015_57354/part-00015-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", - "23/10/06 09:41:56 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=137; previousMaxLatencyMs=134; operationCount=32; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909553770650668910223592_0027_m_000020_57359/part-00020-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", - "23/10/06 09:41:56 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=134; previousMaxLatencyMs=126; operationCount=32; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909552371970894888794726_0027_m_000025_57364/part-00025-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", - "23/10/06 09:41:56 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=136; previousMaxLatencyMs=134; operationCount=32; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_20231006090955320032532820679068_0027_m_000009_57348/part-00009-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", - "23/10/06 09:41:56 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=139; previousMaxLatencyMs=136; operationCount=32; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909554704118087127617221_0027_m_000031_57370/part-00031-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", - "23/10/06 09:41:56 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=139; previousMaxLatencyMs=136; operationCount=32; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_20231006090955146935648450954616_0027_m_000021_57360/part-00021-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", - "23/10/06 09:41:56 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=140; previousMaxLatencyMs=139; operationCount=32; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909557457999139377546046_0027_m_000026_57365/part-00026-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", - "23/10/06 09:41:56 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=141; previousMaxLatencyMs=140; operationCount=32; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909557648490159907156305_0027_m_000017_57356/part-00017-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", - "23/10/06 09:41:56 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=144; previousMaxLatencyMs=141; operationCount=32; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909556136722862237844168_0027_m_000013_57352/part-00013-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", - "23/10/06 09:41:56 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=143; previousMaxLatencyMs=141; operationCount=32; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_20231006090955993438161489409499_0027_m_000016_57355/part-00016-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", - "23/10/06 09:41:56 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=144; previousMaxLatencyMs=141; operationCount=32; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909552708616931813844767_0027_m_000006_57345/part-00006-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", - "23/10/06 09:41:56 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=145; previousMaxLatencyMs=144; operationCount=32; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909555919710644676214353_0027_m_000004_57343/part-00004-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", - "23/10/06 09:41:56 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=145; previousMaxLatencyMs=144; operationCount=32; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909551292246187607294419_0027_m_000002_57341/part-00002-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", - "23/10/06 09:41:56 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=146; previousMaxLatencyMs=145; operationCount=32; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909551853556311935071964_0027_m_000030_57369/part-00030-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", - "23/10/06 09:41:56 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=147; previousMaxLatencyMs=146; operationCount=32; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909555640079838863826112_0027_m_000022_57361/part-00022-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", - "23/10/06 09:41:56 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=147; previousMaxLatencyMs=146; operationCount=32; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_20231006090955962380753726438814_0027_m_000000_57339/part-00000-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", - "23/10/06 09:41:56 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=149; previousMaxLatencyMs=147; operationCount=32; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909551603246466691698658_0027_m_000001_57340/part-00001-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", - "23/10/06 09:41:56 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=150; previousMaxLatencyMs=149; operationCount=32; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909554079176040000118228_0027_m_000027_57366/part-00027-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", - "23/10/06 09:41:56 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=154; previousMaxLatencyMs=150; operationCount=32; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909553545408253172771512_0027_m_000005_57344/part-00005-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", - "23/10/06 09:41:56 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=156; previousMaxLatencyMs=154; operationCount=32; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909556087040172921209608_0027_m_000018_57357/part-00018-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", - "23/10/06 09:41:56 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=160; previousMaxLatencyMs=156; operationCount=32; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_20231006090955995307818437095879_0027_m_000024_57363/part-00024-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", - "23/10/06 09:41:56 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=161; previousMaxLatencyMs=160; operationCount=32; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909552743075067405201713_0027_m_000014_57353/part-00014-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", - "23/10/06 09:41:56 WARN GhfsStorageStatistics: Detected potential high latency for operation stream_write_close_operations. latencyMs=106; previousMaxLatencyMs=95; operationCount=30; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909551603246466691698658_0027_m_000001_57340/part-00001-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", - "23/10/06 09:41:57 WARN GhfsStorageStatistics: Detected potential high latency for operation stream_write_close_operations. latencyMs=138; previousMaxLatencyMs=106; operationCount=31; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909552371970894888794726_0027_m_000025_57364/part-00025-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", - "23/10/06 09:41:57 WARN GhfsStorageStatistics: Detected potential high latency for operation op_rename. latencyMs=165; previousMaxLatencyMs=0; operationCount=30; context=rename(gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_20231006090955320032532820679068_0027_m_000009_57348/part-00009-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet -> gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/part-00009-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet)\n", - "23/10/06 09:41:57 WARN GhfsStorageStatistics: Detected potential high latency for operation op_rename. latencyMs=183; previousMaxLatencyMs=165; operationCount=30; context=rename(gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_20231006090955962380753726438814_0027_m_000000_57339/part-00000-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet -> gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/part-00000-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet)\n", - "23/10/06 09:41:57 WARN GhfsStorageStatistics: Detected potential high latency for operation op_rename. latencyMs=186; previousMaxLatencyMs=183; operationCount=30; context=rename(gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909552708616931813844767_0027_m_000006_57345/part-00006-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet -> gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/part-00006-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet)\n", - "23/10/06 09:41:57 WARN GhfsStorageStatistics: Detected potential high latency for operation op_rename. latencyMs=191; previousMaxLatencyMs=186; operationCount=30; context=rename(gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909555919710644676214353_0027_m_000004_57343/part-00004-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet -> gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/part-00004-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet)\n", - "23/10/06 09:41:57 WARN GhfsStorageStatistics: Detected potential high latency for operation op_rename. latencyMs=227; previousMaxLatencyMs=186; operationCount=30; context=rename(gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909554079176040000118228_0027_m_000027_57366/part-00027-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet -> gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/part-00027-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet)\n", - "23/10/06 09:41:57 WARN GhfsStorageStatistics: Detected potential high latency for operation op_rename. latencyMs=233; previousMaxLatencyMs=227; operationCount=30; context=rename(gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909556216099889261123757_0027_m_000015_57354/part-00015-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet -> gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/part-00015-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet)\n", - "23/10/06 09:41:57 WARN GhfsStorageStatistics: Detected potential high latency for operation op_rename. latencyMs=239; previousMaxLatencyMs=233; operationCount=31; context=rename(gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909554704118087127617221_0027_m_000031_57370/part-00031-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet -> gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/part-00031-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet)\n", - "23/10/06 09:41:57 WARN GhfsStorageStatistics: Detected potential high latency for operation op_rename. latencyMs=284; previousMaxLatencyMs=239; operationCount=31; context=rename(gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909551853556311935071964_0027_m_000030_57369/part-00030-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet -> gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/part-00030-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet)\n", - "23/10/06 09:41:57 WARN GhfsStorageStatistics: Detected potential high latency for operation op_delete. latencyMs=128; previousMaxLatencyMs=0; operationCount=28; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909555919710644676214353_0027_m_000004_57343\n", - "23/10/06 09:41:57 WARN GhfsStorageStatistics: Detected potential high latency for operation op_rename. latencyMs=318; previousMaxLatencyMs=284; operationCount=31; context=rename(gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_20231006090955146935648450954616_0027_m_000021_57360/part-00021-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet -> gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/part-00021-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet)\n", - "23/10/06 09:41:57 WARN GhfsStorageStatistics: Detected potential high latency for operation op_delete. latencyMs=150; previousMaxLatencyMs=128; operationCount=29; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909555920613268130744433_0027_m_000010_57349\n", - "23/10/06 09:41:57 WARN GhfsStorageStatistics: Detected potential high latency for operation op_delete. latencyMs=190; previousMaxLatencyMs=150; operationCount=29; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_20231006090955320032532820679068_0027_m_000009_57348\n", - "23/10/06 09:41:57 WARN GhfsStorageStatistics: Detected potential high latency for operation op_delete. latencyMs=226; previousMaxLatencyMs=190; operationCount=30; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909554079176040000118228_0027_m_000027_57366\n", - "23/10/06 09:41:57 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=172; previousMaxLatencyMs=161; operationCount=53; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909557479860471944928338_0027_m_000035_57374/part-00035-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", - "23/10/06 09:41:57 WARN GhfsStorageStatistics: Detected potential high latency for operation stream_write_close_operations. latencyMs=146; previousMaxLatencyMs=138; operationCount=53; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909557479860471944928338_0027_m_000035_57374/part-00035-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", - "23/10/06 09:41:58 WARN GhfsStorageStatistics: Detected potential high latency for operation stream_write_close_operations. latencyMs=150; previousMaxLatencyMs=146; operationCount=60; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909551578112291921242039_0027_m_000054_57393/part-00054-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", - "23/10/06 09:41:58 WARN GhfsStorageStatistics: Detected potential high latency for operation op_delete. latencyMs=1259; previousMaxLatencyMs=226; operationCount=53; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909551853556311935071964_0027_m_000030_57369\n", - "23/10/06 09:41:58 WARN GhfsStorageStatistics: Detected potential high latency for operation op_delete. latencyMs=1497; previousMaxLatencyMs=1259; operationCount=56; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909557355876953011052025_0027_m_000019_57358\n", - "23/10/06 09:41:58 WARN GhfsStorageStatistics: Detected potential high latency for operation op_rename. latencyMs=711; previousMaxLatencyMs=318; operationCount=75; context=rename(gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909557693125728422191174_0027_m_000050_57389/part-00050-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet -> gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/part-00050-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet)\n", - "23/10/06 09:41:59 WARN GhfsStorageStatistics: Detected potential high latency for operation stream_write_close_operations. latencyMs=157; previousMaxLatencyMs=150; operationCount=93; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909551476648569527086024_0027_m_000080_57419/part-00080-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", - "23/10/06 09:41:59 WARN GhfsStorageStatistics: Detected potential high latency for operation op_rename. latencyMs=752; previousMaxLatencyMs=711; operationCount=91; context=rename(gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909554631887941475021153_0027_m_000057_57396/part-00057-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet -> gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/part-00057-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet)\n", - "23/10/06 09:41:59 WARN GhfsStorageStatistics: Detected potential high latency for operation stream_write_close_operations. latencyMs=182; previousMaxLatencyMs=157; operationCount=96; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909556932256815778386100_0027_m_000093_57432/part-00093-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", - "23/10/06 09:42:00 WARN GhfsStorageStatistics: Detected potential high latency for operation stream_write_close_operations. latencyMs=201; previousMaxLatencyMs=182; operationCount=128; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909554714655772639032866_0027_m_000122_57461/part-00122-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", - "23/10/06 09:42:01 WARN GhfsStorageStatistics: Detected potential high latency for operation stream_write_close_operations. latencyMs=253; previousMaxLatencyMs=201; operationCount=187; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909555299227751328654817_0027_m_000175_57513/part-00175-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", - "23/10/06 09:42:02 WARN GhfsStorageStatistics: Detected potential high latency for operation op_rename. latencyMs=1159; previousMaxLatencyMs=752; operationCount=198; context=rename(gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909556191692784728530413_0027_m_000172_57510/part-00172-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet -> gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/part-00172-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet)\n", - "23/10/06 09:42:02 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=1051; previousMaxLatencyMs=172; operationCount=200; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_20231006090955452778920582844510_0027_m_000198_57536/part-00198-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", - "23/10/06 09:42:08 WARN GhfsStorageStatistics: Detected potential high latency for operation op_delete. latencyMs=11057; previousMaxLatencyMs=1497; operationCount=199; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909557457999139377546046_0027_m_000026_57365\n", - "23/10/06 09:42:08 WARN GhfsStorageStatistics: Detected potential high latency for operation op_delete. latencyMs=11233; previousMaxLatencyMs=11057; operationCount=199; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909551292246187607294419_0027_m_000002_57341\n", - "23/10/06 09:42:08 WARN GhfsStorageStatistics: Detected potential high latency for operation op_delete. latencyMs=11402; previousMaxLatencyMs=11233; operationCount=199; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909552371970894888794726_0027_m_000025_57364\n", - "23/10/06 09:42:08 WARN GhfsStorageStatistics: Detected potential high latency for operation op_delete. latencyMs=11583; previousMaxLatencyMs=11402; operationCount=199; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909556136722862237844168_0027_m_000013_57352\n", - "23/10/06 09:42:09 WARN GhfsStorageStatistics: Detected potential high latency for operation op_delete. latencyMs=12651; previousMaxLatencyMs=11583; operationCount=199; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909553722108484298157195_0027_m_000023_57362\n", - "23/10/06 09:42:10 WARN GhfsStorageStatistics: Detected potential high latency for operation op_delete. latencyMs=13120; previousMaxLatencyMs=12651; operationCount=199; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909554704118087127617221_0027_m_000031_57370\n", - "23/10/06 09:42:10 WARN GhfsStorageStatistics: Detected potential high latency for operation op_delete. latencyMs=13440; previousMaxLatencyMs=13120; operationCount=199; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909553545408253172771512_0027_m_000005_57344\n", - " \r" - ] - } - ], - "source": [ - "(\n", - " # To annotate study/locus, study level info and ld panel is needed:\n", - " LDAnnotator.ld_annotate(\n", - " StudyLocus.from_parquet(session, window_based_clumped_output),\n", - " study_index, \n", - " ld_index\n", - " )\n", - " # Clumping linked study-loci together:\n", - " .clump()\n", - " .df.write.mode('overwrite').parquet(ld_clumped_output)\n", - ")\n", - "\n" - ] - }, + "name": "stderr", + "output_type": "stream", + "text": [ + "23/10/06 09:11:42 WARN GhfsStorageStatistics: Detected potential high latency for operation stream_read_operations. latencyMs=1312; previousMaxLatencyMs=1306; operationCount=59583672; context=gs://genetics_etl_python_playground/output/python_etl/parquet/XX.XX/preprocess/finngen/summary_stats/FINNGEN_R9_RX_N05C/chromosome=1/part-00012-a13aba14-79f4-45c0-9af0-937d599fa3f0.c000.snappy.parquet\n", + "23/10/06 09:11:43 WARN GhfsStorageStatistics: Detected potential high latency for operation stream_read_operations. latencyMs=1316; previousMaxLatencyMs=1312; operationCount=59631953; context=gs://genetics_etl_python_playground/output/python_etl/parquet/XX.XX/preprocess/finngen/summary_stats/FINNGEN_R9_RX_CODEINE_TRAMADOL/chromosome=1/part-00012-36e099c5-3f60-4091-bf73-6fa15d48af6c.c000.snappy.parquet\n", + "23/10/06 09:16:19 WARN GhfsStorageStatistics: Detected potential high latency for operation stream_read_operations. latencyMs=1489; previousMaxLatencyMs=1316; operationCount=76331604; context=gs://genetics_etl_python_playground/output/python_etl/parquet/XX.XX/ld_index/chromosome=7/part-00010-ff42773a-494c-46d2-bc22-322062b5e715.c000.snappy.parquet\n", + "23/10/06 09:16:21 WARN GhfsStorageStatistics: Detected potential high latency for operation stream_read_operations. latencyMs=1735; previousMaxLatencyMs=1489; operationCount=76482674; context=gs://genetics_etl_python_playground/output/python_etl/parquet/XX.XX/ld_index/chromosome=7/part-00010-ff42773a-494c-46d2-bc22-322062b5e715.c000.snappy.parquet\n", + "23/10/06 09:16:23 WARN GhfsStorageStatistics: Detected potential high latency for operation stream_write_operations. latencyMs=460; previousMaxLatencyMs=337; operationCount=17471; context=gs://dataproc-temp-europe-west1-426265110888-ymkbpaze/64dcfdf8-46d3-4b5c-aad4-0a12ee0ba91a/spark-job-history/local-1696579691428.inprogress\n", + "23/10/06 09:27:35 WARN GhfsStorageStatistics: Detected potential high latency for operation op_open. latencyMs=1041; previousMaxLatencyMs=1034; operationCount=215062; context=gs://genetics_etl_python_playground/output/python_etl/parquet/XX.XX/preprocess/finngen/summary_stats/FINNGEN_R9_M13_DORSOPATHYNAS/chromosome=19/part-00009-09e75b10-c64d-4b79-9c84-6b0ca039c439.c000.snappy.parquet\n", + "23/10/06 09:41:56 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=126; previousMaxLatencyMs=93; operationCount=32; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909552056325521918358154_0027_m_000008_57347/part-00008-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", + "23/10/06 09:41:56 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=134; previousMaxLatencyMs=126; operationCount=32; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909555844252084106444775_0027_m_000028_57367/part-00028-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", + "23/10/06 09:41:56 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=134; previousMaxLatencyMs=126; operationCount=32; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909556216099889261123757_0027_m_000015_57354/part-00015-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", + "23/10/06 09:41:56 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=137; previousMaxLatencyMs=134; operationCount=32; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909553770650668910223592_0027_m_000020_57359/part-00020-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", + "23/10/06 09:41:56 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=134; previousMaxLatencyMs=126; operationCount=32; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909552371970894888794726_0027_m_000025_57364/part-00025-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", + "23/10/06 09:41:56 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=136; previousMaxLatencyMs=134; operationCount=32; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_20231006090955320032532820679068_0027_m_000009_57348/part-00009-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", + "23/10/06 09:41:56 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=139; previousMaxLatencyMs=136; operationCount=32; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909554704118087127617221_0027_m_000031_57370/part-00031-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", + "23/10/06 09:41:56 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=139; previousMaxLatencyMs=136; operationCount=32; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_20231006090955146935648450954616_0027_m_000021_57360/part-00021-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", + "23/10/06 09:41:56 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=140; previousMaxLatencyMs=139; operationCount=32; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909557457999139377546046_0027_m_000026_57365/part-00026-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", + "23/10/06 09:41:56 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=141; previousMaxLatencyMs=140; operationCount=32; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909557648490159907156305_0027_m_000017_57356/part-00017-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", + "23/10/06 09:41:56 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=144; previousMaxLatencyMs=141; operationCount=32; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909556136722862237844168_0027_m_000013_57352/part-00013-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", + "23/10/06 09:41:56 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=143; previousMaxLatencyMs=141; operationCount=32; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_20231006090955993438161489409499_0027_m_000016_57355/part-00016-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", + "23/10/06 09:41:56 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=144; previousMaxLatencyMs=141; operationCount=32; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909552708616931813844767_0027_m_000006_57345/part-00006-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", + "23/10/06 09:41:56 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=145; previousMaxLatencyMs=144; operationCount=32; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909555919710644676214353_0027_m_000004_57343/part-00004-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", + "23/10/06 09:41:56 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=145; previousMaxLatencyMs=144; operationCount=32; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909551292246187607294419_0027_m_000002_57341/part-00002-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", + "23/10/06 09:41:56 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=146; previousMaxLatencyMs=145; operationCount=32; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909551853556311935071964_0027_m_000030_57369/part-00030-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", + "23/10/06 09:41:56 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=147; previousMaxLatencyMs=146; operationCount=32; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909555640079838863826112_0027_m_000022_57361/part-00022-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", + "23/10/06 09:41:56 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=147; previousMaxLatencyMs=146; operationCount=32; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_20231006090955962380753726438814_0027_m_000000_57339/part-00000-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", + "23/10/06 09:41:56 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=149; previousMaxLatencyMs=147; operationCount=32; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909551603246466691698658_0027_m_000001_57340/part-00001-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", + "23/10/06 09:41:56 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=150; previousMaxLatencyMs=149; operationCount=32; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909554079176040000118228_0027_m_000027_57366/part-00027-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", + "23/10/06 09:41:56 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=154; previousMaxLatencyMs=150; operationCount=32; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909553545408253172771512_0027_m_000005_57344/part-00005-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", + "23/10/06 09:41:56 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=156; previousMaxLatencyMs=154; operationCount=32; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909556087040172921209608_0027_m_000018_57357/part-00018-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", + "23/10/06 09:41:56 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=160; previousMaxLatencyMs=156; operationCount=32; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_20231006090955995307818437095879_0027_m_000024_57363/part-00024-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", + "23/10/06 09:41:56 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=161; previousMaxLatencyMs=160; operationCount=32; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909552743075067405201713_0027_m_000014_57353/part-00014-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", + "23/10/06 09:41:56 WARN GhfsStorageStatistics: Detected potential high latency for operation stream_write_close_operations. latencyMs=106; previousMaxLatencyMs=95; operationCount=30; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909551603246466691698658_0027_m_000001_57340/part-00001-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", + "23/10/06 09:41:57 WARN GhfsStorageStatistics: Detected potential high latency for operation stream_write_close_operations. latencyMs=138; previousMaxLatencyMs=106; operationCount=31; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909552371970894888794726_0027_m_000025_57364/part-00025-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", + "23/10/06 09:41:57 WARN GhfsStorageStatistics: Detected potential high latency for operation op_rename. latencyMs=165; previousMaxLatencyMs=0; operationCount=30; context=rename(gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_20231006090955320032532820679068_0027_m_000009_57348/part-00009-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet -> gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/part-00009-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet)\n", + "23/10/06 09:41:57 WARN GhfsStorageStatistics: Detected potential high latency for operation op_rename. latencyMs=183; previousMaxLatencyMs=165; operationCount=30; context=rename(gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_20231006090955962380753726438814_0027_m_000000_57339/part-00000-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet -> gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/part-00000-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet)\n", + "23/10/06 09:41:57 WARN GhfsStorageStatistics: Detected potential high latency for operation op_rename. latencyMs=186; previousMaxLatencyMs=183; operationCount=30; context=rename(gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909552708616931813844767_0027_m_000006_57345/part-00006-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet -> gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/part-00006-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet)\n", + "23/10/06 09:41:57 WARN GhfsStorageStatistics: Detected potential high latency for operation op_rename. latencyMs=191; previousMaxLatencyMs=186; operationCount=30; context=rename(gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909555919710644676214353_0027_m_000004_57343/part-00004-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet -> gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/part-00004-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet)\n", + "23/10/06 09:41:57 WARN GhfsStorageStatistics: Detected potential high latency for operation op_rename. latencyMs=227; previousMaxLatencyMs=186; operationCount=30; context=rename(gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909554079176040000118228_0027_m_000027_57366/part-00027-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet -> gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/part-00027-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet)\n", + "23/10/06 09:41:57 WARN GhfsStorageStatistics: Detected potential high latency for operation op_rename. latencyMs=233; previousMaxLatencyMs=227; operationCount=30; context=rename(gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909556216099889261123757_0027_m_000015_57354/part-00015-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet -> gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/part-00015-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet)\n", + "23/10/06 09:41:57 WARN GhfsStorageStatistics: Detected potential high latency for operation op_rename. latencyMs=239; previousMaxLatencyMs=233; operationCount=31; context=rename(gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909554704118087127617221_0027_m_000031_57370/part-00031-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet -> gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/part-00031-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet)\n", + "23/10/06 09:41:57 WARN GhfsStorageStatistics: Detected potential high latency for operation op_rename. latencyMs=284; previousMaxLatencyMs=239; operationCount=31; context=rename(gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909551853556311935071964_0027_m_000030_57369/part-00030-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet -> gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/part-00030-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet)\n", + "23/10/06 09:41:57 WARN GhfsStorageStatistics: Detected potential high latency for operation op_delete. latencyMs=128; previousMaxLatencyMs=0; operationCount=28; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909555919710644676214353_0027_m_000004_57343\n", + "23/10/06 09:41:57 WARN GhfsStorageStatistics: Detected potential high latency for operation op_rename. latencyMs=318; previousMaxLatencyMs=284; operationCount=31; context=rename(gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_20231006090955146935648450954616_0027_m_000021_57360/part-00021-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet -> gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/part-00021-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet)\n", + "23/10/06 09:41:57 WARN GhfsStorageStatistics: Detected potential high latency for operation op_delete. latencyMs=150; previousMaxLatencyMs=128; operationCount=29; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909555920613268130744433_0027_m_000010_57349\n", + "23/10/06 09:41:57 WARN GhfsStorageStatistics: Detected potential high latency for operation op_delete. latencyMs=190; previousMaxLatencyMs=150; operationCount=29; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_20231006090955320032532820679068_0027_m_000009_57348\n", + "23/10/06 09:41:57 WARN GhfsStorageStatistics: Detected potential high latency for operation op_delete. latencyMs=226; previousMaxLatencyMs=190; operationCount=30; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909554079176040000118228_0027_m_000027_57366\n", + "23/10/06 09:41:57 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=172; previousMaxLatencyMs=161; operationCount=53; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909557479860471944928338_0027_m_000035_57374/part-00035-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", + "23/10/06 09:41:57 WARN GhfsStorageStatistics: Detected potential high latency for operation stream_write_close_operations. latencyMs=146; previousMaxLatencyMs=138; operationCount=53; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909557479860471944928338_0027_m_000035_57374/part-00035-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", + "23/10/06 09:41:58 WARN GhfsStorageStatistics: Detected potential high latency for operation stream_write_close_operations. latencyMs=150; previousMaxLatencyMs=146; operationCount=60; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909551578112291921242039_0027_m_000054_57393/part-00054-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", + "23/10/06 09:41:58 WARN GhfsStorageStatistics: Detected potential high latency for operation op_delete. latencyMs=1259; previousMaxLatencyMs=226; operationCount=53; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909551853556311935071964_0027_m_000030_57369\n", + "23/10/06 09:41:58 WARN GhfsStorageStatistics: Detected potential high latency for operation op_delete. latencyMs=1497; previousMaxLatencyMs=1259; operationCount=56; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909557355876953011052025_0027_m_000019_57358\n", + "23/10/06 09:41:58 WARN GhfsStorageStatistics: Detected potential high latency for operation op_rename. latencyMs=711; previousMaxLatencyMs=318; operationCount=75; context=rename(gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909557693125728422191174_0027_m_000050_57389/part-00050-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet -> gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/part-00050-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet)\n", + "23/10/06 09:41:59 WARN GhfsStorageStatistics: Detected potential high latency for operation stream_write_close_operations. latencyMs=157; previousMaxLatencyMs=150; operationCount=93; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909551476648569527086024_0027_m_000080_57419/part-00080-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", + "23/10/06 09:41:59 WARN GhfsStorageStatistics: Detected potential high latency for operation op_rename. latencyMs=752; previousMaxLatencyMs=711; operationCount=91; context=rename(gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909554631887941475021153_0027_m_000057_57396/part-00057-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet -> gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/part-00057-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet)\n", + "23/10/06 09:41:59 WARN GhfsStorageStatistics: Detected potential high latency for operation stream_write_close_operations. latencyMs=182; previousMaxLatencyMs=157; operationCount=96; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909556932256815778386100_0027_m_000093_57432/part-00093-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", + "23/10/06 09:42:00 WARN GhfsStorageStatistics: Detected potential high latency for operation stream_write_close_operations. latencyMs=201; previousMaxLatencyMs=182; operationCount=128; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909554714655772639032866_0027_m_000122_57461/part-00122-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", + "23/10/06 09:42:01 WARN GhfsStorageStatistics: Detected potential high latency for operation stream_write_close_operations. latencyMs=253; previousMaxLatencyMs=201; operationCount=187; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909555299227751328654817_0027_m_000175_57513/part-00175-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", + "23/10/06 09:42:02 WARN GhfsStorageStatistics: Detected potential high latency for operation op_rename. latencyMs=1159; previousMaxLatencyMs=752; operationCount=198; context=rename(gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909556191692784728530413_0027_m_000172_57510/part-00172-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet -> gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/part-00172-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet)\n", + "23/10/06 09:42:02 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=1051; previousMaxLatencyMs=172; operationCount=200; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_20231006090955452778920582844510_0027_m_000198_57536/part-00198-a0adc7ff-71a9-4671-ad1e-0093f9d7d260-c000.snappy.parquet\n", + "23/10/06 09:42:08 WARN GhfsStorageStatistics: Detected potential high latency for operation op_delete. latencyMs=11057; previousMaxLatencyMs=1497; operationCount=199; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909557457999139377546046_0027_m_000026_57365\n", + "23/10/06 09:42:08 WARN GhfsStorageStatistics: Detected potential high latency for operation op_delete. latencyMs=11233; previousMaxLatencyMs=11057; operationCount=199; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909551292246187607294419_0027_m_000002_57341\n", + "23/10/06 09:42:08 WARN GhfsStorageStatistics: Detected potential high latency for operation op_delete. latencyMs=11402; previousMaxLatencyMs=11233; operationCount=199; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909552371970894888794726_0027_m_000025_57364\n", + "23/10/06 09:42:08 WARN GhfsStorageStatistics: Detected potential high latency for operation op_delete. latencyMs=11583; previousMaxLatencyMs=11402; operationCount=199; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909556136722862237844168_0027_m_000013_57352\n", + "23/10/06 09:42:09 WARN GhfsStorageStatistics: Detected potential high latency for operation op_delete. latencyMs=12651; previousMaxLatencyMs=11583; operationCount=199; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909553722108484298157195_0027_m_000023_57362\n", + "23/10/06 09:42:10 WARN GhfsStorageStatistics: Detected potential high latency for operation op_delete. latencyMs=13120; previousMaxLatencyMs=12651; operationCount=199; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909554704118087127617221_0027_m_000031_57370\n", + "23/10/06 09:42:10 WARN GhfsStorageStatistics: Detected potential high latency for operation op_delete. latencyMs=13440; previousMaxLatencyMs=13120; operationCount=199; context=gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped/_temporary/0/_temporary/attempt_202310060909553545408253172771512_0027_m_000005_57344\n", + " \r" + ] + } + ], + "source": [ + "(\n", + " # To annotate study/locus, study level info and ld panel is needed:\n", + " LDAnnotator.ld_annotate(\n", + " StudyLocus.from_parquet(session, window_based_clumped_output),\n", + " study_index,\n", + " ld_index\n", + " )\n", + " # Clumping linked study-loci together:\n", + " .clump()\n", + " .df.write.mode(\"overwrite\").parquet(ld_clumped_output)\n", + ")\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "id": "3ec08141", + "metadata": {}, + "source": [ + "## 5. PICS - finemapping." + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "aab9d72e", + "metadata": { + "ExecuteTime": { + "end_time": "2023-10-06T09:50:46.179833Z", + "start_time": "2023-10-06T09:49:25.408253Z" + } + }, + "outputs": [ { - "cell_type": "markdown", - "id": "3ec08141", - "metadata": {}, - "source": [ - "## 5. PICS - finemapping." - ] - }, + "name": "stderr", + "output_type": "stream", + "text": [ + "23/10/06 09:50:16 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=1081; previousMaxLatencyMs=1051; operationCount=396; context=gs://ot-team/dsuveges/finngen/2023.10.06_PICSed/_temporary/0/_temporary/attempt_202310060949259143728196112407547_0033_m_000193_57732/part-00193-9d4ae5b4-a18c-4406-bd26-9387e62477de-c000.snappy.parquet\n", + " \r" + ] + } + ], + "source": [ + "(\n", + " # The previously generated LD clumped dataset is read as StudyLocus:\n", + " PICS.finemap(StudyLocus.from_parquet(session, ld_clumped_output))\n", + " .annotate_credible_sets()\n", + " .df.write.mode(\"overwrite\").parquet(picsed_output)\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "0bc2cb6e", + "metadata": {}, + "source": [ + "## QC results - Sumstats" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "id": "7cbeab8b", + "metadata": { + "ExecuteTime": { + "end_time": "2023-10-06T10:40:53.295506Z", + "start_time": "2023-10-06T10:26:04.284592Z" + } + }, + "outputs": [ { - "cell_type": "code", - "execution_count": 21, - "id": "aab9d72e", - "metadata": { - "ExecuteTime": { - "end_time": "2023-10-06T09:50:46.179833Z", - "start_time": "2023-10-06T09:49:25.408253Z" - } - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "23/10/06 09:50:16 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=1081; previousMaxLatencyMs=1051; operationCount=396; context=gs://ot-team/dsuveges/finngen/2023.10.06_PICSed/_temporary/0/_temporary/attempt_202310060949259143728196112407547_0033_m_000193_57732/part-00193-9d4ae5b4-a18c-4406-bd26-9387e62477de-c000.snappy.parquet\n", - " \r" - ] - } - ], - "source": [ - "(\n", - " # The previously generated LD clumped dataset is read as StudyLocus:\n", - " PICS.finemap(StudyLocus.from_parquet(session, ld_clumped_output))\n", - " .annotate_credible_sets()\n", - " .df.write.mode('overwrite').parquet(picsed_output)\n", - ")" - ] + "name": "stderr", + "output_type": "stream", + "text": [ + "23/10/06 10:26:41 WARN GhfsStorageStatistics: Detected potential high latency for operation stream_write_operations. latencyMs=572; previousMaxLatencyMs=460; operationCount=925353; context=gs://dataproc-temp-europe-west1-426265110888-ymkbpaze/64dcfdf8-46d3-4b5c-aad4-0a12ee0ba91a/spark-job-history/local-1696579691428.inprogress\n", + "[Stage 57:===========================================> (3 + 1) / 4]\r" + ] }, { - "cell_type": "markdown", - "id": "0bc2cb6e", - "metadata": {}, - "source": [ - "## QC results - Sumstats" - ] + "name": "stdout", + "output_type": "stream", + "text": [ + "In the Finngen dataset, there are 45,820,490,260 associations from 2,272 studies.\n" + ] }, { - "cell_type": "code", - "execution_count": 35, - "id": "7cbeab8b", - "metadata": { - "ExecuteTime": { - "end_time": "2023-10-06T10:40:53.295506Z", - "start_time": "2023-10-06T10:26:04.284592Z" - } - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "23/10/06 10:26:41 WARN GhfsStorageStatistics: Detected potential high latency for operation stream_write_operations. latencyMs=572; previousMaxLatencyMs=460; operationCount=925353; context=gs://dataproc-temp-europe-west1-426265110888-ymkbpaze/64dcfdf8-46d3-4b5c-aad4-0a12ee0ba91a/spark-job-history/local-1696579691428.inprogress\n", - "[Stage 57:===========================================> (3 + 1) / 4]\r" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "In the Finngen dataset, there are 45,820,490,260 associations from 2,272 studies.\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - } - ], - "source": [ - "assoc_count = finngen_sumstats.df.count()\n", - "study_count = finngen_sumstats.df.select('studyId').distinct().count()\n", - "\n", - "print(f'In the Finngen dataset, there are {assoc_count:,} associations from {study_count:,} studies.')" - ] - }, + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + } + ], + "source": [ + "assoc_count = finngen_sumstats.df.count()\n", + "study_count = finngen_sumstats.df.select(\"studyId\").distinct().count()\n" + ] + }, + { + "cell_type": "markdown", + "id": "19f94399", + "metadata": {}, + "source": [ + "## QC results - Window based clumping" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "id": "5ff794d4", + "metadata": { + "ExecuteTime": { + "end_time": "2023-10-06T10:41:39.724996Z", + "start_time": "2023-10-06T10:41:38.322389Z" + } + }, + "outputs": [ { - "cell_type": "markdown", - "id": "19f94399", - "metadata": {}, - "source": [ - "## QC results - Window based clumping" - ] - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "In the window based cluped dataset, there are 19,005 semi-indices, from 1,387 studies.\n" + ] + } + ], + "source": [ + "windowed_count = session.spark.read.parquet(window_based_clumped_output).count()\n", + "windowed_studies = session.spark.read.parquet(window_based_clumped_output).select(\"studyId\").distinct().count()\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "id": "d88b0d87", + "metadata": { + "ExecuteTime": { + "end_time": "2023-10-06T10:08:22.129308Z", + "start_time": "2023-10-06T10:08:18.802493Z" + } + }, + "source": [ + "## QC results - LD clumping" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "id": "3cd88471", + "metadata": { + "ExecuteTime": { + "end_time": "2023-10-06T10:43:29.370733Z", + "start_time": "2023-10-06T10:43:26.646342Z" + } + }, + "outputs": [ { - "cell_type": "code", - "execution_count": 37, - "id": "5ff794d4", - "metadata": { - "ExecuteTime": { - "end_time": "2023-10-06T10:41:39.724996Z", - "start_time": "2023-10-06T10:41:38.322389Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "In the window based cluped dataset, there are 19,005 semi-indices, from 1,387 studies.\n" - ] - } - ], - "source": [ - "windowed_count = session.spark.read.parquet(window_based_clumped_output).count()\n", - "windowed_studies = session.spark.read.parquet(window_based_clumped_output).select('studyId').distinct().count()\n", - "\n", - "print(f'In the window based cluped dataset, there are {windowed_count:,} semi-indices, from {windowed_studies:,} studies.')\n" - ] + "name": "stderr", + "output_type": "stream", + "text": [ + "[Stage 87:======================================================> (28 + 1) / 29]\r" + ] }, { - "cell_type": "markdown", - "id": "d88b0d87", - "metadata": { - "ExecuteTime": { - "end_time": "2023-10-06T10:08:22.129308Z", - "start_time": "2023-10-06T10:08:18.802493Z" - } - }, - "source": [ - "## QC results - LD clumping" - ] + "name": "stdout", + "output_type": "stream", + "text": [ + "In the LD based cluped dataset, there are 19,005 semi-indices, from 1,387 studies.\n" + ] }, { - "cell_type": "code", - "execution_count": 38, - "id": "3cd88471", - "metadata": { - "ExecuteTime": { - "end_time": "2023-10-06T10:43:29.370733Z", - "start_time": "2023-10-06T10:43:26.646342Z" - } - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "[Stage 87:======================================================> (28 + 1) / 29]\r" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "In the LD based cluped dataset, there are 19,005 semi-indices, from 1,387 studies.\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - } - ], - "source": [ - "ld_clumped_df = session.spark.read.parquet(ld_clumped_output)\n", - "\n", - "windowed_count = ld_clumped_df.count()\n", - "windowed_studies = ld_clumped_df.select('studyId').distinct().count()\n", - "\n", - "print(f'In the LD based cluped dataset, there are {windowed_count:,} semi-indices, from {windowed_studies:,} studies.')\n" - ] - }, + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + } + ], + "source": [ + "ld_clumped_df = session.spark.read.parquet(ld_clumped_output)\n", + "\n", + "windowed_count = ld_clumped_df.count()\n", + "windowed_studies = ld_clumped_df.select(\"studyId\").distinct().count()\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "id": "d9d002d0", + "metadata": { + "ExecuteTime": { + "end_time": "2023-10-06T10:44:36.008520Z", + "start_time": "2023-10-06T10:44:34.483964Z" + } + }, + "outputs": [ { - "cell_type": "code", - "execution_count": 40, - "id": "d9d002d0", - "metadata": { - "ExecuteTime": { - "end_time": "2023-10-06T10:44:36.008520Z", - "start_time": "2023-10-06T10:44:34.483964Z" - } - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "[Stage 93:====================================================> (27 + 2) / 29]\r" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "+--------------------------------------------------------------+-----+\n", - "|qualityControls |count|\n", - "+--------------------------------------------------------------+-----+\n", - "|[Variant not found in LD reference] |4706 |\n", - "|[] |13714|\n", - "|[Explained by a more significant variant in high LD (clumped)]|585 |\n", - "+--------------------------------------------------------------+-----+\n", - "\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - } - ], - "source": [ - "ld_clumped_df.groupBy('qualityControls').count().show(truncate=False)" - ] + "name": "stderr", + "output_type": "stream", + "text": [ + "[Stage 93:====================================================> (27 + 2) / 29]\r" + ] }, { - "cell_type": "markdown", - "id": "7a3be915", - "metadata": {}, - "source": [ - "## QC results - PICS" - ] + "name": "stdout", + "output_type": "stream", + "text": [ + "+--------------------------------------------------------------+-----+\n", + "|qualityControls |count|\n", + "+--------------------------------------------------------------+-----+\n", + "|[Variant not found in LD reference] |4706 |\n", + "|[] |13714|\n", + "|[Explained by a more significant variant in high LD (clumped)]|585 |\n", + "+--------------------------------------------------------------+-----+\n", + "\n" + ] }, { - "cell_type": "code", - "execution_count": 43, - "id": "b1ddd53c", - "metadata": { - "ExecuteTime": { - "end_time": "2023-10-06T10:59:16.339543Z", - "start_time": "2023-10-06T10:59:15.930105Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "-RECORD 0-----------------------------------------------\n", - " variantId | 20_35437976_G_A \n", - " chromosome | 20 \n", - " studyId | FINNGEN_R9_HEIGHT... \n", - " position | 35437976 \n", - " pValueMantissa | 3.811 \n", - " pValueExponent | -193 \n", - " beta | -0.0551669 \n", - " standardError | 0.00186085 \n", - " effectAlleleFrequencyFromSource | 0.5599 \n", - " betaConfidenceIntervalLower | -0.05702774999999... \n", - " betaConfidenceIntervalUpper | -0.05330605 \n", - " studyLocusId | 5242723067793949472 \n", - " qualityControls | [Variant not foun... \n", - " ldSet | null \n", - " locus | null \n", - "only showing top 1 row\n", - "\n", - "root\n", - " |-- variantId: string (nullable = true)\n", - " |-- chromosome: string (nullable = true)\n", - " |-- studyId: string (nullable = true)\n", - " |-- position: integer (nullable = true)\n", - " |-- pValueMantissa: float (nullable = true)\n", - " |-- pValueExponent: integer (nullable = true)\n", - " |-- beta: double (nullable = true)\n", - " |-- standardError: double (nullable = true)\n", - " |-- effectAlleleFrequencyFromSource: float (nullable = true)\n", - " |-- betaConfidenceIntervalLower: double (nullable = true)\n", - " |-- betaConfidenceIntervalUpper: double (nullable = true)\n", - " |-- studyLocusId: long (nullable = true)\n", - " |-- qualityControls: array (nullable = true)\n", - " | |-- element: string (containsNull = true)\n", - " |-- ldSet: array (nullable = true)\n", - " | |-- element: struct (containsNull = true)\n", - " | | |-- tagVariantId: string (nullable = true)\n", - " | | |-- r2Overall: double (nullable = true)\n", - " |-- locus: array (nullable = true)\n", - " | |-- element: struct (containsNull = true)\n", - " | | |-- variantId: string (nullable = true)\n", - " | | |-- r2Overall: double (nullable = true)\n", - " | | |-- posteriorProbability: double (nullable = true)\n", - " | | |-- standardError: double (nullable = true)\n", - " | | |-- is95CredibleSet: boolean (nullable = true)\n", - " | | |-- is99CredibleSet: boolean (nullable = true)\n", - "\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "23/10/06 10:59:16 WARN CacheManager: Asked to cache already cached data.\n" - ] - }, - { - "data": { - "text/plain": [ - "19005" - ] - }, - "execution_count": 43, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "picsed_df = session.spark.read.parquet(picsed_output).persist()\n", - "picsed_df.show(1, vertical=True)\n", - "picsed_df.printSchema()\n", - "picsed_df.count()\n" - ] - }, + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + } + ], + "source": [ + "ld_clumped_df.groupBy(\"qualityControls\").count().show(truncate=False)" + ] + }, + { + "cell_type": "markdown", + "id": "7a3be915", + "metadata": {}, + "source": [ + "## QC results - PICS" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "id": "b1ddd53c", + "metadata": { + "ExecuteTime": { + "end_time": "2023-10-06T10:59:16.339543Z", + "start_time": "2023-10-06T10:59:15.930105Z" + } + }, + "outputs": [ { - "cell_type": "code", - "execution_count": 59, - "id": "937e1eb0", - "metadata": { - "ExecuteTime": { - "end_time": "2023-10-06T11:11:55.487431Z", - "start_time": "2023-10-06T11:11:54.898030Z" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 59, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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zZs317Rp02Sz2RQdHa1du3bp7bffNts8cOBApa6gTJkyRS+//LIef/xxSdLbb7+tdevWafr06frjH/9Y6XE7f/683n//fd1+++2SpBEjRuj111+XJNWvX18+Pj4qLS1VSEhIpdusiloViAAAqMsWLFigp59+Wrfeeqs8PDx0zz33KCkpSTt27JAkDRgwwKyNiYlRbGysIiIitGLFCvXr10+GYVzT98XGxpr//vrrr3Xu3DkzIF1UVlamu+++W9KPDytu3769y13WF8PTRZW5m7u4uFhHjx5Vx44dXfZ37NhRX3755TWdg6+vrxmGJCk0NFSFhYXX1IY7EIgAAHCT22+/XRs2bNDp06dVXFys0NBQDRgwQJGRkZetDw0NVUREhDkzdPEOsn//+98Vgsrl+Pn5mf++cOGCJGnFihW69dZbXersdrskVSpwRUVFae/evT9bJ1390Ti33HJLhe88f/58hTa8vLwqtHmtwdAdavxJ1QAA3Gz8/PwUGhqqoqIirVq16rLrcSTpxIkTOnz4sPl4mYSEBAUGBmry5MmXrb/as4Jat24tu92ub7/9Vi1atHDZLj42pnXr1hVu8b/0c1JSkvbv369PP/20wncYhiGn06kGDRooLCzMZW2UJG3atEmtWrWSJDVp0kSSzAXS0o+Lqq+Vt7e3y/tJbxQCEQAAbrJq1SplZmYqLy9PWVlZ6tKli6Kjo/XUU0+ppKREqamp2rx5sw4ePKj169froYceUmBgoB555BFJPwapP/3pT1qxYoUSExO1Zs0aHTx4UNu3b9e4ceM0fPjwK363v7+/UlNT9dJLL2n+/Pn65ptvtHPnTv3xj380n300fPhwffPNNxozZoz27dunxYsXa968eS7t9O/fXwMGDNATTzyh9PR0bd++XYcOHdJnn32m7t27a926dZKkX/3qV3r77bf18ccfa9++fXrllVeUm5ur0aNHS5IZxNLS0rR//36tWLFC77zzzjWP6W233aavvvpK+/bt0/fff3/ZWSZ3IBABAOAmTqdTL774ou644w4NGjRI9913n1avXi0vLy95eHho165d6tu3r6KiojR48GBFRUVp8+bNLndP9+3bV5s2bZKXl5eSkpJ0xx136IknnpDT6dTEiROv+v1vvPGG/u///k/p6elq1aqVevbsqb///e/mJbtmzZrpk08+0d///ne1bdtW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R1fPyQIAgFqr1q4hysvLU0FBgRISEsx9drtdnTp10qZNmyRJOTk5On/+vEtNWFiYYmJizJrNmzfL4XCYYUiS2rdvL4fDYdZcTmlpqYqLi102AABwc6q1gaigoECSFBwc7LI/ODjYPFZQUCBvb281atToqjVBQUEV2g8KCjJrLic9Pd1cc+RwOBQeHn5d5wMAAGqvWhuILrLZbC6fDcOosO9Sl9Zcrv7n2hk/frycTqe5HT58+Bp7DgAA6opaG4hCQkIkqcIsTmFhoTlrFBISorKyMhUVFV215tixYxXaP378eIXZp5+y2+1q0KCBywYAAG5OtTYQRUZGKiQkRFlZWea+srIybdiwQR06dJAktWvXTl5eXi41+fn52r17t1kTHx8vp9OprVu3mjVbtmyR0+k0awAAgLXV6F1mJSUl+s9//mN+zsvLU25urgICAtSsWTOlpKRo0qRJatmypVq2bKlJkybJ19dXSUlJkiSHw6GhQ4dq7Nixaty4sQICApSamqo2bdqYd521atVKvXr10rBhwzRr1ixJ0rPPPqs+ffpwhxkAAJBUw4Fo+/bt6tKli/l5zJgxkqTBgwdr3rx5GjdunM6ePasXXnhBRUVFiouL0+rVq+Xv72/+zLRp0+Tp6an+/fvr7Nmz6tatm+bNmycPDw+zZtGiRRo1apR5N1piYuIVn30EAACsx2YYhlHTnagLiouL5XA45HQ63b6eaPOcVLe2V1vED51S010AAFhcZf9+19o1RAAAANWFQAQAACyPQAQAACyvRhdV4+Y2LWu/W9p5qUeUW9oBAOBKmCECAACWRyACAACWRyACAACWxxoi3DDtv/3ATS3xPCMAwI3FDBEAALA8AhEAALA8AhEAALA8AhEAALA8AhEAALA8AhEAALA8brtHreeuV4BIvAYEAHB5zBABAADLIxABAADLIxABAADLIxABAADLY1E1aj33vRNN4r1oAIDLYYYIAABYHoEIAABYHoEIAABYHoEIAABYHoEIAABYHneZwVLc9RoQXgECADcXZogAAIDlMUMES3HfM414nhEA3EyYIQIAAJZHIAIAAJZHIAIAAJZXqwNRWlqabDabyxYSEmIeNwxDaWlpCgsLk4+Pjzp37qw9e/a4tFFaWqqRI0cqMDBQfn5+SkxM1JEjR6r7VAAAQC1WqwORJN15553Kz883t127dpnHJk+erKlTp2rGjBnatm2bQkJC1KNHD506dcqsSUlJ0bJly5SRkaGNGzeqpKREffr0UXl5eU2cDgAAqIVq/V1mnp6eLrNCFxmGoenTp+vVV19Vv379JEnz589XcHCwFi9erOeee05Op1Nz5szRggUL1L17d0nSwoULFR4erjVr1qhnz57Vei4AAKB2qvWB6MCBAwoLC5PdbldcXJwmTZqk5s2bKy8vTwUFBUpISDBr7Xa7OnXqpE2bNum5555TTk6Ozp8/71ITFhammJgYbdq06aqBqLS0VKWlpebn4uLiG3OCqJN4wCMA3Fxq9SWzuLg4ffTRR1q1apVmz56tgoICdejQQSdOnFBBQYEkKTg42OVngoODzWMFBQXy9vZWo0aNrlhzJenp6XI4HOYWHh7uxjMDAAC1Sa0ORL1799ajjz6qNm3aqHv37lqxYoWkHy+NXWSz2Vx+xjCMCvsuVZma8ePHy+l0mtvhw4ereBYAAKC2q9WB6FJ+fn5q06aNDhw4YK4runSmp7Cw0Jw1CgkJUVlZmYqKiq5YcyV2u10NGjRw2QAAwM2pTgWi0tJS7d27V6GhoYqMjFRISIiysrLM42VlZdqwYYM6dOggSWrXrp28vLxcavLz87V7926zBgAAoFYvqk5NTdVDDz2kZs2aqbCwUBMnTlRxcbEGDx4sm82mlJQUTZo0SS1btlTLli01adIk+fr6KikpSZLkcDg0dOhQjR07Vo0bN1ZAQIBSU1PNS3AAAABSLQ9ER44c0RNPPKHvv/9eTZo0Ufv27ZWdna2IiAhJ0rhx43T27Fm98MILKioqUlxcnFavXi1/f3+zjWnTpsnT01P9+/fX2bNn1a1bN82bN08eHh41dVoAAKCWsRmGYdR0J+qC4uJiORwOOZ1Ot68n2jwn1a3t4cbLbvasW9rhtnsAuLEq+/e7Vs8QAbVV+28/cFNLU9zUDgDgehCIgBrEAx4BoHaoU3eZAQAA3AgEIgAAYHkEIgAAYHkEIgAAYHksqgZqkLvuVpuWxWMAAOB6MEMEAAAsj0AEAAAsj0AEAAAsjzVEwE2AtUgAcH2YIQIAAJZHIAIAAJbHJTMAbsc72gDUNQQiACZ3rUXKbuaetUgAUF24ZAYAACyPGSIAtRaX3gBUFwIRgFrLXZfwpCluagfAzYpLZgAAwPKYIQKASnLXJTx34VIg4D4EIgBu575LXe5R24KMu7DGCnAfAhEAVBKPJQBuXqwhAgAAlscMEQBUs9o208SlN4BABABwE4IV6jICEYCbXm1b5I2rI1hdHeNzYxCIAAA3pZv17kJ3IVi5IhABQB1V22a+uHsOdRmBCABQq9S2ReewBgIRAMAtatuMFarHzXLpjUAEALgpMdOEa2GpBzO+9957ioyMVL169dSuXTv985//rOkuAQCAWsAyM0Qff/yxUlJS9N5776ljx46aNWuWevfura+//lrNmjWr6e4BAGopZpqswTIzRFOnTtXQoUP1zDPPqFWrVpo+fbrCw8M1c+bMmu4aAACoYZaYISorK1NOTo5eeeUVl/0JCQnatGnTZX+mtLRUpaWl5men0ylJKi4udnv/Tp8t/fkiAECd1mbfH9zSzramT7mlndrmRvx9/Wm7hmFctc4Sgej7779XeXm5goODXfYHBweroKDgsj+Tnp6u3/72txX2h4eH35A+AgBQOTNqugM3xIQb3P6pU6fkcDiueNwSgegim83m8tkwjAr7Lho/frzGjBljfr5w4YL+97//qXHjxlf8mcooLi5WeHi4Dh8+rAYNGlS5HVQO4129GO/qxXhXL8a7erlrvA3D0KlTpxQWFnbVOksEosDAQHl4eFSYDSosLKwwa3SR3W6X3W532dewYUO39alBgwb8F6oaMd7Vi/GuXox39WK8q5c7xvtqM0MXWWJRtbe3t9q1a6esrCyX/VlZWerQoUMN9QoAANQWlpghkqQxY8YoOTlZsbGxio+P1wcffKBvv/1Ww4cPr+muAQCAGmaZQDRgwACdOHFCr7/+uvLz8xUTE6OVK1cqIiKiWvtht9v1m9/8psLlONwYjHf1YryrF+NdvRjv6lXd420zfu4+NAAAgJucJdYQAQAAXA2BCAAAWB6BCAAAWB6BCAAAWB6BqBq99957ioyMVL169dSuXTv985//rOku3RTS09N17733yt/fX0FBQXr44Ye1b98+lxrDMJSWlqawsDD5+Pioc+fO2rNnTw31+OaSnp4um82mlJQUcx/j7V7fffedBg4cqMaNG8vX11e/+MUvlJOTYx5nvN3nhx9+0K9//WtFRkbKx8dHzZs31+uvv64LFy6YNYx31X3xxRd66KGHFBYWJpvNpr/97W8uxysztqWlpRo5cqQCAwPl5+enxMREHTly5Po7Z6BaZGRk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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "(\n", - " picsed_df\n", - " .filter(f.col('locus').isNotNull())\n", - " .select(\n", - " 'studyId',\n", - " 'variantId',\n", - " f.aggregate(\n", - " f.transform(\n", - " f.col('locus'),\n", - " lambda locus: f.when(locus.is99CredibleSet, f.lit(1.0)).otherwise( f.lit(0.0))\n", - " ),\n", - " f.lit(0.0),\n", - " lambda summa, value: summa + value\n", - " ).alias('99CredCount'),\n", - " f.aggregate(\n", - " f.transform(\n", - " f.col('locus'),\n", - " lambda locus: f.when(locus.is95CredibleSet, f.lit(1.0)).otherwise( f.lit(0.0))\n", - " ),\n", - " f.lit(0.0),\n", - " lambda summa, value: summa + value\n", - " ).alias('95CredCount'),\n", - " )\n", - "# .orderBy(f.col('99CredCount').desc())\n", - "# .show()\n", - " .filter(f.col('99CredCount') < 100)\n", - "# .count()\n", - " .toPandas()\n", - " [['99CredCount', '95CredCount']]\n", - " .plot.hist(bins=25, alpha=0.5, label='Credible set size')\n", - ")" - ] + "name": "stdout", + "output_type": "stream", + "text": [ + "-RECORD 0-----------------------------------------------\n", + " variantId | 20_35437976_G_A \n", + " chromosome | 20 \n", + " studyId | FINNGEN_R9_HEIGHT... \n", + " position | 35437976 \n", + " pValueMantissa | 3.811 \n", + " pValueExponent | -193 \n", + " beta | -0.0551669 \n", + " standardError | 0.00186085 \n", + " effectAlleleFrequencyFromSource | 0.5599 \n", + " betaConfidenceIntervalLower | -0.05702774999999... \n", + " betaConfidenceIntervalUpper | -0.05330605 \n", + " studyLocusId | 5242723067793949472 \n", + " qualityControls | [Variant not foun... \n", + " ldSet | null \n", + " locus | null \n", + "only showing top 1 row\n", + "\n", + "root\n", + " |-- variantId: string (nullable = true)\n", + " |-- chromosome: string (nullable = true)\n", + " |-- studyId: string (nullable = true)\n", + " |-- position: integer (nullable = true)\n", + " |-- pValueMantissa: float (nullable = true)\n", + " |-- pValueExponent: integer (nullable = true)\n", + " |-- beta: double (nullable = true)\n", + " |-- standardError: double (nullable = true)\n", + " |-- effectAlleleFrequencyFromSource: float (nullable = true)\n", + " |-- betaConfidenceIntervalLower: double (nullable = true)\n", + " |-- betaConfidenceIntervalUpper: double (nullable = true)\n", + " |-- studyLocusId: long (nullable = true)\n", + " |-- qualityControls: array (nullable = true)\n", + " | |-- element: string (containsNull = true)\n", + " |-- ldSet: array (nullable = true)\n", + " | |-- element: struct (containsNull = true)\n", + " | | |-- tagVariantId: string (nullable = true)\n", + " | | |-- r2Overall: double (nullable = true)\n", + " |-- locus: array (nullable = true)\n", + " | |-- element: struct (containsNull = true)\n", + " | | |-- variantId: string (nullable = true)\n", + " | | |-- r2Overall: double (nullable = true)\n", + " | | |-- posteriorProbability: double (nullable = true)\n", + " | | |-- standardError: double (nullable = true)\n", + " | | |-- is95CredibleSet: boolean (nullable = true)\n", + " | | |-- is99CredibleSet: boolean (nullable = true)\n", + "\n" + ] }, { - "cell_type": "markdown", - "id": "a8b99c39", - "metadata": {}, - "source": [ - "## Finngen clumping with locus\n", - "\n", - "- Window width: 500kbp\n", - "- Locus width: 250kbp\n", - "- LD threshold: 0.5\n", - "\n" - ] + "name": "stderr", + "output_type": "stream", + "text": [ + "23/10/06 10:59:16 WARN CacheManager: Asked to cache already cached data.\n" + ] }, { - "cell_type": "code", - "execution_count": 2, - "id": "09f14d49", - "metadata": { - "ExecuteTime": { - "end_time": "2023-10-13T09:54:35.337711Z", - "start_time": "2023-10-13T09:54:34.446422Z" - } - }, - "outputs": [], - "source": [ - "# Import:\n", - "from pyspark.sql import functions as f, types as t\n", - "\n", - "from gentropy.common.session import Session\n", - "\n", - "from gentropy.dataset.summary_statistics import SummaryStatistics\n", - "from gentropy.dataset.study_locus import StudyLocus\n", - "from gentropy.dataset.study_index import StudyIndex\n", - "from gentropy.dataset.ld_index import LDIndex\n", - "from gentropy.method.ld import LDAnnotator\n", - "\n", - "from gentropy.method.pics import PICS\n", - "\n", - "# Initialize session:\n", - "session = Session()\n", - "\n", - "# Input:\n", - "sumstats = 'gs://genetics_etl_python_playground/output/python_etl/parquet/XX.XX/preprocess/finngen/summary_stats/*'\n", - "ld_index_path = 'gs://genetics_etl_python_playground/output/python_etl/parquet/XX.XX/ld_index/'\n", - "\n", - "# Output:\n", - "ld_clumped_output = 'gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped'\n", - "picsed_output = 'gs://ot-team/dsuveges/finngen/2023.10.06_PICSed'\n", - "window_based_clumped_output = 'gs://ot-team/dsuveges/finngen/2023.10.06_window_clumped'" + "data": { + "text/plain": [ + "19005" ] - }, + }, + "execution_count": 43, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "picsed_df = session.spark.read.parquet(picsed_output).persist()\n", + "picsed_df.show(1, vertical=True)\n", + "picsed_df.printSchema()\n", + "picsed_df.count()\n" + ] + }, + { + "cell_type": "code", + "execution_count": 59, + "id": "937e1eb0", + "metadata": { + "ExecuteTime": { + "end_time": "2023-10-06T11:11:55.487431Z", + "start_time": "2023-10-06T11:11:54.898030Z" + } + }, + "outputs": [ { - "cell_type": "code", - "execution_count": 16, - "id": "52861491", - "metadata": { - "ExecuteTime": { - "end_time": "2023-10-13T11:39:14.790777Z", - "start_time": "2023-10-13T10:47:20.349271Z" - }, - "code_folding": [], - "scrolled": false - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "23/10/13 10:47:53 WARN HintErrorLogger: Hint (strategy=broadcast) is not supported in the query: build right for right outer join.\n", - "23/10/13 10:47:53 WARN package: Truncated the string representation of a plan since it was too large. This behavior can be adjusted by setting 'spark.sql.debug.maxToStringFields'.\n", - "23/10/13 10:48:19 WARN GhfsStorageStatistics: Detected potential high latency for operation stream_read_operations. latencyMs=1248; previousMaxLatencyMs=1230; operationCount=59116581; context=gs://genetics_etl_python_playground/output/python_etl/parquet/XX.XX/preprocess/finngen/summary_stats/FINNGEN_R9_OTHER_SYSTCON_FG/chromosome=2/part-00019-1d683f00-9247-401b-846c-8b2498bc68bf.c000.snappy.parquet\n", - "23/10/13 10:49:02 WARN GhfsStorageStatistics: Detected potential high latency for operation op_get_file_status. latencyMs=1039; previousMaxLatencyMs=1037; operationCount=126124; context=gs://genetics_etl_python_playground/output/python_etl/parquet/XX.XX/preprocess/finngen/summary_stats/FINNGEN_R9_K11_SCISS_BITE_INCLAVO/chromosome=2/part-00018-e37f4a01-bdb4-442f-8dcd-681da303e876.c000.snappy.parquet\n", - "23/10/13 10:52:37 WARN GhfsStorageStatistics: Detected potential high latency for operation op_get_file_status. latencyMs=1917; previousMaxLatencyMs=1039; operationCount=144264; context=gs://genetics_etl_python_playground/output/python_etl/parquet/XX.XX/preprocess/finngen/summary_stats/FINNGEN_R9_AUTOIMMUNE_NONTHYROID_STRICT/chromosome=5/part-00006-02537c5f-2dea-47c5-8655-b0d84827115a.c000.snappy.parquet\n", - "23/10/13 10:52:38 WARN GhfsStorageStatistics: Detected potential high latency for operation stream_read_operations. latencyMs=1942; previousMaxLatencyMs=1248; operationCount=94444057; context=gs://genetics_etl_python_playground/output/python_etl/parquet/XX.XX/preprocess/finngen/summary_stats/FINNGEN_R9_K11_PULPITIS_1_ONLYAVO/chromosome=5/part-00006-de277609-305a-4cec-8bb1-5b37a70be48b.c000.snappy.parquet\n", - "23/10/13 11:07:41 WARN HintErrorLogger: Hint (strategy=broadcast) is not supported in the query: build right for right outer join.\n", - "23/10/13 11:12:32 WARN HintErrorLogger: Hint (strategy=broadcast) is not supported in the query: build right for right outer join.\n", - "23/10/13 11:12:48 WARN HintErrorLogger: Hint (strategy=broadcast) is not supported in the query: build right for right outer join.\n", - "23/10/13 11:21:40 WARN GoogleCloudStorageReadChannel: Failed read retry #1/10 for 'gs://genetics_etl_python_playground/output/python_etl/parquet/XX.XX/preprocess/finngen/summary_stats/FINNGEN_R9_H7_CONJUHAEMOR/chromosome=12/part-00016-03e2c019-d707-414b-b4e1-8b6474ccfb26.c000.snappy.parquet'. Sleeping...\n", - "java.net.SocketException: Connection reset\n", - "\tat java.net.SocketInputStream.read(SocketInputStream.java:186) ~[?:?]\n", - "\tat java.net.SocketInputStream.read(SocketInputStream.java:140) ~[?:?]\n", - "\tat org.conscrypt.ConscryptEngineSocket$SSLInputStream.readFromSocket(ConscryptEngineSocket.java:920) ~[conscrypt-openjdk-2.5.2-linux-x86_64.jar:2.5.2]\n", - "\tat org.conscrypt.ConscryptEngineSocket$SSLInputStream.processDataFromSocket(ConscryptEngineSocket.java:884) ~[conscrypt-openjdk-2.5.2-linux-x86_64.jar:2.5.2]\n", - "\tat org.conscrypt.ConscryptEngineSocket$SSLInputStream.readUntilDataAvailable(ConscryptEngineSocket.java:799) ~[conscrypt-openjdk-2.5.2-linux-x86_64.jar:2.5.2]\n", - "\tat org.conscrypt.ConscryptEngineSocket$SSLInputStream.read(ConscryptEngineSocket.java:772) ~[conscrypt-openjdk-2.5.2-linux-x86_64.jar:2.5.2]\n", - "\tat java.io.BufferedInputStream.read1(BufferedInputStream.java:290) ~[?:?]\n", - "\tat java.io.BufferedInputStream.read(BufferedInputStream.java:351) ~[?:?]\n", - "\tat sun.net.www.MeteredStream.read(MeteredStream.java:134) ~[?:?]\n", - "\tat java.io.FilterInputStream.read(FilterInputStream.java:133) ~[?:?]\n", - "\tat sun.net.www.protocol.http.HttpURLConnection$HttpInputStream.read(HttpURLConnection.java:3529) ~[?:?]\n", - "\tat com.google.cloud.hadoop.repackaged.gcs.com.google.api.client.http.javanet.NetHttpResponse$SizeValidatingInputStream.read(NetHttpResponse.java:164) ~[gcs-connector-hadoop3-2.2.16.jar:?]\n", - "\tat java.io.BufferedInputStream.read1(BufferedInputStream.java:290) ~[?:?]\n", - "\tat java.io.BufferedInputStream.read(BufferedInputStream.java:351) ~[?:?]\n", - "\tat java.nio.channels.Channels$ReadableByteChannelImpl.read(Channels.java:388) ~[?:?]\n", - "\tat com.google.cloud.hadoop.repackaged.gcs.com.google.cloud.hadoop.gcsio.GoogleCloudStorageReadChannel.read(GoogleCloudStorageReadChannel.java:315) ~[gcs-connector-hadoop3-2.2.16.jar:?]\n", - "\tat com.google.cloud.hadoop.fs.gcs.GoogleHadoopFSInputStream.lambda$read$1(GoogleHadoopFSInputStream.java:170) ~[gcs-connector-hadoop3-2.2.16.jar:?]\n", - "\tat com.google.cloud.hadoop.fs.gcs.GhfsStorageStatistics.trackDuration(GhfsStorageStatistics.java:77) ~[gcs-connector-hadoop3-2.2.16.jar:?]\n", - "\tat com.google.cloud.hadoop.fs.gcs.GoogleHadoopFSInputStream.read(GoogleHadoopFSInputStream.java:159) ~[gcs-connector-hadoop3-2.2.16.jar:?]\n", - "\tat java.io.DataInputStream.read(DataInputStream.java:149) ~[?:?]\n", - "\tat org.apache.parquet.io.DelegatingSeekableInputStream.readFully(DelegatingSeekableInputStream.java:102) ~[parquet-common-1.12.2.jar:1.12.2]\n", - "\tat org.apache.parquet.io.DelegatingSeekableInputStream.readFullyHeapBuffer(DelegatingSeekableInputStream.java:127) ~[parquet-common-1.12.2.jar:1.12.2]\n", - "\tat org.apache.parquet.io.DelegatingSeekableInputStream.readFully(DelegatingSeekableInputStream.java:91) ~[parquet-common-1.12.2.jar:1.12.2]\n", - "\tat org.apache.parquet.hadoop.ParquetFileReader$ConsecutivePartList.readAll(ParquetFileReader.java:1704) ~[parquet-hadoop-1.12.2.jar:1.12.2]\n", - "\tat org.apache.parquet.hadoop.ParquetFileReader.readNextRowGroup(ParquetFileReader.java:925) ~[parquet-hadoop-1.12.2.jar:1.12.2]\n", - "\tat org.apache.parquet.hadoop.ParquetFileReader.readNextFilteredRowGroup(ParquetFileReader.java:972) ~[parquet-hadoop-1.12.2.jar:1.12.2]\n", - "\tat org.apache.spark.sql.execution.datasources.parquet.SpecificParquetRecordReaderBase$ParquetRowGroupReaderImpl.readNextRowGroup(SpecificParquetRecordReaderBase.java:320) ~[spark-sql_2.12-3.3.0.jar:3.3.0]\n", - "\tat org.apache.spark.sql.execution.datasources.parquet.VectorizedParquetRecordReader.checkEndOfRowGroup(VectorizedParquetRecordReader.java:403) ~[spark-sql_2.12-3.3.0.jar:3.3.0]\n", - "\tat org.apache.spark.sql.execution.datasources.parquet.VectorizedParquetRecordReader.nextBatch(VectorizedParquetRecordReader.java:324) ~[spark-sql_2.12-3.3.0.jar:3.3.0]\n", - "\tat org.apache.spark.sql.execution.datasources.parquet.VectorizedParquetRecordReader.nextKeyValue(VectorizedParquetRecordReader.java:227) ~[spark-sql_2.12-3.3.0.jar:3.3.0]\n", - "\tat org.apache.spark.sql.execution.datasources.RecordReaderIterator.hasNext(RecordReaderIterator.scala:39) ~[spark-sql_2.12-3.3.0.jar:3.3.0]\n", - "\tat org.apache.spark.sql.execution.datasources.FileScanRDD$$anon$1.hasNext(FileScanRDD.scala:116) ~[spark-sql_2.12-3.3.0.jar:3.3.0]\n", - "\tat org.apache.spark.sql.execution.datasources.FileScanRDD$$anon$1.nextIterator(FileScanRDD.scala:274) ~[spark-sql_2.12-3.3.0.jar:3.3.0]\n", - "\tat org.apache.spark.sql.execution.datasources.FileScanRDD$$anon$1.hasNext(FileScanRDD.scala:116) ~[spark-sql_2.12-3.3.0.jar:3.3.0]\n", - "\tat org.apache.spark.sql.execution.FileSourceScanExec$$anon$1.hasNext(DataSourceScanExec.scala:565) ~[spark-sql_2.12-3.3.0.jar:3.3.0]\n", - "\tat org.apache.spark.sql.catalyst.expressions.GeneratedClass$GeneratedIteratorForCodegenStage1.columnartorow_nextBatch_0$(Unknown Source) ~[?:?]\n", - "\tat org.apache.spark.sql.catalyst.expressions.GeneratedClass$GeneratedIteratorForCodegenStage1.processNext(Unknown Source) ~[?:?]\n", - "\tat org.apache.spark.sql.execution.BufferedRowIterator.hasNext(BufferedRowIterator.java:43) ~[spark-sql_2.12-3.3.0.jar:3.3.0]\n", - "\tat org.apache.spark.sql.execution.WholeStageCodegenExec$$anon$1.hasNext(WholeStageCodegenExec.scala:760) ~[spark-sql_2.12-3.3.0.jar:3.3.0]\n", - "\tat scala.collection.Iterator$$anon$10.hasNext(Iterator.scala:460) ~[scala-library-2.12.14.jar:?]\n", - "\tat org.apache.spark.shuffle.sort.BypassMergeSortShuffleWriter.write(BypassMergeSortShuffleWriter.java:142) ~[spark-core_2.12-3.3.0.jar:3.3.0]\n", - "\tat org.apache.spark.shuffle.ShuffleWriteProcessor.write(ShuffleWriteProcessor.scala:59) ~[spark-core_2.12-3.3.0.jar:3.3.0]\n", - "\tat org.apache.spark.scheduler.ShuffleMapTask.runTask(ShuffleMapTask.scala:99) ~[spark-core_2.12-3.3.0.jar:3.3.0]\n", - "\tat org.apache.spark.scheduler.ShuffleMapTask.runTask(ShuffleMapTask.scala:52) ~[spark-core_2.12-3.3.0.jar:3.3.0]\n", - "\tat org.apache.spark.scheduler.Task.run(Task.scala:136) ~[spark-core_2.12-3.3.0.jar:3.3.0]\n", - "\tat org.apache.spark.executor.Executor$TaskRunner.$anonfun$run$3(Executor.scala:548) ~[spark-core_2.12-3.3.0.jar:3.3.0]\n", - "\tat org.apache.spark.util.Utils$.tryWithSafeFinally(Utils.scala:1504) ~[spark-core_2.12-3.3.0.jar:3.3.0]\n", - "\tat org.apache.spark.executor.Executor$TaskRunner.run(Executor.scala:551) ~[spark-core_2.12-3.3.0.jar:3.3.0]\n", - "\tat java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) ~[?:?]\n", - "\tat java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) ~[?:?]\n", - "\tat java.lang.Thread.run(Thread.java:829) ~[?:?]\n", - "23/10/13 11:21:41 WARN GoogleCloudStorageReadChannel: Failed read retry #1/10 for 'gs://genetics_etl_python_playground/output/python_etl/parquet/XX.XX/preprocess/finngen/summary_stats/FINNGEN_R9_AMN2/chromosome=12/part-00016-6c463da6-b063-495d-8b62-8ad766491cfb.c000.snappy.parquet'. Sleeping...\n", - "java.net.SocketException: Connection reset\n", - "\tat java.net.SocketInputStream.read(SocketInputStream.java:186) ~[?:?]\n", - "\tat java.net.SocketInputStream.read(SocketInputStream.java:140) ~[?:?]\n", - "\tat org.conscrypt.ConscryptEngineSocket$SSLInputStream.readFromSocket(ConscryptEngineSocket.java:920) ~[conscrypt-openjdk-2.5.2-linux-x86_64.jar:2.5.2]\n", - "\tat org.conscrypt.ConscryptEngineSocket$SSLInputStream.processDataFromSocket(ConscryptEngineSocket.java:884) ~[conscrypt-openjdk-2.5.2-linux-x86_64.jar:2.5.2]\n", - "\tat org.conscrypt.ConscryptEngineSocket$SSLInputStream.readUntilDataAvailable(ConscryptEngineSocket.java:799) ~[conscrypt-openjdk-2.5.2-linux-x86_64.jar:2.5.2]\n", - "\tat org.conscrypt.ConscryptEngineSocket$SSLInputStream.read(ConscryptEngineSocket.java:772) ~[conscrypt-openjdk-2.5.2-linux-x86_64.jar:2.5.2]\n", - "\tat java.io.BufferedInputStream.read1(BufferedInputStream.java:290) ~[?:?]\n", - "\tat java.io.BufferedInputStream.read(BufferedInputStream.java:351) ~[?:?]\n", - "\tat sun.net.www.MeteredStream.read(MeteredStream.java:134) ~[?:?]\n", - "\tat java.io.FilterInputStream.read(FilterInputStream.java:133) ~[?:?]\n", - "\tat sun.net.www.protocol.http.HttpURLConnection$HttpInputStream.read(HttpURLConnection.java:3529) ~[?:?]\n", - "\tat com.google.cloud.hadoop.repackaged.gcs.com.google.api.client.http.javanet.NetHttpResponse$SizeValidatingInputStream.read(NetHttpResponse.java:164) ~[gcs-connector-hadoop3-2.2.16.jar:?]\n", - "\tat java.io.BufferedInputStream.read1(BufferedInputStream.java:290) ~[?:?]\n", - "\tat java.io.BufferedInputStream.read(BufferedInputStream.java:351) ~[?:?]\n", - "\tat java.nio.channels.Channels$ReadableByteChannelImpl.read(Channels.java:388) ~[?:?]\n", - "\tat com.google.cloud.hadoop.repackaged.gcs.com.google.cloud.hadoop.gcsio.GoogleCloudStorageReadChannel.read(GoogleCloudStorageReadChannel.java:315) ~[gcs-connector-hadoop3-2.2.16.jar:?]\n", - "\tat com.google.cloud.hadoop.fs.gcs.GoogleHadoopFSInputStream.lambda$read$1(GoogleHadoopFSInputStream.java:170) ~[gcs-connector-hadoop3-2.2.16.jar:?]\n", - "\tat com.google.cloud.hadoop.fs.gcs.GhfsStorageStatistics.trackDuration(GhfsStorageStatistics.java:77) ~[gcs-connector-hadoop3-2.2.16.jar:?]\n", - "\tat com.google.cloud.hadoop.fs.gcs.GoogleHadoopFSInputStream.read(GoogleHadoopFSInputStream.java:159) ~[gcs-connector-hadoop3-2.2.16.jar:?]\n", - "\tat java.io.DataInputStream.read(DataInputStream.java:149) ~[?:?]\n", - "\tat org.apache.parquet.io.DelegatingSeekableInputStream.readFully(DelegatingSeekableInputStream.java:102) ~[parquet-common-1.12.2.jar:1.12.2]\n", - "\tat org.apache.parquet.io.DelegatingSeekableInputStream.readFullyHeapBuffer(DelegatingSeekableInputStream.java:127) ~[parquet-common-1.12.2.jar:1.12.2]\n", - "\tat org.apache.parquet.io.DelegatingSeekableInputStream.readFully(DelegatingSeekableInputStream.java:91) ~[parquet-common-1.12.2.jar:1.12.2]\n", - "\tat org.apache.parquet.hadoop.ParquetFileReader$ConsecutivePartList.readAll(ParquetFileReader.java:1704) ~[parquet-hadoop-1.12.2.jar:1.12.2]\n", - "\tat org.apache.parquet.hadoop.ParquetFileReader.readNextRowGroup(ParquetFileReader.java:925) ~[parquet-hadoop-1.12.2.jar:1.12.2]\n", - "\tat org.apache.parquet.hadoop.ParquetFileReader.readNextFilteredRowGroup(ParquetFileReader.java:972) ~[parquet-hadoop-1.12.2.jar:1.12.2]\n", - "\tat org.apache.spark.sql.execution.datasources.parquet.SpecificParquetRecordReaderBase$ParquetRowGroupReaderImpl.readNextRowGroup(SpecificParquetRecordReaderBase.java:320) ~[spark-sql_2.12-3.3.0.jar:3.3.0]\n", - "\tat org.apache.spark.sql.execution.datasources.parquet.VectorizedParquetRecordReader.checkEndOfRowGroup(VectorizedParquetRecordReader.java:403) ~[spark-sql_2.12-3.3.0.jar:3.3.0]\n", - "\tat org.apache.spark.sql.execution.datasources.parquet.VectorizedParquetRecordReader.nextBatch(VectorizedParquetRecordReader.java:324) ~[spark-sql_2.12-3.3.0.jar:3.3.0]\n", - "\tat org.apache.spark.sql.execution.datasources.parquet.VectorizedParquetRecordReader.nextKeyValue(VectorizedParquetRecordReader.java:227) ~[spark-sql_2.12-3.3.0.jar:3.3.0]\n", - "\tat org.apache.spark.sql.execution.datasources.RecordReaderIterator.hasNext(RecordReaderIterator.scala:39) ~[spark-sql_2.12-3.3.0.jar:3.3.0]\n", - "\tat org.apache.spark.sql.execution.datasources.FileScanRDD$$anon$1.hasNext(FileScanRDD.scala:116) ~[spark-sql_2.12-3.3.0.jar:3.3.0]\n", - "\tat org.apache.spark.sql.execution.datasources.FileScanRDD$$anon$1.nextIterator(FileScanRDD.scala:274) ~[spark-sql_2.12-3.3.0.jar:3.3.0]\n", - "\tat org.apache.spark.sql.execution.datasources.FileScanRDD$$anon$1.hasNext(FileScanRDD.scala:116) ~[spark-sql_2.12-3.3.0.jar:3.3.0]\n", - "\tat org.apache.spark.sql.execution.FileSourceScanExec$$anon$1.hasNext(DataSourceScanExec.scala:565) ~[spark-sql_2.12-3.3.0.jar:3.3.0]\n", - "\tat org.apache.spark.sql.catalyst.expressions.GeneratedClass$GeneratedIteratorForCodegenStage1.columnartorow_nextBatch_0$(Unknown Source) ~[?:?]\n", - "\tat org.apache.spark.sql.catalyst.expressions.GeneratedClass$GeneratedIteratorForCodegenStage1.processNext(Unknown Source) ~[?:?]\n", - "\tat org.apache.spark.sql.execution.BufferedRowIterator.hasNext(BufferedRowIterator.java:43) ~[spark-sql_2.12-3.3.0.jar:3.3.0]\n", - "\tat org.apache.spark.sql.execution.WholeStageCodegenExec$$anon$1.hasNext(WholeStageCodegenExec.scala:760) ~[spark-sql_2.12-3.3.0.jar:3.3.0]\n", - "\tat scala.collection.Iterator$$anon$10.hasNext(Iterator.scala:460) ~[scala-library-2.12.14.jar:?]\n", - "\tat org.apache.spark.shuffle.sort.BypassMergeSortShuffleWriter.write(BypassMergeSortShuffleWriter.java:170) ~[spark-core_2.12-3.3.0.jar:3.3.0]\n", - "\tat org.apache.spark.shuffle.ShuffleWriteProcessor.write(ShuffleWriteProcessor.scala:59) ~[spark-core_2.12-3.3.0.jar:3.3.0]\n", - "\tat org.apache.spark.scheduler.ShuffleMapTask.runTask(ShuffleMapTask.scala:99) ~[spark-core_2.12-3.3.0.jar:3.3.0]\n", - "\tat org.apache.spark.scheduler.ShuffleMapTask.runTask(ShuffleMapTask.scala:52) ~[spark-core_2.12-3.3.0.jar:3.3.0]\n", - "\tat org.apache.spark.scheduler.Task.run(Task.scala:136) ~[spark-core_2.12-3.3.0.jar:3.3.0]\n", - "\tat org.apache.spark.executor.Executor$TaskRunner.$anonfun$run$3(Executor.scala:548) ~[spark-core_2.12-3.3.0.jar:3.3.0]\n", - "\tat org.apache.spark.util.Utils$.tryWithSafeFinally(Utils.scala:1504) ~[spark-core_2.12-3.3.0.jar:3.3.0]\n", - "\tat org.apache.spark.executor.Executor$TaskRunner.run(Executor.scala:551) ~[spark-core_2.12-3.3.0.jar:3.3.0]\n", - "\tat java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) ~[?:?]\n", - "\tat java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) ~[?:?]\n", - "\tat java.lang.Thread.run(Thread.java:829) ~[?:?]\n", - "23/10/13 11:36:03 WARN HintErrorLogger: Hint (strategy=broadcast) is not supported in the query: build right for right outer join.\n", - "23/10/13 11:39:00 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=202; previousMaxLatencyMs=190; operationCount=105; context=gs://ot-team/dsuveges/finngen/2023.10.13_window_clumped_w_locus/_temporary/0/_temporary/attempt_20231013113900962145652452525416_0067_m_000009_79286/part-00009-65e9ae61-ec7d-4672-a525-8de91e583465-c000.snappy.parquet\n", - "23/10/13 11:39:00 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=216; previousMaxLatencyMs=202; operationCount=105; context=gs://ot-team/dsuveges/finngen/2023.10.13_window_clumped_w_locus/_temporary/0/_temporary/attempt_202310131139003257422348970599913_0067_m_000028_79305/part-00028-65e9ae61-ec7d-4672-a525-8de91e583465-c000.snappy.parquet\n", - "23/10/13 11:39:00 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=218; previousMaxLatencyMs=216; operationCount=105; context=gs://ot-team/dsuveges/finngen/2023.10.13_window_clumped_w_locus/_temporary/0/_temporary/attempt_202310131139006484121277706965747_0067_m_000003_79280/part-00003-65e9ae61-ec7d-4672-a525-8de91e583465-c000.snappy.parquet\n", - "23/10/13 11:39:01 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=243; previousMaxLatencyMs=218; operationCount=105; context=gs://ot-team/dsuveges/finngen/2023.10.13_window_clumped_w_locus/_temporary/0/_temporary/attempt_202310131139004953018478188900860_0067_m_000023_79300/part-00023-65e9ae61-ec7d-4672-a525-8de91e583465-c000.snappy.parquet\n", - "23/10/13 11:39:02 WARN GhfsStorageStatistics: Detected potential high latency for operation stream_write_close_operations. latencyMs=165; previousMaxLatencyMs=153; operationCount=92; context=gs://ot-team/dsuveges/finngen/2023.10.13_window_clumped_w_locus/_temporary/0/_temporary/attempt_202310131139003598197994288369319_0067_m_000026_79303/part-00026-65e9ae61-ec7d-4672-a525-8de91e583465-c000.snappy.parquet\n", - "23/10/13 11:39:02 WARN GhfsStorageStatistics: Detected potential high latency for operation stream_write_close_operations. latencyMs=193; previousMaxLatencyMs=165; operationCount=99; context=gs://ot-team/dsuveges/finngen/2023.10.13_window_clumped_w_locus/_temporary/0/_temporary/attempt_202310131139004279983947938826985_0067_m_000025_79302/part-00025-65e9ae61-ec7d-4672-a525-8de91e583465-c000.snappy.parquet\n", - "23/10/13 11:39:02 WARN GhfsStorageStatistics: Detected potential high latency for operation stream_write_close_operations. latencyMs=243; previousMaxLatencyMs=193; operationCount=103; context=gs://ot-team/dsuveges/finngen/2023.10.13_window_clumped_w_locus/_temporary/0/_temporary/attempt_202310131139004602145763603687891_0067_m_000030_79307/part-00030-65e9ae61-ec7d-4672-a525-8de91e583465-c000.snappy.parquet\n", - "23/10/13 11:39:02 WARN GhfsStorageStatistics: Detected potential high latency for operation stream_write_close_operations. latencyMs=329; previousMaxLatencyMs=243; operationCount=104; context=gs://ot-team/dsuveges/finngen/2023.10.13_window_clumped_w_locus/_temporary/0/_temporary/attempt_20231013113900353649088592248874_0067_m_000005_79282/part-00005-65e9ae61-ec7d-4672-a525-8de91e583465-c000.snappy.parquet\n", - " \r" - ] - } - ], - "source": [ - "window_based_clumped_output = 'gs://ot-team/dsuveges/finngen/2023.10.13_window_clumped_w_locus'\n", - "\n", - "clump_window_length = 500_000\n", - "locus_window_length = 250_000\n", - "\n", - "(\n", - " SummaryStatistics(\n", - " _df=(\n", - " session.spark.read.parquet(sumstats, recursiveFileLookup=True)\n", - " .withColumn(\n", - " 'chromosome',\n", - " f.split(f.col('variantId'), '_')[0]\n", - " )\n", - " ),\n", - " _schema=SummaryStatistics.get_schema()\n", - " )\n", - " .window_based_clumping(\n", - " distance=clump_window_length,\n", - " locus_collect_distance=locus_window_length,\n", - " with_locus=True\n", - " )\n", - " .df.write.mode('overwrite')\n", - " .parquet(window_based_clumped_output)\n", - ")\n" + "data": { + "text/plain": [ + "" ] + }, + "execution_count": 59, + "metadata": {}, + "output_type": "execute_result" }, { - "cell_type": "code", - "execution_count": 18, - "id": "6b234362", - "metadata": { - "ExecuteTime": { - "end_time": "2023-10-13T12:39:15.023402Z", - "start_time": "2023-10-13T11:50:42.603425Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "+--------------------+---------------------+---------+---------+---------------+\n", - "| studyId|ldPopulationStructure|projectId|studyType|traitFromSource|\n", - "+--------------------+---------------------+---------+---------+---------------+\n", - "|FINNGEN_R9_K11_EN...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", - "|FINNGEN_R9_H7_KER...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", - "|FINNGEN_R9_H8_EXT...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", - "|FINNGEN_R9_H7_RET...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", - "|FINNGEN_R9_RHEUMA...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", - "|FINNGEN_R9_H7_KER...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", - "|FINNGEN_R9_HEIGHT...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", - "|FINNGEN_R9_M13_SY...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", - "|FINNGEN_R9_M13_DO...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", - "|FINNGEN_R9_M13_PY...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", - "| FINNGEN_R9_GOUT_NOS| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", - "|FINNGEN_R9_M13_FI...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", - "|FINNGEN_R9_ALLERG...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", - "|FINNGEN_R9_E4_DM2...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", - "|FINNGEN_R9_G6_CER...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", - "|FINNGEN_R9_L12_UR...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", - "|FINNGEN_R9_AUTOIM...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", - "|FINNGEN_R9_I9_HYP...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", - "|FINNGEN_R9_M13_AR...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", - "|FINNGEN_R9_K11_AP...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", - "+--------------------+---------------------+---------+---------+---------------+\n", - "only showing top 20 rows\n", - "\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "23/10/13 11:55:34 WARN GhfsStorageStatistics: Detected potential high latency for operation op_open. latencyMs=676; previousMaxLatencyMs=470; operationCount=333148; context=gs://genetics_etl_python_playground/output/python_etl/parquet/XX.XX/ld_index/chromosome=5/part-00076-ff42773a-494c-46d2-bc22-322062b5e715.c000.snappy.parquet\n", - "23/10/13 12:39:11 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=279; previousMaxLatencyMs=243; operationCount=140; context=gs://ot-team/dsuveges/finngen/2023.10.13_ld_clumped_w_locus/_temporary/0/_temporary/attempt_202310131239103300432709600941830_0086_m_000000_80535/part-00000-17d449c4-f0c3-4617-b378-b74b864ab64a-c000.snappy.parquet\n", - "23/10/13 12:39:11 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=335; previousMaxLatencyMs=279; operationCount=140; context=gs://ot-team/dsuveges/finngen/2023.10.13_ld_clumped_w_locus/_temporary/0/_temporary/attempt_202310131239106417331548307580589_0086_m_000027_80562/part-00027-17d449c4-f0c3-4617-b378-b74b864ab64a-c000.snappy.parquet\n", - " \r" - ] - } - ], - "source": [ - "ld_clumped_output = 'gs://ot-team/dsuveges/finngen/2023.10.13_ld_clumped_w_locus'\n", - "\n", - "studies_df = (\n", - " session.spark.read.parquet(window_based_clumped_output)\n", - " # Generating a list of study identifiers:\n", - " .select('studyId')\n", - " .distinct()\n", - " # Adding fabricated values required to parse as gwas catalog study:\n", - " .select(\n", - " 'studyId',\n", - " StudyIndex.aggregate_and_map_ancestries(\n", - " f.array(\n", - " f.struct(\n", - " f.lit('Finnish').alias('ancestry'),\n", - " f.lit(100).cast('long').alias('sampleSize')\n", - " )\n", - " )\n", - " ).alias('ldPopulationStructure'),\n", - " f.lit('FINNGEN').alias('projectId'),\n", - " f.lit('gwas').alias('studyType'),\n", - " f.lit('cicaful').alias('traitFromSource')\n", - " )\n", - ")\n", - "\n", - "study_index = (\n", - " StudyIndex(\n", - " _df=studies_df,\n", - " _schema=StudyIndex.get_schema()\n", - " )\n", - ")\n", - "\n", - "study_index.df.show()\n", - "\n", - "# Loading ld index:\n", - "ld_index = LDIndex.from_parquet(session, ld_index_path)\n", - "\n", - "(\n", - " # To annotate study/locus, study level info and ld panel is needed:\n", - " LDAnnotator.ld_annotate(\n", - " StudyLocus.from_parquet(session, window_based_clumped_output),\n", - " study_index, \n", - " ld_index\n", - " )\n", - " # Clumping linked study-loci together:\n", - " .clump()\n", - " .df.write.mode('overwrite').parquet(ld_clumped_output)\n", - ")\n", - "\n", - "\n" + "data": { + "image/png": "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zZs317Rp02Sz2RQdHa1du3bp7bffNts8cOBApa6gTJkyRS+//LIef/xxSdLbb7+tdevWafr06frjH/9Y6XE7f/683n//fd1+++2SpBEjRuj111+XJNWvX18+Pj4qLS1VSEhIpdusiloViAAAqMsWLFigp59+Wrfeeqs8PDx0zz33KCkpSTt27JAkDRgwwKyNiYlRbGysIiIitGLFCvXr10+GYVzT98XGxpr//vrrr3Xu3DkzIF1UVlamu+++W9KPDytu3769y13WF8PTRZW5m7u4uFhHjx5Vx44dXfZ37NhRX3755TWdg6+vrxmGJCk0NFSFhYXX1IY7EIgAAHCT22+/XRs2bNDp06dVXFys0NBQDRgwQJGRkZetDw0NVUREhDkzdPEOsn//+98Vgsrl+Pn5mf++cOGCJGnFihW69dZbXersdrskVSpwRUVFae/evT9bJ1390Ti33HJLhe88f/58hTa8vLwqtHmtwdAdavxJ1QAA3Gz8/PwUGhqqoqIirVq16rLrcSTpxIkTOnz4sPl4mYSEBAUGBmry5MmXrb/as4Jat24tu92ub7/9Vi1atHDZLj42pnXr1hVu8b/0c1JSkvbv369PP/20wncYhiGn06kGDRooLCzMZW2UJG3atEmtWrWSJDVp0kSSzAXS0o+Lqq+Vt7e3y/tJbxQCEQAAbrJq1SplZmYqLy9PWVlZ6tKli6Kjo/XUU0+ppKREqamp2rx5sw4ePKj169froYceUmBgoB555BFJPwapP/3pT1qxYoUSExO1Zs0aHTx4UNu3b9e4ceM0fPjwK363v7+/UlNT9dJLL2n+/Pn65ptvtHPnTv3xj380n300fPhwffPNNxozZoz27dunxYsXa968eS7t9O/fXwMGDNATTzyh9PR0bd++XYcOHdJnn32m7t27a926dZKkX/3qV3r77bf18ccfa9++fXrllVeUm5ur0aNHS5IZxNLS0rR//36tWLFC77zzzjWP6W233aavvvpK+/bt0/fff3/ZWSZ3IBABAOAmTqdTL774ou644w4NGjRI9913n1avXi0vLy95eHho165d6tu3r6KiojR48GBFRUVp8+bNLndP9+3bV5s2bZKXl5eSkpJ0xx136IknnpDT6dTEiROv+v1vvPGG/u///k/p6elq1aqVevbsqb///e/mJbtmzZrpk08+0d///ne1bdtW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R1fPyQIAgFqr1q4hysvLU0FBgRISEsx9drtdnTp10qZNmyRJOTk5On/+vEtNWFiYYmJizJrNmzfL4XCYYUiS2rdvL4fDYdZcTmlpqYqLi102AABwc6q1gaigoECSFBwc7LI/ODjYPFZQUCBvb281atToqjVBQUEV2g8KCjJrLic9Pd1cc+RwOBQeHn5d5wMAAGqvWhuILrLZbC6fDcOosO9Sl9Zcrv7n2hk/frycTqe5HT58+Bp7DgAA6opaG4hCQkIkqcIsTmFhoTlrFBISorKyMhUVFV215tixYxXaP378eIXZp5+y2+1q0KCBywYAAG5OtTYQRUZGKiQkRFlZWea+srIybdiwQR06dJAktWvXTl5eXi41+fn52r17t1kTHx8vp9OprVu3mjVbtmyR0+k0awAAgLXV6F1mJSUl+s9//mN+zsvLU25urgICAtSsWTOlpKRo0qRJatmypVq2bKlJkybJ19dXSUlJkiSHw6GhQ4dq7Nixaty4sQICApSamqo2bdqYd521atVKvXr10rBhwzRr1ixJ0rPPPqs+ffpwhxkAAJBUw4Fo+/bt6tKli/l5zJgxkqTBgwdr3rx5GjdunM6ePasXXnhBRUVFiouL0+rVq+Xv72/+zLRp0+Tp6an+/fvr7Nmz6tatm+bNmycPDw+zZtGiRRo1apR5N1piYuIVn30EAACsx2YYhlHTnagLiouL5XA45HQ63b6eaPOcVLe2V1vED51S010AAFhcZf9+19o1RAAAANWFQAQAACyPQAQAACyvRhdV4+Y2LWu/W9p5qUeUW9oBAOBKmCECAACWRyACAACWRyACAACWxxoi3DDtv/3ATS3xPCMAwI3FDBEAALA8AhEAALA8AhEAALA8AhEAALA8AhEAALA8AhEAALA8brtHreeuV4BIvAYEAHB5zBABAADLIxABAADLIxABAADLIxABAADLY1E1aj33vRNN4r1oAIDLYYYIAABYHoEIAABYHoEIAABYHoEIAABYHoEIAABYHneZwVLc9RoQXgECADcXZogAAIDlMUMES3HfM414nhEA3EyYIQIAAJZHIAIAAJZHIAIAAJZXqwNRWlqabDabyxYSEmIeNwxDaWlpCgsLk4+Pjzp37qw9e/a4tFFaWqqRI0cqMDBQfn5+SkxM1JEjR6r7VAAAQC1WqwORJN15553Kz883t127dpnHJk+erKlTp2rGjBnatm2bQkJC1KNHD506dcqsSUlJ0bJly5SRkaGNGzeqpKREffr0UXl5eU2cDgAAqIVq/V1mnp6eLrNCFxmGoenTp+vVV19Vv379JEnz589XcHCwFi9erOeee05Op1Nz5szRggUL1L17d0nSwoULFR4erjVr1qhnz57Vei4AAKB2qvWB6MCBAwoLC5PdbldcXJwmTZqk5s2bKy8vTwUFBUpISDBr7Xa7OnXqpE2bNum5555TTk6Ozp8/71ITFhammJgYbdq06aqBqLS0VKWlpebn4uLiG3OCqJN4wCMA3Fxq9SWzuLg4ffTRR1q1apVmz56tgoICdejQQSdOnFBBQYEkKTg42OVngoODzWMFBQXy9vZWo0aNrlhzJenp6XI4HOYWHh7uxjMDAAC1Sa0ORL1799ajjz6qNm3aqHv37lqxYoWkHy+NXWSz2Vx+xjCMCvsuVZma8ePHy+l0mtvhw4ereBYAAKC2q9WB6FJ+fn5q06aNDhw4YK4runSmp7Cw0Jw1CgkJUVlZmYqKiq5YcyV2u10NGjRw2QAAwM2pTgWi0tJS7d27V6GhoYqMjFRISIiysrLM42VlZdqwYYM6dOggSWrXrp28vLxcavLz87V7926zBgAAoFYvqk5NTdVDDz2kZs2aqbCwUBMnTlRxcbEGDx4sm82mlJQUTZo0SS1btlTLli01adIk+fr6KikpSZLkcDg0dOhQjR07Vo0bN1ZAQIBSU1PNS3AAAABSLQ9ER44c0RNPPKHvv/9eTZo0Ufv27ZWdna2IiAhJ0rhx43T27Fm98MILKioqUlxcnFavXi1/f3+zjWnTpsnT01P9+/fX2bNn1a1bN82bN08eHh41dVoAAKCWsRmGYdR0J+qC4uJiORwOOZ1Ot68n2jwn1a3t4cbLbvasW9rhtnsAuLEq+/e7Vs8QAbVV+28/cFNLU9zUDgDgehCIgBrEAx4BoHaoU3eZAQAA3AgEIgAAYHkEIgAAYHkEIgAAYHksqgZqkLvuVpuWxWMAAOB6MEMEAAAsj0AEAAAsj0AEAAAsjzVEwE2AtUgAcH2YIQIAAJZHIAIAAJbHJTMAbsc72gDUNQQiACZ3rUXKbuaetUgAUF24ZAYAACyPGSIAtRaX3gBUFwIRgFrLXZfwpCluagfAzYpLZgAAwPKYIQKASnLXJTx34VIg4D4EIgBu575LXe5R24KMu7DGCnAfAhEAVBKPJQBuXqwhAgAAlscMEQBUs9o208SlN4BABABwE4IV6jICEYCbXm1b5I2rI1hdHeNzYxCIAAA3pZv17kJ3IVi5IhABQB1V22a+uHsOdRmBCABQq9S2ReewBgIRAMAtatuMFarHzXLpjUAEALgpMdOEa2GpBzO+9957ioyMVL169dSuXTv985//rOkuAQCAWsAyM0Qff/yxUlJS9N5776ljx46aNWuWevfura+//lrNmjWr6e4BAGopZpqswTIzRFOnTtXQoUP1zDPPqFWrVpo+fbrCw8M1c+bMmu4aAACoYZaYISorK1NOTo5eeeUVl/0JCQnatGnTZX+mtLRUpaWl5men0ylJKi4udnv/Tp8t/fkiAECd1mbfH9zSzramT7mlndrmRvx9/Wm7hmFctc4Sgej7779XeXm5goODXfYHBweroKDgsj+Tnp6u3/72txX2h4eH35A+AgBQOTNqugM3xIQb3P6pU6fkcDiueNwSgegim83m8tkwjAr7Lho/frzGjBljfr5w4YL+97//qXHjxlf8mcooLi5WeHi4Dh8+rAYNGlS5HVQO4129GO/qxXhXL8a7erlrvA3D0KlTpxQWFnbVOksEosDAQHl4eFSYDSosLKwwa3SR3W6X3W532dewYUO39alBgwb8F6oaMd7Vi/GuXox39WK8q5c7xvtqM0MXWWJRtbe3t9q1a6esrCyX/VlZWerQoUMN9QoAANQWlpghkqQxY8YoOTlZsbGxio+P1wcffKBvv/1Ww4cPr+muAQCAGmaZQDRgwACdOHFCr7/+uvLz8xUTE6OVK1cqIiKiWvtht9v1m9/8psLlONwYjHf1YryrF+NdvRjv6lXd420zfu4+NAAAgJucJdYQAQAAXA2BCAAAWB6BCAAAWB6BCAAAWB6BqBq99957ioyMVL169dSuXTv985//rOku3RTS09N17733yt/fX0FBQXr44Ye1b98+lxrDMJSWlqawsDD5+Pioc+fO2rNnTw31+OaSnp4um82mlJQUcx/j7V7fffedBg4cqMaNG8vX11e/+MUvlJOTYx5nvN3nhx9+0K9//WtFRkbKx8dHzZs31+uvv64LFy6YNYx31X3xxRd66KGHFBYWJpvNpr/97W8uxysztqWlpRo5cqQCAwPl5+enxMREHTly5Po7Z6BaZGRk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", + "text/plain": [ + "
" ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "(\n", + " picsed_df\n", + " .filter(f.col(\"locus\").isNotNull())\n", + " .select(\n", + " \"studyId\",\n", + " \"variantId\",\n", + " f.aggregate(\n", + " f.transform(\n", + " f.col(\"locus\"),\n", + " lambda locus: f.when(locus.is99CredibleSet, f.lit(1.0)).otherwise( f.lit(0.0))\n", + " ),\n", + " f.lit(0.0),\n", + " lambda summa, value: summa + value\n", + " ).alias(\"99CredCount\"),\n", + " f.aggregate(\n", + " f.transform(\n", + " f.col(\"locus\"),\n", + " lambda locus: f.when(locus.is95CredibleSet, f.lit(1.0)).otherwise( f.lit(0.0))\n", + " ),\n", + " f.lit(0.0),\n", + " lambda summa, value: summa + value\n", + " ).alias(\"95CredCount\"),\n", + " )\n", + "# .orderBy(f.col('99CredCount').desc())\n", + "# .show()\n", + " .filter(f.col(\"99CredCount\") < 100)\n", + "# .count()\n", + " .toPandas()\n", + " [[\"99CredCount\", \"95CredCount\"]]\n", + " .plot.hist(bins=25, alpha=0.5, label=\"Credible set size\")\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "a8b99c39", + "metadata": {}, + "source": [ + "## Finngen clumping with locus\n", + "\n", + "- Window width: 500kbp\n", + "- Locus width: 250kbp\n", + "- LD threshold: 0.5\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "09f14d49", + "metadata": { + "ExecuteTime": { + "end_time": "2023-10-13T09:54:35.337711Z", + "start_time": "2023-10-13T09:54:34.446422Z" + } + }, + "outputs": [], + "source": [ + "# Import:\n", + "from pyspark.sql import functions as f\n", + "\n", + "from gentropy.common.session import Session\n", + "from gentropy.dataset.ld_index import LDIndex\n", + "from gentropy.dataset.study_index import StudyIndex\n", + "from gentropy.dataset.study_locus import StudyLocus\n", + "from gentropy.dataset.summary_statistics import SummaryStatistics\n", + "from gentropy.method.ld import LDAnnotator\n", + "from gentropy.method.pics import PICS\n", + "\n", + "# Initialize session:\n", + "session = Session()\n", + "\n", + "# Input:\n", + "sumstats = \"gs://genetics_etl_python_playground/output/python_etl/parquet/XX.XX/preprocess/finngen/summary_stats/*\"\n", + "ld_index_path = \"gs://genetics_etl_python_playground/output/python_etl/parquet/XX.XX/ld_index/\"\n", + "\n", + "# Output:\n", + "ld_clumped_output = \"gs://ot-team/dsuveges/finngen/2023.10.06_LD_clumped\"\n", + "picsed_output = \"gs://ot-team/dsuveges/finngen/2023.10.06_PICSed\"\n", + "window_based_clumped_output = \"gs://ot-team/dsuveges/finngen/2023.10.06_window_clumped\"" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "52861491", + "metadata": { + "ExecuteTime": { + "end_time": "2023-10-13T11:39:14.790777Z", + "start_time": "2023-10-13T10:47:20.349271Z" }, + "code_folding": [], + "scrolled": false + }, + "outputs": [ { - "cell_type": "code", - "execution_count": 9, - "id": "f637e3c0", - "metadata": { - "ExecuteTime": { - "end_time": "2023-10-13T10:43:26.766382Z", - "start_time": "2023-10-13T10:43:25.980232Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "+--------------------------------------------------------------+-----+\n", - "|qualityControls |count|\n", - "+--------------------------------------------------------------+-----+\n", - "|[Variant not found in LD reference] |4607 |\n", - "|[] |13813|\n", - "|[Explained by a more significant variant in high LD (clumped)]|585 |\n", - "+--------------------------------------------------------------+-----+\n", - "\n" - ] - } - ], - "source": [ - "(\n", - " session.spark.read.parquet(ld_clumped_output)\n", - " .groupBy('qualityControls')\n", - " .count()\n", - "# .show(1, False, True)\n", - " .show(truncate=False)\n", - ")" - ] - }, + "name": "stderr", + "output_type": "stream", + "text": [ + "23/10/13 10:47:53 WARN HintErrorLogger: Hint (strategy=broadcast) is not supported in the query: build right for right outer join.\n", + "23/10/13 10:47:53 WARN package: Truncated the string representation of a plan since it was too large. This behavior can be adjusted by setting 'spark.sql.debug.maxToStringFields'.\n", + "23/10/13 10:48:19 WARN GhfsStorageStatistics: Detected potential high latency for operation stream_read_operations. latencyMs=1248; previousMaxLatencyMs=1230; operationCount=59116581; context=gs://genetics_etl_python_playground/output/python_etl/parquet/XX.XX/preprocess/finngen/summary_stats/FINNGEN_R9_OTHER_SYSTCON_FG/chromosome=2/part-00019-1d683f00-9247-401b-846c-8b2498bc68bf.c000.snappy.parquet\n", + "23/10/13 10:49:02 WARN GhfsStorageStatistics: Detected potential high latency for operation op_get_file_status. latencyMs=1039; previousMaxLatencyMs=1037; operationCount=126124; context=gs://genetics_etl_python_playground/output/python_etl/parquet/XX.XX/preprocess/finngen/summary_stats/FINNGEN_R9_K11_SCISS_BITE_INCLAVO/chromosome=2/part-00018-e37f4a01-bdb4-442f-8dcd-681da303e876.c000.snappy.parquet\n", + "23/10/13 10:52:37 WARN GhfsStorageStatistics: Detected potential high latency for operation op_get_file_status. latencyMs=1917; previousMaxLatencyMs=1039; operationCount=144264; context=gs://genetics_etl_python_playground/output/python_etl/parquet/XX.XX/preprocess/finngen/summary_stats/FINNGEN_R9_AUTOIMMUNE_NONTHYROID_STRICT/chromosome=5/part-00006-02537c5f-2dea-47c5-8655-b0d84827115a.c000.snappy.parquet\n", + "23/10/13 10:52:38 WARN GhfsStorageStatistics: Detected potential high latency for operation stream_read_operations. latencyMs=1942; previousMaxLatencyMs=1248; operationCount=94444057; context=gs://genetics_etl_python_playground/output/python_etl/parquet/XX.XX/preprocess/finngen/summary_stats/FINNGEN_R9_K11_PULPITIS_1_ONLYAVO/chromosome=5/part-00006-de277609-305a-4cec-8bb1-5b37a70be48b.c000.snappy.parquet\n", + "23/10/13 11:07:41 WARN HintErrorLogger: Hint (strategy=broadcast) is not supported in the query: build right for right outer join.\n", + "23/10/13 11:12:32 WARN HintErrorLogger: Hint (strategy=broadcast) is not supported in the query: build right for right outer join.\n", + "23/10/13 11:12:48 WARN HintErrorLogger: Hint (strategy=broadcast) is not supported in the query: build right for right outer join.\n", + "23/10/13 11:21:40 WARN GoogleCloudStorageReadChannel: Failed read retry #1/10 for 'gs://genetics_etl_python_playground/output/python_etl/parquet/XX.XX/preprocess/finngen/summary_stats/FINNGEN_R9_H7_CONJUHAEMOR/chromosome=12/part-00016-03e2c019-d707-414b-b4e1-8b6474ccfb26.c000.snappy.parquet'. Sleeping...\n", + "java.net.SocketException: Connection reset\n", + "\tat java.net.SocketInputStream.read(SocketInputStream.java:186) ~[?:?]\n", + "\tat java.net.SocketInputStream.read(SocketInputStream.java:140) ~[?:?]\n", + "\tat org.conscrypt.ConscryptEngineSocket$SSLInputStream.readFromSocket(ConscryptEngineSocket.java:920) ~[conscrypt-openjdk-2.5.2-linux-x86_64.jar:2.5.2]\n", + "\tat org.conscrypt.ConscryptEngineSocket$SSLInputStream.processDataFromSocket(ConscryptEngineSocket.java:884) ~[conscrypt-openjdk-2.5.2-linux-x86_64.jar:2.5.2]\n", + "\tat org.conscrypt.ConscryptEngineSocket$SSLInputStream.readUntilDataAvailable(ConscryptEngineSocket.java:799) ~[conscrypt-openjdk-2.5.2-linux-x86_64.jar:2.5.2]\n", + "\tat org.conscrypt.ConscryptEngineSocket$SSLInputStream.read(ConscryptEngineSocket.java:772) ~[conscrypt-openjdk-2.5.2-linux-x86_64.jar:2.5.2]\n", + "\tat java.io.BufferedInputStream.read1(BufferedInputStream.java:290) ~[?:?]\n", + "\tat java.io.BufferedInputStream.read(BufferedInputStream.java:351) ~[?:?]\n", + "\tat sun.net.www.MeteredStream.read(MeteredStream.java:134) ~[?:?]\n", + "\tat java.io.FilterInputStream.read(FilterInputStream.java:133) ~[?:?]\n", + "\tat sun.net.www.protocol.http.HttpURLConnection$HttpInputStream.read(HttpURLConnection.java:3529) ~[?:?]\n", + "\tat com.google.cloud.hadoop.repackaged.gcs.com.google.api.client.http.javanet.NetHttpResponse$SizeValidatingInputStream.read(NetHttpResponse.java:164) ~[gcs-connector-hadoop3-2.2.16.jar:?]\n", + "\tat java.io.BufferedInputStream.read1(BufferedInputStream.java:290) ~[?:?]\n", + "\tat java.io.BufferedInputStream.read(BufferedInputStream.java:351) ~[?:?]\n", + "\tat java.nio.channels.Channels$ReadableByteChannelImpl.read(Channels.java:388) ~[?:?]\n", + "\tat com.google.cloud.hadoop.repackaged.gcs.com.google.cloud.hadoop.gcsio.GoogleCloudStorageReadChannel.read(GoogleCloudStorageReadChannel.java:315) ~[gcs-connector-hadoop3-2.2.16.jar:?]\n", + "\tat com.google.cloud.hadoop.fs.gcs.GoogleHadoopFSInputStream.lambda$read$1(GoogleHadoopFSInputStream.java:170) ~[gcs-connector-hadoop3-2.2.16.jar:?]\n", + "\tat com.google.cloud.hadoop.fs.gcs.GhfsStorageStatistics.trackDuration(GhfsStorageStatistics.java:77) ~[gcs-connector-hadoop3-2.2.16.jar:?]\n", + "\tat com.google.cloud.hadoop.fs.gcs.GoogleHadoopFSInputStream.read(GoogleHadoopFSInputStream.java:159) ~[gcs-connector-hadoop3-2.2.16.jar:?]\n", + "\tat java.io.DataInputStream.read(DataInputStream.java:149) ~[?:?]\n", + "\tat org.apache.parquet.io.DelegatingSeekableInputStream.readFully(DelegatingSeekableInputStream.java:102) ~[parquet-common-1.12.2.jar:1.12.2]\n", + "\tat org.apache.parquet.io.DelegatingSeekableInputStream.readFullyHeapBuffer(DelegatingSeekableInputStream.java:127) ~[parquet-common-1.12.2.jar:1.12.2]\n", + "\tat org.apache.parquet.io.DelegatingSeekableInputStream.readFully(DelegatingSeekableInputStream.java:91) ~[parquet-common-1.12.2.jar:1.12.2]\n", + "\tat org.apache.parquet.hadoop.ParquetFileReader$ConsecutivePartList.readAll(ParquetFileReader.java:1704) ~[parquet-hadoop-1.12.2.jar:1.12.2]\n", + "\tat org.apache.parquet.hadoop.ParquetFileReader.readNextRowGroup(ParquetFileReader.java:925) ~[parquet-hadoop-1.12.2.jar:1.12.2]\n", + "\tat org.apache.parquet.hadoop.ParquetFileReader.readNextFilteredRowGroup(ParquetFileReader.java:972) ~[parquet-hadoop-1.12.2.jar:1.12.2]\n", + "\tat org.apache.spark.sql.execution.datasources.parquet.SpecificParquetRecordReaderBase$ParquetRowGroupReaderImpl.readNextRowGroup(SpecificParquetRecordReaderBase.java:320) ~[spark-sql_2.12-3.3.0.jar:3.3.0]\n", + "\tat org.apache.spark.sql.execution.datasources.parquet.VectorizedParquetRecordReader.checkEndOfRowGroup(VectorizedParquetRecordReader.java:403) ~[spark-sql_2.12-3.3.0.jar:3.3.0]\n", + "\tat org.apache.spark.sql.execution.datasources.parquet.VectorizedParquetRecordReader.nextBatch(VectorizedParquetRecordReader.java:324) ~[spark-sql_2.12-3.3.0.jar:3.3.0]\n", + "\tat org.apache.spark.sql.execution.datasources.parquet.VectorizedParquetRecordReader.nextKeyValue(VectorizedParquetRecordReader.java:227) ~[spark-sql_2.12-3.3.0.jar:3.3.0]\n", + "\tat org.apache.spark.sql.execution.datasources.RecordReaderIterator.hasNext(RecordReaderIterator.scala:39) ~[spark-sql_2.12-3.3.0.jar:3.3.0]\n", + "\tat org.apache.spark.sql.execution.datasources.FileScanRDD$$anon$1.hasNext(FileScanRDD.scala:116) ~[spark-sql_2.12-3.3.0.jar:3.3.0]\n", + "\tat org.apache.spark.sql.execution.datasources.FileScanRDD$$anon$1.nextIterator(FileScanRDD.scala:274) ~[spark-sql_2.12-3.3.0.jar:3.3.0]\n", + "\tat org.apache.spark.sql.execution.datasources.FileScanRDD$$anon$1.hasNext(FileScanRDD.scala:116) ~[spark-sql_2.12-3.3.0.jar:3.3.0]\n", + "\tat org.apache.spark.sql.execution.FileSourceScanExec$$anon$1.hasNext(DataSourceScanExec.scala:565) ~[spark-sql_2.12-3.3.0.jar:3.3.0]\n", + "\tat org.apache.spark.sql.catalyst.expressions.GeneratedClass$GeneratedIteratorForCodegenStage1.columnartorow_nextBatch_0$(Unknown Source) ~[?:?]\n", + "\tat org.apache.spark.sql.catalyst.expressions.GeneratedClass$GeneratedIteratorForCodegenStage1.processNext(Unknown Source) ~[?:?]\n", + "\tat org.apache.spark.sql.execution.BufferedRowIterator.hasNext(BufferedRowIterator.java:43) ~[spark-sql_2.12-3.3.0.jar:3.3.0]\n", + "\tat org.apache.spark.sql.execution.WholeStageCodegenExec$$anon$1.hasNext(WholeStageCodegenExec.scala:760) ~[spark-sql_2.12-3.3.0.jar:3.3.0]\n", + "\tat scala.collection.Iterator$$anon$10.hasNext(Iterator.scala:460) ~[scala-library-2.12.14.jar:?]\n", + "\tat org.apache.spark.shuffle.sort.BypassMergeSortShuffleWriter.write(BypassMergeSortShuffleWriter.java:142) ~[spark-core_2.12-3.3.0.jar:3.3.0]\n", + "\tat org.apache.spark.shuffle.ShuffleWriteProcessor.write(ShuffleWriteProcessor.scala:59) ~[spark-core_2.12-3.3.0.jar:3.3.0]\n", + "\tat org.apache.spark.scheduler.ShuffleMapTask.runTask(ShuffleMapTask.scala:99) ~[spark-core_2.12-3.3.0.jar:3.3.0]\n", + "\tat org.apache.spark.scheduler.ShuffleMapTask.runTask(ShuffleMapTask.scala:52) ~[spark-core_2.12-3.3.0.jar:3.3.0]\n", + "\tat org.apache.spark.scheduler.Task.run(Task.scala:136) ~[spark-core_2.12-3.3.0.jar:3.3.0]\n", + "\tat org.apache.spark.executor.Executor$TaskRunner.$anonfun$run$3(Executor.scala:548) ~[spark-core_2.12-3.3.0.jar:3.3.0]\n", + "\tat org.apache.spark.util.Utils$.tryWithSafeFinally(Utils.scala:1504) ~[spark-core_2.12-3.3.0.jar:3.3.0]\n", + "\tat org.apache.spark.executor.Executor$TaskRunner.run(Executor.scala:551) ~[spark-core_2.12-3.3.0.jar:3.3.0]\n", + "\tat java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) ~[?:?]\n", + "\tat java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) ~[?:?]\n", + "\tat java.lang.Thread.run(Thread.java:829) ~[?:?]\n", + "23/10/13 11:21:41 WARN GoogleCloudStorageReadChannel: Failed read retry #1/10 for 'gs://genetics_etl_python_playground/output/python_etl/parquet/XX.XX/preprocess/finngen/summary_stats/FINNGEN_R9_AMN2/chromosome=12/part-00016-6c463da6-b063-495d-8b62-8ad766491cfb.c000.snappy.parquet'. Sleeping...\n", + "java.net.SocketException: Connection reset\n", + "\tat java.net.SocketInputStream.read(SocketInputStream.java:186) ~[?:?]\n", + "\tat java.net.SocketInputStream.read(SocketInputStream.java:140) ~[?:?]\n", + "\tat org.conscrypt.ConscryptEngineSocket$SSLInputStream.readFromSocket(ConscryptEngineSocket.java:920) ~[conscrypt-openjdk-2.5.2-linux-x86_64.jar:2.5.2]\n", + "\tat org.conscrypt.ConscryptEngineSocket$SSLInputStream.processDataFromSocket(ConscryptEngineSocket.java:884) ~[conscrypt-openjdk-2.5.2-linux-x86_64.jar:2.5.2]\n", + "\tat org.conscrypt.ConscryptEngineSocket$SSLInputStream.readUntilDataAvailable(ConscryptEngineSocket.java:799) ~[conscrypt-openjdk-2.5.2-linux-x86_64.jar:2.5.2]\n", + "\tat org.conscrypt.ConscryptEngineSocket$SSLInputStream.read(ConscryptEngineSocket.java:772) ~[conscrypt-openjdk-2.5.2-linux-x86_64.jar:2.5.2]\n", + "\tat java.io.BufferedInputStream.read1(BufferedInputStream.java:290) ~[?:?]\n", + "\tat java.io.BufferedInputStream.read(BufferedInputStream.java:351) ~[?:?]\n", + "\tat sun.net.www.MeteredStream.read(MeteredStream.java:134) ~[?:?]\n", + "\tat java.io.FilterInputStream.read(FilterInputStream.java:133) ~[?:?]\n", + "\tat sun.net.www.protocol.http.HttpURLConnection$HttpInputStream.read(HttpURLConnection.java:3529) ~[?:?]\n", + "\tat com.google.cloud.hadoop.repackaged.gcs.com.google.api.client.http.javanet.NetHttpResponse$SizeValidatingInputStream.read(NetHttpResponse.java:164) ~[gcs-connector-hadoop3-2.2.16.jar:?]\n", + "\tat java.io.BufferedInputStream.read1(BufferedInputStream.java:290) ~[?:?]\n", + "\tat java.io.BufferedInputStream.read(BufferedInputStream.java:351) ~[?:?]\n", + "\tat java.nio.channels.Channels$ReadableByteChannelImpl.read(Channels.java:388) ~[?:?]\n", + "\tat com.google.cloud.hadoop.repackaged.gcs.com.google.cloud.hadoop.gcsio.GoogleCloudStorageReadChannel.read(GoogleCloudStorageReadChannel.java:315) ~[gcs-connector-hadoop3-2.2.16.jar:?]\n", + "\tat com.google.cloud.hadoop.fs.gcs.GoogleHadoopFSInputStream.lambda$read$1(GoogleHadoopFSInputStream.java:170) ~[gcs-connector-hadoop3-2.2.16.jar:?]\n", + "\tat com.google.cloud.hadoop.fs.gcs.GhfsStorageStatistics.trackDuration(GhfsStorageStatistics.java:77) ~[gcs-connector-hadoop3-2.2.16.jar:?]\n", + "\tat com.google.cloud.hadoop.fs.gcs.GoogleHadoopFSInputStream.read(GoogleHadoopFSInputStream.java:159) ~[gcs-connector-hadoop3-2.2.16.jar:?]\n", + "\tat java.io.DataInputStream.read(DataInputStream.java:149) ~[?:?]\n", + "\tat org.apache.parquet.io.DelegatingSeekableInputStream.readFully(DelegatingSeekableInputStream.java:102) ~[parquet-common-1.12.2.jar:1.12.2]\n", + "\tat org.apache.parquet.io.DelegatingSeekableInputStream.readFullyHeapBuffer(DelegatingSeekableInputStream.java:127) ~[parquet-common-1.12.2.jar:1.12.2]\n", + "\tat org.apache.parquet.io.DelegatingSeekableInputStream.readFully(DelegatingSeekableInputStream.java:91) ~[parquet-common-1.12.2.jar:1.12.2]\n", + "\tat org.apache.parquet.hadoop.ParquetFileReader$ConsecutivePartList.readAll(ParquetFileReader.java:1704) ~[parquet-hadoop-1.12.2.jar:1.12.2]\n", + "\tat org.apache.parquet.hadoop.ParquetFileReader.readNextRowGroup(ParquetFileReader.java:925) ~[parquet-hadoop-1.12.2.jar:1.12.2]\n", + "\tat org.apache.parquet.hadoop.ParquetFileReader.readNextFilteredRowGroup(ParquetFileReader.java:972) ~[parquet-hadoop-1.12.2.jar:1.12.2]\n", + "\tat org.apache.spark.sql.execution.datasources.parquet.SpecificParquetRecordReaderBase$ParquetRowGroupReaderImpl.readNextRowGroup(SpecificParquetRecordReaderBase.java:320) ~[spark-sql_2.12-3.3.0.jar:3.3.0]\n", + "\tat org.apache.spark.sql.execution.datasources.parquet.VectorizedParquetRecordReader.checkEndOfRowGroup(VectorizedParquetRecordReader.java:403) ~[spark-sql_2.12-3.3.0.jar:3.3.0]\n", + "\tat org.apache.spark.sql.execution.datasources.parquet.VectorizedParquetRecordReader.nextBatch(VectorizedParquetRecordReader.java:324) ~[spark-sql_2.12-3.3.0.jar:3.3.0]\n", + "\tat org.apache.spark.sql.execution.datasources.parquet.VectorizedParquetRecordReader.nextKeyValue(VectorizedParquetRecordReader.java:227) ~[spark-sql_2.12-3.3.0.jar:3.3.0]\n", + "\tat org.apache.spark.sql.execution.datasources.RecordReaderIterator.hasNext(RecordReaderIterator.scala:39) ~[spark-sql_2.12-3.3.0.jar:3.3.0]\n", + "\tat org.apache.spark.sql.execution.datasources.FileScanRDD$$anon$1.hasNext(FileScanRDD.scala:116) ~[spark-sql_2.12-3.3.0.jar:3.3.0]\n", + "\tat org.apache.spark.sql.execution.datasources.FileScanRDD$$anon$1.nextIterator(FileScanRDD.scala:274) ~[spark-sql_2.12-3.3.0.jar:3.3.0]\n", + "\tat org.apache.spark.sql.execution.datasources.FileScanRDD$$anon$1.hasNext(FileScanRDD.scala:116) ~[spark-sql_2.12-3.3.0.jar:3.3.0]\n", + "\tat org.apache.spark.sql.execution.FileSourceScanExec$$anon$1.hasNext(DataSourceScanExec.scala:565) ~[spark-sql_2.12-3.3.0.jar:3.3.0]\n", + "\tat org.apache.spark.sql.catalyst.expressions.GeneratedClass$GeneratedIteratorForCodegenStage1.columnartorow_nextBatch_0$(Unknown Source) ~[?:?]\n", + "\tat org.apache.spark.sql.catalyst.expressions.GeneratedClass$GeneratedIteratorForCodegenStage1.processNext(Unknown Source) ~[?:?]\n", + "\tat org.apache.spark.sql.execution.BufferedRowIterator.hasNext(BufferedRowIterator.java:43) ~[spark-sql_2.12-3.3.0.jar:3.3.0]\n", + "\tat org.apache.spark.sql.execution.WholeStageCodegenExec$$anon$1.hasNext(WholeStageCodegenExec.scala:760) ~[spark-sql_2.12-3.3.0.jar:3.3.0]\n", + "\tat scala.collection.Iterator$$anon$10.hasNext(Iterator.scala:460) ~[scala-library-2.12.14.jar:?]\n", + "\tat org.apache.spark.shuffle.sort.BypassMergeSortShuffleWriter.write(BypassMergeSortShuffleWriter.java:170) ~[spark-core_2.12-3.3.0.jar:3.3.0]\n", + "\tat org.apache.spark.shuffle.ShuffleWriteProcessor.write(ShuffleWriteProcessor.scala:59) ~[spark-core_2.12-3.3.0.jar:3.3.0]\n", + "\tat org.apache.spark.scheduler.ShuffleMapTask.runTask(ShuffleMapTask.scala:99) ~[spark-core_2.12-3.3.0.jar:3.3.0]\n", + "\tat org.apache.spark.scheduler.ShuffleMapTask.runTask(ShuffleMapTask.scala:52) ~[spark-core_2.12-3.3.0.jar:3.3.0]\n", + "\tat org.apache.spark.scheduler.Task.run(Task.scala:136) ~[spark-core_2.12-3.3.0.jar:3.3.0]\n", + "\tat org.apache.spark.executor.Executor$TaskRunner.$anonfun$run$3(Executor.scala:548) ~[spark-core_2.12-3.3.0.jar:3.3.0]\n", + "\tat org.apache.spark.util.Utils$.tryWithSafeFinally(Utils.scala:1504) ~[spark-core_2.12-3.3.0.jar:3.3.0]\n", + "\tat org.apache.spark.executor.Executor$TaskRunner.run(Executor.scala:551) ~[spark-core_2.12-3.3.0.jar:3.3.0]\n", + "\tat java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) ~[?:?]\n", + "\tat java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) ~[?:?]\n", + "\tat java.lang.Thread.run(Thread.java:829) ~[?:?]\n", + "23/10/13 11:36:03 WARN HintErrorLogger: Hint (strategy=broadcast) is not supported in the query: build right for right outer join.\n", + "23/10/13 11:39:00 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=202; previousMaxLatencyMs=190; operationCount=105; context=gs://ot-team/dsuveges/finngen/2023.10.13_window_clumped_w_locus/_temporary/0/_temporary/attempt_20231013113900962145652452525416_0067_m_000009_79286/part-00009-65e9ae61-ec7d-4672-a525-8de91e583465-c000.snappy.parquet\n", + "23/10/13 11:39:00 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=216; previousMaxLatencyMs=202; operationCount=105; context=gs://ot-team/dsuveges/finngen/2023.10.13_window_clumped_w_locus/_temporary/0/_temporary/attempt_202310131139003257422348970599913_0067_m_000028_79305/part-00028-65e9ae61-ec7d-4672-a525-8de91e583465-c000.snappy.parquet\n", + "23/10/13 11:39:00 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=218; previousMaxLatencyMs=216; operationCount=105; context=gs://ot-team/dsuveges/finngen/2023.10.13_window_clumped_w_locus/_temporary/0/_temporary/attempt_202310131139006484121277706965747_0067_m_000003_79280/part-00003-65e9ae61-ec7d-4672-a525-8de91e583465-c000.snappy.parquet\n", + "23/10/13 11:39:01 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=243; previousMaxLatencyMs=218; operationCount=105; context=gs://ot-team/dsuveges/finngen/2023.10.13_window_clumped_w_locus/_temporary/0/_temporary/attempt_202310131139004953018478188900860_0067_m_000023_79300/part-00023-65e9ae61-ec7d-4672-a525-8de91e583465-c000.snappy.parquet\n", + "23/10/13 11:39:02 WARN GhfsStorageStatistics: Detected potential high latency for operation stream_write_close_operations. latencyMs=165; previousMaxLatencyMs=153; operationCount=92; context=gs://ot-team/dsuveges/finngen/2023.10.13_window_clumped_w_locus/_temporary/0/_temporary/attempt_202310131139003598197994288369319_0067_m_000026_79303/part-00026-65e9ae61-ec7d-4672-a525-8de91e583465-c000.snappy.parquet\n", + "23/10/13 11:39:02 WARN GhfsStorageStatistics: Detected potential high latency for operation stream_write_close_operations. latencyMs=193; previousMaxLatencyMs=165; operationCount=99; context=gs://ot-team/dsuveges/finngen/2023.10.13_window_clumped_w_locus/_temporary/0/_temporary/attempt_202310131139004279983947938826985_0067_m_000025_79302/part-00025-65e9ae61-ec7d-4672-a525-8de91e583465-c000.snappy.parquet\n", + "23/10/13 11:39:02 WARN GhfsStorageStatistics: Detected potential high latency for operation stream_write_close_operations. latencyMs=243; previousMaxLatencyMs=193; operationCount=103; context=gs://ot-team/dsuveges/finngen/2023.10.13_window_clumped_w_locus/_temporary/0/_temporary/attempt_202310131139004602145763603687891_0067_m_000030_79307/part-00030-65e9ae61-ec7d-4672-a525-8de91e583465-c000.snappy.parquet\n", + "23/10/13 11:39:02 WARN GhfsStorageStatistics: Detected potential high latency for operation stream_write_close_operations. latencyMs=329; previousMaxLatencyMs=243; operationCount=104; context=gs://ot-team/dsuveges/finngen/2023.10.13_window_clumped_w_locus/_temporary/0/_temporary/attempt_20231013113900353649088592248874_0067_m_000005_79282/part-00005-65e9ae61-ec7d-4672-a525-8de91e583465-c000.snappy.parquet\n", + " \r" + ] + } + ], + "source": [ + "window_based_clumped_output = \"gs://ot-team/dsuveges/finngen/2023.10.13_window_clumped_w_locus\"\n", + "\n", + "clump_window_length = 500_000\n", + "locus_window_length = 250_000\n", + "\n", + "(\n", + " SummaryStatistics(\n", + " _df=(\n", + " session.spark.read.parquet(sumstats, recursiveFileLookup=True)\n", + " .withColumn(\n", + " \"chromosome\",\n", + " f.split(f.col(\"variantId\"), \"_\")[0]\n", + " )\n", + " ),\n", + " _schema=SummaryStatistics.get_schema()\n", + " )\n", + " .window_based_clumping(\n", + " distance=clump_window_length,\n", + " locus_collect_distance=locus_window_length,\n", + " with_locus=True\n", + " )\n", + " .df.write.mode(\"overwrite\")\n", + " .parquet(window_based_clumped_output)\n", + ")\n" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "6b234362", + "metadata": { + "ExecuteTime": { + "end_time": "2023-10-13T12:39:15.023402Z", + "start_time": "2023-10-13T11:50:42.603425Z" + } + }, + "outputs": [ { - "cell_type": "code", - "execution_count": 29, - "id": "5bf42196", - "metadata": { - "ExecuteTime": { - "end_time": "2023-10-13T12:55:39.212186Z", - "start_time": "2023-10-13T12:55:38.131092Z" - } - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - }, - { - "data": { - "text/plain": [ - "[Row(locus=[Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99764322_T_C', pValueMantissa=2.3949999809265137, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0201963, standardError=0.00665169, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99764860_G_A', pValueMantissa=1.0499999523162842, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00813303, standardError=0.00248194, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99765280_C_T', pValueMantissa=7.499000072479248, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0147615, standardError=0.00437943, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99765335_A_G', pValueMantissa=1.2640000581741333, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0107816, standardError=0.00189456, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99766311_C_T', pValueMantissa=1.0579999685287476, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.010837, standardError=0.00189422, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99766702_A_G', pValueMantissa=1.2059999704360962, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0107966, standardError=0.00189453, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99766923_T_C', pValueMantissa=1.3300000429153442, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.010765, standardError=0.00189451, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99767090_TTTG_T', pValueMantissa=1.2740000486373901, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0107778, standardError=0.00189432, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99768341_T_C', pValueMantissa=1.2289999723434448, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0107887, standardError=0.00189422, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99768718_A_G', pValueMantissa=1.2649999856948853, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0107795, standardError=0.0018942, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99768993_G_A', pValueMantissa=1.1629999876022339, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0108066, standardError=0.00189423, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99769297_T_C', pValueMantissa=1.2929999828338623, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0113037, standardError=0.00186275, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99769386_C_T', pValueMantissa=1.7280000448226929, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00670209, standardError=0.00281514, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99769548_A_G', pValueMantissa=1.7280000448226929, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0067021, standardError=0.00281514, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99769607_C_T', pValueMantissa=1.2710000276565552, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0107775, standardError=0.00189416, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99770233_A_AT', pValueMantissa=1.1360000371932983, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0108149, standardError=0.00189434, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99771038_C_A', pValueMantissa=1.1039999723434448, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0108218, standardError=0.00189392, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99771332_T_C', pValueMantissa=1.284999966621399, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00972726, standardError=0.00390986, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99771548_C_T', pValueMantissa=1.1369999647140503, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0108168, standardError=0.00189473, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99774249_G_A', pValueMantissa=1.0410000085830688, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00813435, standardError=0.00248058, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99774476_AT_A', pValueMantissa=1.1540000438690186, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0108061, standardError=0.0018937, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99777761_G_A', pValueMantissa=2.9170000553131104, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0857961, standardError=0.0393337, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99777984_T_G', pValueMantissa=9.097999572753906, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0108749, standardError=0.00189236, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99778063_G_A', pValueMantissa=1.2730000019073486, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00887632, standardError=0.00203368, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99778821_G_A', pValueMantissa=1.6679999828338623, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00682868, standardError=0.00285271, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99779613_C_G', pValueMantissa=7.630000114440918, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0109299, standardError=0.00189215, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99781296_A_G', pValueMantissa=8.560999870300293, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.010892, standardError=0.00189195, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99781822_G_A', pValueMantissa=1.4390000104904175, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00689344, standardError=0.00281655, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99781826_A_G', pValueMantissa=7.65500020980835, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0109284, standardError=0.00189207, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99782821_C_T', pValueMantissa=1.3680000305175781, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00573303, standardError=0.00232523, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99783206_A_G', pValueMantissa=7.632999897003174, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0109293, standardError=0.00189206, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99783290_A_C', pValueMantissa=8.821999549865723, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0108841, standardError=0.00189224, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99784269_C_T', pValueMantissa=9.149999618530273, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0108721, standardError=0.00189218, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99784331_G_A', pValueMantissa=4.435999870300293, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0327234, standardError=0.0162747, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99784751_C_A', pValueMantissa=3.0409998893737793, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.149822, standardError=0.0692119, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99785581_A_G', pValueMantissa=7.164000034332275, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0113888, standardError=0.00423514, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99786875_C_T', pValueMantissa=5.257999897003174, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0110515, standardError=0.00189278, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99787050_C_G', pValueMantissa=6.671999931335449, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0109731, standardError=0.00189226, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99787264_C_A', pValueMantissa=7.834000110626221, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0109198, standardError=0.00189186, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99787285_C_T', pValueMantissa=9.189000129699707, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0108723, standardError=0.00189246, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99787359_T_G', pValueMantissa=7.504000186920166, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0109356, standardError=0.00189222, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99787460_G_T', pValueMantissa=6.499000072479248, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.010984, standardError=0.00189269, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99787461_G_T', pValueMantissa=6.499000072479248, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.010984, standardError=0.00189269, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99787483_G_A', pValueMantissa=7.631999969482422, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0109293, standardError=0.00189206, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99787568_C_T', pValueMantissa=7.631999969482422, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0109293, standardError=0.00189206, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99787571_C_T', pValueMantissa=7.631999969482422, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0109293, standardError=0.00189206, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99787694_A_AT', pValueMantissa=7.631999969482422, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0109293, standardError=0.00189206, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99787855_C_T', pValueMantissa=8.937999725341797, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0108798, standardError=0.00189223, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99787860_C_T', pValueMantissa=7.64300012588501, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0231471, standardError=0.0086776, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99787890_G_A', pValueMantissa=7.631999969482422, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0109293, standardError=0.00189206, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99787906_T_A', pValueMantissa=7.631999969482422, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0109293, standardError=0.00189206, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99787915_T_G', pValueMantissa=7.631999969482422, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0109293, standardError=0.00189206, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99788026_C_T', pValueMantissa=7.7870001792907715, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0109255, standardError=0.00189252, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99788420_A_C', pValueMantissa=7.001999855041504, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0109573, standardError=0.00189216, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99788711_G_A', pValueMantissa=1.0420000553131104, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0108302, standardError=0.00189215, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99788859_C_T', pValueMantissa=7.632999897003174, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0109293, standardError=0.00189206, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99788952_C_T', pValueMantissa=9.12399959564209, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0108727, standardError=0.00189214, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99789038_A_G', pValueMantissa=7.164000034332275, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0109498, standardError=0.00189212, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99789217_G_C', pValueMantissa=7.72599983215332, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0109277, standardError=0.00189247, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99789506_G_C', pValueMantissa=7.671000003814697, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0109278, standardError=0.00189209, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99789829_T_G', pValueMantissa=7.632999897003174, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0109293, standardError=0.00189206, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99790008_G_A', pValueMantissa=7.603000164031982, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0109305, standardError=0.00189206, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99790154_G_A', pValueMantissa=7.632999897003174, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0109293, standardError=0.00189206, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99790319_T_G', pValueMantissa=7.857999801635742, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0109213, standardError=0.00189229, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99791174_G_A', pValueMantissa=7.623000144958496, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0276216, standardError=0.00820577, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99791224_A_G', pValueMantissa=7.632999897003174, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0109293, standardError=0.00189206, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99793129_A_T', pValueMantissa=9.17300033569336, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0108711, standardError=0.00189215, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99793502_C_T', pValueMantissa=1.0099999904632568, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0108395, standardError=0.00189201, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99793829_C_CGTAT', pValueMantissa=3.756999969482422, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.201946, standardError=0.0971122, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99794292_T_A', pValueMantissa=1.8420000076293945, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0427514, standardError=0.0181376, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99794803_C_G', pValueMantissa=3.76200008392334, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0754336, standardError=0.0362844, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99797363_G_A', pValueMantissa=2.696000099182129, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0451691, standardError=0.0204184, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99797572_A_C', pValueMantissa=7.729000091552734, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0109255, standardError=0.0018921, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99798877_A_T', pValueMantissa=5.47599983215332, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0111187, standardError=0.0019065, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99798989_G_T', pValueMantissa=4.708000183105469, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00645552, standardError=0.00184611, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99799669_G_A', pValueMantissa=1.3769999742507935, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0283588, standardError=0.0115134, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99801055_G_A', pValueMantissa=5.751999855041504, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0863438, standardError=0.0312661, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99801648_T_C', pValueMantissa=5.201000213623047, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.35431, standardError=0.126797, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99802216_C_T', pValueMantissa=8.795999526977539, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0312825, standardError=0.00584722, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99803737_A_G', pValueMantissa=4.105000019073486, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0838538, standardError=0.0410448, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99804058_G_A', pValueMantissa=9.253999710083008, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00819335, standardError=0.00247362, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99804255_C_G', pValueMantissa=8.798999786376953, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0312823, standardError=0.00584723, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99804875_C_T', pValueMantissa=2.2079999446868896, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0532293, standardError=0.023254, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99805400_A_G', pValueMantissa=5.626999855041504, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0215236, standardError=0.00777382, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99805994_G_A', pValueMantissa=1.6449999809265137, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0125221, standardError=0.00522031, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99806253_C_T', pValueMantissa=1.2120000123977661, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00800751, standardError=0.00247451, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99806469_CAT_C', pValueMantissa=1.996999979019165, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.01596, standardError=0.00685871, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99807109_T_A', pValueMantissa=3.994999885559082, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0097045, standardError=0.00274107, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99807669_A_G', pValueMantissa=4.577000141143799, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0111561, standardError=0.00190316, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99807962_A_G', pValueMantissa=3.7709999084472656, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0677375, standardError=0.0325981, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99809156_C_A', pValueMantissa=1.4980000257492065, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00696552, standardError=0.0028632, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99809726_T_C', pValueMantissa=4.446000099182129, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0111654, standardError=0.00190318, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99809873_G_A', pValueMantissa=4.642000198364258, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.122379, standardError=0.0614495, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99811236_C_A', pValueMantissa=7.059999942779541, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0110215, standardError=0.00190371, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99811771_C_T', pValueMantissa=4.526000022888184, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0111597, standardError=0.00190317, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99815174_G_C', pValueMantissa=6.111000061035156, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0110649, standardError=0.00190324, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99815628_A_G', pValueMantissa=9.194999694824219, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0211397, standardError=0.00637879, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99815640_A_G', pValueMantissa=8.413999557495117, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0902758, standardError=0.0342605, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99816387_G_A', pValueMantissa=4.604000091552734, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0346061, standardError=0.0173466, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99816562_G_A', pValueMantissa=3.677000045776367, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00976812, standardError=0.00274214, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99816570_G_A', pValueMantissa=1.152999997138977, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00804666, standardError=0.00247569, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99817203_T_C', pValueMantissa=7.421999931335449, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0110057, standardError=0.00190374, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99818525_T_C', pValueMantissa=1.4880000352859497, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0186574, standardError=0.0076615, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99819195_T_G', pValueMantissa=6.382999897003174, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0124767, standardError=0.0045745, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99820908_A_G', pValueMantissa=1.4980000257492065, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00696602, standardError=0.0028633, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99821086_GA_G', pValueMantissa=3.259999990463257, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0113261, standardError=0.00272622, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99821094_C_T', pValueMantissa=4.098999977111816, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0112471, standardError=0.00191273, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99821955_T_G', pValueMantissa=4.670000076293945, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0112087, standardError=0.00191323, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99822427_T_C', pValueMantissa=2.058000087738037, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0115151, standardError=0.00192136, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99822696_T_C', pValueMantissa=7.763000011444092, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.162918, standardError=0.0611962, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99823047_A_G', pValueMantissa=7.198999881744385, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0110742, standardError=0.0019139, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99823280_T_C', pValueMantissa=1.1619999408721924, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00804213, standardError=0.00247592, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99825419_A_G', pValueMantissa=1.2710000276565552, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0826158, standardError=0.0331567, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99825752_T_C', pValueMantissa=6.0370001792907715, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0111297, standardError=0.00191372, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99825835_C_T', pValueMantissa=6.0320000648498535, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0111299, standardError=0.00191372, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99827260_C_T', pValueMantissa=3.6500000953674316, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0489284, standardError=0.0233964, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99828083_C_T', pValueMantissa=3.938999891281128, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0959414, standardError=0.0465714, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99828402_T_A', pValueMantissa=9.142000198364258, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0211518, standardError=0.00637931, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99828407_A_T', pValueMantissa=9.133999824523926, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0211533, standardError=0.0063793, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99829453_A_AT', pValueMantissa=6.083000183105469, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0111253, standardError=0.00191338, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99829545_ATATTT_A', pValueMantissa=4.810999870300293, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0112061, standardError=0.00191441, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99830168_G_A', pValueMantissa=1.218999981880188, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00801018, standardError=0.00247653, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99830263_G_A', pValueMantissa=1.6970000267028809, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0179959, standardError=0.00753787, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99832187_T_C', pValueMantissa=4.421000003814697, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0112213, standardError=0.0019124, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99832400_AAC_A', pValueMantissa=6.706999778747559, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0110021, standardError=0.00189753, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99832402_C_CTGTGTGT', pValueMantissa=6.710999965667725, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0110019, standardError=0.00189753, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99832563_A_G', pValueMantissa=1.4479999542236328, pValueExponent=-6, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0090241, standardError=0.00187287, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99832865_A_G', pValueMantissa=4.169000148773193, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0105412, standardError=0.00192234, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99834145_G_C', pValueMantissa=6.802999973297119, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.260334, standardError=0.0961939, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99834214_T_C', pValueMantissa=1.784000039100647, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0474718, standardError=0.0200386, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99835361_G_A', pValueMantissa=2.0769999027252197, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0595141, standardError=0.0257408, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99841479_C_T', pValueMantissa=6.188000202178955, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0104861, standardError=0.00193711, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99842816_A_G', pValueMantissa=8.645000457763672, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00723726, standardError=0.00184352, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99844024_C_G', pValueMantissa=2.3450000286102295, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0107969, standardError=0.00193341, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99844450_C_T', pValueMantissa=2.874000072479248, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0107269, standardError=0.00193316, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99845178_C_T', pValueMantissa=4.0320000648498535, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0656125, standardError=0.0319983, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99845936_A_G', pValueMantissa=3.069999933242798, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00675859, standardError=0.00312767, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99848765_C_G', pValueMantissa=2.8910000324249268, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0114511, standardError=0.00192855, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99850966_A_G', pValueMantissa=8.373000144958496, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0101864, standardError=0.00190084, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99852563_C_T', pValueMantissa=4.5329999923706055, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0113089, standardError=0.0019287, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99853411_T_TG', pValueMantissa=9.414999961853027, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.011087, standardError=0.00193121, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99856822_A_G', pValueMantissa=2.7119998931884766, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0114876, standardError=0.00193129, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99856987_G_C', pValueMantissa=5.239999771118164, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.010358, standardError=0.001903, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99857429_C_T', pValueMantissa=1.718000054359436, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0116617, standardError=0.00193637, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99857502_A_G', pValueMantissa=6.296000003814697, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.010296, standardError=0.00190308, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99857670_G_A', pValueMantissa=2.7939999103546143, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.011478, standardError=0.00193126, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99857979_C_T', pValueMantissa=2.5840001106262207, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00775769, standardError=0.00184386, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99858035_C_T', pValueMantissa=2.7939999103546143, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.011478, standardError=0.00193127, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99858181_G_C', pValueMantissa=2.7920000553131104, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0114783, standardError=0.00193127, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99858624_T_C', pValueMantissa=6.314000129699707, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0103011, standardError=0.0019042, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99859267_C_A', pValueMantissa=1.5019999742507935, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0239274, standardError=0.00753783, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99859558_G_A', pValueMantissa=6.2779998779296875, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0321283, standardError=0.00593792, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99859674_G_A', pValueMantissa=1.1050000190734863, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0100907, standardError=0.00190082, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99861014_C_G', pValueMantissa=1.350000023841858, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0080568, standardError=0.00185135, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99861191_A_G', pValueMantissa=2.062000036239624, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00788332, standardError=0.00185141, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99861743_A_C', pValueMantissa=1.621999979019165, pValueExponent=-6, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00893977, standardError=0.00186417, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99861975_TTGG_T', pValueMantissa=1.5509999990463257, pValueExponent=-6, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00895366, standardError=0.00186357, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99862766_C_T', pValueMantissa=1.7289999723434448, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00993376, standardError=0.0019007, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99863009_T_C', pValueMantissa=1.3009999990463257, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0535743, standardError=0.0215732, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99863999_T_C', pValueMantissa=1.4730000495910645, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0137073, standardError=0.00361145, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99864093_A_C', pValueMantissa=5.741000175476074, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0322238, standardError=0.00593803, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99864115_G_T', pValueMantissa=7.295000076293945, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.150642, standardError=0.0445916, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99865012_T_C', pValueMantissa=2.450000047683716, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00781456, standardError=0.00185205, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99865013_G_A', pValueMantissa=1.7259999513626099, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0159887, standardError=0.00510203, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99865261_T_C', pValueMantissa=1.4459999799728394, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00999453, standardError=0.00190036, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99865337_G_GAAGA', pValueMantissa=1.3170000314712524, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00806712, standardError=0.00185143, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99865513_C_G', pValueMantissa=1.3250000476837158, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0080656, standardError=0.00185165, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99866792_C_T', pValueMantissa=1.4500000476837158, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00803164, standardError=0.00185225, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99867170_C_T', pValueMantissa=8.121000289916992, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0111182, standardError=0.00192825, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99867197_T_C', pValueMantissa=2.680999994277954, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0171717, standardError=0.00775509, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99867487_C_G', pValueMantissa=2.8310000896453857, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.359987, standardError=0.164156, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99867528_G_T', pValueMantissa=2.8389999866485596, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0077156, standardError=0.0018432, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99868259_G_A', pValueMantissa=2.265000104904175, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.119984, standardError=0.0392983, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99868412_T_G', pValueMantissa=1.6779999732971191, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00994383, standardError=0.00190064, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99868443_A_G', pValueMantissa=1.4809999465942383, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00801978, standardError=0.0018515, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99868585_TC_T', pValueMantissa=1.437999963760376, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0080333, standardError=0.00185188, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99868691_T_G', pValueMantissa=1.4730000495910645, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00802444, standardError=0.00185208, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99869742_G_A', pValueMantissa=4.677000045776367, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0101608, standardError=0.00185986, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99870037_G_A', pValueMantissa=3.996999979019165, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0939625, standardError=0.0326443, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99870234_G_A', pValueMantissa=2.5759999752044678, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0270256, standardError=0.00896575, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99871164_A_T', pValueMantissa=9.444999694824219, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0101485, standardError=0.0019015, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99871248_A_C', pValueMantissa=4.265999794006348, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.011332, standardError=0.00192934, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99871256_C_T', pValueMantissa=1.0980000495910645, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0100932, standardError=0.00190087, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99871596_T_C', pValueMantissa=1.097000002861023, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0100928, standardError=0.00190078, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99871838_G_C', pValueMantissa=4.270999908447266, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0113316, standardError=0.00192933, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99871912_T_C', pValueMantissa=1.0989999771118164, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0100928, standardError=0.00190087, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99872008_T_C', pValueMantissa=1.0989999771118164, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0100927, standardError=0.00190087, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99872112_C_T', pValueMantissa=1.093000054359436, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0100944, standardError=0.00190084, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99872802_A_G', pValueMantissa=2.828000068664551, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0103237, standardError=0.00185953, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99873074_C_T', pValueMantissa=4.716000080108643, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0112996, standardError=0.00192927, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99873158_C_T', pValueMantissa=1.1759999990463257, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.010069, standardError=0.00190084, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99873263_C_T', pValueMantissa=1.1440000534057617, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.010071, standardError=0.00189938, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99873471_G_A', pValueMantissa=6.283999919891357, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0723658, standardError=0.0264824, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99873553_C_T', pValueMantissa=1.8109999895095825, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0122764, standardError=0.00286365, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99873602_C_T', pValueMantissa=3.7880001068115234, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0102286, standardError=0.00185958, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99874022_C_T', pValueMantissa=3.7920000553131104, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0102286, standardError=0.00185966, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99874186_C_CT', pValueMantissa=1.2230000495910645, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0100561, standardError=0.00190097, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99875195_T_C', pValueMantissa=4.964000225067139, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0112867, standardError=0.00192988, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99875202_G_T', pValueMantissa=1.312999963760376, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0100339, standardError=0.00190142, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99875320_C_A', pValueMantissa=1.2369999885559082, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0100535, standardError=0.00190119, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99875381_T_C', pValueMantissa=1.2410000562667847, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0100525, standardError=0.00190121, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99875452_C_T', pValueMantissa=2.5290000438690186, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0135056, standardError=0.00447237, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99875704_T_A', pValueMantissa=2.9600000381469727, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00410906, standardError=0.00188882, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99875760_A_AG', pValueMantissa=1.2430000305175781, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.010052, standardError=0.00190125, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99876031_G_GT', pValueMantissa=1.3940000534057617, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0240895, standardError=0.00753787, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99876891_T_C', pValueMantissa=3.986999988555908, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0102146, standardError=0.0018601, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99878758_G_A', pValueMantissa=2.763000011444092, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.151851, standardError=0.0689453, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99878850_C_G', pValueMantissa=4.1519999504089355, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0102024, standardError=0.0018603, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99880039_G_A', pValueMantissa=4.0960001945495605, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0102077, standardError=0.00186045, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99880120_A_C', pValueMantissa=4.75, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0113026, standardError=0.00193019, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99880736_G_C', pValueMantissa=2.4639999866485596, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.11912, standardError=0.039343, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99882938_G_A', pValueMantissa=4.218999862670898, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0102002, standardError=0.00186086, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99883489_C_T', pValueMantissa=7.486000061035156, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0140267, standardError=0.00524475, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99884754_C_T', pValueMantissa=2.5510001182556152, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.011665, standardError=0.00195783, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99885306_C_T', pValueMantissa=7.618000030517578, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0122854, standardError=0.00460381, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99885741_T_C', pValueMantissa=4.251999855041504, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0101963, standardError=0.00186062, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99887218_A_G', pValueMantissa=1.3589999675750732, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0100249, standardError=0.00190197, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99887854_C_T', pValueMantissa=1.3580000400543213, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.010025, standardError=0.00190197, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99888103_G_A', pValueMantissa=3.808000087738037, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0456176, standardError=0.0219955, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99889239_G_C', pValueMantissa=1.3580000400543213, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0100256, standardError=0.00190207, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99890983_C_T', pValueMantissa=1.3830000162124634, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.01002, standardError=0.00190223, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99891336_A_G', pValueMantissa=3.815000057220459, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0102374, standardError=0.00186162, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99891408_C_T', pValueMantissa=1.6360000371932983, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00996155, standardError=0.00190233, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99891590_G_A', pValueMantissa=6.8420000076293945, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0114132, standardError=0.00422021, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99891697_T_C', pValueMantissa=4.46999979019165, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.010205, standardError=0.00186523, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99892983_T_C', pValueMantissa=3.4000000953674316, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.177641, standardError=0.083791, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99893179_G_C', pValueMantissa=5.1570000648498535, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0112781, standardError=0.00193051, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99893428_C_T', pValueMantissa=4.14300012588501, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0102059, standardError=0.00186081, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99894094_G_C', pValueMantissa=4.321000099182129, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0249459, standardError=0.00708754, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99894492_G_T', pValueMantissa=8.531999588012695, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0101123, standardError=0.00188821, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99894565_A_G', pValueMantissa=4.785999774932861, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00954874, standardError=0.00273411, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99894939_T_C', pValueMantissa=8.916999816894531, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00988844, standardError=0.00184916, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99895167_T_C', pValueMantissa=4.169000148773193, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00948941, standardError=0.00187497, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99895555_C_T', pValueMantissa=4.659999847412109, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0340557, standardError=0.0120355, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99896225_G_A', pValueMantissa=1.0920000076293945, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0110344, standardError=0.0019305, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99896692_A_G', pValueMantissa=3.4130001068115234, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0110917, standardError=0.00187665, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99896979_T_G', pValueMantissa=3.2119998931884766, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0401381, standardError=0.0187308, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99897831_T_C', pValueMantissa=1.9040000438690186, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.14616, standardError=0.0623359, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99898123_G_A', pValueMantissa=1.1069999933242798, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0110304, standardError=0.00193059, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99898484_T_A', pValueMantissa=1.1139999628067017, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0110285, standardError=0.00193061, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99898828_T_C', pValueMantissa=3.2699999809265137, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0111045, standardError=0.00187657, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99899677_C_CTTGT', pValueMantissa=3.51200008392334, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0110858, standardError=0.00187714, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99900290_T_G', pValueMantissa=7.426000118255615, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0109405, standardError=0.00189249, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99900292_A_AT', pValueMantissa=1.1360000371932983, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00988613, standardError=0.00390553, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99900500_A_C', pValueMantissa=2.2009999752044678, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0412365, standardError=0.0180062, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99901642_T_C', pValueMantissa=5.086999893188477, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.113465, standardError=0.0405014, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99901731_C_T', pValueMantissa=1.5379999876022339, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0140283, standardError=0.00442901, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99902496_G_A', pValueMantissa=1.2289999723434448, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0224604, standardError=0.00897057, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99902603_C_T', pValueMantissa=4.140999794006348, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0854585, standardError=0.0419028, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99902712_G_C', pValueMantissa=1.1929999589920044, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0110082, standardError=0.00193099, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99902720_C_G', pValueMantissa=3.492000102996826, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.011087, standardError=0.00187705, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99902757_G_A', pValueMantissa=4.366000175476074, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0110198, standardError=0.00187741, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99903008_A_C', pValueMantissa=3.4590001106262207, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.01109, standardError=0.00187705, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99903292_G_A', pValueMantissa=3.4660000801086426, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0110895, standardError=0.00187709, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99903681_G_T', pValueMantissa=6.072000026702881, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0110979, standardError=0.00190858, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99904413_A_G', pValueMantissa=3.4719998836517334, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0110894, standardError=0.00187714, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99904499_G_A', pValueMantissa=1.1369999647140503, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0110237, standardError=0.00193097, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99904588_G_A', pValueMantissa=9.54800033569336, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0142134, standardError=0.00430252, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99905340_C_T', pValueMantissa=1.184000015258789, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0110128, standardError=0.00193138, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99905534_G_C', pValueMantissa=1.2209999561309814, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0379664, standardError=0.0151507, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99905541_A_G', pValueMantissa=3.575000047683716, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0110805, standardError=0.00187717, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99905693_A_G', pValueMantissa=3.490999937057495, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0110881, standardError=0.00187721, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99906210_T_C', pValueMantissa=3.5, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0110874, standardError=0.00187724, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99906644_G_A', pValueMantissa=1.0570000410079956, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0110495, standardError=0.00193126, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99906718_T_C', pValueMantissa=3.4709999561309814, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0110901, standardError=0.00187726, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99908035_C_T', pValueMantissa=7.296000003814697, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0148557, standardError=0.00439751, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99908057_A_G', pValueMantissa=7.160999774932861, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0149937, standardError=0.00443164, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99908221_T_C', pValueMantissa=3.878000020980835, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0110578, standardError=0.0018776, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99908813_T_C', pValueMantissa=5.124000072479248, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0112768, standardError=0.00192994, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99909229_T_C', pValueMantissa=8.24899959564209, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00998922, standardError=0.0018631, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99909454_A_C', pValueMantissa=7.598999977111816, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0109359, standardError=0.00189297, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99910263_C_T', pValueMantissa=5.330999851226807, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0111417, standardError=0.00190898, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99910368_T_C', pValueMantissa=3.302999973297119, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.011106, standardError=0.00187736, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99910580_T_G', pValueMantissa=1.1369999647140503, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0110251, standardError=0.00193122, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99911338_T_C', pValueMantissa=3.4579999446868896, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.011092, standardError=0.00187738, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99911811_G_A', pValueMantissa=2.575000047683716, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.118741, standardError=0.0393917, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99912354_A_G', pValueMantissa=5.099999904632568, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0112784, standardError=0.00192997, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99912584_A_G', pValueMantissa=3.447999954223633, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.011093, standardError=0.00187739, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99913097_C_G', pValueMantissa=3.181999921798706, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0111182, standardError=0.00187747, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99913702_T_C', pValueMantissa=1.0369999408721924, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0108274, standardError=0.00422404, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99914373_T_G', pValueMantissa=3.0360000133514404, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.248118, standardError=0.114583, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99915372_A_G', pValueMantissa=3.250999927520752, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0111123, standardError=0.0018776, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99915373_G_A', pValueMantissa=3.3289999961853027, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0111042, standardError=0.00187747, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99915884_T_C', pValueMantissa=5.684999942779541, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0109318, standardError=0.00187645, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99915918_T_G', pValueMantissa=1.281000018119812, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00983696, standardError=0.00186253, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99916127_T_C', pValueMantissa=5.081999778747559, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0112798, standardError=0.00193, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99916503_A_T', pValueMantissa=6.974999904632568, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00734427, standardError=0.00184662, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99916552_T_C', pValueMantissa=2.9839999675750732, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0122137, standardError=0.00562257, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99917731_C_T', pValueMantissa=5.0289998054504395, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0112837, standardError=0.0019301, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99919106_C_T', pValueMantissa=2.8299999237060547, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0131403, standardError=0.00440112, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99920364_C_T', pValueMantissa=4.159999847412109, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0219416, standardError=0.0076565, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99921641_GC_G', pValueMantissa=5.14900016784668, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0112777, standardError=0.00193036, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99922010_GAAGA_G', pValueMantissa=3.134999990463257, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0255599, standardError=0.00709237, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99922205_A_G', pValueMantissa=8.65999984741211, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00997687, standardError=0.00186386, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99922419_C_T', pValueMantissa=5.785999774932861, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0112417, standardError=0.00193063, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99923392_A_AAAT', pValueMantissa=7.868000030517578, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.010012, standardError=0.00186439, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99924208_C_T', pValueMantissa=6.610000133514404, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0112121, standardError=0.00193293, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99924251_CACGGTGAA_C', pValueMantissa=5.901000022888184, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0112486, standardError=0.0019329, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99924611_T_C', pValueMantissa=3.5799999237060547, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.028521, standardError=0.0135863, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99924854_A_G', pValueMantissa=4.103000164031982, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.135756, standardError=0.0664409, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99925030_G_A', pValueMantissa=7.132999897003174, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0123943, standardError=0.00460661, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99925171_T_C', pValueMantissa=2.7660000324249268, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0131669, standardError=0.00439981, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99925527_C_T', pValueMantissa=3.3429999351501465, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.011112, standardError=0.00187899, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99926307_T_C', pValueMantissa=1.2309999465942383, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00985993, standardError=0.0018643, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99926344_G_A', pValueMantissa=7.146999835968018, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0123917, standardError=0.00460668, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99928121_C_T', pValueMantissa=2.6080000400543213, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0237748, standardError=0.0106854, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99928961_T_A', pValueMantissa=7.409999847412109, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0092492, standardError=0.00274137, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99929621_G_C', pValueMantissa=2.4159998893737793, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00965232, standardError=0.00186913, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99930293_C_T', pValueMantissa=2.371000051498413, pValueExponent=-6, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00891412, standardError=0.00188903, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99930622_A_G', pValueMantissa=2.9200000762939453, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0122713, standardError=0.0019469, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99930880_C_G', pValueMantissa=6.189000129699707, pValueExponent=-11, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0126631, standardError=0.00193652, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99931871_G_T', pValueMantissa=1.0870000123977661, pValueExponent=-11, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0132779, standardError=0.00195421, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99932501_G_T', pValueMantissa=7.144999980926514, pValueExponent=-11, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0130514, standardError=0.0020025, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99932525_C_G', pValueMantissa=3.86299991607666, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0132541, standardError=0.00190924, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99932591_G_A', pValueMantissa=3.625999927520752, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0057824, standardError=0.00276148, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99933095_G_A', pValueMantissa=6.820000171661377, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.041325, standardError=0.0152743, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99933333_G_A', pValueMantissa=7.736000061035156, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0130529, standardError=0.00190738, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99933398_T_G', pValueMantissa=1.1490000486373901, pValueExponent=-11, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0132623, standardError=0.00195424, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99933499_T_C', pValueMantissa=7.710999965667725, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0130536, standardError=0.00190735, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99933515_AG_A', pValueMantissa=6.0929999351501465, pValueExponent=-11, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0130982, standardError=0.00200234, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99933811_A_C', pValueMantissa=3.0450000762939453, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0271544, standardError=0.009164, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99933841_A_G', pValueMantissa=7.820000171661377, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0130497, standardError=0.00190735, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99935601_G_A', pValueMantissa=6.01200008392334, pValueExponent=-11, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0131034, standardError=0.00200253, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99935839_G_A', pValueMantissa=1.9040000438690186, pValueExponent=-6, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0088457, standardError=0.00185702, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99936985_A_C', pValueMantissa=8.661999702453613, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0130204, standardError=0.00190715, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99937543_C_A', pValueMantissa=6.139999866485596, pValueExponent=-11, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0130966, standardError=0.00200245, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99938738_G_A', pValueMantissa=1.0329999923706055, pValueExponent=-11, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0132869, standardError=0.00195344, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99939547_T_C', pValueMantissa=6.979000091552734, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0130948, standardError=0.00190939, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99939652_G_A', pValueMantissa=4.034999847412109, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0132546, standardError=0.00191099, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99940864_C_T', pValueMantissa=5.973999977111816, pValueExponent=-11, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0131208, standardError=0.0020049, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99941429_ACCTCAGGGTTACC_A', pValueMantissa=4.370999813079834, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.187402, standardError=0.0929166, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99941625_T_C', pValueMantissa=7.7729997634887695, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0130649, standardError=0.00190932, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99942056_T_C', pValueMantissa=4.118000030517578, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0832392, standardError=0.0407701, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99942622_C_G', pValueMantissa=4.414999961853027, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0132329, standardError=0.00191137, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99942695_T_C', pValueMantissa=5.933000087738037, pValueExponent=-11, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0131229, standardError=0.0020049, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99942879_G_C', pValueMantissa=4.004000186920166, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0132567, standardError=0.001911, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99943051_G_T', pValueMantissa=5.098999977111816, pValueExponent=-6, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0153013, standardError=0.00335503, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99943272_T_C', pValueMantissa=4.004000186920166, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0132567, standardError=0.001911, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99943700_G_A', pValueMantissa=1.340000033378601, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0629333, standardError=0.0254482, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99943766_A_G', pValueMantissa=3.8440001010894775, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0136334, standardError=0.00196368, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99944281_T_C', pValueMantissa=7.932000160217285, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0130606, standardError=0.00190951, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99944562_A_T', pValueMantissa=4.39300012588501, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0135957, standardError=0.0019636, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99944721_TC_T', pValueMantissa=4.39300012588501, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0135957, standardError=0.0019636, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99945215_A_G', pValueMantissa=4.004000186920166, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0132567, standardError=0.001911, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99946139_G_A', pValueMantissa=1.3140000104904175, pValueExponent=-6, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00899244, standardError=0.00185887, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99946260_A_G', pValueMantissa=4.004000186920166, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0132567, standardError=0.001911, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99946307_A_C', pValueMantissa=4.873000144958496, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.12509, standardError=0.063468, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99946514_A_C', pValueMantissa=4.004000186920166, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0132567, standardError=0.001911, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99946634_G_A', pValueMantissa=4.004000186920166, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0132567, standardError=0.001911, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99947232_A_G', pValueMantissa=5.947999954223633, pValueExponent=-11, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0131222, standardError=0.00200491, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99947807_T_C', pValueMantissa=4.004000186920166, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0132567, standardError=0.001911, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99947876_G_A', pValueMantissa=4.059000015258789, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0132552, standardError=0.00191131, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99948681_A_G', pValueMantissa=7.769999980926514, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0130649, standardError=0.00190932, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99949062_G_A', pValueMantissa=4.873000144958496, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.12509, standardError=0.063468, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99950056_G_A', pValueMantissa=4.761000156402588, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.107573, standardError=0.0543081, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99952120_T_C', pValueMantissa=1.062000036239624, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0236237, standardError=0.00721645, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99953194_G_A', pValueMantissa=5.874000072479248, pValueExponent=-11, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0131262, standardError=0.00200494, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99953842_C_T', pValueMantissa=4.118000030517578, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0132617, standardError=0.00191282, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99953915_A_G', pValueMantissa=3.8420000076293945, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0132682, standardError=0.00191106, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99954520_G_A', pValueMantissa=6.242000102996826, pValueExponent=-11, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0131087, standardError=0.00200505, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99954533_T_G', pValueMantissa=4.175000190734863, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0132459, standardError=0.00191108, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99956142_G_A', pValueMantissa=4.054999828338623, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0132533, standardError=0.001911, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99956727_G_A', pValueMantissa=2.9579999446868896, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0132311, standardError=0.00445185, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99958027_A_G', pValueMantissa=7.925000190734863, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0130596, standardError=0.00190933, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99959825_G_A', pValueMantissa=4.172999858856201, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0163596, standardError=0.00803454, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99959911_G_A', pValueMantissa=2.3239998817443848, pValueExponent=-11, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0134674, standardError=0.00201484, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99962154_T_G', pValueMantissa=6.442999839782715, pValueExponent=-11, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0130988, standardError=0.002005, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99962896_A_G', pValueMantissa=4.985000133514404, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.018755, standardError=0.00956281, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99963747_T_C', pValueMantissa=3.8350000381469727, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.10415, standardError=0.0360205, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99963755_G_A', pValueMantissa=4.4070000648498535, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0132354, standardError=0.00191167, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99963792_C_T', pValueMantissa=1.0329999923706055, pValueExponent=-11, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0133147, standardError=0.0019575, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99963855_G_A', pValueMantissa=6.202000141143799, pValueExponent=-11, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0131113, standardError=0.00200516, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99963858_G_C', pValueMantissa=4.052000045776367, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0132537, standardError=0.00191104, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99964474_C_A', pValueMantissa=1.5709999799728394, pValueExponent=-11, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.013808, standardError=0.0020483, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99964716_C_T', pValueMantissa=3.6579999923706055, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.022367, standardError=0.00769613, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99965353_C_T', pValueMantissa=4.11899995803833, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0832401, standardError=0.0407717, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99965381_C_T', pValueMantissa=3.3989999294281006, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0154555, standardError=0.00728972, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99965782_C_T', pValueMantissa=1.2259999513626099, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0312055, standardError=0.00547846, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99966311_G_A', pValueMantissa=4.085000038146973, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0132514, standardError=0.00191102, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99966874_G_A', pValueMantissa=9.85099983215332, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0133219, standardError=0.00195661, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99967655_A_C', pValueMantissa=4.085999965667725, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0132548, standardError=0.00191151, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99968174_T_C', pValueMantissa=6.03000020980835, pValueExponent=-11, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0131184, standardError=0.00200495, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99970196_C_T', pValueMantissa=1.940999984741211, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0134874, standardError=0.00191619, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99971874_A_G', pValueMantissa=4.980999946594238, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0132011, standardError=0.0019115, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99973080_C_CATTT', pValueMantissa=9.527999877929688, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00936982, standardError=0.00191176, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99973080_CATTT_C', pValueMantissa=3.311000108718872, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.013347, standardError=0.00191661, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99973360_A_G', pValueMantissa=1.6030000448226929, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0940323, standardError=0.0390452, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99973664_T_C', pValueMantissa=4.126999855041504, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.013249, standardError=0.00191107, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99973694_T_C', pValueMantissa=3.937000036239624, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.13666, standardError=0.0663293, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99973733_A_G', pValueMantissa=4.34499979019165, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0132363, standardError=0.00191125, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99974260_C_T', pValueMantissa=2.316999912261963, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0316527, standardError=0.0139405, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99975197_T_C', pValueMantissa=2.117000102996826, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0134651, standardError=0.00191633, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99975489_C_G', pValueMantissa=5.743000030517578, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0354502, standardError=0.0128345, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99976504_G_A', pValueMantissa=8.508999824523926, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0819298, standardError=0.031138, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99977161_A_G', pValueMantissa=4.061999797821045, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0132532, standardError=0.00191106, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99977721_G_A', pValueMantissa=6.2829999923706055, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0246959, standardError=0.00903733, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99979375_G_A', pValueMantissa=3.937000036239624, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.13666, standardError=0.0663293, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99979565_C_T', pValueMantissa=4.479000091552734, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0275515, standardError=0.0137302, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99979592_G_A', pValueMantissa=3.3989999294281006, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0133022, standardError=0.00191119, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99980479_A_C', pValueMantissa=7.7230000495910645, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0930047, standardError=0.0349125, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99980767_T_TG', pValueMantissa=3.1600000858306885, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0133205, standardError=0.001911, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99981303_T_C', pValueMantissa=1.0260000228881836, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0129016, standardError=0.0019962, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99982408_C_T', pValueMantissa=4.807000160217285, pValueExponent=-11, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0131845, standardError=0.00200471, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99982941_G_A', pValueMantissa=3.236999988555908, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0133135, standardError=0.00191092, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99983547_G_T', pValueMantissa=1.378000020980835, pValueExponent=-11, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0138444, standardError=0.00204793, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99983965_C_T', pValueMantissa=1.3339999914169312, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.276188, standardError=0.0722979, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99984671_A_G', pValueMantissa=1.090999960899353, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.012885, standardError=0.00199651, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99984912_C_T', pValueMantissa=3.328000068664551, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0133085, standardError=0.00191128, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99986015_T_C', pValueMantissa=1.0609999895095825, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.012891, standardError=0.00199615, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99988026_G_T', pValueMantissa=7.709000110626221, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0122774, standardError=0.0046077, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99988174_G_A', pValueMantissa=3.121999979019165, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0133243, standardError=0.0019111, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99988593_A_C', pValueMantissa=4.09499979019165, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0833533, standardError=0.0407789, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99988730_T_C', pValueMantissa=3.1760001182556152, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0133191, standardError=0.00191101, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99988731_G_A', pValueMantissa=5.669000148773193, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0144037, standardError=0.00520681, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99988980_A_G', pValueMantissa=4.874000072479248, pValueExponent=-11, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0131807, standardError=0.00200475, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99989148_T_C', pValueMantissa=4.875, pValueExponent=-11, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0131806, standardError=0.00200475, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99989685_T_C', pValueMantissa=4.556000232696533, pValueExponent=-11, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0132006, standardError=0.00200472, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99989906_C_T', pValueMantissa=3.2639999389648438, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0133133, standardError=0.00191121, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99990445_G_A', pValueMantissa=6.452000141143799, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.090219, standardError=0.0331213, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99990521_G_A', pValueMantissa=2.9019999504089355, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.013345, standardError=0.00191124, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99990640_T_A', pValueMantissa=1.5579999685287476, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0139907, standardError=0.00442234, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99992006_G_GA', pValueMantissa=3.0260000228881836, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0133329, standardError=0.00191111, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99992015_T_C', pValueMantissa=3.5850000381469727, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.013291, standardError=0.00191165, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99992806_A_G', pValueMantissa=3.0290000438690186, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0133327, standardError=0.00191112, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99993453_A_G', pValueMantissa=3.0329999923706055, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0133323, standardError=0.00191113, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99993852_T_C', pValueMantissa=3.0360000133514404, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0133322, standardError=0.00191113, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99994177_C_T', pValueMantissa=4.533999919891357, pValueExponent=-11, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0132032, standardError=0.00200489, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99994349_A_T', pValueMantissa=1.0379999876022339, pValueExponent=-11, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0287633, standardError=0.00422921, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99995001_T_C', pValueMantissa=3.2860000133514404, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0133152, standardError=0.00191176, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99995032_G_C', pValueMantissa=4.89900016784668, pValueExponent=-11, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0131854, standardError=0.00200569, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99995714_T_C', pValueMantissa=3.374000072479248, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0133048, standardError=0.00191128, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99995753_C_CTT', pValueMantissa=3.372999906539917, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0133049, standardError=0.00191128, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99996207_C_G', pValueMantissa=3.384000062942505, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0133041, standardError=0.00191129, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99997268_A_G', pValueMantissa=3.378999948501587, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0133047, standardError=0.00191132, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99997438_CCA_C', pValueMantissa=6.603000164031982, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.109829, standardError=0.0404341, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99997720_A_G', pValueMantissa=2.815999984741211, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0133548, standardError=0.00191149, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99998079_C_CA', pValueMantissa=4.61299991607666, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0922906, standardError=0.0462786, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99998104_G_A', pValueMantissa=1.2979999780654907, pValueExponent=-6, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00911911, standardError=0.0018841, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99999971_A_G', pValueMantissa=2.9570000171661377, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.030431, standardError=0.0102384, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100000235_C_T', pValueMantissa=5.6519999504089355, pValueExponent=-13, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.014492, standardError=0.00201036, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100000486_G_A', pValueMantissa=4.172999858856201, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.305198, standardError=0.149885, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100002038_G_A', pValueMantissa=3.7739999294281006, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0211624, standardError=0.0073064, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100002628_A_C', pValueMantissa=2.953000068664551, pValueExponent=-13, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0138093, standardError=0.00189258, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100004140_G_A', pValueMantissa=2.6459999084472656, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0994314, standardError=0.0448022, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100004827_A_C', pValueMantissa=6.945000171661377, pValueExponent=-14, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0142296, standardError=0.0019001, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100005233_T_C', pValueMantissa=3.111999988555908, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0216712, standardError=0.00733013, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100005358_G_C', pValueMantissa=4.872000217437744, pValueExponent=-13, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0145472, standardError=0.00201239, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100005438_A_G', pValueMantissa=1.093000054359436, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0533162, standardError=0.02095, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100006780_C_T', pValueMantissa=5.067999839782715, pValueExponent=-13, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0145408, standardError=0.002013, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100007241_C_T', pValueMantissa=6.783999919891357, pValueExponent=-14, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0142505, standardError=0.0019021, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100007404_G_GC', pValueMantissa=1.3420000076293945, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0198944, standardError=0.00377285, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100008640_A_G', pValueMantissa=5.019999980926514, pValueExponent=-13, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0145435, standardError=0.002013, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100009013_G_A', pValueMantissa=6.611999988555908, pValueExponent=-14, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0142475, standardError=0.00190084, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100009635_T_G', pValueMantissa=1.0549999475479126, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0134968, standardError=0.0018948, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100011477_C_G', pValueMantissa=2.444999933242798, pValueExponent=-13, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0148805, standardError=0.00203232, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100011685_CAAAT_C', pValueMantissa=4.139999866485596, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0101715, standardError=0.00185449, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100011812_A_T', pValueMantissa=1.2029999494552612, pValueExponent=-13, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0141145, standardError=0.00190314, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100013275_A_T', pValueMantissa=2.174999952316284, pValueExponent=-14, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0145924, standardError=0.00191005, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100013744_G_A', pValueMantissa=4.76800012588501, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.51719, standardError=0.261177, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100014566_A_G', pValueMantissa=8.550999641418457, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0119513, standardError=0.00358432, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100014970_T_C', pValueMantissa=3.993000030517578, pValueExponent=-13, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0146099, standardError=0.00201355, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100015400_G_A', pValueMantissa=5.646999835968018, pValueExponent=-13, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0160357, standardError=0.00222448, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100015645_T_C', pValueMantissa=2.236999988555908, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0145559, standardError=0.00207384, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100015854_C_T', pValueMantissa=6.158999919891357, pValueExponent=-13, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0160044, standardError=0.0022238, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100016635_T_G', pValueMantissa=1.718999981880188, pValueExponent=-11, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0147181, standardError=0.00218755, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100016645_C_T', pValueMantissa=4.622000217437744, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0256776, standardError=0.00906606, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100017027_A_T', pValueMantissa=6.242000102996826, pValueExponent=-13, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0160069, standardError=0.0022247, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100017624_A_G', pValueMantissa=1.7170000076293945, pValueExponent=-11, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0147203, standardError=0.00218782, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100018116_C_T', pValueMantissa=2.197000026702881, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0145668, standardError=0.00207465, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100018135_G_C', pValueMantissa=1.4559999704360962, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.275534, standardError=0.0725377, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100018265_A_T', pValueMantissa=2.7190001010894775, pValueExponent=-6, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00874366, standardError=0.00186392, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100020857_T_C', pValueMantissa=9.112000465393066, pValueExponent=-14, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0156784, standardError=0.00210358, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100021675_C_A', pValueMantissa=3.066999912261963, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0233385, standardError=0.0107983, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100021907_C_T', pValueMantissa=7.229000091552734, pValueExponent=-13, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0159723, standardError=0.00222609, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100022313_C_CT', pValueMantissa=6.171999931335449, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0504229, standardError=0.0184125, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100023134_T_G', pValueMantissa=1.3980000019073486, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0268617, standardError=0.0109298, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100024168_G_A', pValueMantissa=2.3359999656677246, pValueExponent=-6, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00880598, standardError=0.00186491, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100024869_C_T', pValueMantissa=3.556999921798706, pValueExponent=-13, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0162101, standardError=0.00222929, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100025927_T_TA', pValueMantissa=3.621999979019165, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.014426, standardError=0.00207534, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100026878_C_T', pValueMantissa=9.258999824523926, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0185461, standardError=0.00712673, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100027354_G_A', pValueMantissa=1.968000054359436, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.103617, standardError=0.0444235, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100027592_G_C', pValueMantissa=1.965999960899353, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.103629, standardError=0.0444216, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100027903_T_C', pValueMantissa=2.75600004196167, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0384662, standardError=0.0128487, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100028049_C_T', pValueMantissa=4.144000053405762, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.130023, standardError=0.0637634, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100029663_A_G', pValueMantissa=8.883999824523926, pValueExponent=-13, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0147895, standardError=0.00206939, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100030853_G_A', pValueMantissa=7.5980000495910645, pValueExponent=-13, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0158245, standardError=0.00220759, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100030993_G_A', pValueMantissa=3.437000036239624, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0224965, standardError=0.00768921, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100031808_C_T', pValueMantissa=5.959000110626221, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0212214, standardError=0.00771671, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100032684_A_C', pValueMantissa=5.459000110626221, pValueExponent=-13, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.014926, standardError=0.00206922, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100033239_T_A', pValueMantissa=1.3669999837875366, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0463194, standardError=0.0187842, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100033337_C_T', pValueMantissa=9.138999938964844, pValueExponent=-14, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0165264, standardError=0.00221749, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100033635_G_GT', pValueMantissa=1.0110000371932983, pValueExponent=-13, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0164902, standardError=0.00221658, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100035604_T_A', pValueMantissa=3.4110000133514404, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.01433, standardError=0.002059, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100037190_G_A', pValueMantissa=3.2070000171661377, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0120692, standardError=0.00203849, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100037544_C_T', pValueMantissa=1.6990000009536743, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00996527, standardError=0.00417483, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100037655_A_G', pValueMantissa=6.13100004196167, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0127317, standardError=0.00219016, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100038188_C_T', pValueMantissa=7.738999843597412, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0126728, standardError=0.00219478, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100038589_T_C', pValueMantissa=3.734999895095825, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.010628, standardError=0.00193133, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100038648_G_A', pValueMantissa=1.7230000495910645, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00994355, standardError=0.00417478, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100039544_T_C', pValueMantissa=5.021999835968018, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0126227, standardError=0.00202988, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100039545_G_T', pValueMantissa=1.5509999990463257, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0130939, standardError=0.00204582, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100039976_C_T', pValueMantissa=1.7209999561309814, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00994495, standardError=0.00417473, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100039997_T_C', pValueMantissa=5.01800012588501, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0126197, standardError=0.00202937, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100040770_T_G', pValueMantissa=3.059999942779541, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.120454, standardError=0.0557085, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100042338_T_C', pValueMantissa=2.61899995803833, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.189007, standardError=0.085007, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100042505_G_A', pValueMantissa=3.4860000610351562, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0101879, standardError=0.00482832, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100042848_C_CT', pValueMantissa=4.413000106811523, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0093599, standardError=0.00185336, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100043308_C_T', pValueMantissa=5.076000213623047, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0126162, standardError=0.00202939, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100044357_C_T', pValueMantissa=5.36299991607666, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0127797, standardError=0.00218999, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100044501_A_G', pValueMantissa=1.7130000591278076, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00995148, standardError=0.00417441, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100044818_C_T', pValueMantissa=4.927000045776367, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0204248, standardError=0.00726406, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100044839_G_T', pValueMantissa=4.875, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0126274, standardError=0.00202913, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100045047_A_C', pValueMantissa=4.922999858856201, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0204266, standardError=0.00726404, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100045603_T_A', pValueMantissa=1.6740000247955322, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00998325, standardError=0.00417297, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100045685_C_T', pValueMantissa=1.3309999704360962, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0131383, standardError=0.00204533, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100045864_G_A', pValueMantissa=1.6770000457763672, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00998092, standardError=0.00417295, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100046495_A_G', pValueMantissa=4.683000087738037, pValueExponent=-11, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0133938, standardError=0.00203532, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100046569_C_T', pValueMantissa=1.6740000247955322, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0129058, standardError=0.00202014, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100047823_TA_T', pValueMantissa=1.5670000314712524, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0129238, standardError=0.00201974, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100049106_G_A', pValueMantissa=1.690000057220459, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0130999, standardError=0.00217423, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100049236_C_T', pValueMantissa=1.690000057220459, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00996986, standardError=0.00417357, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100049902_G_A', pValueMantissa=1.8940000534057617, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0130591, standardError=0.00217409, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100050211_A_T', pValueMantissa=2.1419999599456787, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0633556, standardError=0.0275398, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100050359_GAACA_G', pValueMantissa=1.6019999980926514, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0129195, standardError=0.00202015, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100051409_C_G', pValueMantissa=1.7120000123977661, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0130944, standardError=0.00217407, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100051504_G_A', pValueMantissa=1.7549999952316284, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00990516, standardError=0.00417051, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100052545_C_G', pValueMantissa=1.5299999713897705, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0129286, standardError=0.00201936, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100052742_T_C', pValueMantissa=1.687000036239624, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00997036, standardError=0.00417237, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100054045_C_T', pValueMantissa=1.3009999990463257, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0129769, standardError=0.0020191, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100054117_T_C', pValueMantissa=4.938000202178955, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0716183, standardError=0.0364414, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100054574_T_G', pValueMantissa=1.6629999876022339, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00999072, standardError=0.00417196, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100055122_T_C', pValueMantissa=6.368000030517578, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0124774, standardError=0.00214876, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100055153_G_A', pValueMantissa=1.6540000438690186, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00999801, standardError=0.0041714, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100055199_C_G', pValueMantissa=1.8609999418258667, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0130598, standardError=0.00217319, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100055816_G_A', pValueMantissa=3.3589999675750732, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0126847, standardError=0.00201947, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100055862_T_G', pValueMantissa=4.1529998779296875, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0446939, standardError=0.0219282, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100056323_C_T', pValueMantissa=4.943999767303467, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0267439, standardError=0.0136118, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100056440_C_T', pValueMantissa=4.486999988555908, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00779499, standardError=0.00388601, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100057584_A_G', pValueMantissa=5.919000148773193, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.011644, standardError=0.00200103, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100057785_T_C', pValueMantissa=4.816999912261963, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0128495, standardError=0.00219523, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100057800_C_T', pValueMantissa=1.0049999952316284, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0122603, standardError=0.00200707, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100059207_A_C', pValueMantissa=3.622999906539917, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0143322, standardError=0.00401899, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100059401_T_TAACAAC', pValueMantissa=3.5920000076293945, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00695612, standardError=0.00194938, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100059401_T_TAACAACAAC', pValueMantissa=3.884999990463257, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0133237, standardError=0.00644961, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100059657_G_A', pValueMantissa=3.880000114440918, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0133275, standardError=0.00645004, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100060102_G_C', pValueMantissa=3.874000072479248, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0133327, standardError=0.00645048, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100060272_A_G', pValueMantissa=4.5370001792907715, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0594699, standardError=0.0297173, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100060908_A_G', pValueMantissa=2.742000102996826, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0113896, standardError=0.00204953, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100061298_C_T', pValueMantissa=2.503000020980835, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0150616, standardError=0.00672123, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100061574_G_C', pValueMantissa=2.7809998989105225, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0113862, standardError=0.00204983, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100061627_C_T', pValueMantissa=1.6690000295639038, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0323984, standardError=0.00537545, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100061926_T_C', pValueMantissa=1.1759999990463257, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0122155, standardError=0.00200796, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100062022_C_T', pValueMantissa=9.611000061035156, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0212829, standardError=0.00821882, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100062212_C_T', pValueMantissa=3.7899999618530273, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0133927, standardError=0.00645157, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100062744_C_A', pValueMantissa=3.752000093460083, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0134223, standardError=0.00645282, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100062935_C_T', pValueMantissa=3.7669999599456787, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0134118, standardError=0.00645294, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100063173_T_G', pValueMantissa=2.7899999618530273, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.011387, standardError=0.00205019, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100063265_C_T', pValueMantissa=2.61299991607666, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0142012, standardError=0.00638472, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100063639_C_T', pValueMantissa=2.7750000953674316, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0276973, standardError=0.0125851, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100063786_T_C', pValueMantissa=2.9630000591278076, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.011365, standardError=0.00205011, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100064214_T_C', pValueMantissa=5.559999942779541, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0128066, standardError=0.00219686, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100064301_T_C', pValueMantissa=2.427999973297119, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0540203, standardError=0.0239811, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100064486_T_C', pValueMantissa=2.484999895095825, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0271265, standardError=0.00428678, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100064533_A_G', pValueMantissa=8.324000358581543, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00771332, standardError=0.00196024, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100064544_T_C', pValueMantissa=8.236000061035156, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00771787, standardError=0.00196013, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100065403_C_G', pValueMantissa=1.7259999513626099, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00799338, standardError=0.00185995, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100066509_T_C', pValueMantissa=3.444999933242798, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0925747, standardError=0.0437751, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100066929_C_A', pValueMantissa=4.581999778747559, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0250808, standardError=0.012559, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100067656_G_A', pValueMantissa=2.6489999294281006, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0143151, standardError=0.00645107, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100067862_G_A', pValueMantissa=7.921999931335449, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0119879, standardError=0.00195036, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100068504_C_T', pValueMantissa=6.7170000076293945, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00746427, standardError=0.00187258, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100068843_C_A', pValueMantissa=1.2430000305175781, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0115969, standardError=0.00203679, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100068866_G_GT', pValueMantissa=1.312000036239624, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0115787, standardError=0.00203689, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100069305_A_T', pValueMantissa=2.6449999809265137, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0143181, standardError=0.00645098, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100069570_T_C', pValueMantissa=2.6549999713897705, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0151566, standardError=0.00504359, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100069757_C_T', pValueMantissa=2.5869998931884766, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0145205, standardError=0.00481941, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100070175_A_G', pValueMantissa=2.000999927520752, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0130301, standardError=0.00421666, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100072279_G_C', pValueMantissa=1.2419999837875366, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0115973, standardError=0.00203683, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100073428_G_T', pValueMantissa=2.609999895095825, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0143509, standardError=0.00645062, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100073963_C_T', pValueMantissa=1.0750000476837158, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0116458, standardError=0.00203655, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100074034_T_TC', pValueMantissa=2.005000114440918, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0113741, standardError=0.0020269, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100074335_C_T', pValueMantissa=1.0729999542236328, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0116458, standardError=0.00203643, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100074511_G_A', pValueMantissa=4.894000053405762, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0166749, standardError=0.00478271, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100074712_C_T', pValueMantissa=1.2990000247955322, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0487079, standardError=0.0196078, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100075164_G_A', pValueMantissa=1.2369999885559082, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0115989, standardError=0.00203683, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100075228_C_T', pValueMantissa=2.6029999256134033, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0143577, standardError=0.00645054, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100075751_C_A', pValueMantissa=1.7940000295639038, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0172016, standardError=0.00726754, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100076243_C_A', pValueMantissa=2.6019999980926514, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0143585, standardError=0.00645053, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100077499_A_G', pValueMantissa=4.675000190734863, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00753971, standardError=0.00185191, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100077617_C_A', pValueMantissa=8.185999870300293, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.013965, standardError=0.00417311, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100078024_G_A', pValueMantissa=4.400000095367432, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0760544, standardError=0.0267049, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100078160_G_A', pValueMantissa=2.5989999771118164, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0143609, standardError=0.00645053, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100078351_A_T', pValueMantissa=5.255000114440918, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0358513, standardError=0.0103395, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100078510_A_C', pValueMantissa=8.102999687194824, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0119828, standardError=0.00195067, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100078923_G_A', pValueMantissa=1.805999994277954, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0171834, standardError=0.00726738, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100079042_G_A', pValueMantissa=2.5889999866485596, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0143712, standardError=0.00645058, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100080295_T_C', pValueMantissa=5.934000015258789, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0121315, standardError=0.00195916, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100080362_T_A', pValueMantissa=9.142000198364258, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0117746, standardError=0.00204921, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100081203_A_G', pValueMantissa=7.883999824523926, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0119901, standardError=0.00195049, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100082411_T_C', pValueMantissa=2.5829999446868896, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0143766, standardError=0.00645057, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100083012_C_A', pValueMantissa=3.0209999084472656, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0125696, standardError=0.0019959, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100083306_C_T', pValueMantissa=2.5810000896453857, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0143789, standardError=0.00645062, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100083442_A_T', pValueMantissa=4.665999889373779, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00754005, standardError=0.0018518, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100083679_C_T', pValueMantissa=2.5810000896453857, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0143785, standardError=0.00645064, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100083851_G_A', pValueMantissa=7.6570000648498535, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0119987, standardError=0.00195041, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100083869_GTGGA_G', pValueMantissa=2.5769999027252197, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0143832, standardError=0.00645065, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100084120_A_G', pValueMantissa=2.5739998817443848, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0143853, standardError=0.00645064, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100085028_A_G', pValueMantissa=1.2200000286102295, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0116042, standardError=0.00203692, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100085123_T_C', pValueMantissa=2.569999933242798, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0143893, standardError=0.00645068, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100085191_A_C', pValueMantissa=1.0609999895095825, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0116492, standardError=0.00203632, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100085317_T_C', pValueMantissa=2.6549999713897705, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0151555, standardError=0.00504327, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100085356_CT_C', pValueMantissa=2.989000082015991, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.012573, standardError=0.00199591, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100085677_T_C', pValueMantissa=7.4720001220703125, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0120068, standardError=0.0019505, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100085790_C_T', pValueMantissa=9.621999740600586, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0119266, standardError=0.0019502, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100085791_G_A', pValueMantissa=6.89300012588501, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0076585, standardError=0.00283442, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100086416_A_C', pValueMantissa=4.2779998779296875, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00757727, standardError=0.00185176, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100087170_C_T', pValueMantissa=4.797999858856201, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0249466, standardError=0.0126147, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100088100_T_C', pValueMantissa=1.2690000534057617, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0115908, standardError=0.00203699, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100088206_G_A', pValueMantissa=1.8480000495910645, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0171185, standardError=0.00726652, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100088307_G_A', pValueMantissa=8.534000396728516, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0258604, standardError=0.00421546, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100088565_A_AGAG', pValueMantissa=2.5799999237060547, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.01438, standardError=0.00645071, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100088687_C_T', pValueMantissa=4.041999816894531, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0124937, standardError=0.00199821, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100088994_G_C', pValueMantissa=4.744999885559082, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.26271, standardError=0.13253, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100089654_C_A', pValueMantissa=1.2940000295639038, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0115954, standardError=0.00203897, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100090029_G_T', pValueMantissa=3.2170000076293945, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0322465, standardError=0.00583203, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100093119_C_T', pValueMantissa=3.0880000591278076, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.379152, standardError=0.0909911, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100095173_CA_C', pValueMantissa=1.1920000314712524, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0116127, standardError=0.00203702, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100095421_C_T', pValueMantissa=4.376999855041504, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00756736, standardError=0.00185174, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100095474_G_C', pValueMantissa=1.0429999828338623, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.011657, standardError=0.00203668, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100095491_G_A', pValueMantissa=2.575000047683716, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0143845, standardError=0.00645073, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100095666_A_G', pValueMantissa=2.997999906539917, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0125726, standardError=0.001996, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100095766_C_T', pValueMantissa=2.5769999027252197, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0143829, standardError=0.00645074, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100096097_G_A', pValueMantissa=4.854000091552734, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.159194, standardError=0.0807015, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100096882_A_T', pValueMantissa=1.875, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0170779, standardError=0.00726586, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100097204_C_G', pValueMantissa=4.326000213623047, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00757235, standardError=0.00185173, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100097630_G_A', pValueMantissa=6.629000186920166, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0183017, standardError=0.0067411, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100097685_G_A', pValueMantissa=2.1630001068115234, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00784104, standardError=0.00341393, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100098591_G_A', pValueMantissa=7.1529998779296875, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00762397, standardError=0.00283455, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100099448_G_A', pValueMantissa=2.5399999618530273, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0110489, standardError=0.00198346, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100100113_A_G', pValueMantissa=2.996000051498413, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.012573, standardError=0.00199604, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100100236_G_A', pValueMantissa=2.565000057220459, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0143946, standardError=0.00645086, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100101678_G_A', pValueMantissa=1.065000057220459, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0116505, standardError=0.00203676, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100101681_G_A', pValueMantissa=2.572999954223633, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0143872, standardError=0.00645085, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100101734_C_T', pValueMantissa=2.805000066757202, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0388904, standardError=0.0177047, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100101865_T_C', pValueMantissa=7.827000141143799, pValueExponent=-6, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00939164, standardError=0.0021011, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100101978_T_A', pValueMantissa=2.565000057220459, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0143954, standardError=0.00645086, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100102891_G_A', pValueMantissa=3.0280001163482666, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0125699, standardError=0.00199607, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100102937_T_C', pValueMantissa=1.0709999799728394, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0116485, standardError=0.00203677, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100103034_T_C', pValueMantissa=1.062000036239624, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0116512, standardError=0.00203676, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100103075_C_T', pValueMantissa=2.5480000972747803, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0144117, standardError=0.0064509, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100103232_C_T', pValueMantissa=1.059999942779541, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0116519, standardError=0.00203676, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100103284_T_C', pValueMantissa=1.2389999628067017, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0115998, standardError=0.00203711, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100103427_G_A', pValueMantissa=2.5409998893737793, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0144177, standardError=0.0064504, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100103653_C_A', pValueMantissa=1.2389999628067017, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0116, standardError=0.00203711, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100104060_G_C', pValueMantissa=1.0570000410079956, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.011653, standardError=0.00203678, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100104416_A_G', pValueMantissa=1.062999963760376, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0116511, standardError=0.00203678, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100104538_T_A', pValueMantissa=3.0250000953674316, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0125704, standardError=0.0019961, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100104974_T_C', pValueMantissa=2.5460000038146973, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0144144, standardError=0.00645109, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100105358_T_A', pValueMantissa=1.246000051498413, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0115981, standardError=0.00203714, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100105587_G_A', pValueMantissa=1.0700000524520874, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0116489, standardError=0.0020368, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100105759_A_T', pValueMantissa=1.253000020980835, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0115962, standardError=0.00203715, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100106124_T_C', pValueMantissa=1.0019999742507935, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0116787, standardError=0.00203801, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100106127_T_C', pValueMantissa=1.0019999742507935, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0116787, standardError=0.00203801, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100106157_C_A', pValueMantissa=2.5399999618530273, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.01442, standardError=0.00645108, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100106705_G_GGCAGAGTAA', pValueMantissa=3.0460000038146973, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0125685, standardError=0.00199613, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100107060_CG_C', pValueMantissa=1.2519999742507935, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0115965, standardError=0.00203718, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100107246_C_T', pValueMantissa=1.8339999914169312, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.148529, standardError=0.0629731, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100107759_T_C', pValueMantissa=3.5490000247955322, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00765844, standardError=0.00185209, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100107761_A_G', pValueMantissa=5.459000110626221, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.272006, standardError=0.0786791, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100108013_C_T', pValueMantissa=2.561000108718872, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0243527, standardError=0.00807438, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100108920_T_G', pValueMantissa=9.07699966430664, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.011727, standardError=0.00204049, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100109874_G_A', pValueMantissa=4.85099983215332, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0248793, standardError=0.0126104, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100110231_C_T', pValueMantissa=7.883999824523926, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0117687, standardError=0.00203931, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100110702_T_G', pValueMantissa=3.5929999351501465, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0606656, standardError=0.0289201, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100110795_TTA_T', pValueMantissa=6.190999984741211, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0118518, standardError=0.00203936, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100111161_G_A', pValueMantissa=2.000999927520752, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0497915, standardError=0.0161136, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100111179_C_T', pValueMantissa=6.201000213623047, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0118489, standardError=0.00203896, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100111991_C_A', pValueMantissa=6.7820000648498535, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0118202, standardError=0.00203929, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100112419_TA_T', pValueMantissa=5.803999900817871, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0118714, standardError=0.00203896, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100112828_C_T', pValueMantissa=2.8289999961853027, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0388309, standardError=0.0177045, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100112930_A_C', pValueMantissa=6.804999828338623, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0118191, standardError=0.0020393, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100114067_A_G', pValueMantissa=1.0110000371932983, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0104825, standardError=0.00196864, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100115072_C_T', pValueMantissa=1.034999966621399, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0104694, standardError=0.00196776, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100115087_C_T', pValueMantissa=5.876999855041504, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0118682, standardError=0.00203912, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100115453_T_C', pValueMantissa=1.0360000133514404, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0104692, standardError=0.00196776, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100116179_G_C', pValueMantissa=5.88100004196167, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0118679, standardError=0.00203913, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100116494_A_T', pValueMantissa=1.0360000133514404, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.010469, standardError=0.00196776, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100116607_C_T', pValueMantissa=1.0160000324249268, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0104762, standardError=0.00196781, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100116979_C_G', pValueMantissa=1.0180000066757202, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0104755, standardError=0.0019678, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100117013_G_A', pValueMantissa=1.0379999876022339, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0104684, standardError=0.00196777, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100118204_T_G', pValueMantissa=1.0509999990463257, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0104641, standardError=0.00196778, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100118462_G_A', pValueMantissa=5.9079999923706055, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0118664, standardError=0.00203914, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100118652_C_T', pValueMantissa=1.128999948501587, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0104375, standardError=0.00196763, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100119929_C_G', pValueMantissa=8.840999603271484, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0121944, standardError=0.0019896, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100120722_G_A', pValueMantissa=5.441999912261963, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0106837, standardError=0.00196527, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100121497_C_T', pValueMantissa=1.5360000133514404, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.573298, standardError=0.23652, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100124748_T_C', pValueMantissa=2.8399999141693115, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0388018, standardError=0.0177043, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100125143_C_CA', pValueMantissa=3.8269999027252197, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0260846, standardError=0.0125892, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100125152_C_A', pValueMantissa=7.866000175476074, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0105533, standardError=0.00196517, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100125180_C_T', pValueMantissa=7.633999824523926, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0105635, standardError=0.00196509, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100125779_A_G', pValueMantissa=7.78000020980835, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0105568, standardError=0.00196509, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100126618_A_C', pValueMantissa=4.631999969482422, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.133295, standardError=0.0668985, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100126748_A_G', pValueMantissa=7.800000190734863, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0105558, standardError=0.00196509, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100127494_A_T', pValueMantissa=1.8029999732971191, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0082724, standardError=0.00349777, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100128204_G_GAGAGAA', pValueMantissa=5.4019999504089355, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0107556, standardError=0.00197804, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100128221_A_G', pValueMantissa=6.446000099182129, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0106227, standardError=0.001965, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100128550_G_A', pValueMantissa=8.194000244140625, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0105396, standardError=0.00196532, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100128651_T_C', pValueMantissa=7.315000057220459, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0105796, standardError=0.00196528, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100128763_C_T', pValueMantissa=7.829999923706055, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0105544, standardError=0.00196508, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100128883_C_T', pValueMantissa=8.057000160217285, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0105443, standardError=0.00196508, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100128958_G_A', pValueMantissa=2.124000072479248, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00680841, standardError=0.00295533, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100129035_C_A', pValueMantissa=3.3989999294281006, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0925999, standardError=0.043676, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100129320_C_T', pValueMantissa=2.13100004196167, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00680465, standardError=0.00295531, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100129629_A_C', pValueMantissa=1.8580000400543213, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.148278, standardError=0.0629939, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100129660_T_C', pValueMantissa=8.699000358581543, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0115118, standardError=0.00200055, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100129776_G_A', pValueMantissa=1.690000057220459, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0884659, standardError=0.0281741, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100130207_C_T', pValueMantissa=3.569000005722046, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0140895, standardError=0.00483524, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100130573_C_G', pValueMantissa=2.9149999618530273, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00674022, standardError=0.00186053, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100130860_A_G', pValueMantissa=9.043999671936035, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0114981, standardError=0.00200046, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100131042_G_A', pValueMantissa=3.619999885559082, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.179459, standardError=0.0503203, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100131063_C_G', pValueMantissa=2.2909998893737793, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00671867, standardError=0.00295325, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100131465_G_T', pValueMantissa=8.934000015258789, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0115031, standardError=0.00200061, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100132172_C_G', pValueMantissa=2.128000020980835, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00680593, standardError=0.00295533, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100132602_T_TTAAA', pValueMantissa=4.828000068664551, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00431663, standardError=0.00218576, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100132602_T_TTAAATAAA', pValueMantissa=4.5980000495910645, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0519863, standardError=0.0260513, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100132602_TTAAATAAATAAA_T', pValueMantissa=7.363999843597412, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0116156, standardError=0.00200877, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100133539_G_T', pValueMantissa=2.6610000133514404, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00678474, standardError=0.00186073, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100133661_G_A', pValueMantissa=2.6619999408721924, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00678444, standardError=0.00186073, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100134226_T_TAAAC', pValueMantissa=9.397000312805176, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0114918, standardError=0.00200162, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100134368_G_T', pValueMantissa=2.305999994277954, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00685323, standardError=0.0018608, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100134849_C_G', pValueMantissa=2.5420000553131104, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00680611, standardError=0.00186063, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100136849_G_A', pValueMantissa=2.4240000247955322, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00682879, standardError=0.00186061, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100137626_G_C', pValueMantissa=4.564000129699707, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.133964, standardError=0.067025, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100139939_C_T', pValueMantissa=2.2850000858306885, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0168361, standardError=0.00739727, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100140109_A_G', pValueMantissa=8.161999702453613, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0116036, standardError=0.00201274, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100140433_T_C', pValueMantissa=8.460000038146973, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00745523, standardError=0.00283129, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100140822_C_T', pValueMantissa=4.0370001792907715, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00653853, standardError=0.00184827, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100140993_C_T', pValueMantissa=8.553999900817871, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00744479, standardError=0.00283137, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100141769_G_C', pValueMantissa=4.497000217437744, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.134653, standardError=0.0671606, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100142018_C_T', pValueMantissa=8.651000022888184, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00615783, standardError=0.00184859, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100142970_A_T', pValueMantissa=3.749000072479248, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0279115, standardError=0.00962947, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100143128_C_A', pValueMantissa=2.7290000915527344, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0151084, standardError=0.0050416, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100143200_T_G', pValueMantissa=8.8100004196167, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00751992, standardError=0.00191775, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100143201_T_C', pValueMantissa=8.812999725341797, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00751979, standardError=0.00191775, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100143322_A_G', pValueMantissa=8.62600040435791, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0074353, standardError=0.00283084, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100143412_T_C', pValueMantissa=3.306999921798706, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0244099, standardError=0.00588015, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100143655_T_C', pValueMantissa=5.8420000076293945, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0063633, standardError=0.00185041, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100144149_T_G', pValueMantissa=5.2210001945495605, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0106098, standardError=0.00194903, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100144392_A_ACGTG', pValueMantissa=1.059999942779541, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0122106, standardError=0.00200172, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100144587_G_A', pValueMantissa=4.710000038146973, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0106442, standardError=0.00194881, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100144738_C_T', pValueMantissa=3.628999948501587, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00387717, standardError=0.00185181, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100145180_CA_C', pValueMantissa=7.709000110626221, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00754349, standardError=0.00283104, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100145446_T_C', pValueMantissa=4.289000034332275, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00722839, standardError=0.0025309, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100145462_G_A', pValueMantissa=1.184999942779541, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00704211, standardError=0.00279842, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100145533_C_T', pValueMantissa=6.809999942779541, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0688508, standardError=0.0254439, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100145864_T_C', pValueMantissa=2.5959999561309814, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00556169, standardError=0.00184654, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100146576_G_A', pValueMantissa=2.239000082015991, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0102862, standardError=0.0027873, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100147206_C_G', pValueMantissa=2.24399995803833, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0102847, standardError=0.00278728, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100148436_A_G', pValueMantissa=7.232999801635742, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.01072, standardError=0.00317104, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100148745_A_G', pValueMantissa=9.111000061035156, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.011124, standardError=0.00335401, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100150256_TG_T', pValueMantissa=1.621000051498413, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0058237, standardError=0.00184761, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100151385_A_G', pValueMantissa=2.200000047683716, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0102977, standardError=0.002787, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100151760_T_G', pValueMantissa=1.680999994277954, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0116223, standardError=0.00369954, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100151918_T_C', pValueMantissa=1.305999994277954, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.01191, standardError=0.00370485, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100152307_T_C', pValueMantissa=9.949999809265137, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0108402, standardError=0.00189131, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100152437_C_T', pValueMantissa=1.0140000581741333, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0108394, standardError=0.00189222, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100153963_AT_A', pValueMantissa=3.984999895095825, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00551895, standardError=0.00191674, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100155294_C_T', pValueMantissa=5.695000171661377, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0370698, standardError=0.0134074, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100155300_C_A', pValueMantissa=3.9560000896453857, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.013611, standardError=0.0066127, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100155337_G_C', pValueMantissa=9.121999740600586, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0129497, standardError=0.00390489, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100155409_G_C', pValueMantissa=1.305999994277954, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.01191, standardError=0.00370485, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100155608_A_G', pValueMantissa=2.359999895095825, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0102538, standardError=0.00278865, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100157105_C_T', pValueMantissa=1.9290000200271606, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0114702, standardError=0.00369896, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100157116_T_A', pValueMantissa=1.4279999732971191, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00588326, standardError=0.00184495, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100157609_G_A', pValueMantissa=2.1989998817443848, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0103034, standardError=0.00278846, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100157763_C_T', pValueMantissa=3.859999895095825, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00711467, standardError=0.00343966, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100158037_G_A', pValueMantissa=4.420000076293945, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0259169, standardError=0.00910471, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100158360_A_G', pValueMantissa=1.7910000085830688, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0115545, standardError=0.0037, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100158691_C_T', pValueMantissa=6.251999855041504, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0131114, standardError=0.00327532, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100159080_T_C', pValueMantissa=8.289999961853027, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0343476, standardError=0.0102747, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100159144_G_A', pValueMantissa=1.3380000591278076, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00857697, standardError=0.00346768, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100159600_GAAATCAACAATAA_G', pValueMantissa=1.7860000133514404, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0115575, standardError=0.0037, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100159706_T_TTTAAA', pValueMantissa=2.239000082015991, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0102922, standardError=0.00278886, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100161011_T_C', pValueMantissa=1.305999994277954, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.01191, standardError=0.00370485, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100161641_G_T', pValueMantissa=1.305999994277954, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.01191, standardError=0.00370485, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100162586_C_T', pValueMantissa=1.5570000410079956, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0117095, standardError=0.00370097, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100162599_A_G', pValueMantissa=1.7910000085830688, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0115545, standardError=0.0037, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100164449_A_T', pValueMantissa=8.289999961853027, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0343476, standardError=0.0102747, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100164555_T_C', pValueMantissa=1.8140000104904175, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0162269, standardError=0.00686797, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100164661_T_C', pValueMantissa=1.065000057220459, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0108199, standardError=0.00189161, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100166335_G_A', pValueMantissa=1.569000005722046, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.011701, standardError=0.00370099, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100167234_TA_T', pValueMantissa=1.9529999494552612, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0114517, standardError=0.00369739, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100167290_A_G', pValueMantissa=1.9539999961853027, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0114514, standardError=0.00369739, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100167685_C_T', pValueMantissa=3.9630000591278076, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0526946, standardError=0.0256104, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100167711_G_A', pValueMantissa=1.3270000219345093, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.011893, standardError=0.00370488, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100168884_G_A', pValueMantissa=1.815000057220459, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.01154, standardError=0.00370004, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100169073_T_A', pValueMantissa=1.659000039100647, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0164986, standardError=0.00688708, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100170367_T_A', pValueMantissa=1.8220000267028809, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0115361, standardError=0.00370004, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100170447_T_C', pValueMantissa=1.8200000524520874, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.011537, standardError=0.00370004, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100170652_A_G', pValueMantissa=8.133000373840332, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0162704, standardError=0.00614785, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100170743_T_C', pValueMantissa=1.819000005722046, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0115379, standardError=0.00370004, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100171278_T_G', pValueMantissa=1.965999960899353, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0114445, standardError=0.00369739, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100171408_C_CTATT', pValueMantissa=1.8220000267028809, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0115357, standardError=0.00370003, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100171892_C_A', pValueMantissa=4.783999919891357, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0290312, standardError=0.0146713, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100171937_A_T', pValueMantissa=3.7090001106262207, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0264529, standardError=0.0126887, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100172580_C_A', pValueMantissa=1.8209999799728394, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0115368, standardError=0.00370004, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100172766_C_T', pValueMantissa=1.3320000171661377, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0118891, standardError=0.00370488, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100173406_G_C', pValueMantissa=3.993000030517578, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0276948, standardError=0.00962055, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100173454_A_G', pValueMantissa=1.8220000267028809, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.011536, standardError=0.00370004, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100174322_A_AT', pValueMantissa=1.9670000076293945, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0114438, standardError=0.00369738, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100174478_C_T', pValueMantissa=5.164999961853027, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0114058, standardError=0.00195247, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100175179_A_G', pValueMantissa=1.968000054359436, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0114433, standardError=0.00369738, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100175211_T_C', pValueMantissa=9.72700023651123, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0910994, standardError=0.02762, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100175305_C_T', pValueMantissa=1.8240000009536743, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.011535, standardError=0.00370003, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100175350_T_C', pValueMantissa=1.8240000009536743, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.011535, standardError=0.00370003, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100176550_CAAAAGACCGTTTTTA_C', pValueMantissa=1.8869999647140503, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0115298, standardError=0.00371041, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100177021_C_G', pValueMantissa=1.8309999704360962, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0115307, standardError=0.00370003, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100177437_T_C', pValueMantissa=4.168000221252441, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00536168, standardError=0.00187135, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100177850_C_T', pValueMantissa=7.14300012588501, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0216516, standardError=0.00545178, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100178264_G_A', pValueMantissa=1.8339999914169312, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.011529, standardError=0.00370002, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100178377_T_A', pValueMantissa=3.9769999980926514, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0277079, standardError=0.00962096, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100178824_A_C', pValueMantissa=1.1480000019073486, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0273359, standardError=0.0108138, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100178873_G_C', pValueMantissa=3.313999891281128, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00845972, standardError=0.00288043, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100178957_A_G', pValueMantissa=1.8370000123977661, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.011527, standardError=0.00370001, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100181244_T_A', pValueMantissa=9.291000366210938, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0116765, standardError=0.00352639, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100182158_GT_G', pValueMantissa=1.440999984741211, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0118051, standardError=0.00370502, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100182496_T_C', pValueMantissa=2.2899999618530273, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0102733, standardError=0.00278807, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100182799_A_G', pValueMantissa=2.365000009536743, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0102471, standardError=0.00278728, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100183196_T_C', pValueMantissa=1.8519999980926514, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.011518, standardError=0.00369996, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100183255_G_A', pValueMantissa=1.3580000400543213, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0118679, standardError=0.0037048, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100183966_G_A', pValueMantissa=1.8609999418258667, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0115126, standardError=0.00369993, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100184256_T_C', pValueMantissa=4.7220001220703125, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.029124, standardError=0.0146772, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100184474_G_A', pValueMantissa=3.7109999656677246, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00543283, standardError=0.00187227, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100184568_G_A', pValueMantissa=2.1500000953674316, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0103173, standardError=0.00278792, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100186257_C_G', pValueMantissa=1.2259999513626099, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00596993, standardError=0.00184663, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100186688_C_T', pValueMantissa=1.9229999780654907, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0114751, standardError=0.00369939, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100187980_C_T', pValueMantissa=4.630000114440918, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00813035, standardError=0.00287118, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100189674_T_G', pValueMantissa=9.279999732971191, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.126539, standardError=0.0486397, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100190351_G_A', pValueMantissa=4.619999885559082, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00813223, standardError=0.00287113, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100190395_G_A', pValueMantissa=2.0, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0760922, standardError=0.024623, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100192759_T_C', pValueMantissa=1.9559999704360962, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0114555, standardError=0.00369915, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100193524_C_T', pValueMantissa=9.555000305175781, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0122529, standardError=0.0037093, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100193948_A_C', pValueMantissa=3.0179998874664307, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0115477, standardError=0.00194714, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100195245_A_T', pValueMantissa=4.635000228881836, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0081285, standardError=0.00287091, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100195684_C_CA', pValueMantissa=4.2270002365112305, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.137066, standardError=0.0674911, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100195855_G_A', pValueMantissa=4.870999813079834, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00807719, standardError=0.00286889, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100197192_T_C', pValueMantissa=4.242000102996826, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.136954, standardError=0.067486, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100197458_C_A', pValueMantissa=4.629000186920166, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00812979, standardError=0.00287088, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100197612_C_G', pValueMantissa=4.498000144958496, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00815595, standardError=0.00287088, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100197640_T_C', pValueMantissa=1.965000033378601, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0114501, standardError=0.00369901, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100197675_G_A', pValueMantissa=2.75600004196167, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0386379, standardError=0.0175348, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100197920_A_G', pValueMantissa=2.384999990463257, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0167093, standardError=0.00739523, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100198475_T_C', pValueMantissa=1.9639999866485596, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0114509, standardError=0.00369901, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100199282_C_G', pValueMantissa=1.1059999465942383, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0127328, standardError=0.00390313, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100199476_G_A', pValueMantissa=1.319000005722046, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0118973, standardError=0.00370432, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100200167_G_A', pValueMantissa=3.1589999198913574, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0376207, standardError=0.012745, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100201209_C_T', pValueMantissa=1.097000002861023, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00602792, standardError=0.0018465, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100201414_G_A', pValueMantissa=4.788000106811523, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0068162, standardError=0.00344526, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100201633_T_A', pValueMantissa=1.3179999589920044, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0118983, standardError=0.00370432, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100202455_T_C', pValueMantissa=1.9600000381469727, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0114531, standardError=0.00369901, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100202467_G_A', pValueMantissa=3.875999927520752, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0277856, standardError=0.00962082, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100202772_A_T', pValueMantissa=1.9600000381469727, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0114531, standardError=0.00369901, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100203494_T_C', pValueMantissa=1.9589999914169312, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0114534, standardError=0.00369901, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100203542_G_T', pValueMantissa=1.6130000352859497, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00697446, standardError=0.00184854, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100203788_C_A', pValueMantissa=4.110000133514404, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.113144, standardError=0.0394286, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100204779_C_A', pValueMantissa=4.3379998207092285, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0101425, standardError=0.00502088, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100205801_A_G', pValueMantissa=4.5329999923706055, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00814881, standardError=0.00287085, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100206194_A_T', pValueMantissa=1.9570000171661377, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0114546, standardError=0.003699, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100206333_A_G', pValueMantissa=4.160999774932861, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0263098, standardError=0.0129133, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100206660_A_G', pValueMantissa=2.4539999961853027, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.113651, standardError=0.0505422, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100206733_C_T', pValueMantissa=1.315999984741211, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0119003, standardError=0.00370432, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100207009_TA_T', pValueMantissa=1.9559999704360962, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0114549, standardError=0.003699, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100207455_C_G', pValueMantissa=1.305999994277954, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00593547, standardError=0.00184639, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100207653_G_A', pValueMantissa=3.6470000743865967, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0114874, standardError=0.00194719, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100207898_CAAGTT_C', pValueMantissa=3.384999990463257, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0921644, standardError=0.0434369, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100208164_G_C', pValueMantissa=3.874000072479248, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0277875, standardError=0.0096208, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100209200_T_C', pValueMantissa=1.315000057220459, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0119009, standardError=0.00370431, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100210277_C_T', pValueMantissa=1.3040000200271606, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0119097, standardError=0.00370434, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100211064_G_A', pValueMantissa=1.9550000429153442, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0114558, standardError=0.003699, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100211240_A_G', pValueMantissa=7.230000019073486, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00932586, standardError=0.00188208, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100212531_T_C', pValueMantissa=3.874000072479248, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0277872, standardError=0.00962078, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100212621_T_C', pValueMantissa=1.6109999418258667, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00697491, standardError=0.00184852, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100213072_C_T', pValueMantissa=1.9529999494552612, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0114567, standardError=0.003699, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100213340_T_C', pValueMantissa=1.6119999885559082, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00697479, standardError=0.00184851, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100213631_T_C', pValueMantissa=1.6119999885559082, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00697476, standardError=0.00184851, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100214977_G_T', pValueMantissa=4.242000102996826, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.136966, standardError=0.0674913, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100215512_G_A', pValueMantissa=4.473999977111816, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00816059, standardError=0.0028708, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100215525_C_CA', pValueMantissa=1.9509999752044678, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0114578, standardError=0.003699, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100215535_T_A', pValueMantissa=9.406000137329102, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0122847, standardError=0.00371395, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100215669_A_G', pValueMantissa=1.9509999752044678, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.011458, standardError=0.003699, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100216129_G_T', pValueMantissa=1.312000036239624, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0119034, standardError=0.00370431, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100216744_G_C', pValueMantissa=2.9519999027252197, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0115543, standardError=0.00194705, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100217073_T_TCATA', pValueMantissa=4.507999897003174, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00815394, standardError=0.00287084, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100218126_C_T', pValueMantissa=1.055999994277954, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00604851, standardError=0.00184672, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100218867_A_G', pValueMantissa=3.3550000190734863, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.205837, standardError=0.0968422, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100218929_A_C', pValueMantissa=1.9490000009536743, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.011459, standardError=0.003699, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100219439_G_A', pValueMantissa=1.3109999895095825, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0119039, standardError=0.00370431, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100219496_T_C', pValueMantissa=1.9490000009536743, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.011459, standardError=0.003699, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100219653_G_A', pValueMantissa=8.52400016784668, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0210222, standardError=0.00799145, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100219661_T_C', pValueMantissa=7.915999889373779, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0163115, standardError=0.00614227, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100220164_T_C', pValueMantissa=1.3109999895095825, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0119039, standardError=0.00370431, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100220814_T_TA', pValueMantissa=4.504000186920166, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00815468, standardError=0.00287084, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100220831_C_A', pValueMantissa=4.275000095367432, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.136751, standardError=0.0674941, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100221396_C_T', pValueMantissa=2.944000005722046, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0115551, standardError=0.00194705, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100221486_T_G', pValueMantissa=1.3890000581741333, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0160699, standardError=0.00653242, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100221517_C_A', pValueMantissa=2.5439999103546143, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00413576, standardError=0.00185074, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100221594_C_G', pValueMantissa=2.0799999237060547, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0779801, standardError=0.0337333, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100223656_G_A', pValueMantissa=3.621000051498413, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0114895, standardError=0.00194717, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100223788_T_C', pValueMantissa=1.3109999895095825, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0119039, standardError=0.00370431, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100224059_G_A', pValueMantissa=3.621000051498413, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0114895, standardError=0.00194717, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100224086_A_ACT', pValueMantissa=1.0759999752044678, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00473991, standardError=0.00185855, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100224086_A_ACTCTCTCT', pValueMantissa=9.140999794006348, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0123865, standardError=0.00373569, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100224729_G_A', pValueMantissa=9.512999534606934, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0122608, standardError=0.00371028, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100224788_C_T', pValueMantissa=4.552000045776367, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00814496, standardError=0.00287083, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100224846_CA_C', pValueMantissa=4.505000114440918, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00815457, standardError=0.00287084, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100225330_C_T', pValueMantissa=4.679999828338623, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00811972, standardError=0.0028709, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100225460_G_A', pValueMantissa=1.4520000219345093, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0138989, standardError=0.00568655, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100227298_T_G', pValueMantissa=4.505000114440918, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00815457, standardError=0.00287084, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100227436_A_C', pValueMantissa=2.1089999675750732, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0204774, standardError=0.00887858, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100227710_T_C', pValueMantissa=2.624000072479248, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0115932, standardError=0.00194728, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100228161_T_C', pValueMantissa=1.1180000305175781, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0127208, standardError=0.00390316, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100228188_C_G', pValueMantissa=1.3109999895095825, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0119039, standardError=0.00370431, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100228581_G_GGGA', pValueMantissa=1.9490000009536743, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.011459, standardError=0.003699, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100228620_A_G', pValueMantissa=1.9490000009536743, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.011459, standardError=0.003699, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100229692_G_T', pValueMantissa=1.9490000009536743, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.011459, standardError=0.003699, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100229731_G_C', pValueMantissa=4.275000095367432, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.136751, standardError=0.0674941, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100230118_T_C', pValueMantissa=1.9490000009536743, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.011459, standardError=0.003699, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100230958_C_A', pValueMantissa=3.694000005722046, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0264656, standardError=0.0126847, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100231193_T_TTTG', pValueMantissa=2.11299991607666, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0113217, standardError=0.00368321, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100231368_T_A', pValueMantissa=1.9490000009536743, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.011459, standardError=0.003699, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100231561_G_GT', pValueMantissa=4.546000003814697, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00815129, standardError=0.00287266, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100231791_G_C', pValueMantissa=1.3109999895095825, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0119039, standardError=0.00370431, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100233804_CAG_C', pValueMantissa=3.674999952316284, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0114848, standardError=0.00194718, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100235720_T_G', pValueMantissa=4.255000114440918, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0683751, standardError=0.0337137, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100236254_A_G', pValueMantissa=1.8240000009536743, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.621107, standardError=0.263096, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100236529_C_T', pValueMantissa=1.5670000314712524, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00698791, standardError=0.00184852, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100236538_A_G', pValueMantissa=1.5640000104904175, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00698861, standardError=0.00184852, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100236603_C_T', pValueMantissa=3.1489999294281006, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0115356, standardError=0.00194738, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100237030_C_T', pValueMantissa=1.3109999895095825, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0119039, standardError=0.00370431, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100237733_G_A', pValueMantissa=4.505000114440918, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00815457, standardError=0.00287084, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100237772_G_A', pValueMantissa=9.51200008392334, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0122572, standardError=0.00370917, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100237893_A_T', pValueMantissa=4.275000095367432, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.136751, standardError=0.0674941, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100238295_A_G', pValueMantissa=4.505000114440918, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00815457, standardError=0.00287084, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100238581_A_G', pValueMantissa=6.859000205993652, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0255013, standardError=0.00751108, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100238657_T_C', pValueMantissa=2.809000015258789, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.01157, standardError=0.00194702, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100239610_G_T', pValueMantissa=1.9490000009536743, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.011459, standardError=0.003699, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100239637_A_G', pValueMantissa=1.1369999647140503, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00600877, standardError=0.00184638, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100239850_T_C', pValueMantissa=1.9490000009536743, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.011459, standardError=0.003699, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100239989_G_A', pValueMantissa=3.2009999752044678, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.011529, standardError=0.00194715, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100240726_T_G', pValueMantissa=4.000999927520752, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0525952, standardError=0.0256104, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100240944_C_T', pValueMantissa=2.8889999389648438, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0115616, standardError=0.00194713, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100242014_C_T', pValueMantissa=4.505000114440918, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00815457, standardError=0.00287084, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100242478_A_G', pValueMantissa=9.51200008392334, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0122572, standardError=0.00370917, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100242630_C_T', pValueMantissa=1.253999948501587, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.011921, standardError=0.00369498, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100242920_TGA_T', pValueMantissa=4.275000095367432, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.136751, standardError=0.0674941, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100243390_G_A', pValueMantissa=8.79800033569336, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0252612, standardError=0.00439142, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100244149_G_C', pValueMantissa=3.316999912261963, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.011525, standardError=0.0019484, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100244398_T_C', pValueMantissa=3.694000005722046, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00834099, standardError=0.00287304, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100244540_A_G', pValueMantissa=1.8240000009536743, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.621107, standardError=0.263096, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100244650_T_C', pValueMantissa=1.8240000009536743, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.621107, standardError=0.263096, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100244773_C_G', pValueMantissa=1.8240000009536743, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.621107, standardError=0.263096, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100244991_G_C', pValueMantissa=1.8240000009536743, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.621107, standardError=0.263096, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100245546_T_C', pValueMantissa=1.472000002861023, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0117796, standardError=0.00370405, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100245863_C_T', pValueMantissa=1.472000002861023, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0117796, standardError=0.00370405, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100246645_C_T', pValueMantissa=3.694000005722046, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00834099, standardError=0.00287304, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100246672_T_C', pValueMantissa=1.1399999856948853, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00600727, standardError=0.00184638, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100246924_C_T', pValueMantissa=3.4030001163482666, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0281666, standardError=0.00961714, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100247616_T_C', pValueMantissa=3.694000005722046, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00834089, standardError=0.00287304, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100248412_C_G', pValueMantissa=1.4470000267028809, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00702484, standardError=0.00184863, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100248726_A_G', pValueMantissa=3.694999933242798, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00834082, standardError=0.00287304, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100249239_A_C', pValueMantissa=2.0339999198913574, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0353474, standardError=0.0152353, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100249267_A_T', pValueMantissa=1.472000002861023, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0117796, standardError=0.00370405, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100249476_T_TC', pValueMantissa=3.694999933242798, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00834082, standardError=0.00287304, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100249705_T_C', pValueMantissa=1.472000002861023, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0117796, standardError=0.00370405, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100250941_T_C', pValueMantissa=1.8240000009536743, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.621107, standardError=0.263096, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100250976_T_A', pValueMantissa=6.709000110626221, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0690304, standardError=0.0254633, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100251390_T_A', pValueMantissa=2.9049999713897705, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0055723, standardError=0.00187139, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100251454_A_G', pValueMantissa=1.1790000200271606, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00712036, standardError=0.00184919, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100251790_C_T', pValueMantissa=3.497999906539917, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00593413, standardError=0.00281426, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100252662_G_A', pValueMantissa=1.5770000219345093, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.011701, standardError=0.00370274, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100252768_G_A', pValueMantissa=1.5770000219345093, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.011701, standardError=0.00370274, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100252920_T_G', pValueMantissa=1.5770000219345093, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.011701, standardError=0.00370274, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100254207_CCAGA_C', pValueMantissa=3.382999897003174, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0921782, standardError=0.0434383, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100254700_T_C', pValueMantissa=1.3079999685287476, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0884636, standardError=0.0275222, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100254749_C_A', pValueMantissa=3.940999984741211, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00710422, standardError=0.00344885, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100255058_C_G', pValueMantissa=1.3109999895095825, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0119039, standardError=0.00370431, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100255162_C_T', pValueMantissa=3.9679999351501465, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00827516, standardError=0.00287265, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100256000_C_A', pValueMantissa=1.5770000219345093, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.011701, standardError=0.00370274, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100256287_C_T', pValueMantissa=4.053999900817871, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00825485, standardError=0.00287235, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100256511_G_A', pValueMantissa=1.0700000524520874, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00604016, standardError=0.00184634, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100257612_C_T', pValueMantissa=1.9170000553131104, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0082026, standardError=0.00350204, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100258083_A_G', pValueMantissa=2.7039999961853027, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0635849, standardError=0.0287601, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100258094_C_T', pValueMantissa=1.5770000219345093, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.011701, standardError=0.00370274, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100258332_C_T', pValueMantissa=3.9760000705718994, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0082729, standardError=0.00287251, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100260000_A_G', pValueMantissa=1.6239999532699585, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0116706, standardError=0.00370306, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100260586_A_G', pValueMantissa=3.8919999599456787, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00829222, standardError=0.00287251, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100260869_C_T', pValueMantissa=4.205999851226807, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0082302, standardError=0.00287541, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100262992_C_T', pValueMantissa=1.5770000219345093, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.011701, standardError=0.00370274, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100263055_G_C', pValueMantissa=1.3109999895095825, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0119039, standardError=0.00370431, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100263140_C_T', pValueMantissa=1.5770000219345093, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.011701, standardError=0.00370274, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100263249_C_T', pValueMantissa=1.1790000200271606, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00711917, standardError=0.00184892, betaConditioned=None, standardErrorConditioned=None, r2Overall=None)], size=1001)]" - ] - }, - "execution_count": 29, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "window_based_clumped_output = 'gs://ot-team/dsuveges/finngen/2023.10.13_window_clumped_w_locus'\n", - "\n", - "(\n", - " session.spark.read.parquet(ld_clumped_output)\n", - " .filter(f.size(f.col('qualityControls')) == 0)\n", - "# .show(1, False, True)\n", - " .select('locus', f.size(f.col('locus')).alias('size'))\n", - " .limit(1)\n", - " .collect()\n", - ")" - ] + "name": "stdout", + "output_type": "stream", + "text": [ + "+--------------------+---------------------+---------+---------+---------------+\n", + "| studyId|ldPopulationStructure|projectId|studyType|traitFromSource|\n", + "+--------------------+---------------------+---------+---------+---------------+\n", + "|FINNGEN_R9_K11_EN...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", + "|FINNGEN_R9_H7_KER...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", + "|FINNGEN_R9_H8_EXT...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", + "|FINNGEN_R9_H7_RET...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", + "|FINNGEN_R9_RHEUMA...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", + "|FINNGEN_R9_H7_KER...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", + "|FINNGEN_R9_HEIGHT...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", + "|FINNGEN_R9_M13_SY...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", + "|FINNGEN_R9_M13_DO...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", + "|FINNGEN_R9_M13_PY...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", + "| FINNGEN_R9_GOUT_NOS| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", + "|FINNGEN_R9_M13_FI...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", + "|FINNGEN_R9_ALLERG...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", + "|FINNGEN_R9_E4_DM2...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", + "|FINNGEN_R9_G6_CER...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", + "|FINNGEN_R9_L12_UR...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", + "|FINNGEN_R9_AUTOIM...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", + "|FINNGEN_R9_I9_HYP...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", + "|FINNGEN_R9_M13_AR...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", + "|FINNGEN_R9_K11_AP...| [{fin, 1.0}]| FINNGEN| gwas| cicaful|\n", + "+--------------------+---------------------+---------+---------+---------------+\n", + "only showing top 20 rows\n", + "\n" + ] }, { - "cell_type": "code", - "execution_count": null, - "id": "e242acdd", - "metadata": {}, - "outputs": [], - "source": [] + "name": "stderr", + "output_type": "stream", + "text": [ + "23/10/13 11:55:34 WARN GhfsStorageStatistics: Detected potential high latency for operation op_open. latencyMs=676; previousMaxLatencyMs=470; operationCount=333148; context=gs://genetics_etl_python_playground/output/python_etl/parquet/XX.XX/ld_index/chromosome=5/part-00076-ff42773a-494c-46d2-bc22-322062b5e715.c000.snappy.parquet\n", + "23/10/13 12:39:11 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=279; previousMaxLatencyMs=243; operationCount=140; context=gs://ot-team/dsuveges/finngen/2023.10.13_ld_clumped_w_locus/_temporary/0/_temporary/attempt_202310131239103300432709600941830_0086_m_000000_80535/part-00000-17d449c4-f0c3-4617-b378-b74b864ab64a-c000.snappy.parquet\n", + "23/10/13 12:39:11 WARN GhfsStorageStatistics: Detected potential high latency for operation op_create. latencyMs=335; previousMaxLatencyMs=279; operationCount=140; context=gs://ot-team/dsuveges/finngen/2023.10.13_ld_clumped_w_locus/_temporary/0/_temporary/attempt_202310131239106417331548307580589_0086_m_000027_80562/part-00027-17d449c4-f0c3-4617-b378-b74b864ab64a-c000.snappy.parquet\n", + " \r" + ] } - ], - "metadata": { - "gist": { - "data": { - "description": "GCS/dsuveges/PICS/2023.10.06 - PICS FINNGEN from top to bottom.ipynb", - "public": false - }, - "id": "" - }, - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" + ], + "source": [ + "ld_clumped_output = \"gs://ot-team/dsuveges/finngen/2023.10.13_ld_clumped_w_locus\"\n", + "\n", + "studies_df = (\n", + " session.spark.read.parquet(window_based_clumped_output)\n", + " # Generating a list of study identifiers:\n", + " .select(\"studyId\")\n", + " .distinct()\n", + " # Adding fabricated values required to parse as gwas catalog study:\n", + " .select(\n", + " \"studyId\",\n", + " StudyIndex.aggregate_and_map_ancestries(\n", + " f.array(\n", + " f.struct(\n", + " f.lit(\"Finnish\").alias(\"ancestry\"),\n", + " f.lit(100).cast(\"long\").alias(\"sampleSize\")\n", + " )\n", + " )\n", + " ).alias(\"ldPopulationStructure\"),\n", + " f.lit(\"FINNGEN\").alias(\"projectId\"),\n", + " f.lit(\"gwas\").alias(\"studyType\"),\n", + " f.lit(\"cicaful\").alias(\"traitFromSource\")\n", + " )\n", + ")\n", + "\n", + "study_index = (\n", + " StudyIndex(\n", + " _df=studies_df,\n", + " _schema=StudyIndex.get_schema()\n", + " )\n", + ")\n", + "\n", + "study_index.df.show()\n", + "\n", + "# Loading ld index:\n", + "ld_index = LDIndex.from_parquet(session, ld_index_path)\n", + "\n", + "(\n", + " # To annotate study/locus, study level info and ld panel is needed:\n", + " LDAnnotator.ld_annotate(\n", + " StudyLocus.from_parquet(session, window_based_clumped_output),\n", + " study_index,\n", + " ld_index\n", + " )\n", + " # Clumping linked study-loci together:\n", + " .clump()\n", + " .df.write.mode(\"overwrite\").parquet(ld_clumped_output)\n", + ")\n", + "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "f637e3c0", + "metadata": { + "ExecuteTime": { + "end_time": "2023-10-13T10:43:26.766382Z", + "start_time": "2023-10-13T10:43:25.980232Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "+--------------------------------------------------------------+-----+\n", + "|qualityControls |count|\n", + "+--------------------------------------------------------------+-----+\n", + "|[Variant not found in LD reference] |4607 |\n", + "|[] |13813|\n", + "|[Explained by a more significant variant in high LD (clumped)]|585 |\n", + "+--------------------------------------------------------------+-----+\n", + "\n" + ] + } + ], + "source": [ + "(\n", + " session.spark.read.parquet(ld_clumped_output)\n", + " .groupBy(\"qualityControls\")\n", + " .count()\n", + "# .show(1, False, True)\n", + " .show(truncate=False)\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "id": "5bf42196", + "metadata": { + "ExecuteTime": { + "end_time": "2023-10-13T12:55:39.212186Z", + "start_time": "2023-10-13T12:55:38.131092Z" + } + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.8" + { + "data": { + "text/plain": [ + "[Row(locus=[Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99764322_T_C', pValueMantissa=2.3949999809265137, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0201963, standardError=0.00665169, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99764860_G_A', pValueMantissa=1.0499999523162842, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00813303, standardError=0.00248194, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99765280_C_T', pValueMantissa=7.499000072479248, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0147615, standardError=0.00437943, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99765335_A_G', pValueMantissa=1.2640000581741333, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0107816, standardError=0.00189456, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99766311_C_T', pValueMantissa=1.0579999685287476, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.010837, standardError=0.00189422, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99766702_A_G', pValueMantissa=1.2059999704360962, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0107966, standardError=0.00189453, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99766923_T_C', pValueMantissa=1.3300000429153442, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.010765, standardError=0.00189451, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99767090_TTTG_T', pValueMantissa=1.2740000486373901, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0107778, standardError=0.00189432, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99768341_T_C', pValueMantissa=1.2289999723434448, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0107887, standardError=0.00189422, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99768718_A_G', pValueMantissa=1.2649999856948853, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0107795, standardError=0.0018942, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99768993_G_A', pValueMantissa=1.1629999876022339, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0108066, standardError=0.00189423, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99769297_T_C', pValueMantissa=1.2929999828338623, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0113037, standardError=0.00186275, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99769386_C_T', pValueMantissa=1.7280000448226929, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00670209, standardError=0.00281514, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99769548_A_G', pValueMantissa=1.7280000448226929, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0067021, standardError=0.00281514, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99769607_C_T', pValueMantissa=1.2710000276565552, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0107775, standardError=0.00189416, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99770233_A_AT', pValueMantissa=1.1360000371932983, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0108149, standardError=0.00189434, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99771038_C_A', pValueMantissa=1.1039999723434448, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0108218, standardError=0.00189392, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99771332_T_C', pValueMantissa=1.284999966621399, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00972726, standardError=0.00390986, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99771548_C_T', pValueMantissa=1.1369999647140503, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0108168, standardError=0.00189473, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99774249_G_A', pValueMantissa=1.0410000085830688, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00813435, standardError=0.00248058, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99774476_AT_A', pValueMantissa=1.1540000438690186, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0108061, standardError=0.0018937, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99777761_G_A', pValueMantissa=2.9170000553131104, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0857961, standardError=0.0393337, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99777984_T_G', pValueMantissa=9.097999572753906, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0108749, standardError=0.00189236, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99778063_G_A', pValueMantissa=1.2730000019073486, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00887632, standardError=0.00203368, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99778821_G_A', pValueMantissa=1.6679999828338623, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00682868, standardError=0.00285271, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99779613_C_G', pValueMantissa=7.630000114440918, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0109299, standardError=0.00189215, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99781296_A_G', pValueMantissa=8.560999870300293, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.010892, standardError=0.00189195, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99781822_G_A', pValueMantissa=1.4390000104904175, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00689344, standardError=0.00281655, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99781826_A_G', pValueMantissa=7.65500020980835, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0109284, standardError=0.00189207, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99782821_C_T', pValueMantissa=1.3680000305175781, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00573303, standardError=0.00232523, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99783206_A_G', pValueMantissa=7.632999897003174, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0109293, standardError=0.00189206, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99783290_A_C', pValueMantissa=8.821999549865723, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0108841, standardError=0.00189224, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99784269_C_T', pValueMantissa=9.149999618530273, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0108721, standardError=0.00189218, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99784331_G_A', pValueMantissa=4.435999870300293, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0327234, standardError=0.0162747, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99784751_C_A', pValueMantissa=3.0409998893737793, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.149822, standardError=0.0692119, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99785581_A_G', pValueMantissa=7.164000034332275, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0113888, standardError=0.00423514, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99786875_C_T', pValueMantissa=5.257999897003174, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0110515, standardError=0.00189278, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99787050_C_G', pValueMantissa=6.671999931335449, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0109731, standardError=0.00189226, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99787264_C_A', pValueMantissa=7.834000110626221, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0109198, standardError=0.00189186, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99787285_C_T', pValueMantissa=9.189000129699707, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0108723, standardError=0.00189246, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99787359_T_G', pValueMantissa=7.504000186920166, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0109356, standardError=0.00189222, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99787460_G_T', pValueMantissa=6.499000072479248, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.010984, standardError=0.00189269, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99787461_G_T', pValueMantissa=6.499000072479248, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.010984, standardError=0.00189269, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99787483_G_A', pValueMantissa=7.631999969482422, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0109293, standardError=0.00189206, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99787568_C_T', pValueMantissa=7.631999969482422, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0109293, standardError=0.00189206, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99787571_C_T', pValueMantissa=7.631999969482422, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0109293, standardError=0.00189206, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99787694_A_AT', pValueMantissa=7.631999969482422, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0109293, standardError=0.00189206, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99787855_C_T', pValueMantissa=8.937999725341797, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0108798, standardError=0.00189223, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99787860_C_T', pValueMantissa=7.64300012588501, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0231471, standardError=0.0086776, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99787890_G_A', pValueMantissa=7.631999969482422, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0109293, standardError=0.00189206, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99787906_T_A', pValueMantissa=7.631999969482422, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0109293, standardError=0.00189206, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99787915_T_G', pValueMantissa=7.631999969482422, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0109293, standardError=0.00189206, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99788026_C_T', pValueMantissa=7.7870001792907715, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0109255, standardError=0.00189252, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99788420_A_C', pValueMantissa=7.001999855041504, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0109573, standardError=0.00189216, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99788711_G_A', pValueMantissa=1.0420000553131104, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0108302, standardError=0.00189215, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99788859_C_T', pValueMantissa=7.632999897003174, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0109293, standardError=0.00189206, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99788952_C_T', pValueMantissa=9.12399959564209, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0108727, standardError=0.00189214, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99789038_A_G', pValueMantissa=7.164000034332275, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0109498, standardError=0.00189212, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99789217_G_C', pValueMantissa=7.72599983215332, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0109277, standardError=0.00189247, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99789506_G_C', pValueMantissa=7.671000003814697, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0109278, standardError=0.00189209, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99789829_T_G', pValueMantissa=7.632999897003174, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0109293, standardError=0.00189206, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99790008_G_A', pValueMantissa=7.603000164031982, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0109305, standardError=0.00189206, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99790154_G_A', pValueMantissa=7.632999897003174, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0109293, standardError=0.00189206, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99790319_T_G', pValueMantissa=7.857999801635742, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0109213, standardError=0.00189229, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99791174_G_A', pValueMantissa=7.623000144958496, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0276216, standardError=0.00820577, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99791224_A_G', pValueMantissa=7.632999897003174, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0109293, standardError=0.00189206, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99793129_A_T', pValueMantissa=9.17300033569336, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0108711, standardError=0.00189215, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99793502_C_T', pValueMantissa=1.0099999904632568, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0108395, standardError=0.00189201, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99793829_C_CGTAT', pValueMantissa=3.756999969482422, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.201946, standardError=0.0971122, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99794292_T_A', pValueMantissa=1.8420000076293945, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0427514, standardError=0.0181376, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99794803_C_G', pValueMantissa=3.76200008392334, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0754336, standardError=0.0362844, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99797363_G_A', pValueMantissa=2.696000099182129, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0451691, standardError=0.0204184, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99797572_A_C', pValueMantissa=7.729000091552734, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0109255, standardError=0.0018921, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99798877_A_T', pValueMantissa=5.47599983215332, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0111187, standardError=0.0019065, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99798989_G_T', pValueMantissa=4.708000183105469, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00645552, standardError=0.00184611, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99799669_G_A', pValueMantissa=1.3769999742507935, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0283588, standardError=0.0115134, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99801055_G_A', pValueMantissa=5.751999855041504, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0863438, standardError=0.0312661, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99801648_T_C', pValueMantissa=5.201000213623047, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.35431, standardError=0.126797, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99802216_C_T', pValueMantissa=8.795999526977539, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0312825, standardError=0.00584722, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99803737_A_G', pValueMantissa=4.105000019073486, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0838538, standardError=0.0410448, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99804058_G_A', pValueMantissa=9.253999710083008, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00819335, standardError=0.00247362, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99804255_C_G', pValueMantissa=8.798999786376953, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0312823, standardError=0.00584723, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99804875_C_T', pValueMantissa=2.2079999446868896, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0532293, standardError=0.023254, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99805400_A_G', pValueMantissa=5.626999855041504, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0215236, standardError=0.00777382, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99805994_G_A', pValueMantissa=1.6449999809265137, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0125221, standardError=0.00522031, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99806253_C_T', pValueMantissa=1.2120000123977661, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00800751, standardError=0.00247451, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99806469_CAT_C', pValueMantissa=1.996999979019165, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.01596, standardError=0.00685871, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99807109_T_A', pValueMantissa=3.994999885559082, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0097045, standardError=0.00274107, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99807669_A_G', pValueMantissa=4.577000141143799, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0111561, standardError=0.00190316, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99807962_A_G', pValueMantissa=3.7709999084472656, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0677375, standardError=0.0325981, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99809156_C_A', pValueMantissa=1.4980000257492065, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00696552, standardError=0.0028632, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99809726_T_C', pValueMantissa=4.446000099182129, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0111654, standardError=0.00190318, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99809873_G_A', pValueMantissa=4.642000198364258, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.122379, standardError=0.0614495, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99811236_C_A', pValueMantissa=7.059999942779541, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0110215, standardError=0.00190371, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99811771_C_T', pValueMantissa=4.526000022888184, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0111597, standardError=0.00190317, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99815174_G_C', pValueMantissa=6.111000061035156, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0110649, standardError=0.00190324, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99815628_A_G', pValueMantissa=9.194999694824219, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0211397, standardError=0.00637879, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99815640_A_G', pValueMantissa=8.413999557495117, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0902758, standardError=0.0342605, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99816387_G_A', pValueMantissa=4.604000091552734, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0346061, standardError=0.0173466, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99816562_G_A', pValueMantissa=3.677000045776367, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00976812, standardError=0.00274214, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99816570_G_A', pValueMantissa=1.152999997138977, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00804666, standardError=0.00247569, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99817203_T_C', pValueMantissa=7.421999931335449, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0110057, standardError=0.00190374, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99818525_T_C', pValueMantissa=1.4880000352859497, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0186574, standardError=0.0076615, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99819195_T_G', pValueMantissa=6.382999897003174, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0124767, standardError=0.0045745, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99820908_A_G', pValueMantissa=1.4980000257492065, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00696602, standardError=0.0028633, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99821086_GA_G', pValueMantissa=3.259999990463257, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0113261, standardError=0.00272622, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99821094_C_T', pValueMantissa=4.098999977111816, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0112471, standardError=0.00191273, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99821955_T_G', pValueMantissa=4.670000076293945, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0112087, standardError=0.00191323, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99822427_T_C', pValueMantissa=2.058000087738037, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0115151, standardError=0.00192136, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99822696_T_C', pValueMantissa=7.763000011444092, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.162918, standardError=0.0611962, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99823047_A_G', pValueMantissa=7.198999881744385, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0110742, standardError=0.0019139, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99823280_T_C', pValueMantissa=1.1619999408721924, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00804213, standardError=0.00247592, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99825419_A_G', pValueMantissa=1.2710000276565552, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0826158, standardError=0.0331567, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99825752_T_C', pValueMantissa=6.0370001792907715, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0111297, standardError=0.00191372, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99825835_C_T', pValueMantissa=6.0320000648498535, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0111299, standardError=0.00191372, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99827260_C_T', pValueMantissa=3.6500000953674316, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0489284, standardError=0.0233964, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99828083_C_T', pValueMantissa=3.938999891281128, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0959414, standardError=0.0465714, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99828402_T_A', pValueMantissa=9.142000198364258, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0211518, standardError=0.00637931, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99828407_A_T', pValueMantissa=9.133999824523926, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0211533, standardError=0.0063793, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99829453_A_AT', pValueMantissa=6.083000183105469, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0111253, standardError=0.00191338, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99829545_ATATTT_A', pValueMantissa=4.810999870300293, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0112061, standardError=0.00191441, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99830168_G_A', pValueMantissa=1.218999981880188, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00801018, standardError=0.00247653, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99830263_G_A', pValueMantissa=1.6970000267028809, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0179959, standardError=0.00753787, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99832187_T_C', pValueMantissa=4.421000003814697, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0112213, standardError=0.0019124, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99832400_AAC_A', pValueMantissa=6.706999778747559, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0110021, standardError=0.00189753, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99832402_C_CTGTGTGT', pValueMantissa=6.710999965667725, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0110019, standardError=0.00189753, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99832563_A_G', pValueMantissa=1.4479999542236328, pValueExponent=-6, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0090241, standardError=0.00187287, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99832865_A_G', pValueMantissa=4.169000148773193, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0105412, standardError=0.00192234, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99834145_G_C', pValueMantissa=6.802999973297119, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.260334, standardError=0.0961939, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99834214_T_C', pValueMantissa=1.784000039100647, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0474718, standardError=0.0200386, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99835361_G_A', pValueMantissa=2.0769999027252197, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0595141, standardError=0.0257408, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99841479_C_T', pValueMantissa=6.188000202178955, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0104861, standardError=0.00193711, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99842816_A_G', pValueMantissa=8.645000457763672, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00723726, standardError=0.00184352, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99844024_C_G', pValueMantissa=2.3450000286102295, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0107969, standardError=0.00193341, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99844450_C_T', pValueMantissa=2.874000072479248, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0107269, standardError=0.00193316, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99845178_C_T', pValueMantissa=4.0320000648498535, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0656125, standardError=0.0319983, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99845936_A_G', pValueMantissa=3.069999933242798, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00675859, standardError=0.00312767, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99848765_C_G', pValueMantissa=2.8910000324249268, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0114511, standardError=0.00192855, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99850966_A_G', pValueMantissa=8.373000144958496, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0101864, standardError=0.00190084, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99852563_C_T', pValueMantissa=4.5329999923706055, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0113089, standardError=0.0019287, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99853411_T_TG', pValueMantissa=9.414999961853027, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.011087, standardError=0.00193121, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99856822_A_G', pValueMantissa=2.7119998931884766, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0114876, standardError=0.00193129, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99856987_G_C', pValueMantissa=5.239999771118164, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.010358, standardError=0.001903, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99857429_C_T', pValueMantissa=1.718000054359436, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0116617, standardError=0.00193637, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99857502_A_G', pValueMantissa=6.296000003814697, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.010296, standardError=0.00190308, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99857670_G_A', pValueMantissa=2.7939999103546143, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.011478, standardError=0.00193126, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99857979_C_T', pValueMantissa=2.5840001106262207, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00775769, standardError=0.00184386, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99858035_C_T', pValueMantissa=2.7939999103546143, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.011478, standardError=0.00193127, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99858181_G_C', pValueMantissa=2.7920000553131104, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0114783, standardError=0.00193127, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99858624_T_C', pValueMantissa=6.314000129699707, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0103011, standardError=0.0019042, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99859267_C_A', pValueMantissa=1.5019999742507935, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0239274, standardError=0.00753783, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99859558_G_A', pValueMantissa=6.2779998779296875, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0321283, standardError=0.00593792, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99859674_G_A', pValueMantissa=1.1050000190734863, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0100907, standardError=0.00190082, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99861014_C_G', pValueMantissa=1.350000023841858, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0080568, standardError=0.00185135, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99861191_A_G', pValueMantissa=2.062000036239624, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00788332, standardError=0.00185141, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99861743_A_C', pValueMantissa=1.621999979019165, pValueExponent=-6, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00893977, standardError=0.00186417, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99861975_TTGG_T', pValueMantissa=1.5509999990463257, pValueExponent=-6, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00895366, standardError=0.00186357, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99862766_C_T', pValueMantissa=1.7289999723434448, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00993376, standardError=0.0019007, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99863009_T_C', pValueMantissa=1.3009999990463257, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0535743, standardError=0.0215732, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99863999_T_C', pValueMantissa=1.4730000495910645, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0137073, standardError=0.00361145, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99864093_A_C', pValueMantissa=5.741000175476074, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0322238, standardError=0.00593803, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99864115_G_T', pValueMantissa=7.295000076293945, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.150642, standardError=0.0445916, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99865012_T_C', pValueMantissa=2.450000047683716, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00781456, standardError=0.00185205, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99865013_G_A', pValueMantissa=1.7259999513626099, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0159887, standardError=0.00510203, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99865261_T_C', pValueMantissa=1.4459999799728394, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00999453, standardError=0.00190036, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99865337_G_GAAGA', pValueMantissa=1.3170000314712524, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00806712, standardError=0.00185143, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99865513_C_G', pValueMantissa=1.3250000476837158, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0080656, standardError=0.00185165, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99866792_C_T', pValueMantissa=1.4500000476837158, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00803164, standardError=0.00185225, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99867170_C_T', pValueMantissa=8.121000289916992, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0111182, standardError=0.00192825, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99867197_T_C', pValueMantissa=2.680999994277954, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0171717, standardError=0.00775509, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99867487_C_G', pValueMantissa=2.8310000896453857, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.359987, standardError=0.164156, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99867528_G_T', pValueMantissa=2.8389999866485596, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0077156, standardError=0.0018432, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99868259_G_A', pValueMantissa=2.265000104904175, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.119984, standardError=0.0392983, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99868412_T_G', pValueMantissa=1.6779999732971191, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00994383, standardError=0.00190064, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99868443_A_G', pValueMantissa=1.4809999465942383, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00801978, standardError=0.0018515, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99868585_TC_T', pValueMantissa=1.437999963760376, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0080333, standardError=0.00185188, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99868691_T_G', pValueMantissa=1.4730000495910645, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00802444, standardError=0.00185208, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99869742_G_A', pValueMantissa=4.677000045776367, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0101608, standardError=0.00185986, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99870037_G_A', pValueMantissa=3.996999979019165, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0939625, standardError=0.0326443, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99870234_G_A', pValueMantissa=2.5759999752044678, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0270256, standardError=0.00896575, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99871164_A_T', pValueMantissa=9.444999694824219, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0101485, standardError=0.0019015, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99871248_A_C', pValueMantissa=4.265999794006348, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.011332, standardError=0.00192934, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99871256_C_T', pValueMantissa=1.0980000495910645, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0100932, standardError=0.00190087, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99871596_T_C', pValueMantissa=1.097000002861023, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0100928, standardError=0.00190078, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99871838_G_C', pValueMantissa=4.270999908447266, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0113316, standardError=0.00192933, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99871912_T_C', pValueMantissa=1.0989999771118164, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0100928, standardError=0.00190087, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99872008_T_C', pValueMantissa=1.0989999771118164, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0100927, standardError=0.00190087, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99872112_C_T', pValueMantissa=1.093000054359436, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0100944, standardError=0.00190084, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99872802_A_G', pValueMantissa=2.828000068664551, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0103237, standardError=0.00185953, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99873074_C_T', pValueMantissa=4.716000080108643, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0112996, standardError=0.00192927, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99873158_C_T', pValueMantissa=1.1759999990463257, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.010069, standardError=0.00190084, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99873263_C_T', pValueMantissa=1.1440000534057617, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.010071, standardError=0.00189938, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99873471_G_A', pValueMantissa=6.283999919891357, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0723658, standardError=0.0264824, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99873553_C_T', pValueMantissa=1.8109999895095825, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0122764, standardError=0.00286365, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99873602_C_T', pValueMantissa=3.7880001068115234, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0102286, standardError=0.00185958, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99874022_C_T', pValueMantissa=3.7920000553131104, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0102286, standardError=0.00185966, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99874186_C_CT', pValueMantissa=1.2230000495910645, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0100561, standardError=0.00190097, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99875195_T_C', pValueMantissa=4.964000225067139, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0112867, standardError=0.00192988, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99875202_G_T', pValueMantissa=1.312999963760376, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0100339, standardError=0.00190142, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99875320_C_A', pValueMantissa=1.2369999885559082, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0100535, standardError=0.00190119, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99875381_T_C', pValueMantissa=1.2410000562667847, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0100525, standardError=0.00190121, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99875452_C_T', pValueMantissa=2.5290000438690186, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0135056, standardError=0.00447237, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99875704_T_A', pValueMantissa=2.9600000381469727, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00410906, standardError=0.00188882, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99875760_A_AG', pValueMantissa=1.2430000305175781, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.010052, standardError=0.00190125, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99876031_G_GT', pValueMantissa=1.3940000534057617, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0240895, standardError=0.00753787, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99876891_T_C', pValueMantissa=3.986999988555908, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0102146, standardError=0.0018601, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99878758_G_A', pValueMantissa=2.763000011444092, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.151851, standardError=0.0689453, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99878850_C_G', pValueMantissa=4.1519999504089355, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0102024, standardError=0.0018603, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99880039_G_A', pValueMantissa=4.0960001945495605, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0102077, standardError=0.00186045, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99880120_A_C', pValueMantissa=4.75, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0113026, standardError=0.00193019, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99880736_G_C', pValueMantissa=2.4639999866485596, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.11912, standardError=0.039343, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99882938_G_A', pValueMantissa=4.218999862670898, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0102002, standardError=0.00186086, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99883489_C_T', pValueMantissa=7.486000061035156, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0140267, standardError=0.00524475, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99884754_C_T', pValueMantissa=2.5510001182556152, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.011665, standardError=0.00195783, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99885306_C_T', pValueMantissa=7.618000030517578, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0122854, standardError=0.00460381, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99885741_T_C', pValueMantissa=4.251999855041504, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0101963, standardError=0.00186062, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99887218_A_G', pValueMantissa=1.3589999675750732, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0100249, standardError=0.00190197, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99887854_C_T', pValueMantissa=1.3580000400543213, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.010025, standardError=0.00190197, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99888103_G_A', pValueMantissa=3.808000087738037, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0456176, standardError=0.0219955, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99889239_G_C', pValueMantissa=1.3580000400543213, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0100256, standardError=0.00190207, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99890983_C_T', pValueMantissa=1.3830000162124634, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.01002, standardError=0.00190223, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99891336_A_G', pValueMantissa=3.815000057220459, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0102374, standardError=0.00186162, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99891408_C_T', pValueMantissa=1.6360000371932983, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00996155, standardError=0.00190233, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99891590_G_A', pValueMantissa=6.8420000076293945, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0114132, standardError=0.00422021, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99891697_T_C', pValueMantissa=4.46999979019165, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.010205, standardError=0.00186523, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99892983_T_C', pValueMantissa=3.4000000953674316, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.177641, standardError=0.083791, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99893179_G_C', pValueMantissa=5.1570000648498535, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0112781, standardError=0.00193051, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99893428_C_T', pValueMantissa=4.14300012588501, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0102059, standardError=0.00186081, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99894094_G_C', pValueMantissa=4.321000099182129, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0249459, standardError=0.00708754, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99894492_G_T', pValueMantissa=8.531999588012695, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0101123, standardError=0.00188821, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99894565_A_G', pValueMantissa=4.785999774932861, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00954874, standardError=0.00273411, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99894939_T_C', pValueMantissa=8.916999816894531, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00988844, standardError=0.00184916, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99895167_T_C', pValueMantissa=4.169000148773193, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00948941, standardError=0.00187497, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99895555_C_T', pValueMantissa=4.659999847412109, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0340557, standardError=0.0120355, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99896225_G_A', pValueMantissa=1.0920000076293945, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0110344, standardError=0.0019305, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99896692_A_G', pValueMantissa=3.4130001068115234, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0110917, standardError=0.00187665, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99896979_T_G', pValueMantissa=3.2119998931884766, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0401381, standardError=0.0187308, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99897831_T_C', pValueMantissa=1.9040000438690186, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.14616, standardError=0.0623359, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99898123_G_A', pValueMantissa=1.1069999933242798, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0110304, standardError=0.00193059, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99898484_T_A', pValueMantissa=1.1139999628067017, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0110285, standardError=0.00193061, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99898828_T_C', pValueMantissa=3.2699999809265137, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0111045, standardError=0.00187657, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99899677_C_CTTGT', pValueMantissa=3.51200008392334, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0110858, standardError=0.00187714, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99900290_T_G', pValueMantissa=7.426000118255615, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0109405, standardError=0.00189249, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99900292_A_AT', pValueMantissa=1.1360000371932983, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00988613, standardError=0.00390553, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99900500_A_C', pValueMantissa=2.2009999752044678, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0412365, standardError=0.0180062, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99901642_T_C', pValueMantissa=5.086999893188477, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.113465, standardError=0.0405014, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99901731_C_T', pValueMantissa=1.5379999876022339, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0140283, standardError=0.00442901, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99902496_G_A', pValueMantissa=1.2289999723434448, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0224604, standardError=0.00897057, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99902603_C_T', pValueMantissa=4.140999794006348, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0854585, standardError=0.0419028, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99902712_G_C', pValueMantissa=1.1929999589920044, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0110082, standardError=0.00193099, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99902720_C_G', pValueMantissa=3.492000102996826, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.011087, standardError=0.00187705, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99902757_G_A', pValueMantissa=4.366000175476074, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0110198, standardError=0.00187741, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99903008_A_C', pValueMantissa=3.4590001106262207, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.01109, standardError=0.00187705, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99903292_G_A', pValueMantissa=3.4660000801086426, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0110895, standardError=0.00187709, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99903681_G_T', pValueMantissa=6.072000026702881, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0110979, standardError=0.00190858, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99904413_A_G', pValueMantissa=3.4719998836517334, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0110894, standardError=0.00187714, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99904499_G_A', pValueMantissa=1.1369999647140503, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0110237, standardError=0.00193097, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99904588_G_A', pValueMantissa=9.54800033569336, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0142134, standardError=0.00430252, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99905340_C_T', pValueMantissa=1.184000015258789, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0110128, standardError=0.00193138, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99905534_G_C', pValueMantissa=1.2209999561309814, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0379664, standardError=0.0151507, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99905541_A_G', pValueMantissa=3.575000047683716, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0110805, standardError=0.00187717, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99905693_A_G', pValueMantissa=3.490999937057495, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0110881, standardError=0.00187721, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99906210_T_C', pValueMantissa=3.5, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0110874, standardError=0.00187724, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99906644_G_A', pValueMantissa=1.0570000410079956, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0110495, standardError=0.00193126, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99906718_T_C', pValueMantissa=3.4709999561309814, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0110901, standardError=0.00187726, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99908035_C_T', pValueMantissa=7.296000003814697, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0148557, standardError=0.00439751, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99908057_A_G', pValueMantissa=7.160999774932861, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0149937, standardError=0.00443164, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99908221_T_C', pValueMantissa=3.878000020980835, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0110578, standardError=0.0018776, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99908813_T_C', pValueMantissa=5.124000072479248, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0112768, standardError=0.00192994, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99909229_T_C', pValueMantissa=8.24899959564209, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00998922, standardError=0.0018631, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99909454_A_C', pValueMantissa=7.598999977111816, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0109359, standardError=0.00189297, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99910263_C_T', pValueMantissa=5.330999851226807, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0111417, standardError=0.00190898, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99910368_T_C', pValueMantissa=3.302999973297119, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.011106, standardError=0.00187736, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99910580_T_G', pValueMantissa=1.1369999647140503, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0110251, standardError=0.00193122, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99911338_T_C', pValueMantissa=3.4579999446868896, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.011092, standardError=0.00187738, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99911811_G_A', pValueMantissa=2.575000047683716, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.118741, standardError=0.0393917, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99912354_A_G', pValueMantissa=5.099999904632568, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0112784, standardError=0.00192997, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99912584_A_G', pValueMantissa=3.447999954223633, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.011093, standardError=0.00187739, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99913097_C_G', pValueMantissa=3.181999921798706, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0111182, standardError=0.00187747, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99913702_T_C', pValueMantissa=1.0369999408721924, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0108274, standardError=0.00422404, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99914373_T_G', pValueMantissa=3.0360000133514404, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.248118, standardError=0.114583, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99915372_A_G', pValueMantissa=3.250999927520752, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0111123, standardError=0.0018776, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99915373_G_A', pValueMantissa=3.3289999961853027, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0111042, standardError=0.00187747, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99915884_T_C', pValueMantissa=5.684999942779541, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0109318, standardError=0.00187645, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99915918_T_G', pValueMantissa=1.281000018119812, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00983696, standardError=0.00186253, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99916127_T_C', pValueMantissa=5.081999778747559, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0112798, standardError=0.00193, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99916503_A_T', pValueMantissa=6.974999904632568, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00734427, standardError=0.00184662, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99916552_T_C', pValueMantissa=2.9839999675750732, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0122137, standardError=0.00562257, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99917731_C_T', pValueMantissa=5.0289998054504395, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0112837, standardError=0.0019301, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99919106_C_T', pValueMantissa=2.8299999237060547, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0131403, standardError=0.00440112, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99920364_C_T', pValueMantissa=4.159999847412109, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0219416, standardError=0.0076565, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99921641_GC_G', pValueMantissa=5.14900016784668, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0112777, standardError=0.00193036, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99922010_GAAGA_G', pValueMantissa=3.134999990463257, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0255599, standardError=0.00709237, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99922205_A_G', pValueMantissa=8.65999984741211, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00997687, standardError=0.00186386, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99922419_C_T', pValueMantissa=5.785999774932861, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0112417, standardError=0.00193063, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99923392_A_AAAT', pValueMantissa=7.868000030517578, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.010012, standardError=0.00186439, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99924208_C_T', pValueMantissa=6.610000133514404, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0112121, standardError=0.00193293, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99924251_CACGGTGAA_C', pValueMantissa=5.901000022888184, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0112486, standardError=0.0019329, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99924611_T_C', pValueMantissa=3.5799999237060547, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.028521, standardError=0.0135863, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99924854_A_G', pValueMantissa=4.103000164031982, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.135756, standardError=0.0664409, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99925030_G_A', pValueMantissa=7.132999897003174, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0123943, standardError=0.00460661, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99925171_T_C', pValueMantissa=2.7660000324249268, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0131669, standardError=0.00439981, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99925527_C_T', pValueMantissa=3.3429999351501465, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.011112, standardError=0.00187899, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99926307_T_C', pValueMantissa=1.2309999465942383, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00985993, standardError=0.0018643, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99926344_G_A', pValueMantissa=7.146999835968018, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0123917, standardError=0.00460668, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99928121_C_T', pValueMantissa=2.6080000400543213, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0237748, standardError=0.0106854, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99928961_T_A', pValueMantissa=7.409999847412109, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0092492, standardError=0.00274137, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99929621_G_C', pValueMantissa=2.4159998893737793, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00965232, standardError=0.00186913, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99930293_C_T', pValueMantissa=2.371000051498413, pValueExponent=-6, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00891412, standardError=0.00188903, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99930622_A_G', pValueMantissa=2.9200000762939453, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0122713, standardError=0.0019469, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99930880_C_G', pValueMantissa=6.189000129699707, pValueExponent=-11, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0126631, standardError=0.00193652, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99931871_G_T', pValueMantissa=1.0870000123977661, pValueExponent=-11, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0132779, standardError=0.00195421, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99932501_G_T', pValueMantissa=7.144999980926514, pValueExponent=-11, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0130514, standardError=0.0020025, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99932525_C_G', pValueMantissa=3.86299991607666, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0132541, standardError=0.00190924, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99932591_G_A', pValueMantissa=3.625999927520752, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0057824, standardError=0.00276148, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99933095_G_A', pValueMantissa=6.820000171661377, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.041325, standardError=0.0152743, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99933333_G_A', pValueMantissa=7.736000061035156, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0130529, standardError=0.00190738, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99933398_T_G', pValueMantissa=1.1490000486373901, pValueExponent=-11, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0132623, standardError=0.00195424, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99933499_T_C', pValueMantissa=7.710999965667725, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0130536, standardError=0.00190735, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99933515_AG_A', pValueMantissa=6.0929999351501465, pValueExponent=-11, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0130982, standardError=0.00200234, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99933811_A_C', pValueMantissa=3.0450000762939453, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0271544, standardError=0.009164, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99933841_A_G', pValueMantissa=7.820000171661377, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0130497, standardError=0.00190735, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99935601_G_A', pValueMantissa=6.01200008392334, pValueExponent=-11, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0131034, standardError=0.00200253, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99935839_G_A', pValueMantissa=1.9040000438690186, pValueExponent=-6, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0088457, standardError=0.00185702, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99936985_A_C', pValueMantissa=8.661999702453613, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0130204, standardError=0.00190715, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99937543_C_A', pValueMantissa=6.139999866485596, pValueExponent=-11, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0130966, standardError=0.00200245, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99938738_G_A', pValueMantissa=1.0329999923706055, pValueExponent=-11, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0132869, standardError=0.00195344, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99939547_T_C', pValueMantissa=6.979000091552734, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0130948, standardError=0.00190939, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99939652_G_A', pValueMantissa=4.034999847412109, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0132546, standardError=0.00191099, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99940864_C_T', pValueMantissa=5.973999977111816, pValueExponent=-11, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0131208, standardError=0.0020049, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99941429_ACCTCAGGGTTACC_A', pValueMantissa=4.370999813079834, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.187402, standardError=0.0929166, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99941625_T_C', pValueMantissa=7.7729997634887695, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0130649, standardError=0.00190932, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99942056_T_C', pValueMantissa=4.118000030517578, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0832392, standardError=0.0407701, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99942622_C_G', pValueMantissa=4.414999961853027, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0132329, standardError=0.00191137, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99942695_T_C', pValueMantissa=5.933000087738037, pValueExponent=-11, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0131229, standardError=0.0020049, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99942879_G_C', pValueMantissa=4.004000186920166, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0132567, standardError=0.001911, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99943051_G_T', pValueMantissa=5.098999977111816, pValueExponent=-6, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0153013, standardError=0.00335503, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99943272_T_C', pValueMantissa=4.004000186920166, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0132567, standardError=0.001911, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99943700_G_A', pValueMantissa=1.340000033378601, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0629333, standardError=0.0254482, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99943766_A_G', pValueMantissa=3.8440001010894775, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0136334, standardError=0.00196368, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99944281_T_C', pValueMantissa=7.932000160217285, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0130606, standardError=0.00190951, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99944562_A_T', pValueMantissa=4.39300012588501, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0135957, standardError=0.0019636, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99944721_TC_T', pValueMantissa=4.39300012588501, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0135957, standardError=0.0019636, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99945215_A_G', pValueMantissa=4.004000186920166, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0132567, standardError=0.001911, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99946139_G_A', pValueMantissa=1.3140000104904175, pValueExponent=-6, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00899244, standardError=0.00185887, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99946260_A_G', pValueMantissa=4.004000186920166, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0132567, standardError=0.001911, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99946307_A_C', pValueMantissa=4.873000144958496, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.12509, standardError=0.063468, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99946514_A_C', pValueMantissa=4.004000186920166, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0132567, standardError=0.001911, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99946634_G_A', pValueMantissa=4.004000186920166, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0132567, standardError=0.001911, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99947232_A_G', pValueMantissa=5.947999954223633, pValueExponent=-11, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0131222, standardError=0.00200491, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99947807_T_C', pValueMantissa=4.004000186920166, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0132567, standardError=0.001911, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99947876_G_A', pValueMantissa=4.059000015258789, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0132552, standardError=0.00191131, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99948681_A_G', pValueMantissa=7.769999980926514, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0130649, standardError=0.00190932, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99949062_G_A', pValueMantissa=4.873000144958496, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.12509, standardError=0.063468, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99950056_G_A', pValueMantissa=4.761000156402588, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.107573, standardError=0.0543081, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99952120_T_C', pValueMantissa=1.062000036239624, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0236237, standardError=0.00721645, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99953194_G_A', pValueMantissa=5.874000072479248, pValueExponent=-11, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0131262, standardError=0.00200494, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99953842_C_T', pValueMantissa=4.118000030517578, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0132617, standardError=0.00191282, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99953915_A_G', pValueMantissa=3.8420000076293945, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0132682, standardError=0.00191106, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99954520_G_A', pValueMantissa=6.242000102996826, pValueExponent=-11, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0131087, standardError=0.00200505, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99954533_T_G', pValueMantissa=4.175000190734863, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0132459, standardError=0.00191108, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99956142_G_A', pValueMantissa=4.054999828338623, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0132533, standardError=0.001911, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99956727_G_A', pValueMantissa=2.9579999446868896, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0132311, standardError=0.00445185, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99958027_A_G', pValueMantissa=7.925000190734863, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0130596, standardError=0.00190933, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99959825_G_A', pValueMantissa=4.172999858856201, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0163596, standardError=0.00803454, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99959911_G_A', pValueMantissa=2.3239998817443848, pValueExponent=-11, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0134674, standardError=0.00201484, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99962154_T_G', pValueMantissa=6.442999839782715, pValueExponent=-11, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0130988, standardError=0.002005, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99962896_A_G', pValueMantissa=4.985000133514404, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.018755, standardError=0.00956281, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99963747_T_C', pValueMantissa=3.8350000381469727, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.10415, standardError=0.0360205, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99963755_G_A', pValueMantissa=4.4070000648498535, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0132354, standardError=0.00191167, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99963792_C_T', pValueMantissa=1.0329999923706055, pValueExponent=-11, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0133147, standardError=0.0019575, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99963855_G_A', pValueMantissa=6.202000141143799, pValueExponent=-11, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0131113, standardError=0.00200516, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99963858_G_C', pValueMantissa=4.052000045776367, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0132537, standardError=0.00191104, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99964474_C_A', pValueMantissa=1.5709999799728394, pValueExponent=-11, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.013808, standardError=0.0020483, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99964716_C_T', pValueMantissa=3.6579999923706055, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.022367, standardError=0.00769613, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99965353_C_T', pValueMantissa=4.11899995803833, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0832401, standardError=0.0407717, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99965381_C_T', pValueMantissa=3.3989999294281006, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0154555, standardError=0.00728972, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99965782_C_T', pValueMantissa=1.2259999513626099, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0312055, standardError=0.00547846, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99966311_G_A', pValueMantissa=4.085000038146973, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0132514, standardError=0.00191102, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99966874_G_A', pValueMantissa=9.85099983215332, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0133219, standardError=0.00195661, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99967655_A_C', pValueMantissa=4.085999965667725, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0132548, standardError=0.00191151, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99968174_T_C', pValueMantissa=6.03000020980835, pValueExponent=-11, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0131184, standardError=0.00200495, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99970196_C_T', pValueMantissa=1.940999984741211, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0134874, standardError=0.00191619, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99971874_A_G', pValueMantissa=4.980999946594238, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0132011, standardError=0.0019115, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99973080_C_CATTT', pValueMantissa=9.527999877929688, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00936982, standardError=0.00191176, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99973080_CATTT_C', pValueMantissa=3.311000108718872, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.013347, standardError=0.00191661, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99973360_A_G', pValueMantissa=1.6030000448226929, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0940323, standardError=0.0390452, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99973664_T_C', pValueMantissa=4.126999855041504, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.013249, standardError=0.00191107, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99973694_T_C', pValueMantissa=3.937000036239624, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.13666, standardError=0.0663293, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99973733_A_G', pValueMantissa=4.34499979019165, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0132363, standardError=0.00191125, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99974260_C_T', pValueMantissa=2.316999912261963, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0316527, standardError=0.0139405, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99975197_T_C', pValueMantissa=2.117000102996826, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0134651, standardError=0.00191633, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99975489_C_G', pValueMantissa=5.743000030517578, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0354502, standardError=0.0128345, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99976504_G_A', pValueMantissa=8.508999824523926, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0819298, standardError=0.031138, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99977161_A_G', pValueMantissa=4.061999797821045, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0132532, standardError=0.00191106, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99977721_G_A', pValueMantissa=6.2829999923706055, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0246959, standardError=0.00903733, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99979375_G_A', pValueMantissa=3.937000036239624, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.13666, standardError=0.0663293, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99979565_C_T', pValueMantissa=4.479000091552734, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0275515, standardError=0.0137302, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99979592_G_A', pValueMantissa=3.3989999294281006, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0133022, standardError=0.00191119, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99980479_A_C', pValueMantissa=7.7230000495910645, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0930047, standardError=0.0349125, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99980767_T_TG', pValueMantissa=3.1600000858306885, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0133205, standardError=0.001911, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99981303_T_C', pValueMantissa=1.0260000228881836, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0129016, standardError=0.0019962, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99982408_C_T', pValueMantissa=4.807000160217285, pValueExponent=-11, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0131845, standardError=0.00200471, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99982941_G_A', pValueMantissa=3.236999988555908, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0133135, standardError=0.00191092, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99983547_G_T', pValueMantissa=1.378000020980835, pValueExponent=-11, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0138444, standardError=0.00204793, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99983965_C_T', pValueMantissa=1.3339999914169312, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.276188, standardError=0.0722979, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99984671_A_G', pValueMantissa=1.090999960899353, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.012885, standardError=0.00199651, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99984912_C_T', pValueMantissa=3.328000068664551, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0133085, standardError=0.00191128, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99986015_T_C', pValueMantissa=1.0609999895095825, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.012891, standardError=0.00199615, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99988026_G_T', pValueMantissa=7.709000110626221, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0122774, standardError=0.0046077, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99988174_G_A', pValueMantissa=3.121999979019165, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0133243, standardError=0.0019111, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99988593_A_C', pValueMantissa=4.09499979019165, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0833533, standardError=0.0407789, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99988730_T_C', pValueMantissa=3.1760001182556152, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0133191, standardError=0.00191101, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99988731_G_A', pValueMantissa=5.669000148773193, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0144037, standardError=0.00520681, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99988980_A_G', pValueMantissa=4.874000072479248, pValueExponent=-11, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0131807, standardError=0.00200475, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99989148_T_C', pValueMantissa=4.875, pValueExponent=-11, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0131806, standardError=0.00200475, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99989685_T_C', pValueMantissa=4.556000232696533, pValueExponent=-11, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0132006, standardError=0.00200472, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99989906_C_T', pValueMantissa=3.2639999389648438, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0133133, standardError=0.00191121, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99990445_G_A', pValueMantissa=6.452000141143799, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.090219, standardError=0.0331213, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99990521_G_A', pValueMantissa=2.9019999504089355, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.013345, standardError=0.00191124, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99990640_T_A', pValueMantissa=1.5579999685287476, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0139907, standardError=0.00442234, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99992006_G_GA', pValueMantissa=3.0260000228881836, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0133329, standardError=0.00191111, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99992015_T_C', pValueMantissa=3.5850000381469727, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.013291, standardError=0.00191165, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99992806_A_G', pValueMantissa=3.0290000438690186, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0133327, standardError=0.00191112, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99993453_A_G', pValueMantissa=3.0329999923706055, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0133323, standardError=0.00191113, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99993852_T_C', pValueMantissa=3.0360000133514404, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0133322, standardError=0.00191113, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99994177_C_T', pValueMantissa=4.533999919891357, pValueExponent=-11, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0132032, standardError=0.00200489, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99994349_A_T', pValueMantissa=1.0379999876022339, pValueExponent=-11, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0287633, standardError=0.00422921, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99995001_T_C', pValueMantissa=3.2860000133514404, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0133152, standardError=0.00191176, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99995032_G_C', pValueMantissa=4.89900016784668, pValueExponent=-11, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0131854, standardError=0.00200569, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99995714_T_C', pValueMantissa=3.374000072479248, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0133048, standardError=0.00191128, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99995753_C_CTT', pValueMantissa=3.372999906539917, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0133049, standardError=0.00191128, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99996207_C_G', pValueMantissa=3.384000062942505, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0133041, standardError=0.00191129, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99997268_A_G', pValueMantissa=3.378999948501587, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0133047, standardError=0.00191132, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99997438_CCA_C', pValueMantissa=6.603000164031982, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.109829, standardError=0.0404341, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99997720_A_G', pValueMantissa=2.815999984741211, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0133548, standardError=0.00191149, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99998079_C_CA', pValueMantissa=4.61299991607666, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0922906, standardError=0.0462786, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99998104_G_A', pValueMantissa=1.2979999780654907, pValueExponent=-6, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00911911, standardError=0.0018841, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_99999971_A_G', pValueMantissa=2.9570000171661377, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.030431, standardError=0.0102384, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100000235_C_T', pValueMantissa=5.6519999504089355, pValueExponent=-13, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.014492, standardError=0.00201036, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100000486_G_A', pValueMantissa=4.172999858856201, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.305198, standardError=0.149885, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100002038_G_A', pValueMantissa=3.7739999294281006, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0211624, standardError=0.0073064, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100002628_A_C', pValueMantissa=2.953000068664551, pValueExponent=-13, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0138093, standardError=0.00189258, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100004140_G_A', pValueMantissa=2.6459999084472656, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0994314, standardError=0.0448022, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100004827_A_C', pValueMantissa=6.945000171661377, pValueExponent=-14, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0142296, standardError=0.0019001, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100005233_T_C', pValueMantissa=3.111999988555908, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0216712, standardError=0.00733013, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100005358_G_C', pValueMantissa=4.872000217437744, pValueExponent=-13, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0145472, standardError=0.00201239, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100005438_A_G', pValueMantissa=1.093000054359436, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0533162, standardError=0.02095, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100006780_C_T', pValueMantissa=5.067999839782715, pValueExponent=-13, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0145408, standardError=0.002013, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100007241_C_T', pValueMantissa=6.783999919891357, pValueExponent=-14, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0142505, standardError=0.0019021, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100007404_G_GC', pValueMantissa=1.3420000076293945, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0198944, standardError=0.00377285, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100008640_A_G', pValueMantissa=5.019999980926514, pValueExponent=-13, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0145435, standardError=0.002013, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100009013_G_A', pValueMantissa=6.611999988555908, pValueExponent=-14, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0142475, standardError=0.00190084, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100009635_T_G', pValueMantissa=1.0549999475479126, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0134968, standardError=0.0018948, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100011477_C_G', pValueMantissa=2.444999933242798, pValueExponent=-13, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0148805, standardError=0.00203232, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100011685_CAAAT_C', pValueMantissa=4.139999866485596, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0101715, standardError=0.00185449, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100011812_A_T', pValueMantissa=1.2029999494552612, pValueExponent=-13, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0141145, standardError=0.00190314, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100013275_A_T', pValueMantissa=2.174999952316284, pValueExponent=-14, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0145924, standardError=0.00191005, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100013744_G_A', pValueMantissa=4.76800012588501, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.51719, standardError=0.261177, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100014566_A_G', pValueMantissa=8.550999641418457, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0119513, standardError=0.00358432, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100014970_T_C', pValueMantissa=3.993000030517578, pValueExponent=-13, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0146099, standardError=0.00201355, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100015400_G_A', pValueMantissa=5.646999835968018, pValueExponent=-13, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0160357, standardError=0.00222448, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100015645_T_C', pValueMantissa=2.236999988555908, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0145559, standardError=0.00207384, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100015854_C_T', pValueMantissa=6.158999919891357, pValueExponent=-13, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0160044, standardError=0.0022238, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100016635_T_G', pValueMantissa=1.718999981880188, pValueExponent=-11, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0147181, standardError=0.00218755, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100016645_C_T', pValueMantissa=4.622000217437744, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0256776, standardError=0.00906606, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100017027_A_T', pValueMantissa=6.242000102996826, pValueExponent=-13, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0160069, standardError=0.0022247, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100017624_A_G', pValueMantissa=1.7170000076293945, pValueExponent=-11, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0147203, standardError=0.00218782, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100018116_C_T', pValueMantissa=2.197000026702881, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0145668, standardError=0.00207465, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100018135_G_C', pValueMantissa=1.4559999704360962, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.275534, standardError=0.0725377, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100018265_A_T', pValueMantissa=2.7190001010894775, pValueExponent=-6, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00874366, standardError=0.00186392, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100020857_T_C', pValueMantissa=9.112000465393066, pValueExponent=-14, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0156784, standardError=0.00210358, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100021675_C_A', pValueMantissa=3.066999912261963, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0233385, standardError=0.0107983, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100021907_C_T', pValueMantissa=7.229000091552734, pValueExponent=-13, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0159723, standardError=0.00222609, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100022313_C_CT', pValueMantissa=6.171999931335449, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0504229, standardError=0.0184125, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100023134_T_G', pValueMantissa=1.3980000019073486, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0268617, standardError=0.0109298, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100024168_G_A', pValueMantissa=2.3359999656677246, pValueExponent=-6, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00880598, standardError=0.00186491, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100024869_C_T', pValueMantissa=3.556999921798706, pValueExponent=-13, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0162101, standardError=0.00222929, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100025927_T_TA', pValueMantissa=3.621999979019165, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.014426, standardError=0.00207534, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100026878_C_T', pValueMantissa=9.258999824523926, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0185461, standardError=0.00712673, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100027354_G_A', pValueMantissa=1.968000054359436, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.103617, standardError=0.0444235, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100027592_G_C', pValueMantissa=1.965999960899353, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.103629, standardError=0.0444216, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100027903_T_C', pValueMantissa=2.75600004196167, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0384662, standardError=0.0128487, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100028049_C_T', pValueMantissa=4.144000053405762, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.130023, standardError=0.0637634, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100029663_A_G', pValueMantissa=8.883999824523926, pValueExponent=-13, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0147895, standardError=0.00206939, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100030853_G_A', pValueMantissa=7.5980000495910645, pValueExponent=-13, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0158245, standardError=0.00220759, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100030993_G_A', pValueMantissa=3.437000036239624, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0224965, standardError=0.00768921, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100031808_C_T', pValueMantissa=5.959000110626221, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0212214, standardError=0.00771671, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100032684_A_C', pValueMantissa=5.459000110626221, pValueExponent=-13, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.014926, standardError=0.00206922, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100033239_T_A', pValueMantissa=1.3669999837875366, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0463194, standardError=0.0187842, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100033337_C_T', pValueMantissa=9.138999938964844, pValueExponent=-14, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0165264, standardError=0.00221749, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100033635_G_GT', pValueMantissa=1.0110000371932983, pValueExponent=-13, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0164902, standardError=0.00221658, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100035604_T_A', pValueMantissa=3.4110000133514404, pValueExponent=-12, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.01433, standardError=0.002059, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100037190_G_A', pValueMantissa=3.2070000171661377, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0120692, standardError=0.00203849, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100037544_C_T', pValueMantissa=1.6990000009536743, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00996527, standardError=0.00417483, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100037655_A_G', pValueMantissa=6.13100004196167, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0127317, standardError=0.00219016, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100038188_C_T', pValueMantissa=7.738999843597412, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0126728, standardError=0.00219478, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100038589_T_C', pValueMantissa=3.734999895095825, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.010628, standardError=0.00193133, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100038648_G_A', pValueMantissa=1.7230000495910645, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00994355, standardError=0.00417478, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100039544_T_C', pValueMantissa=5.021999835968018, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0126227, standardError=0.00202988, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100039545_G_T', pValueMantissa=1.5509999990463257, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0130939, standardError=0.00204582, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100039976_C_T', pValueMantissa=1.7209999561309814, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00994495, standardError=0.00417473, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100039997_T_C', pValueMantissa=5.01800012588501, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0126197, standardError=0.00202937, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100040770_T_G', pValueMantissa=3.059999942779541, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.120454, standardError=0.0557085, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100042338_T_C', pValueMantissa=2.61899995803833, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.189007, standardError=0.085007, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100042505_G_A', pValueMantissa=3.4860000610351562, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0101879, standardError=0.00482832, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100042848_C_CT', pValueMantissa=4.413000106811523, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0093599, standardError=0.00185336, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100043308_C_T', pValueMantissa=5.076000213623047, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0126162, standardError=0.00202939, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100044357_C_T', pValueMantissa=5.36299991607666, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0127797, standardError=0.00218999, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100044501_A_G', pValueMantissa=1.7130000591278076, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00995148, standardError=0.00417441, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100044818_C_T', pValueMantissa=4.927000045776367, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0204248, standardError=0.00726406, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100044839_G_T', pValueMantissa=4.875, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0126274, standardError=0.00202913, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100045047_A_C', pValueMantissa=4.922999858856201, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0204266, standardError=0.00726404, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100045603_T_A', pValueMantissa=1.6740000247955322, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00998325, standardError=0.00417297, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100045685_C_T', pValueMantissa=1.3309999704360962, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0131383, standardError=0.00204533, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100045864_G_A', pValueMantissa=1.6770000457763672, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00998092, standardError=0.00417295, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100046495_A_G', pValueMantissa=4.683000087738037, pValueExponent=-11, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0133938, standardError=0.00203532, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100046569_C_T', pValueMantissa=1.6740000247955322, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0129058, standardError=0.00202014, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100047823_TA_T', pValueMantissa=1.5670000314712524, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0129238, standardError=0.00201974, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100049106_G_A', pValueMantissa=1.690000057220459, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0130999, standardError=0.00217423, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100049236_C_T', pValueMantissa=1.690000057220459, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00996986, standardError=0.00417357, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100049902_G_A', pValueMantissa=1.8940000534057617, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0130591, standardError=0.00217409, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100050211_A_T', pValueMantissa=2.1419999599456787, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0633556, standardError=0.0275398, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100050359_GAACA_G', pValueMantissa=1.6019999980926514, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0129195, standardError=0.00202015, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100051409_C_G', pValueMantissa=1.7120000123977661, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0130944, standardError=0.00217407, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100051504_G_A', pValueMantissa=1.7549999952316284, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00990516, standardError=0.00417051, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100052545_C_G', pValueMantissa=1.5299999713897705, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0129286, standardError=0.00201936, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100052742_T_C', pValueMantissa=1.687000036239624, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00997036, standardError=0.00417237, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100054045_C_T', pValueMantissa=1.3009999990463257, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0129769, standardError=0.0020191, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100054117_T_C', pValueMantissa=4.938000202178955, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0716183, standardError=0.0364414, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100054574_T_G', pValueMantissa=1.6629999876022339, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00999072, standardError=0.00417196, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100055122_T_C', pValueMantissa=6.368000030517578, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0124774, standardError=0.00214876, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100055153_G_A', pValueMantissa=1.6540000438690186, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00999801, standardError=0.0041714, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100055199_C_G', pValueMantissa=1.8609999418258667, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0130598, standardError=0.00217319, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100055816_G_A', pValueMantissa=3.3589999675750732, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0126847, standardError=0.00201947, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100055862_T_G', pValueMantissa=4.1529998779296875, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0446939, standardError=0.0219282, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100056323_C_T', pValueMantissa=4.943999767303467, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0267439, standardError=0.0136118, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100056440_C_T', pValueMantissa=4.486999988555908, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00779499, standardError=0.00388601, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100057584_A_G', pValueMantissa=5.919000148773193, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.011644, standardError=0.00200103, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100057785_T_C', pValueMantissa=4.816999912261963, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0128495, standardError=0.00219523, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100057800_C_T', pValueMantissa=1.0049999952316284, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0122603, standardError=0.00200707, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100059207_A_C', pValueMantissa=3.622999906539917, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0143322, standardError=0.00401899, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100059401_T_TAACAAC', pValueMantissa=3.5920000076293945, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00695612, standardError=0.00194938, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100059401_T_TAACAACAAC', pValueMantissa=3.884999990463257, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0133237, standardError=0.00644961, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100059657_G_A', pValueMantissa=3.880000114440918, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0133275, standardError=0.00645004, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100060102_G_C', pValueMantissa=3.874000072479248, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0133327, standardError=0.00645048, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100060272_A_G', pValueMantissa=4.5370001792907715, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0594699, standardError=0.0297173, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100060908_A_G', pValueMantissa=2.742000102996826, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0113896, standardError=0.00204953, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100061298_C_T', pValueMantissa=2.503000020980835, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0150616, standardError=0.00672123, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100061574_G_C', pValueMantissa=2.7809998989105225, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0113862, standardError=0.00204983, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100061627_C_T', pValueMantissa=1.6690000295639038, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0323984, standardError=0.00537545, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100061926_T_C', pValueMantissa=1.1759999990463257, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0122155, standardError=0.00200796, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100062022_C_T', pValueMantissa=9.611000061035156, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0212829, standardError=0.00821882, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100062212_C_T', pValueMantissa=3.7899999618530273, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0133927, standardError=0.00645157, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100062744_C_A', pValueMantissa=3.752000093460083, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0134223, standardError=0.00645282, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100062935_C_T', pValueMantissa=3.7669999599456787, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0134118, standardError=0.00645294, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100063173_T_G', pValueMantissa=2.7899999618530273, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.011387, standardError=0.00205019, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100063265_C_T', pValueMantissa=2.61299991607666, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0142012, standardError=0.00638472, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100063639_C_T', pValueMantissa=2.7750000953674316, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0276973, standardError=0.0125851, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100063786_T_C', pValueMantissa=2.9630000591278076, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.011365, standardError=0.00205011, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100064214_T_C', pValueMantissa=5.559999942779541, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0128066, standardError=0.00219686, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100064301_T_C', pValueMantissa=2.427999973297119, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0540203, standardError=0.0239811, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100064486_T_C', pValueMantissa=2.484999895095825, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0271265, standardError=0.00428678, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100064533_A_G', pValueMantissa=8.324000358581543, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00771332, standardError=0.00196024, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100064544_T_C', pValueMantissa=8.236000061035156, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00771787, standardError=0.00196013, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100065403_C_G', pValueMantissa=1.7259999513626099, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00799338, standardError=0.00185995, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100066509_T_C', pValueMantissa=3.444999933242798, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0925747, standardError=0.0437751, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100066929_C_A', pValueMantissa=4.581999778747559, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0250808, standardError=0.012559, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100067656_G_A', pValueMantissa=2.6489999294281006, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0143151, standardError=0.00645107, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100067862_G_A', pValueMantissa=7.921999931335449, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0119879, standardError=0.00195036, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100068504_C_T', pValueMantissa=6.7170000076293945, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00746427, standardError=0.00187258, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100068843_C_A', pValueMantissa=1.2430000305175781, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0115969, standardError=0.00203679, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100068866_G_GT', pValueMantissa=1.312000036239624, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0115787, standardError=0.00203689, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100069305_A_T', pValueMantissa=2.6449999809265137, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0143181, standardError=0.00645098, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100069570_T_C', pValueMantissa=2.6549999713897705, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0151566, standardError=0.00504359, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100069757_C_T', pValueMantissa=2.5869998931884766, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0145205, standardError=0.00481941, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100070175_A_G', pValueMantissa=2.000999927520752, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0130301, standardError=0.00421666, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100072279_G_C', pValueMantissa=1.2419999837875366, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0115973, standardError=0.00203683, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100073428_G_T', pValueMantissa=2.609999895095825, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0143509, standardError=0.00645062, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100073963_C_T', pValueMantissa=1.0750000476837158, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0116458, standardError=0.00203655, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100074034_T_TC', pValueMantissa=2.005000114440918, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0113741, standardError=0.0020269, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100074335_C_T', pValueMantissa=1.0729999542236328, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0116458, standardError=0.00203643, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100074511_G_A', pValueMantissa=4.894000053405762, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0166749, standardError=0.00478271, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100074712_C_T', pValueMantissa=1.2990000247955322, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0487079, standardError=0.0196078, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100075164_G_A', pValueMantissa=1.2369999885559082, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0115989, standardError=0.00203683, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100075228_C_T', pValueMantissa=2.6029999256134033, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0143577, standardError=0.00645054, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100075751_C_A', pValueMantissa=1.7940000295639038, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0172016, standardError=0.00726754, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100076243_C_A', pValueMantissa=2.6019999980926514, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0143585, standardError=0.00645053, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100077499_A_G', pValueMantissa=4.675000190734863, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00753971, standardError=0.00185191, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100077617_C_A', pValueMantissa=8.185999870300293, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.013965, standardError=0.00417311, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100078024_G_A', pValueMantissa=4.400000095367432, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0760544, standardError=0.0267049, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100078160_G_A', pValueMantissa=2.5989999771118164, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0143609, standardError=0.00645053, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100078351_A_T', pValueMantissa=5.255000114440918, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0358513, standardError=0.0103395, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100078510_A_C', pValueMantissa=8.102999687194824, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0119828, standardError=0.00195067, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100078923_G_A', pValueMantissa=1.805999994277954, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0171834, standardError=0.00726738, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100079042_G_A', pValueMantissa=2.5889999866485596, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0143712, standardError=0.00645058, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100080295_T_C', pValueMantissa=5.934000015258789, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0121315, standardError=0.00195916, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100080362_T_A', pValueMantissa=9.142000198364258, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0117746, standardError=0.00204921, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100081203_A_G', pValueMantissa=7.883999824523926, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0119901, standardError=0.00195049, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100082411_T_C', pValueMantissa=2.5829999446868896, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0143766, standardError=0.00645057, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100083012_C_A', pValueMantissa=3.0209999084472656, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0125696, standardError=0.0019959, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100083306_C_T', pValueMantissa=2.5810000896453857, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0143789, standardError=0.00645062, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100083442_A_T', pValueMantissa=4.665999889373779, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00754005, standardError=0.0018518, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100083679_C_T', pValueMantissa=2.5810000896453857, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0143785, standardError=0.00645064, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100083851_G_A', pValueMantissa=7.6570000648498535, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0119987, standardError=0.00195041, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100083869_GTGGA_G', pValueMantissa=2.5769999027252197, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0143832, standardError=0.00645065, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100084120_A_G', pValueMantissa=2.5739998817443848, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0143853, standardError=0.00645064, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100085028_A_G', pValueMantissa=1.2200000286102295, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0116042, standardError=0.00203692, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100085123_T_C', pValueMantissa=2.569999933242798, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0143893, standardError=0.00645068, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100085191_A_C', pValueMantissa=1.0609999895095825, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0116492, standardError=0.00203632, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100085317_T_C', pValueMantissa=2.6549999713897705, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0151555, standardError=0.00504327, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100085356_CT_C', pValueMantissa=2.989000082015991, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.012573, standardError=0.00199591, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100085677_T_C', pValueMantissa=7.4720001220703125, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0120068, standardError=0.0019505, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100085790_C_T', pValueMantissa=9.621999740600586, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0119266, standardError=0.0019502, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100085791_G_A', pValueMantissa=6.89300012588501, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0076585, standardError=0.00283442, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100086416_A_C', pValueMantissa=4.2779998779296875, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00757727, standardError=0.00185176, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100087170_C_T', pValueMantissa=4.797999858856201, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0249466, standardError=0.0126147, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100088100_T_C', pValueMantissa=1.2690000534057617, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0115908, standardError=0.00203699, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100088206_G_A', pValueMantissa=1.8480000495910645, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0171185, standardError=0.00726652, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100088307_G_A', pValueMantissa=8.534000396728516, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0258604, standardError=0.00421546, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100088565_A_AGAG', pValueMantissa=2.5799999237060547, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.01438, standardError=0.00645071, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100088687_C_T', pValueMantissa=4.041999816894531, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0124937, standardError=0.00199821, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100088994_G_C', pValueMantissa=4.744999885559082, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.26271, standardError=0.13253, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100089654_C_A', pValueMantissa=1.2940000295639038, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0115954, standardError=0.00203897, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100090029_G_T', pValueMantissa=3.2170000076293945, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0322465, standardError=0.00583203, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100093119_C_T', pValueMantissa=3.0880000591278076, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.379152, standardError=0.0909911, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100095173_CA_C', pValueMantissa=1.1920000314712524, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0116127, standardError=0.00203702, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100095421_C_T', pValueMantissa=4.376999855041504, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00756736, standardError=0.00185174, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100095474_G_C', pValueMantissa=1.0429999828338623, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.011657, standardError=0.00203668, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100095491_G_A', pValueMantissa=2.575000047683716, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0143845, standardError=0.00645073, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100095666_A_G', pValueMantissa=2.997999906539917, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0125726, standardError=0.001996, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100095766_C_T', pValueMantissa=2.5769999027252197, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0143829, standardError=0.00645074, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100096097_G_A', pValueMantissa=4.854000091552734, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.159194, standardError=0.0807015, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100096882_A_T', pValueMantissa=1.875, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0170779, standardError=0.00726586, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100097204_C_G', pValueMantissa=4.326000213623047, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00757235, standardError=0.00185173, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100097630_G_A', pValueMantissa=6.629000186920166, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0183017, standardError=0.0067411, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100097685_G_A', pValueMantissa=2.1630001068115234, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00784104, standardError=0.00341393, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100098591_G_A', pValueMantissa=7.1529998779296875, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00762397, standardError=0.00283455, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100099448_G_A', pValueMantissa=2.5399999618530273, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0110489, standardError=0.00198346, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100100113_A_G', pValueMantissa=2.996000051498413, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.012573, standardError=0.00199604, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100100236_G_A', pValueMantissa=2.565000057220459, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0143946, standardError=0.00645086, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100101678_G_A', pValueMantissa=1.065000057220459, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0116505, standardError=0.00203676, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100101681_G_A', pValueMantissa=2.572999954223633, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0143872, standardError=0.00645085, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100101734_C_T', pValueMantissa=2.805000066757202, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0388904, standardError=0.0177047, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100101865_T_C', pValueMantissa=7.827000141143799, pValueExponent=-6, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00939164, standardError=0.0021011, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100101978_T_A', pValueMantissa=2.565000057220459, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0143954, standardError=0.00645086, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100102891_G_A', pValueMantissa=3.0280001163482666, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0125699, standardError=0.00199607, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100102937_T_C', pValueMantissa=1.0709999799728394, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0116485, standardError=0.00203677, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100103034_T_C', pValueMantissa=1.062000036239624, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0116512, standardError=0.00203676, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100103075_C_T', pValueMantissa=2.5480000972747803, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0144117, standardError=0.0064509, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100103232_C_T', pValueMantissa=1.059999942779541, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0116519, standardError=0.00203676, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100103284_T_C', pValueMantissa=1.2389999628067017, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0115998, standardError=0.00203711, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100103427_G_A', pValueMantissa=2.5409998893737793, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0144177, standardError=0.0064504, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100103653_C_A', pValueMantissa=1.2389999628067017, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0116, standardError=0.00203711, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100104060_G_C', pValueMantissa=1.0570000410079956, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.011653, standardError=0.00203678, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100104416_A_G', pValueMantissa=1.062999963760376, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0116511, standardError=0.00203678, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100104538_T_A', pValueMantissa=3.0250000953674316, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0125704, standardError=0.0019961, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100104974_T_C', pValueMantissa=2.5460000038146973, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0144144, standardError=0.00645109, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100105358_T_A', pValueMantissa=1.246000051498413, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0115981, standardError=0.00203714, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100105587_G_A', pValueMantissa=1.0700000524520874, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0116489, standardError=0.0020368, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100105759_A_T', pValueMantissa=1.253000020980835, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0115962, standardError=0.00203715, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100106124_T_C', pValueMantissa=1.0019999742507935, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0116787, standardError=0.00203801, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100106127_T_C', pValueMantissa=1.0019999742507935, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0116787, standardError=0.00203801, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100106157_C_A', pValueMantissa=2.5399999618530273, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.01442, standardError=0.00645108, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100106705_G_GGCAGAGTAA', pValueMantissa=3.0460000038146973, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0125685, standardError=0.00199613, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100107060_CG_C', pValueMantissa=1.2519999742507935, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0115965, standardError=0.00203718, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100107246_C_T', pValueMantissa=1.8339999914169312, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.148529, standardError=0.0629731, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100107759_T_C', pValueMantissa=3.5490000247955322, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00765844, standardError=0.00185209, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100107761_A_G', pValueMantissa=5.459000110626221, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.272006, standardError=0.0786791, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100108013_C_T', pValueMantissa=2.561000108718872, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0243527, standardError=0.00807438, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100108920_T_G', pValueMantissa=9.07699966430664, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.011727, standardError=0.00204049, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100109874_G_A', pValueMantissa=4.85099983215332, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0248793, standardError=0.0126104, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100110231_C_T', pValueMantissa=7.883999824523926, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0117687, standardError=0.00203931, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100110702_T_G', pValueMantissa=3.5929999351501465, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0606656, standardError=0.0289201, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100110795_TTA_T', pValueMantissa=6.190999984741211, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0118518, standardError=0.00203936, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100111161_G_A', pValueMantissa=2.000999927520752, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0497915, standardError=0.0161136, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100111179_C_T', pValueMantissa=6.201000213623047, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0118489, standardError=0.00203896, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100111991_C_A', pValueMantissa=6.7820000648498535, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0118202, standardError=0.00203929, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100112419_TA_T', pValueMantissa=5.803999900817871, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0118714, standardError=0.00203896, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100112828_C_T', pValueMantissa=2.8289999961853027, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0388309, standardError=0.0177045, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100112930_A_C', pValueMantissa=6.804999828338623, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0118191, standardError=0.0020393, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100114067_A_G', pValueMantissa=1.0110000371932983, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0104825, standardError=0.00196864, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100115072_C_T', pValueMantissa=1.034999966621399, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0104694, standardError=0.00196776, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100115087_C_T', pValueMantissa=5.876999855041504, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0118682, standardError=0.00203912, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100115453_T_C', pValueMantissa=1.0360000133514404, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0104692, standardError=0.00196776, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100116179_G_C', pValueMantissa=5.88100004196167, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0118679, standardError=0.00203913, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100116494_A_T', pValueMantissa=1.0360000133514404, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.010469, standardError=0.00196776, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100116607_C_T', pValueMantissa=1.0160000324249268, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0104762, standardError=0.00196781, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100116979_C_G', pValueMantissa=1.0180000066757202, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0104755, standardError=0.0019678, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100117013_G_A', pValueMantissa=1.0379999876022339, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0104684, standardError=0.00196777, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100118204_T_G', pValueMantissa=1.0509999990463257, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0104641, standardError=0.00196778, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100118462_G_A', pValueMantissa=5.9079999923706055, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0118664, standardError=0.00203914, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100118652_C_T', pValueMantissa=1.128999948501587, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0104375, standardError=0.00196763, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100119929_C_G', pValueMantissa=8.840999603271484, pValueExponent=-10, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0121944, standardError=0.0019896, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100120722_G_A', pValueMantissa=5.441999912261963, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0106837, standardError=0.00196527, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100121497_C_T', pValueMantissa=1.5360000133514404, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.573298, standardError=0.23652, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100124748_T_C', pValueMantissa=2.8399999141693115, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0388018, standardError=0.0177043, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100125143_C_CA', pValueMantissa=3.8269999027252197, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0260846, standardError=0.0125892, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100125152_C_A', pValueMantissa=7.866000175476074, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0105533, standardError=0.00196517, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100125180_C_T', pValueMantissa=7.633999824523926, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0105635, standardError=0.00196509, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100125779_A_G', pValueMantissa=7.78000020980835, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0105568, standardError=0.00196509, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100126618_A_C', pValueMantissa=4.631999969482422, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.133295, standardError=0.0668985, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100126748_A_G', pValueMantissa=7.800000190734863, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0105558, standardError=0.00196509, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100127494_A_T', pValueMantissa=1.8029999732971191, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0082724, standardError=0.00349777, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100128204_G_GAGAGAA', pValueMantissa=5.4019999504089355, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0107556, standardError=0.00197804, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100128221_A_G', pValueMantissa=6.446000099182129, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0106227, standardError=0.001965, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100128550_G_A', pValueMantissa=8.194000244140625, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0105396, standardError=0.00196532, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100128651_T_C', pValueMantissa=7.315000057220459, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0105796, standardError=0.00196528, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100128763_C_T', pValueMantissa=7.829999923706055, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0105544, standardError=0.00196508, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100128883_C_T', pValueMantissa=8.057000160217285, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0105443, standardError=0.00196508, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100128958_G_A', pValueMantissa=2.124000072479248, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00680841, standardError=0.00295533, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100129035_C_A', pValueMantissa=3.3989999294281006, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0925999, standardError=0.043676, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100129320_C_T', pValueMantissa=2.13100004196167, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00680465, standardError=0.00295531, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100129629_A_C', pValueMantissa=1.8580000400543213, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.148278, standardError=0.0629939, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100129660_T_C', pValueMantissa=8.699000358581543, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0115118, standardError=0.00200055, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100129776_G_A', pValueMantissa=1.690000057220459, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0884659, standardError=0.0281741, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100130207_C_T', pValueMantissa=3.569000005722046, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0140895, standardError=0.00483524, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100130573_C_G', pValueMantissa=2.9149999618530273, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00674022, standardError=0.00186053, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100130860_A_G', pValueMantissa=9.043999671936035, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0114981, standardError=0.00200046, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100131042_G_A', pValueMantissa=3.619999885559082, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.179459, standardError=0.0503203, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100131063_C_G', pValueMantissa=2.2909998893737793, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00671867, standardError=0.00295325, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100131465_G_T', pValueMantissa=8.934000015258789, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0115031, standardError=0.00200061, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100132172_C_G', pValueMantissa=2.128000020980835, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00680593, standardError=0.00295533, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100132602_T_TTAAA', pValueMantissa=4.828000068664551, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00431663, standardError=0.00218576, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100132602_T_TTAAATAAA', pValueMantissa=4.5980000495910645, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0519863, standardError=0.0260513, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100132602_TTAAATAAATAAA_T', pValueMantissa=7.363999843597412, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0116156, standardError=0.00200877, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100133539_G_T', pValueMantissa=2.6610000133514404, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00678474, standardError=0.00186073, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100133661_G_A', pValueMantissa=2.6619999408721924, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00678444, standardError=0.00186073, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100134226_T_TAAAC', pValueMantissa=9.397000312805176, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0114918, standardError=0.00200162, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100134368_G_T', pValueMantissa=2.305999994277954, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00685323, standardError=0.0018608, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100134849_C_G', pValueMantissa=2.5420000553131104, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00680611, standardError=0.00186063, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100136849_G_A', pValueMantissa=2.4240000247955322, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00682879, standardError=0.00186061, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100137626_G_C', pValueMantissa=4.564000129699707, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.133964, standardError=0.067025, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100139939_C_T', pValueMantissa=2.2850000858306885, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0168361, standardError=0.00739727, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100140109_A_G', pValueMantissa=8.161999702453613, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0116036, standardError=0.00201274, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100140433_T_C', pValueMantissa=8.460000038146973, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00745523, standardError=0.00283129, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100140822_C_T', pValueMantissa=4.0370001792907715, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00653853, standardError=0.00184827, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100140993_C_T', pValueMantissa=8.553999900817871, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00744479, standardError=0.00283137, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100141769_G_C', pValueMantissa=4.497000217437744, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.134653, standardError=0.0671606, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100142018_C_T', pValueMantissa=8.651000022888184, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00615783, standardError=0.00184859, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100142970_A_T', pValueMantissa=3.749000072479248, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0279115, standardError=0.00962947, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100143128_C_A', pValueMantissa=2.7290000915527344, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0151084, standardError=0.0050416, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100143200_T_G', pValueMantissa=8.8100004196167, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00751992, standardError=0.00191775, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100143201_T_C', pValueMantissa=8.812999725341797, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00751979, standardError=0.00191775, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100143322_A_G', pValueMantissa=8.62600040435791, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0074353, standardError=0.00283084, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100143412_T_C', pValueMantissa=3.306999921798706, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0244099, standardError=0.00588015, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100143655_T_C', pValueMantissa=5.8420000076293945, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0063633, standardError=0.00185041, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100144149_T_G', pValueMantissa=5.2210001945495605, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0106098, standardError=0.00194903, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100144392_A_ACGTG', pValueMantissa=1.059999942779541, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0122106, standardError=0.00200172, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100144587_G_A', pValueMantissa=4.710000038146973, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0106442, standardError=0.00194881, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100144738_C_T', pValueMantissa=3.628999948501587, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00387717, standardError=0.00185181, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100145180_CA_C', pValueMantissa=7.709000110626221, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00754349, standardError=0.00283104, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100145446_T_C', pValueMantissa=4.289000034332275, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00722839, standardError=0.0025309, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100145462_G_A', pValueMantissa=1.184999942779541, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00704211, standardError=0.00279842, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100145533_C_T', pValueMantissa=6.809999942779541, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0688508, standardError=0.0254439, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100145864_T_C', pValueMantissa=2.5959999561309814, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00556169, standardError=0.00184654, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100146576_G_A', pValueMantissa=2.239000082015991, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0102862, standardError=0.0027873, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100147206_C_G', pValueMantissa=2.24399995803833, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0102847, standardError=0.00278728, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100148436_A_G', pValueMantissa=7.232999801635742, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.01072, standardError=0.00317104, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100148745_A_G', pValueMantissa=9.111000061035156, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.011124, standardError=0.00335401, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100150256_TG_T', pValueMantissa=1.621000051498413, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0058237, standardError=0.00184761, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100151385_A_G', pValueMantissa=2.200000047683716, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0102977, standardError=0.002787, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100151760_T_G', pValueMantissa=1.680999994277954, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0116223, standardError=0.00369954, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100151918_T_C', pValueMantissa=1.305999994277954, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.01191, standardError=0.00370485, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100152307_T_C', pValueMantissa=9.949999809265137, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0108402, standardError=0.00189131, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100152437_C_T', pValueMantissa=1.0140000581741333, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0108394, standardError=0.00189222, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100153963_AT_A', pValueMantissa=3.984999895095825, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00551895, standardError=0.00191674, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100155294_C_T', pValueMantissa=5.695000171661377, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0370698, standardError=0.0134074, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100155300_C_A', pValueMantissa=3.9560000896453857, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.013611, standardError=0.0066127, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100155337_G_C', pValueMantissa=9.121999740600586, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0129497, standardError=0.00390489, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100155409_G_C', pValueMantissa=1.305999994277954, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.01191, standardError=0.00370485, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100155608_A_G', pValueMantissa=2.359999895095825, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0102538, standardError=0.00278865, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100157105_C_T', pValueMantissa=1.9290000200271606, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0114702, standardError=0.00369896, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100157116_T_A', pValueMantissa=1.4279999732971191, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00588326, standardError=0.00184495, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100157609_G_A', pValueMantissa=2.1989998817443848, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0103034, standardError=0.00278846, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100157763_C_T', pValueMantissa=3.859999895095825, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00711467, standardError=0.00343966, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100158037_G_A', pValueMantissa=4.420000076293945, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0259169, standardError=0.00910471, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100158360_A_G', pValueMantissa=1.7910000085830688, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0115545, standardError=0.0037, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100158691_C_T', pValueMantissa=6.251999855041504, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0131114, standardError=0.00327532, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100159080_T_C', pValueMantissa=8.289999961853027, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0343476, standardError=0.0102747, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100159144_G_A', pValueMantissa=1.3380000591278076, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00857697, standardError=0.00346768, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100159600_GAAATCAACAATAA_G', pValueMantissa=1.7860000133514404, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0115575, standardError=0.0037, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100159706_T_TTTAAA', pValueMantissa=2.239000082015991, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0102922, standardError=0.00278886, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100161011_T_C', pValueMantissa=1.305999994277954, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.01191, standardError=0.00370485, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100161641_G_T', pValueMantissa=1.305999994277954, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.01191, standardError=0.00370485, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100162586_C_T', pValueMantissa=1.5570000410079956, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0117095, standardError=0.00370097, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100162599_A_G', pValueMantissa=1.7910000085830688, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0115545, standardError=0.0037, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100164449_A_T', pValueMantissa=8.289999961853027, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0343476, standardError=0.0102747, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100164555_T_C', pValueMantissa=1.8140000104904175, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0162269, standardError=0.00686797, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100164661_T_C', pValueMantissa=1.065000057220459, pValueExponent=-8, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0108199, standardError=0.00189161, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100166335_G_A', pValueMantissa=1.569000005722046, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.011701, standardError=0.00370099, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100167234_TA_T', pValueMantissa=1.9529999494552612, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0114517, standardError=0.00369739, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100167290_A_G', pValueMantissa=1.9539999961853027, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0114514, standardError=0.00369739, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100167685_C_T', pValueMantissa=3.9630000591278076, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0526946, standardError=0.0256104, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100167711_G_A', pValueMantissa=1.3270000219345093, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.011893, standardError=0.00370488, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100168884_G_A', pValueMantissa=1.815000057220459, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.01154, standardError=0.00370004, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100169073_T_A', pValueMantissa=1.659000039100647, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0164986, standardError=0.00688708, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100170367_T_A', pValueMantissa=1.8220000267028809, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0115361, standardError=0.00370004, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100170447_T_C', pValueMantissa=1.8200000524520874, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.011537, standardError=0.00370004, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100170652_A_G', pValueMantissa=8.133000373840332, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0162704, standardError=0.00614785, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100170743_T_C', pValueMantissa=1.819000005722046, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0115379, standardError=0.00370004, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100171278_T_G', pValueMantissa=1.965999960899353, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0114445, standardError=0.00369739, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100171408_C_CTATT', pValueMantissa=1.8220000267028809, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0115357, standardError=0.00370003, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100171892_C_A', pValueMantissa=4.783999919891357, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0290312, standardError=0.0146713, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100171937_A_T', pValueMantissa=3.7090001106262207, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0264529, standardError=0.0126887, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100172580_C_A', pValueMantissa=1.8209999799728394, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0115368, standardError=0.00370004, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100172766_C_T', pValueMantissa=1.3320000171661377, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0118891, standardError=0.00370488, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100173406_G_C', pValueMantissa=3.993000030517578, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0276948, standardError=0.00962055, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100173454_A_G', pValueMantissa=1.8220000267028809, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.011536, standardError=0.00370004, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100174322_A_AT', pValueMantissa=1.9670000076293945, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0114438, standardError=0.00369738, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100174478_C_T', pValueMantissa=5.164999961853027, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0114058, standardError=0.00195247, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100175179_A_G', pValueMantissa=1.968000054359436, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0114433, standardError=0.00369738, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100175211_T_C', pValueMantissa=9.72700023651123, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0910994, standardError=0.02762, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100175305_C_T', pValueMantissa=1.8240000009536743, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.011535, standardError=0.00370003, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100175350_T_C', pValueMantissa=1.8240000009536743, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.011535, standardError=0.00370003, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100176550_CAAAAGACCGTTTTTA_C', pValueMantissa=1.8869999647140503, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0115298, standardError=0.00371041, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100177021_C_G', pValueMantissa=1.8309999704360962, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0115307, standardError=0.00370003, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100177437_T_C', pValueMantissa=4.168000221252441, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00536168, standardError=0.00187135, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100177850_C_T', pValueMantissa=7.14300012588501, pValueExponent=-5, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0216516, standardError=0.00545178, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100178264_G_A', pValueMantissa=1.8339999914169312, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.011529, standardError=0.00370002, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100178377_T_A', pValueMantissa=3.9769999980926514, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0277079, standardError=0.00962096, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100178824_A_C', pValueMantissa=1.1480000019073486, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0273359, standardError=0.0108138, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100178873_G_C', pValueMantissa=3.313999891281128, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00845972, standardError=0.00288043, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100178957_A_G', pValueMantissa=1.8370000123977661, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.011527, standardError=0.00370001, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100181244_T_A', pValueMantissa=9.291000366210938, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0116765, standardError=0.00352639, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100182158_GT_G', pValueMantissa=1.440999984741211, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0118051, standardError=0.00370502, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100182496_T_C', pValueMantissa=2.2899999618530273, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0102733, standardError=0.00278807, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100182799_A_G', pValueMantissa=2.365000009536743, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0102471, standardError=0.00278728, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100183196_T_C', pValueMantissa=1.8519999980926514, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.011518, standardError=0.00369996, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100183255_G_A', pValueMantissa=1.3580000400543213, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0118679, standardError=0.0037048, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100183966_G_A', pValueMantissa=1.8609999418258667, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0115126, standardError=0.00369993, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100184256_T_C', pValueMantissa=4.7220001220703125, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.029124, standardError=0.0146772, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100184474_G_A', pValueMantissa=3.7109999656677246, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00543283, standardError=0.00187227, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100184568_G_A', pValueMantissa=2.1500000953674316, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0103173, standardError=0.00278792, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100186257_C_G', pValueMantissa=1.2259999513626099, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00596993, standardError=0.00184663, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100186688_C_T', pValueMantissa=1.9229999780654907, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0114751, standardError=0.00369939, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100187980_C_T', pValueMantissa=4.630000114440918, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00813035, standardError=0.00287118, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100189674_T_G', pValueMantissa=9.279999732971191, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.126539, standardError=0.0486397, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100190351_G_A', pValueMantissa=4.619999885559082, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00813223, standardError=0.00287113, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100190395_G_A', pValueMantissa=2.0, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0760922, standardError=0.024623, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100192759_T_C', pValueMantissa=1.9559999704360962, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0114555, standardError=0.00369915, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100193524_C_T', pValueMantissa=9.555000305175781, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0122529, standardError=0.0037093, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100193948_A_C', pValueMantissa=3.0179998874664307, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0115477, standardError=0.00194714, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100195245_A_T', pValueMantissa=4.635000228881836, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0081285, standardError=0.00287091, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100195684_C_CA', pValueMantissa=4.2270002365112305, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.137066, standardError=0.0674911, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100195855_G_A', pValueMantissa=4.870999813079834, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00807719, standardError=0.00286889, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100197192_T_C', pValueMantissa=4.242000102996826, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.136954, standardError=0.067486, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100197458_C_A', pValueMantissa=4.629000186920166, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00812979, standardError=0.00287088, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100197612_C_G', pValueMantissa=4.498000144958496, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00815595, standardError=0.00287088, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100197640_T_C', pValueMantissa=1.965000033378601, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0114501, standardError=0.00369901, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100197675_G_A', pValueMantissa=2.75600004196167, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0386379, standardError=0.0175348, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100197920_A_G', pValueMantissa=2.384999990463257, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0167093, standardError=0.00739523, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100198475_T_C', pValueMantissa=1.9639999866485596, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0114509, standardError=0.00369901, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100199282_C_G', pValueMantissa=1.1059999465942383, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0127328, standardError=0.00390313, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100199476_G_A', pValueMantissa=1.319000005722046, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0118973, standardError=0.00370432, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100200167_G_A', pValueMantissa=3.1589999198913574, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0376207, standardError=0.012745, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100201209_C_T', pValueMantissa=1.097000002861023, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00602792, standardError=0.0018465, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100201414_G_A', pValueMantissa=4.788000106811523, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0068162, standardError=0.00344526, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100201633_T_A', pValueMantissa=1.3179999589920044, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0118983, standardError=0.00370432, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100202455_T_C', pValueMantissa=1.9600000381469727, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0114531, standardError=0.00369901, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100202467_G_A', pValueMantissa=3.875999927520752, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0277856, standardError=0.00962082, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100202772_A_T', pValueMantissa=1.9600000381469727, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0114531, standardError=0.00369901, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100203494_T_C', pValueMantissa=1.9589999914169312, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0114534, standardError=0.00369901, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100203542_G_T', pValueMantissa=1.6130000352859497, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00697446, standardError=0.00184854, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100203788_C_A', pValueMantissa=4.110000133514404, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.113144, standardError=0.0394286, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100204779_C_A', pValueMantissa=4.3379998207092285, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0101425, standardError=0.00502088, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100205801_A_G', pValueMantissa=4.5329999923706055, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00814881, standardError=0.00287085, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100206194_A_T', pValueMantissa=1.9570000171661377, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0114546, standardError=0.003699, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100206333_A_G', pValueMantissa=4.160999774932861, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0263098, standardError=0.0129133, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100206660_A_G', pValueMantissa=2.4539999961853027, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.113651, standardError=0.0505422, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100206733_C_T', pValueMantissa=1.315999984741211, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0119003, standardError=0.00370432, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100207009_TA_T', pValueMantissa=1.9559999704360962, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0114549, standardError=0.003699, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100207455_C_G', pValueMantissa=1.305999994277954, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00593547, standardError=0.00184639, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100207653_G_A', pValueMantissa=3.6470000743865967, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0114874, standardError=0.00194719, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100207898_CAAGTT_C', pValueMantissa=3.384999990463257, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0921644, standardError=0.0434369, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100208164_G_C', pValueMantissa=3.874000072479248, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0277875, standardError=0.0096208, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100209200_T_C', pValueMantissa=1.315000057220459, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0119009, standardError=0.00370431, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100210277_C_T', pValueMantissa=1.3040000200271606, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0119097, standardError=0.00370434, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100211064_G_A', pValueMantissa=1.9550000429153442, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0114558, standardError=0.003699, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100211240_A_G', pValueMantissa=7.230000019073486, pValueExponent=-7, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00932586, standardError=0.00188208, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100212531_T_C', pValueMantissa=3.874000072479248, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0277872, standardError=0.00962078, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100212621_T_C', pValueMantissa=1.6109999418258667, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00697491, standardError=0.00184852, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100213072_C_T', pValueMantissa=1.9529999494552612, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0114567, standardError=0.003699, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100213340_T_C', pValueMantissa=1.6119999885559082, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00697479, standardError=0.00184851, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100213631_T_C', pValueMantissa=1.6119999885559082, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00697476, standardError=0.00184851, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100214977_G_T', pValueMantissa=4.242000102996826, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.136966, standardError=0.0674913, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100215512_G_A', pValueMantissa=4.473999977111816, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00816059, standardError=0.0028708, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100215525_C_CA', pValueMantissa=1.9509999752044678, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0114578, standardError=0.003699, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100215535_T_A', pValueMantissa=9.406000137329102, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0122847, standardError=0.00371395, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100215669_A_G', pValueMantissa=1.9509999752044678, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.011458, standardError=0.003699, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100216129_G_T', pValueMantissa=1.312000036239624, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0119034, standardError=0.00370431, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100216744_G_C', pValueMantissa=2.9519999027252197, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0115543, standardError=0.00194705, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100217073_T_TCATA', pValueMantissa=4.507999897003174, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00815394, standardError=0.00287084, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100218126_C_T', pValueMantissa=1.055999994277954, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00604851, standardError=0.00184672, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100218867_A_G', pValueMantissa=3.3550000190734863, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.205837, standardError=0.0968422, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100218929_A_C', pValueMantissa=1.9490000009536743, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.011459, standardError=0.003699, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100219439_G_A', pValueMantissa=1.3109999895095825, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0119039, standardError=0.00370431, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100219496_T_C', pValueMantissa=1.9490000009536743, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.011459, standardError=0.003699, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100219653_G_A', pValueMantissa=8.52400016784668, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0210222, standardError=0.00799145, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100219661_T_C', pValueMantissa=7.915999889373779, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0163115, standardError=0.00614227, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100220164_T_C', pValueMantissa=1.3109999895095825, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0119039, standardError=0.00370431, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100220814_T_TA', pValueMantissa=4.504000186920166, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00815468, standardError=0.00287084, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100220831_C_A', pValueMantissa=4.275000095367432, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.136751, standardError=0.0674941, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100221396_C_T', pValueMantissa=2.944000005722046, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0115551, standardError=0.00194705, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100221486_T_G', pValueMantissa=1.3890000581741333, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0160699, standardError=0.00653242, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100221517_C_A', pValueMantissa=2.5439999103546143, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00413576, standardError=0.00185074, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100221594_C_G', pValueMantissa=2.0799999237060547, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0779801, standardError=0.0337333, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100223656_G_A', pValueMantissa=3.621000051498413, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0114895, standardError=0.00194717, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100223788_T_C', pValueMantissa=1.3109999895095825, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0119039, standardError=0.00370431, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100224059_G_A', pValueMantissa=3.621000051498413, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0114895, standardError=0.00194717, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100224086_A_ACT', pValueMantissa=1.0759999752044678, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00473991, standardError=0.00185855, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100224086_A_ACTCTCTCT', pValueMantissa=9.140999794006348, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0123865, standardError=0.00373569, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100224729_G_A', pValueMantissa=9.512999534606934, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0122608, standardError=0.00371028, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100224788_C_T', pValueMantissa=4.552000045776367, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00814496, standardError=0.00287083, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100224846_CA_C', pValueMantissa=4.505000114440918, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00815457, standardError=0.00287084, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100225330_C_T', pValueMantissa=4.679999828338623, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00811972, standardError=0.0028709, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100225460_G_A', pValueMantissa=1.4520000219345093, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0138989, standardError=0.00568655, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100227298_T_G', pValueMantissa=4.505000114440918, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00815457, standardError=0.00287084, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100227436_A_C', pValueMantissa=2.1089999675750732, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0204774, standardError=0.00887858, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100227710_T_C', pValueMantissa=2.624000072479248, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0115932, standardError=0.00194728, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100228161_T_C', pValueMantissa=1.1180000305175781, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0127208, standardError=0.00390316, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100228188_C_G', pValueMantissa=1.3109999895095825, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0119039, standardError=0.00370431, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100228581_G_GGGA', pValueMantissa=1.9490000009536743, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.011459, standardError=0.003699, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100228620_A_G', pValueMantissa=1.9490000009536743, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.011459, standardError=0.003699, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100229692_G_T', pValueMantissa=1.9490000009536743, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.011459, standardError=0.003699, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100229731_G_C', pValueMantissa=4.275000095367432, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.136751, standardError=0.0674941, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100230118_T_C', pValueMantissa=1.9490000009536743, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.011459, standardError=0.003699, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100230958_C_A', pValueMantissa=3.694000005722046, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0264656, standardError=0.0126847, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100231193_T_TTTG', pValueMantissa=2.11299991607666, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0113217, standardError=0.00368321, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100231368_T_A', pValueMantissa=1.9490000009536743, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.011459, standardError=0.003699, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100231561_G_GT', pValueMantissa=4.546000003814697, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00815129, standardError=0.00287266, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100231791_G_C', pValueMantissa=1.3109999895095825, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0119039, standardError=0.00370431, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100233804_CAG_C', pValueMantissa=3.674999952316284, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0114848, standardError=0.00194718, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100235720_T_G', pValueMantissa=4.255000114440918, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0683751, standardError=0.0337137, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100236254_A_G', pValueMantissa=1.8240000009536743, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.621107, standardError=0.263096, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100236529_C_T', pValueMantissa=1.5670000314712524, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00698791, standardError=0.00184852, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100236538_A_G', pValueMantissa=1.5640000104904175, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00698861, standardError=0.00184852, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100236603_C_T', pValueMantissa=3.1489999294281006, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0115356, standardError=0.00194738, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100237030_C_T', pValueMantissa=1.3109999895095825, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0119039, standardError=0.00370431, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100237733_G_A', pValueMantissa=4.505000114440918, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00815457, standardError=0.00287084, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100237772_G_A', pValueMantissa=9.51200008392334, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0122572, standardError=0.00370917, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100237893_A_T', pValueMantissa=4.275000095367432, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.136751, standardError=0.0674941, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100238295_A_G', pValueMantissa=4.505000114440918, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00815457, standardError=0.00287084, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100238581_A_G', pValueMantissa=6.859000205993652, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0255013, standardError=0.00751108, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100238657_T_C', pValueMantissa=2.809000015258789, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.01157, standardError=0.00194702, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100239610_G_T', pValueMantissa=1.9490000009536743, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.011459, standardError=0.003699, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100239637_A_G', pValueMantissa=1.1369999647140503, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00600877, standardError=0.00184638, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100239850_T_C', pValueMantissa=1.9490000009536743, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.011459, standardError=0.003699, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100239989_G_A', pValueMantissa=3.2009999752044678, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.011529, standardError=0.00194715, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100240726_T_G', pValueMantissa=4.000999927520752, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0525952, standardError=0.0256104, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100240944_C_T', pValueMantissa=2.8889999389648438, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0115616, standardError=0.00194713, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100242014_C_T', pValueMantissa=4.505000114440918, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00815457, standardError=0.00287084, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100242478_A_G', pValueMantissa=9.51200008392334, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0122572, standardError=0.00370917, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100242630_C_T', pValueMantissa=1.253999948501587, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.011921, standardError=0.00369498, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100242920_TGA_T', pValueMantissa=4.275000095367432, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.136751, standardError=0.0674941, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100243390_G_A', pValueMantissa=8.79800033569336, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0252612, standardError=0.00439142, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100244149_G_C', pValueMantissa=3.316999912261963, pValueExponent=-9, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.011525, standardError=0.0019484, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100244398_T_C', pValueMantissa=3.694000005722046, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00834099, standardError=0.00287304, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100244540_A_G', pValueMantissa=1.8240000009536743, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.621107, standardError=0.263096, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100244650_T_C', pValueMantissa=1.8240000009536743, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.621107, standardError=0.263096, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100244773_C_G', pValueMantissa=1.8240000009536743, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.621107, standardError=0.263096, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100244991_G_C', pValueMantissa=1.8240000009536743, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.621107, standardError=0.263096, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100245546_T_C', pValueMantissa=1.472000002861023, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0117796, standardError=0.00370405, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100245863_C_T', pValueMantissa=1.472000002861023, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0117796, standardError=0.00370405, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100246645_C_T', pValueMantissa=3.694000005722046, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00834099, standardError=0.00287304, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100246672_T_C', pValueMantissa=1.1399999856948853, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00600727, standardError=0.00184638, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100246924_C_T', pValueMantissa=3.4030001163482666, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0281666, standardError=0.00961714, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100247616_T_C', pValueMantissa=3.694000005722046, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00834089, standardError=0.00287304, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100248412_C_G', pValueMantissa=1.4470000267028809, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00702484, standardError=0.00184863, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100248726_A_G', pValueMantissa=3.694999933242798, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00834082, standardError=0.00287304, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100249239_A_C', pValueMantissa=2.0339999198913574, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0353474, standardError=0.0152353, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100249267_A_T', pValueMantissa=1.472000002861023, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0117796, standardError=0.00370405, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100249476_T_TC', pValueMantissa=3.694999933242798, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00834082, standardError=0.00287304, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100249705_T_C', pValueMantissa=1.472000002861023, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0117796, standardError=0.00370405, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100250941_T_C', pValueMantissa=1.8240000009536743, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.621107, standardError=0.263096, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100250976_T_A', pValueMantissa=6.709000110626221, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0690304, standardError=0.0254633, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100251390_T_A', pValueMantissa=2.9049999713897705, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0055723, standardError=0.00187139, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100251454_A_G', pValueMantissa=1.1790000200271606, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00712036, standardError=0.00184919, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100251790_C_T', pValueMantissa=3.497999906539917, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00593413, standardError=0.00281426, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100252662_G_A', pValueMantissa=1.5770000219345093, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.011701, standardError=0.00370274, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100252768_G_A', pValueMantissa=1.5770000219345093, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.011701, standardError=0.00370274, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100252920_T_G', pValueMantissa=1.5770000219345093, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.011701, standardError=0.00370274, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100254207_CCAGA_C', pValueMantissa=3.382999897003174, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0921782, standardError=0.0434383, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100254700_T_C', pValueMantissa=1.3079999685287476, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.0884636, standardError=0.0275222, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100254749_C_A', pValueMantissa=3.940999984741211, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00710422, standardError=0.00344885, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100255058_C_G', pValueMantissa=1.3109999895095825, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0119039, standardError=0.00370431, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100255162_C_T', pValueMantissa=3.9679999351501465, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00827516, standardError=0.00287265, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100256000_C_A', pValueMantissa=1.5770000219345093, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.011701, standardError=0.00370274, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100256287_C_T', pValueMantissa=4.053999900817871, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00825485, standardError=0.00287235, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100256511_G_A', pValueMantissa=1.0700000524520874, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00604016, standardError=0.00184634, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100257612_C_T', pValueMantissa=1.9170000553131104, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0082026, standardError=0.00350204, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100258083_A_G', pValueMantissa=2.7039999961853027, pValueExponent=-2, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0635849, standardError=0.0287601, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100258094_C_T', pValueMantissa=1.5770000219345093, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.011701, standardError=0.00370274, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100258332_C_T', pValueMantissa=3.9760000705718994, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0082729, standardError=0.00287251, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100260000_A_G', pValueMantissa=1.6239999532699585, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0116706, standardError=0.00370306, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100260586_A_G', pValueMantissa=3.8919999599456787, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.00829222, standardError=0.00287251, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100260869_C_T', pValueMantissa=4.205999851226807, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0082302, standardError=0.00287541, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100262992_C_T', pValueMantissa=1.5770000219345093, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.011701, standardError=0.00370274, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100263055_G_C', pValueMantissa=1.3109999895095825, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.0119039, standardError=0.00370431, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100263140_C_T', pValueMantissa=1.5770000219345093, pValueExponent=-3, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=0.011701, standardError=0.00370274, betaConditioned=None, standardErrorConditioned=None, r2Overall=None), Row(is95CredibleSet=None, is99CredibleSet=None, logABF=None, posteriorProbability=None, variantId='10_100263249_C_T', pValueMantissa=1.1790000200271606, pValueExponent=-4, pValueMantissaConditioned=None, pValueExponentConditioned=None, beta=-0.00711917, standardError=0.00184892, betaConditioned=None, standardErrorConditioned=None, r2Overall=None)], size=1001)]" + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" } + ], + "source": [ + "window_based_clumped_output = \"gs://ot-team/dsuveges/finngen/2023.10.13_window_clumped_w_locus\"\n", + "\n", + "(\n", + " session.spark.read.parquet(ld_clumped_output)\n", + " .filter(f.size(f.col(\"qualityControls\")) == 0)\n", + "# .show(1, False, True)\n", + " .select(\"locus\", f.size(f.col(\"locus\")).alias(\"size\"))\n", + " .limit(1)\n", + " .collect()\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e242acdd", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "gist": { + "data": { + "description": "GCS/dsuveges/PICS/2023.10.06 - PICS FINNGEN from top to bottom.ipynb", + "public": false + }, + "id": "" + }, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" }, - "nbformat": 4, - "nbformat_minor": 5 + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.8" + } + }, + "nbformat": 4, + "nbformat_minor": 5 } diff --git a/notebooks/Mapping_EFO_finngen.ipynb b/notebooks/Mapping_EFO_finngen.ipynb index 594a4f0ad..1feaf890c 100644 --- a/notebooks/Mapping_EFO_finngen.ipynb +++ b/notebooks/Mapping_EFO_finngen.ipynb @@ -109,15 +109,15 @@ ], "source": [ "import os\n", + "\n", "import hail as hl\n", - "import pyspark.sql.functions as f\n", "import pandas as pd\n", - "pd.set_option('display.max_colwidth', None)\n", - "pd.set_option('display.expand_frame_repr', False)\n", "\n", "from gentropy.common.session import Session\n", "from gentropy.dataset.study_index import StudyIndex\n", "\n", + "pd.set_option(\"display.max_colwidth\", None)\n", + "pd.set_option(\"display.expand_frame_repr\", False)\n", "\n", "hail_dir = os.path.dirname(hl.__file__)\n", "session = Session(hail_home=hail_dir, start_hail=True, extended_spark_conf={\"spark.driver.memory\": \"12g\",\n", @@ -228,10 +228,7 @@ ] } ], - "source": [ - "print(si_old.count())\n", - "print(si_new_df.count())" - ] + "source": [] }, { "cell_type": "code", @@ -297,8 +294,8 @@ } ], "source": [ - "si_old = si_old.dropDuplicates(['trait_reported_low'])\n", - "joined_df = si_new_df.join(si_old, \"trait_reported_low\", how='left')\n", + "si_old = si_old.dropDuplicates([\"trait_reported_low\"])\n", + "joined_df = si_new_df.join(si_old, \"trait_reported_low\", how=\"left\")\n", "joined_df.count()" ] }, @@ -379,8 +376,7 @@ } ], "source": [ - "num_non_null_rows = joined_df.filter(joined_df.trait_efos.isNotNull()).count()\n", - "print(num_non_null_rows)" + "num_non_null_rows = joined_df.filter(joined_df.trait_efos.isNotNull()).count()" ] }, { @@ -529,8 +525,7 @@ } ], "source": [ - "column_type = dict(joined_df.dtypes)[\"traitFromSourceMappedIds\"]\n", - "print(column_type)" + "column_type = dict(joined_df.dtypes)[\"traitFromSourceMappedIds\"]" ] }, { @@ -619,8 +614,7 @@ } ], "source": [ - "column_type = dict(joined_df.dtypes)[\"traitFromSourceMappedIds\"]\n", - "print(column_type)" + "column_type = dict(joined_df.dtypes)[\"traitFromSourceMappedIds\"]" ] }, { diff --git a/notebooks/Productionizing_LD_matrix.ipynb b/notebooks/Productionizing_LD_matrix.ipynb deleted file mode 100644 index d02f7c8fb..000000000 --- a/notebooks/Productionizing_LD_matrix.ipynb +++ /dev/null @@ -1,1504 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "baf71347", - "metadata": {}, - "source": [ - "# Extracting square sub-matrices from reference\n", - "\n", - "\n", - "### Conceptual considerations:\n", - "\n", - "```\n", - "Summary statistics\n", - "↓\n", - "[window based clumping]\n", - "[ld based clumping]\n", - "↓\n", - "StudyLocus\n", - "↓\n", - "[ld matrix extraction] <- StudyIndex (studyId, ldPopulations), ldIndex, ldMatrix\n", - "↓\n", - "\n", - "```\n", - "\n", - "\n", - "- Assume we have only one ancestry" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "d75ac655", - "metadata": { - "ExecuteTime": { - "end_time": "2023-10-25T11:18:41.257715Z", - "start_time": "2023-10-25T11:18:14.728571Z" - } - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "SLF4J: No SLF4J providers were found.\n", - "SLF4J: Defaulting to no-operation (NOP) logger implementation\n", - "SLF4J: See https://www.slf4j.org/codes.html#noProviders for further details.\n", - "SLF4J: Class path contains SLF4J bindings targeting slf4j-api versions 1.7.x or earlier.\n", - "SLF4J: Ignoring binding found at [jar:file:/usr/lib/spark/jars/log4j-slf4j-impl-2.18.0.jar!/org/slf4j/impl/StaticLoggerBinder.class]\n", - "SLF4J: See https://www.slf4j.org/codes.html#ignoredBindings for an explanation.\n", - "Setting default log level to \"WARN\".\n", - "To adjust logging level use sc.setLogLevel(newLevel). For SparkR, use setLogLevel(newLevel).\n", - "pip-installed Hail requires additional configuration options in Spark referring\n", - " to the path to the Hail Python module directory HAIL_DIR,\n", - " e.g. /path/to/python/site-packages/hail:\n", - " spark.jars=HAIL_DIR/backend/hail-all-spark.jar\n", - " spark.driver.extraClassPath=HAIL_DIR/backend/hail-all-spark.jar\n", - " spark.executor.extraClassPath=./hail-all-spark.jarRunning on Apache Spark version 3.3.0\n", - "SparkUI available at http://ds-genetics-etl-test-m.c.open-targets-eu-dev.internal:37397\n", - "Welcome to\n", - " __ __ <>__\n", - " / /_/ /__ __/ /\n", - " / __ / _ `/ / /\n", - " /_/ /_/\\_,_/_/_/ version 0.2.122-be9d88a80695\n", - "LOGGING: writing to /dev/null\n" - ] - } - ], - "source": [ - "from gentropy.common.session import Session\n", - "from gentropy.dataset.study_locus import StudyLocus\n", - "from gentropy.dataset.study_index import StudyIndex\n", - "from gentropy.datasource.gnomad.ld import GnomADLDMatrix\n", - "from gentropy.datasource.finngen.study_index import FinnGenStudyIndex\n", - "\n", - "import hail as hl\n", - "from hail.linalg import BlockMatrix\n", - "\n", - "from pyspark.sql import Window\n", - "import pyspark.sql.functions as f\n", - "from pyspark.sql import Column, DataFrame\n", - "\n", - "from urllib.request import urlopen\n", - "\n", - "\n", - "session = Session(hail_home='/opt/conda/miniconda3/lib/python3.10/site-packages/hail', start_hail=True)\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "id": "9eac3419", - "metadata": {}, - "source": [ - "## Generate FINNGEN Study table\n", - "\n", - "- Executed in 2.22s\n", - "- Building a Finngen study table from source." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "51b4cd9c", - "metadata": { - "ExecuteTime": { - "end_time": "2023-10-25T11:19:13.439965Z", - "start_time": "2023-10-25T11:19:11.603603Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "-RECORD 0--------------------------------------------------------------------------------------------------------------------\n", - " studyId | FINNGEN_R9_AB1_ACTINOMYCOSIS \n", - " traitFromSource | Actinomycosis \n", - " nCases | 93 \n", - " nControls | 332343 \n", - " nSamples | 332436 \n", - " projectId | FINNGEN_R9 \n", - " studyType | gwas \n", - " hasSumstats | true \n", - " initialSampleSize | 377,277 (210,870 females and 166,407 males) \n", - " discoverySamples | [{377277, Finnish}] \n", - " summarystatsLocation | https://storage.googleapis.com/finngen-public-data-r9/summary_stats/finngen_R9_AB1_ACTINOMYCOSIS.gz \n", - " ldPopulationStructure | [{fin, 1.0}] \n", - "only showing top 1 row\n", - "\n", - "+--------------------+------------+\n", - "| studyId|ldPopulation|\n", - "+--------------------+------------+\n", - "|FINNGEN_R9_ASTHMA...| fin|\n", - "|FINNGEN_R9_E4_PIT...| fin|\n", - "|FINNGEN_R9_E4_VIT...| fin|\n", - "|FINNGEN_R9_H8_MID...| fin|\n", - "|FINNGEN_R9_L12_PI...| fin|\n", - "|FINNGEN_R9_M13_HA...| fin|\n", - "|FINNGEN_R9_M13_SP...| fin|\n", - "|FINNGEN_R9_Q17_LV...| fin|\n", - "|FINNGEN_R9_ALCOHO...| fin|\n", - "|FINNGEN_R9_CHRONL...| fin|\n", - "|FINNGEN_R9_C_DIFF...| fin|\n", - "|FINNGEN_R9_E4_OBE...| fin|\n", - "|FINNGEN_R9_GOUT_S...| fin|\n", - "|FINNGEN_R9_I9_LYM...| fin|\n", - "|FINNGEN_R9_I9_VAR...| fin|\n", - "|FINNGEN_R9_J10_CH...| fin|\n", - "|FINNGEN_R9_K11_HY...| fin|\n", - "|FINNGEN_R9_K11_RE...| fin|\n", - "|FINNGEN_R9_M13_OS...| fin|\n", - "|FINNGEN_R9_O15_PR...| fin|\n", - "+--------------------+------------+\n", - "only showing top 20 rows\n", - "\n" - ] - } - ], - "source": [ - "# Processing studies:\n", - "def update_population(ld_pop: Column) -> Column:\n", - " return f.when(\n", - " f.size(ld_pop) == 1,\n", - " ld_pop.getItem(0).ldPopulation\n", - " )\n", - "\n", - "\n", - "# Read the JSON data from the URL.\n", - "json_data = urlopen('https://r9.finngen.fi/api/phenos').read().decode(\"utf-8\")\n", - "rdd = session.spark.sparkContext.parallelize([json_data])\n", - "df = session.spark.read.json(rdd)\n", - "\n", - "\n", - "finngen_release_prefix = 'FINNGEN_R9'\n", - "finngen_summary_stats_url_prefix = 'https://storage.googleapis.com/finngen-public-data-r9/summary_stats/finngen_R9_'\n", - "finngen_summary_stats_url_suffix = '.gz'\n", - "\n", - "# Parse the study index data.\n", - "studies = FinnGenStudyIndex.from_source(\n", - " df, \n", - " finngen_release_prefix, \n", - " finngen_summary_stats_url_prefix, \n", - " finngen_summary_stats_url_suffix\n", - ")\n", - "\n", - "studies.df.show(1, False, True)\n", - "\n", - "# From the study table we only need study identifier and the ld population\n", - "# We only need ld population if the study is based on single ancestry.\n", - "studies = (\n", - " studies.df\n", - " .select(\n", - " 'studyId',\n", - " update_population(f.col('ldPopulationStructure')).alias('ldPopulation'), \n", - " )\n", - " .distinct()\n", - " .persist()\n", - ")\n", - "\n", - "studies.show()" - ] - }, - { - "cell_type": "markdown", - "id": "6452e680", - "metadata": { - "ExecuteTime": { - "end_time": "2023-10-24T10:24:17.267975Z", - "start_time": "2023-10-24T10:24:11.432842Z" - } - }, - "source": [ - "## Reading distance and ld clumped Finngen dataset\n", - "\n", - "- Extract two random loci for prototyping purposes.\n", - "- Input dataset: 19,005 study locus from 1,387 studies." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "46e851ca", - "metadata": { - "ExecuteTime": { - "end_time": "2023-10-25T11:25:04.824517Z", - "start_time": "2023-10-25T11:25:00.848659Z" - } - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "[Stage 63:===================================================> (33 + 3) / 36]\r" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "+-----------------------------------------+---------------+--------------+--------------+\n", - "|studyId |variantId |pValueMantissa|pValueExponent|\n", - "+-----------------------------------------+---------------+--------------+--------------+\n", - "|FINNGEN_R9_C3_BASAL_CELL_CARCINOMA_EXALLC|15_29035680_G_A|2.076 |-21 |\n", - "|FINNGEN_R9_G6_SLEEPAPNO |16_53771295_C_A|2.149 |-26 |\n", - "+-----------------------------------------+---------------+--------------+--------------+\n", - "\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - } - ], - "source": [ - "sl = StudyLocus(\n", - " _df= (\n", - " session.spark.read\n", - " .parquet('gs://genetics_etl_python_playground/XX.XX/output/python_etl/parquet/finngen/2023.10.13_ld_clumped_w_locus/')\n", - " .filter(\n", - " (f.size(f.col('qualityControls')) == 0) &\n", - " (f.size(f.col('locus')) > 100)\n", - " )\n", - " .orderBy(f.rand(seed=23))\n", - " .limit(2)\n", - " ),\n", - " _schema=StudyLocus.get_schema()\n", - ").persist()\n", - "\n", - "# Get list of leads and studies:\n", - "sl.df.select('studyId', 'variantId', 'pValueMantissa', 'pValueExponent', ).show(truncate=False)" - ] - }, - { - "cell_type": "code", - "execution_count": 148, - "id": "661d9633", - "metadata": { - "ExecuteTime": { - "end_time": "2023-10-27T11:16:21.754731Z", - "start_time": "2023-10-27T11:16:20.553762Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "+--------------------+---------------+---------+---------+---------+-----------------------------------+\n", - "|studyLocusId |variantId |pValue |locusSize|ldSetSize|qualityControls |\n", - "+--------------------+---------------+---------+---------+---------+-----------------------------------+\n", - "|-6067699795164145074|15_27427129_A_G|9.592E-13|738 |35 |[] |\n", - "|-8027743839728879857|15_27983407_C_T|4.618E-61|837 |78 |[] |\n", - "|4889075444063922922 |15_28519016_G_A|2.786E-33|277 |-1 |[Variant not found in LD reference]|\n", - "|2224601896262245870 |15_29035680_G_A|2.076E-21|647 |5 |[] |\n", - "|-7676564604508510836|15_48134287_A_G|3.572E-12|442 |34 |[] |\n", - "+--------------------+---------------+---------+---------+---------+-----------------------------------+\n", - "\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - } - ], - "source": [ - "# Let's get all top-loci from this study on chromosome 15:\n", - "(\n", - " session.spark.read\n", - " .parquet('gs://genetics_etl_python_playground/XX.XX/output/python_etl/parquet/finngen/2023.10.13_ld_clumped_w_locus/')\n", - " .filter(\n", - " (f.col('studyId') == 'FINNGEN_R9_C3_BASAL_CELL_CARCINOMA_EXALLC') &\n", - " (f.col('chromosome') == '15') \n", - "# f.col('ldSet').isNotNull()\n", - " )\n", - " .orderBy(f.col('position'))\n", - " .select(\n", - " 'studyLocusId',\n", - " 'variantId', \n", - " f.concat_ws('E','pValueMantissa', 'pValueExponent').alias('pValue'), \n", - "# 'studyLocusId', \n", - " f.size(f.col('locus')).alias('locusSize'),\n", - " f.size(f.col('ldSet')).alias('ldSetSize'),\n", - " f.col('qualityControls')\n", - " )\n", - "# .count()\n", - " .show(20, truncate=False)\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d101a072", - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "attachments": { - "image.png": { - "image/png": "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8IseYXz/ww2TU+jEN2tzYM2N9Rs2ar+4T3TYG8mUMaNOU/r090vvvv2087bt2yVvntzGS7TtazWqS19lcunWW2+Nds6bQ1x4OsODQsFuYqpkiVf1rA7MZoGACxREUD7g9/Mv62Tt2p/1uWJFi8rjObLrffz76bo79pFP9rU3wBtmoDp27orT8t33P8rT+W88I9qR/0iABEiABEiABEiABEiABEiABEiABEiABEiABEiABJIUgfCwsLAESfCBAwcFI+whWTJnko4d2lqKCu2o/j3wQHrp3KmDOZRP535u7WOWBRbRRkc31m8wigrLg9rB4stG/v77b7OrF2iev+ALfYyZB2+/9aalqDCeoCyoX6+OOYzRFkoCI18tXWZ2re3CRV9a+zWqV7X2L1y8YHXe16ldy3K372TN+ph16DTjZJ1QO+AycMA7rhUVceFpjxf75cqW8VBUwA0mnzDTwsiZM1GmqMyxv+1vhw5Zpy8p019OKVWqhLRo3lT/cj71pPM0j0mABEiABEiABEiABEiABEiABEiABEiABEiABEiABJIYgQSbWbF7zx4LTVnVue1cLNqcfP65G+aBflp7Y80CKFUWLrihvDD+sYWZpaNHj8mYsR/Yna39HTt+tfZfr1nDq6IDHl6rXk1mzPzQ8ut2p7y6n/4DBmnvXyz8Ui3+3NtaIByzLWDCCYIZAXbzRzmyZ5elSxbpc85/ULbs3rNXr1fhPOftuH69utYi1t7OO93iwtMZVuVKFZxO+jiHbbbE3471MrxecN0Rs0eMSa4aNWtLa7Xgevny5SRH9mxawZXmttuke9fO/oLgORIgARIgARIgARIgARIgARIgARIgARIgARIgARIggSREIMGUFVhHwsjUaTPk++9/MIc+t4cPH4l2DosvY22In9TiyzC9dPC3Q9YC0tE8X3c4fORGOFmyZPHlTR5++CGf5/ydwIyQl18qrEwS/aBNQcHE0QuFnteXfLvyO+tSzJ6ISJXKOjY7UExgTYtNmzfr9TYOKlZQcsREMmfOFBPvlt/Y8LQuvr5zz913O5308e1qFouRyMhrZjfgtm6d2jJ/wUKLwfvjxgt+mBUD81KvFC8qL75QyDKnFTBAeiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEghpAhEJZQbq0KHDFgh0xG/Zus06druDNQ569OylO/S9XYOZC2fPRjc3ZFd63HVXOm+XajezloRPD35OVKtaRSsr4GXp0uWWssJuAsrbDISZH86WwUOGWR3zzijQQe9GcXHzTTc5Lw14HFuezoDvuOMOp1OcjrF+xfzP52gu365cZYUFDjAlZsyJwWzX2716elUAWRdxhwRIgARIgARIgARIgARIgARIgARIgARIgARIgARIIOQJJJiy4o7bb7dglC1TWp4t8Ix17GsnIiLCOnXkyFF57fW61jF2TDiPPPKwZMuaVbAYdfYncnn4wUGa22+M8P/vv/+inTcO9nUujJvb7SvFi1leP1cd6r3VQtfn//c/MQtMY00MLARul4WLFkuvt/taTlC2lFbrMeTKmVNwTzB7tG/f/mj3bV0Qh5248HRGGwyFF0xkTZsyUY6fOCE//rhaflz9k6z45lsPxQ1MdqWOSC293urhTBKPSYAESIAESIAESIAESIAESIAESIAESIAESIAESIAEkhCBG9qAICc6U+aMVgz58uaRBvU9FQ/WSR87n8z51DpTpMhLMn7smGiLSZ8+/bvlx76TKeONuI+otS18yYmTJ32dCuh+2223Si21HsbHn3yqO9TXr98gx44dt66r+VoNa9/sTJ4y1exKh3ZtpF3b1tEWHf9l3XrLT3zuxIVnfKYjUFgZHnxQaqi1RPC7du2a7Ny5S2bMmi1zPp2rL/1YPRc93+ymF/QOFBbPkwAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJhCaB8IRKln1WAdZ28CUHDhyU/AWe17/OXbtb3n5VndRGWjZvFk1RgXPr1nvv2M/46CPmUpk3b75ERkZax/adxUuW2g9jvF+5UkXrmqXLlsvCL7+0jkuVfNXax86VK1c8TGG1btUimqIC/n766Wds4l3iwjPeE2MLcP/+A1b+j37vfdsZ0QqJp556UoYOHmAtVA7TUCdPnfLwxwMSIAESIAESIAESIAESIAESIAESIAESIAESIAESIIGkRSDBlBV58+QWmDmC/KDM+qxTMw+cgpHzg98dptedwNoTzzz9tOUlPPxGUrGwtlNOnTotY94f53TWx3nVTA4TNxb6Xvjl4mj+cP3kKdOiucfEocAzT8uDDzygL5k2faasWvW93q9erYo413Ww3w88HTh4UPu1/1u/YaPApFQwxB5/THnGd3ouXrxoBZkhw4NW/mOWii/F0sULF6xrfC3wbXngDgmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQQEgTCPfVGewm1c2at5I3mrUM+Dt58pTcrtas6NWzuxVstRq19ELJZ86ckUuXLsmOHb9Kg0ZvyLJlX2s/6PQvV7a05T93rpzW/vtjP9DrF1y4cFHQ0f7JnLlSulxF2blrt+Xn2LFjgjUooAC59dZbPeJu266jTJ46TQ4dPiznVaf3j6vX6OvdLGRtReBlBwoAmIJyStXKlZxOepaAfd2Od/oNlA0bNwo67jdt2ixj1D1WrV7TY42G3347rM9HCywWDnHhGYvool0C805Gxn0wQWDuCgoj5FXhF1/Qp2CWq1nL1sqc1jGttLhy9aps275d3urVx5qVAr8333yzCYpbEiABEiABEiABEiABEiABEiABEiABEiABEiABEiCBJEgg7OrVq5H2Ufb+7uHy5cuSNcdT/rx4Pff1ssWSPVs23eHcqk17WbzkK6/+7I6Lvpgn9g51zLQoXOQVj857u3/sF3q+oPyulB/2mQJjRo+UCuXLirpPad6yjbXgtfNaHOfLl1crCrCP2RDDhg7Gbozk4G+/SZFiJaxroHRZ8+Mqr2sqrF37c8DFs+vUriUfzv7YCg87a9d8r2dwjBw9RkapH2TB55/q9OsD27+vli7T9w2n3r16SqOG9fXZuPLs3befTJ8xS4f17ddL5bHHsuh9+z+Y9Cr6Sknt5OS5ddt2KV+xit27XrejvVq7A/n3SskyHud8HaxcsUyyZMns6zTdSYAESIAESIAESIAESIAESIAESIAESIAESIAESIAEkgCB8LCwMNfJjIlfe6ARqaLW8cb1Y8eMkkED+tlPe+wXK1pEFi+c76GogAeYcfrko1mSLVtWD/84SJMmjbRu2VxmzZwmPbp18TgfKVHrU6RKlUrGjxsjHdu39ThvDqDomK2uf/T6+hYREbFbexxrc0DpYeT1Wq95VVTgfMGCz8nokcN0+o1/s4WSA4qWAf36SovmTY2z3kaq2SKQVDbTWOHq/rxJePgNd/s9xZWnyVPEGZ7qhokuexrs7va44efJJ5+Qhg3q2b1b+8jjj2fPtEx3WSdsO2D85cJ5VFTYmHCXBEiABEiABEiABEiABEiABEiABEiABEiABEiABJIqgTBlBiqqNz+B7wAml3bt3i1Y6Pnff/+T9PffL7lz55RMGTP6TQlmd2xUZpKwEHPq1Kklv+q0zpw5k4dCAOaDDh8+IhERqeTJJ56Ithj32XPnZMuWrXoEP67Nkzu3pE9/vySW/PnnX7J5yxY5dOiwTke+vHmjpWfP3r1y7uw5SZs2reTIkd3jfuOS7vjgGZf4YQbs9zNn5SaVl1AUIU+NIG3bt+/QJp/++PNPfe7RRx7R/vLkzuV1QXJzLbckQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAJJh0CMzEAlndtiSkmABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABJIKgUSbWZFUADGdJEACJEACJEACJEACJEACJEACJEACJEACJEACJEACJEACwSXgfbGB4MbJ0EmABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEjAIhB+9epV64A7JEACJEACJEACJEACJEACJEACJEACJEACJEACJEACJEACJJDQBGgGKqGJMz4SIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAEPAjQD5YGDByRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAglNgMqKhCbO+EiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABDwIUFnhgYMHJEACJEACJEACJEACJEACJEACJEACJEACJEACJEACJEACCU0gPDIyMqHjZHwkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkYBGgssJCwR0SIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIIHEIBCmZlZwakVikGecJEACJEACJEACJEACJEACJEACJEACJEACJEACJEACJEACmgDXrOCDQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkkKgEwq9du5aoCWDkJEACJEACJEACJEACJEACJEACJEACJEACJEACJEACJEACKZtAeFhYWMomwLsnARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARJIVAJcYDtR8TNyEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABzqzgM0ACJEACJEACJEACJEACJEACJEACJEACJEACJEACJEACJJCoBCIiIyMlJqagDh48KLt375YzZ87I1atXEzXxjDzuBFKlSiX33nuv5MiRQzJnzhz3ABkCCZAACZAACZAACZAACZAACZAACZAACZAACZAACZAACcSQQJhSVkS6vWb9+vVy8uRJyZMnj2TIkEHQ0U1J2gSgcDp+/Lhs2bJF30i5cuWS9g0x9SRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAkmOQLjbFGNGBRQVpUuXlkceeYSKCrfgQtwfFE7IzxIlSuiUIp8pJEACJEACJEACJEACJEACJEACJEACJEACJEACJEACJJCQBFwvsA3TT5hRwdkUCZk9CRfXTTfdpPMX+UwhARIgARIgARIgARIgARIgARIgARIgARIgARIgARIggYQk4HqBbaxRAdNPlORLAPmLfKaQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQQEIScD2zAmsbcFZFQmZNwseF/OWi6QnPnTGSAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQQEon4FpZkdJB8f5JgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgASCQ8C1GajgRM9QSYAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAEUjoBKitS+hPA+ycBEiABEiABEiABEiABEiABEiABEiABEiABEiABEiCBRCYQnsjxM3oSIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIIEUToDKihT+APD2SYAESIAESIAESIAESIAESIAESIAESIAESIAESIAESCCxCVBZkdg5wPhJgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIIIUTCI+MjEwwBIhr7969cu7cuQSJc8WKFbJw4UIrrrlz58r8+fP18enTp2X69Oly/Phx67y3neXLl8vixYu9nYqx25UrV2Tfvn1y9OhRSUjuMU5oErngjz/+lLmfzZPjJ07oFJ86dVomTpoiv//+u887cOPH58VxPIG0bt++I46h8HISIAESIAESIAESIAESIAESIAESIAESIAESIAESSH4EEkRZAQVF7dq1JW3atJI9e3a555575JFHHrEUB8HC+v7770vfvn118FevXpUaNWpI/fr19fGBAwekYcOG8uuvv/qNfsSIETJo0CC/fgKdvHTpkrRo0UJSp04t2bJl0/cOFhMmTAh0abTza9asEfxCTZYt+1oy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Z/defb5e3drWGhdY46Rundd9Kiv0BS7+QdlQsOBzlqIClzytFF45cz4lW7dt9wihqHo2jTz33LN6d/PmLVpZEegezHXckgAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJRCcQ4a1zPbq32LlgXQXIrl27XAeQNm1aD79GWfHCCy94uONgy5Yt2m3jxo0Cc05OQfy///6709nj2K4YwYlMmTLp83v27NFb+7+dO3fqw06dboy2t58/oWYA+FKQYA2Odu3a6R9G8k+aNEkvLo7ZFVhfIrZh33vvvdosFta+qF+/vk4OFi7v37+/No1lT1+o7N+eJo1HUvbt2y8dO3eVLVu3ebibgwPXTXc98vBDxklvMz76qMdxbA4QZ62aNaJdmiVzJlm9xtO012233VC6pUubTl+DxbQhge5Be+I/EiABEiABEiABEiABEiABEiABEiABEiABEiABEiABrwTCvbrGkyM66DHrwJd5JKz3MG3aNMGaE74kZ86c+hSUDujkt//MItuY6XD48OFoQTjXp4jmQTkcO3bMw/n48eP6+FEvHeFmFgMWxranw+xjPQWn4BxMNWEdBSP33HOPXsi7Zs2acvToUa1QiU3YJjzMIoFCaMeOHTJixAg5pBaHLlmypGANkKQgrdu2l337D8jokcNk9fcrZcfWjQJTUWmuKzUeUut+QDDrwi4n1XoncZUnHs8hJ9SsF6ccP35CMmfK6HT2eRzoHnxeyBMkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAISVGUF+FaqVEkvdG3WeDDMYX6qTZs20qhRI72wsnF3bo1pp23btun1F7CwNX7ffPONtaj1008/rdY3WOahsICCwNvsCGf4H3/8scdC1PPmzdNesNi2U7BOBmTNmjUeaYGSYOHChU7v+nj79u16TYuZM2dGO481JbCGBZQXMQkbMziMQGED81J//vmnNk+FtTbGjx+vT8dkRosJL6G3//33n+zctVvKlC6p15Z4WM2euEWZDVutGBvJniOb3l285CvjpLdYCNufmMXj//jjT5/esC7JunUb9LoYxtNvStmDtTDyXs9v4+5r6+YefF1LdxIgARIgARIgARIgARIgARIgARIgARIgARIgARIgAZGgLrANwCNHjpT169drM01YW6J06dJy/vx5mThxol7nAQtFw5SRLylfvrzuhK9YsaL06dNHMmfOrBUD06dPl7Fjx+rLsPYDFuBG2OisR+fx4MGDfQXp4b5q1SqpVauWVKlSRbAgeL9+/aRYsWICBYhTYCIKppZ69+6t76FgwYICZQQW+a5evbo0aNDAeYkULlxYsmfPLs2aNZMDBw7o40uXLgmUJF999ZVW2KBT3W3YWKgb61OABdhAkH6s9dG5c2e5+eabZejQodq9UKFCehvK/5BezG7AQthQDtynnoWP5syRAwd/s2ZWZMqYUS9sPUkteA2BYuc7tZj5V0uX+b21nNcXzB4/cZJcvnxJSpcqGc0/FvWe8+lcadS4qTSoX0+uXbsmkyZP0XHXfr1mNP/eHNzcg7fr6EYCJEACJEACJEACJEACJEACJEACJEACJEACJEACJBBFIAI298PCwoLGA4tXL1iwQLp27apnAGCtBghmFGAh6xYtWnjEbUbDG0esYbFkyRJp1aqVmLUicO2QIUOsa5955hm9YDWUCGbtCnTmY3YF1oOwizN8KE2mTp2qO/zhDwqAKVOmCBZwhtj9g9OECRMEC4ZDWWKUApgdMmrUKO3f+Q/XYyZG48aNdZqRbiNQ1GBtCYjbsOvVqydLly6Vvn37CkxWIf0zZsyQLl26SLly5XRYMIu1evVqueuuu/RxYvyzcwsU/+hRw6V5i9bSs1dv7bWCWoC7Tu1aMn9B1GwVsHl3yEDNyCgsoOAYNeJdad+xixW88zm+8847pWP7tjJi1HvSoVNXee7ZAtGedYTz8eyZMnzEKOnWo6cO69kCz8iwdwerRd0z62NnuHA0r4w5F+gedED6uuC9ayYObkmABEiABEiABEiABEiABEiABEiABEiABEiABEggqREIU+aYIt10LKND3CzgHNubvHLlip69kC5dOvG2JkSgcDEj4Y8//pD77rvPQ4lgv+7MmTNaEYLR7jERhItroFxxI1DynFJrJsCEU+rUqd1cotet2Lt3r9xyyy2qIzyL+Frc3E3YFy9e1PEapQoScO7cOe0GZU5sJT7yObZx//nnXyr9EdaMCm/h4Bk4f/6CUsRELXDtzY/T7YoyOXbl8mXN3XnOfnzhwkV9aF9I237ezb6be3ATDv2QAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQQEoiEOFGURFfQNCxjjUCYis33XSTYNFuf+LPpJS/62I6CwEj6h944AF/QUY7ByWFt7UwnB7dhI3ZHU7BWh5JWdKlSxsw+XgG8IuJRKRKJfgFkrgoKUzYbu7B+OWWBEiABEiABEiABEiABEiABEiABEiABEiABEiABEggikDQF9gmaBIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARLwRyAcCwpTSIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESCCxCISbBYITKwGMlwRIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIIGUTCMdizhQSIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESSCwCnFmRWOQZLwmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQgCbAmRV8EEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABBKVQLiSRE0AIycBEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEkjZBKipSNn5z7snARIgARIgARIgARIgARIgARIgARIgARIgARIgARIggUQnQDNQiZ4FTAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJpGwCEWFhYSmbAO8+GoEZM2ZEc6MDCZAACZAACZAACZAACZAACZAACZAACZAACZAACZAACQSLQNi1a9ciqbAIFl6GSwIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkEIgAzUAFIsTzJEACJEACJEACJEACJEACJEACJEACJEACJEACJEACJEACQSUQzlkVQeXLwEmABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABAIQoLIiACCeJgESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESCC6B8OAGz9BJgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIwD8BKiv88+FZEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiCBIBOgsiLIgBk8CZAACZAACZAACZAACZAACZAACZAACZAACZAACZAACZCAfwLhkZGR/n3wLAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAkEkQCVFUGEy6BJgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgAQCEwgPCwsL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BOo9A6BHQJbUewQoIQOKQL1nAPQMzpI6z2AFZFD21HsGgc/gbKn3DFZABmRPnWcA9GSypE6SARSlh9VOYS8EFqX1Y7VIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgAQinAAtFRGuIBaPBEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABKKdQBxWHaeQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQQEYRiOPi2hmFnvmSAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmAQJxlWSRBAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAhlGgDMrMgw9MyYBEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEgABzqzgdUACJEACJEACJEACJEACJEACJEACJEACJEACJEACJEACJJChBOJUMrQAzJwESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESCC2CdBSEdv6Z+1JgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIIMMJ0A1UhquABSABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiCB2CbABbZjW/+sPQmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAlkOAHOrMhwFbAAJEACJEACJEACJEACJEACJEACJEACJEACJEACJEACJBDbBGisiG39s/YkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkkOEE6AYqw1XAApAACZAACZAACZAACZAACZAACZAACZAACZAACZAACZBAbBOgsSK29c/akwAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkECGE4jL8BKwACRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAjFNgMaKmFY/K08CJEACJEACJEACJEACJEACJEACJEACJEACJEACJEACGU+AxoqM1wFLQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIxTSDOsqyYBsDKkwAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJZCwBGisylj9zJwESIAESIAESIAESIAESIAESIAESIAESIAESIAESIIGYJxCXJUuWmIdAACRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAhlHgMaKjGPPnEmABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABJRA3NmzZzMdiBw5cmS6MrPAmYMAr63MoafMWEpeW5lRa2krM3WeNn6Z9WzqPbNqLm3lpt7Txi+znk29Z1bNpb7c1Hnq2WXmM6n3zKy91Jedek89u8x6JnUeeZqjTiJPJ+lRojiV9MiHeZAACZAACZAACZAACZAACZAACZAACZAACZAACZAACZAACZBAQAK0VATEwkASIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIIH0IhB35syZ9MqL+ZAACZAACZAACZAACZAACZAACZAACZAACZAACZAACZAACZBAIgJxWbNmTRTIABIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARJILwLZ0iuj9MrnyJEjcuLECbEsK72yZD6ZiECWLFkkZ86ckitXrhSXmtdWipHF1Am8tmJK3aay1Hns6Rw1pt6p95QS4PtDSolFTnze75Gji/QqCXWeXqQjKx/qPbL0kV6lod7Ti3Tk5EOdR44unJJQJw6J2PpNTu9ZtFM/pF79nTt3St68eSOC3qlTpyR79uyJyoI/g2fPnpX4+HjJli3q7DCJ6suAlBM4ffq0HDt2TLCwfCCDBa+tlDPlGTYBXluxdyVQ57Gnc9SYeqfe+f4QO9cA7/fY0bVTU+rcIRFbv9R7bOnbqS317pCInV/qPPJ0TZ1Enk7So0TJ6T2qFtjGjAoaKtLjssq8ecCIhWsE10pKhNdWSmjFZlxeW7Gnd+o89nSOGlPv1HtKCPD9ISW0Ii8u7/fI08m5LhF1fq4JR2b61Htk6uVcl4p6P9eEIy996pw6iTwCsVmi5O7FuBAnVmQKeqgLKkwhgWAEcI2k9LrntRWMKI85BHhtOSRi55c6jx1du2tKvbtpxM429R47unbXlHp304iNbeo8NvTsX0vq3Z9IbOxT77GhZ3ctqXM3jcjYpk4iQw/pXYpgeo8qY0V6g2V+JEACJEACJEACJEACJEACJEACJEACJEACJEACJEACJEACaSegrvujyhNU2okwBRIgARIgARIgAQlvA4QAAEAASURBVBIgARIgARIgARIgARIgARIgARIgARIggXQlQEtFuuJmZiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAv4E4s6ePesfxn0SIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESSDcCcVmyZEm3zJgRCZAACZAACZAACZAACZAACZAACZAACZAACZAACZAACZAACfgT4ALb/kS4TwIkQAIRSOCbb76Rq666SmBgPnPmjKeEM2bMMGEI9//s27fPE48bJEACJEACJEACJEACJEACJEACJEACJEACJBDJBLJxZkUkq4dlIwESiHUClmXJsGHDpFu3bgFR7Nmzx4T37ds30fELL7wwURgDSIAESIAESIAESIAESIAESIAESIAESIAESCASCWRDRxgNFpGoGpaJBEiABESGDBkiPXr0kFatWskFF1wgY8eO9cGC2ROlSpWSF154wSecOyRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiSQmQjEqWSm8rKsJEACJBBTBA4dOiSjRo2SN954Q+Lj4xPVHTMrChQokCicASRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiSQmQhky0yFZVlJgARIINYIPP/885IjR44kq71r1y658sorZerUqfLxxx9Lrly5pFq1atKkSRPJnj17kufxAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAlEEgEusB1J2mBZSIAESMCPQDBDBaLCWDF9+nTp1KmTnDhxQj7//HN5+OGHpU2bNj4Lcfsly10SIAESIAESIAESIAESIAESIAESIAESIAESiCgCcVyvIqL0wcKQAAmQQIoI7N69W8qVKyebNm2SBQsWyJ9//ildu3aVGTNmyNy5c1OUFiOTAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQQEYR4MyKjCLPfEmABEggDAQ2btwo33//vVx11VWe1Pr162e2v/vuO08YN0iABEiABEiABEiABEiABEiABEiABEiABEggkgnQWBHJ2mHZSIAESCAIgf/++082bNggR48e9YmVM2dOsxj33r17fcK5QwIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAKRSoBuoCJVMywXCZAACSRD4OzZs3L33XdLz549fWKuXLlSjh07JpUqVfIJ5w4JkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJRCqBbFyzIlJVw3KRAAmQQHACWHy7devWMnLkSLn00kulQYMG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CZAACZAACZBAVBOgsSKq1cvKkQAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkEDkE6CxIvJ1xBKSAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQQFQTiLMsK6oryMqRAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAlENgEaKyJbPywdCZAACZAACZAACZAACZAACZAACZAACZAACZAACZAACUQ9gTiVqK8kK0gCJEACJEACJEACJEACJEACJEACJEACJEACJEACJEACJBC5BGipiFzdsGQkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkEBME4s6ePRsTFWUlSYAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAEIpNAFjVWWFmyZEm2dDt37pT4+Phk4zECCZAACZAACZAACZAACZAACZAACZAACZAACZAACZAACZAACaSEQDbLsiQUYwUSjRRjxalTpyR79uwpqSfjkkBIBHhthYSJkVJBgNdWKqBl8lOo80yuwFQWn3pPJbhMfhr1nskVmMriU++pBJeJT6POM7Hy0lB06j0N8DLxqdR7JlZeKotOnacS3Dk8jTo5h3AjOOm4UA0VEVwHFo0ESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESCATE4jDzAoKCZAACZAACZAACZAACZAACZAACZAACZAACZAACZAACZAACWQUgTiVjMqb+ZIACZAACZAACZAACZAACZAACZAACZAACZAACZAACZAACZCA0FLBi4AESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESCBDCdANVIbiZ+YkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAJcYJvXAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQQIYS4MyKDMXPzEmABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABGis4DVAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiSQoQToBipD8TNzEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABGit4DZAACZAACZAACZAACZAACZAACZAACZAACZAACZAACZAACWQogbgMzT2TZG5ZIr/tFfnzcNoLvHm/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KZLbMk4k9f4utP5Q5xbWQbycexhh/N+pU3J1jhAdqHXhZfayyy6lkcKQTdtfoc6tUEeOEbn79kWbEfB46aSkHgIJ7fNIjhAGrZ9+/tkonZHXIJTgeoOwI6HCgSA05AHNX5ExU0aTEyNUfVwXmEBC+h1huhASyC3os7NnzwhG1QcTPMYh1EsOvd9ACRqpINwXEnjfcvPNvBdFCs9RPly/I0zI5ZdfZrzlHJuZyWD97y7H+ZRHIFS/w5sCo5cRysf9Eo0+zxgbws/rUSGkD/LZFChQwC+UnHt7PIMilwVy2zD0j5vOhc+H6nPUDi/Cc+fPSZ7Y3ELOPQb6ryf2fRf72B+9XzJlzkSPGif8C5wO1+94VofHbKBk6oH6Hc0Jtc0FNjfo5mjL4V8Pm7ZiwAMlNIFw/Q49B8J4F1DbMwaPhpN/Tlv6IAxcdSfLDrct118cAuH6/OK0gntxEmCfOGmkn+l0ZaxIP93KI00oAV4IE0qO24UjwHMrHKG0t559nvb61MsRsd+9UEp7Zdjvaa9PvRwR+90LpbRVhn2etvrT69Gw372SSlvl2O9pqz+9HA373Auli1uGfXJxeaeUvUVhRB6FBEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABJKLAI0VyUWe+yUBEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEjAENJQpE/PxXCABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEkg+ArRUJB977pkESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESEAJRJ0/f54gSIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESCDZCERlyJAh2XbOHZMACZAACZAACZAACZAACZAACZAACZAACZAACZAACZAACZAAE2zzHCABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEkhWAvSsSFb83DkJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAA9K3gOkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJJCuBKJVkbQB3TgIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkkL4JZIhR8YLg0KFDkjVrVi9FWYYESIAESIAESIAESIAESIAESIAESIAE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yZUrV7zDQn4Idx/jMQ3PYCf+/scYwN3r7UpQDmGkcujo7HBKTnsb/iYegXD9HsmecB5kVA1DICVVJPWwbNITSGi/o4/hIXOLKhTdz5X4L5/TkG/B/uuJdVTYD0INZslyuS+kXGLVnZbrCdfnkV7jL5QV2vPj3n1yba6cfE68UJghtg/X7/v2RWuIr2sC/pcC3duxq1DbhGiKb1Wo64hdCOEjf/r5ZxNqskD+/PZi/nokEKrfkc9h1++WzuamC9D9oCnwykD0DoRzQqjxlCbRf2kISh0QW+wGy5iS0tqXmO0J1eeJuR/W5Z1AqD7BdXB/9H7JlDmTL2qA95pZMiUTyKAJuWK8KC7SgrEiJXcE25YyCIS6EKaMFrIVqZUAz63U2nMJbzf7POHsUvOW7PfU3HsJbzv7PeHsUvOW7PfU3HsJazv7PGHcUvtW7PfU3oMJaz/7PWHcUvNW7POU13vsk5TXJxejRZo7mC7kFwM090ECJEACJEACJEACJEACJEACJEACJEACJEACJEACJEACJBCYQBRcgCkkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkkFwE6FmRXOS5XxIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgAUOAnhU8EUiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABJKVgObWjkrWBnDnJEACJEACJEACJEACJEACJEACJEACJEACJEACJEACJEAC6ZsALRXpu/959CRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiSQ7AQYBirZu4ANIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIIH0TYAJttN3//PoSYAESIAESIAESIAESIAESIAESIAESIAESIAESIAESCDZCdCzItm7gA0gARIgARIgARIgARIgARIgARIgARIgARIgARIgARIggfRNgMaK9N3/PHoSIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESSHYCGc6fPx+TIUOGsA05dOiQZM2aNWw5FiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiCBSAhk8mKosCtMKcaKM2fOSObMme1m8ZcEEo0Az61EQ8mKXAR4brmApINZ9nk66OQAh8h+DwAlHSxiv6eDTg5wiOz3AFDS+CL2eRrv4CCHx34PAiaNL2a/p/EODnB47PMAUJJ5EfskmTsgmXYflUz75W5JgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIwBCgsYInAgmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQQLISoLEiWfFz5yRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAlExMTGkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQALJRoDGimRDzx2TAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmAQFSGDBlIggRIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgASSjQCNFcmGnjsmARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIAgajz58+TBAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAkkG4EolWTbOXdMAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAArRU8BwgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARJIVgJR586dS9YGcOckQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQALpm0BUxowZ0zcBHj0JkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkECyEmAYqGTFz52TAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAnQWMFzgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIIFkJ0FiRrPi5cxIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIggaiYmBhSIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIIFkI0BjRbKh545JgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARA4P/YeNeOUSE9MQAAAABJRU5ErkJggg==" - } - }, - "cell_type": "markdown", - "id": "9db8b8ab", - "metadata": {}, - "source": [ - "## Comparing with Finngen finemapping.\n", - "\n", - "The same [trait](https://r9.finngen.fi/pheno/C3_BASAL_CELL_CARCINOMA_EXALLC) has 3 finemapped credible sets.\n", - "\n", - "![image.png](attachment:image.png)\n", - "\n", - "- `15:27983407:C:T` and `15:27985172:C:T` are very close, I could find `27983407`.\n", - "- Also `15_48134287_A_G` is found by both approach.\n", - "- One of the other three snps was not found in the LD set (`15_28519016_G_A`). \n", - "- `15_27427129_A_G` and `15_29035680_G_A` were resolved in the LD matrix, and were found to be not linked. But they are not in the.\n", - "\n", - "What are the r between these variants?\n", - "\n", - "- 15_27983407_C_T vs 15_27427129_A_G -> r = \n", - "- 15_27983407_C_T vs 15_29035680_G_A -> r =" - ] - }, - { - "cell_type": "code", - "execution_count": 144, - "id": "d8da5802", - "metadata": { - "ExecuteTime": { - "end_time": "2023-10-27T10:19:25.494510Z", - "start_time": "2023-10-27T10:19:23.020596Z" - } - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "+---------------+---------+---------+---------+---------------+----------+--------+--------+------------+\n", - "| variantId| pValue|locusSize|ldSetSize|qualityControls|chromosome|position| idx|ldPopulation|\n", - "+---------------+---------+---------+---------+---------------+----------+--------+--------+------------+\n", - "|15_27427129_A_G|9.592E-13| 738| 35| []| 15|27427129|11130387| fin|\n", - "|15_27983407_C_T|4.618E-61| 837| 78| []| 15|27983407|11133253| fin|\n", - "|15_29035680_G_A|2.076E-21| 647| 5| []| 15|29035680|11136878| fin|\n", - "+---------------+---------+---------+---------+---------------+----------+--------+--------+------------+\n", - "\n" - ] - } - ], - "source": [ - "# Extracting and resolving ld:\n", - "resolved_ld_index = (\n", - " session.spark.read\n", - " .parquet('gs://genetics_etl_python_playground/XX.XX/output/python_etl/parquet/finngen/2023.10.13_ld_clumped_w_locus/')\n", - " .filter(\n", - " (f.col('studyId') == 'FINNGEN_R9_C3_BASAL_CELL_CARCINOMA_EXALLC') &\n", - " f.col('variantId').isin(['15_27983407_C_T', '15_27427129_A_G', '15_29035680_G_A'])\n", - " )\n", - " .orderBy(f.col('position'))\n", - " .select(\n", - " 'variantId', \n", - " f.concat_ws('E','pValueMantissa', 'pValueExponent').alias('pValue'), \n", - "# 'studyLocusId', \n", - " f.size(f.col('locus')).alias('locusSize'),\n", - " f.size(f.col('ldSet')).alias('ldSetSize'),\n", - " f.col('qualityControls')\n", - " )\n", - "# .count()\n", - " .join(ld_index, on = 'variantId', how='left')\n", - " .persist()\n", - ")\n", - "\n", - "resolved_ld_index.show()" - ] - }, - { - "cell_type": "code", - "execution_count": 147, - "id": "722eb21d", - "metadata": { - "ExecuteTime": { - "end_time": "2023-10-27T10:24:03.123125Z", - "start_time": "2023-10-27T10:23:32.607310Z" - } - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2023-10-27 10:23:48.619 Hail: INFO: Coerced sorted dataset \n", - "[Stage 942:> (0 + 1) / 1]\r" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "+---+---+------------------+\n", - "|i |j |entry |\n", - "+---+---+------------------+\n", - "|0 |0 |2.0000000000000084|\n", - "|0 |1 |0.4201370447477838|\n", - "|0 |2 |0.0 |\n", - "|1 |0 |0.4201370447477838|\n", - "|1 |1 |2.0000000000000004|\n", - "|1 |2 |0.0 |\n", - "|2 |0 |0.0 |\n", - "|2 |1 |0.0 |\n", - "|2 |2 |1.9999999999999996|\n", - "+---+---+------------------+\n", - "\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - } - ], - "source": [ - "# Accessing r data from the LD matrix:\n", - "half_matrix = (\n", - " BlockMatrix\n", - " .read(ld_matrix_template.format(POP=ld_population))\n", - " .filter(\n", - " [row['idx'] for row in resolved_ld_index.select('idx').collect()],\n", - " [row['idx'] for row in resolved_ld_index.select('idx').collect()]\n", - " )\n", - ")\n", - "\n", - "# matrix = half_matrix + half_matrix.T\n", - "matrix.entries().to_spark().show(100, truncate=False)" - ] - }, - { - "cell_type": "code", - "execution_count": 153, - "id": "c316e0d0", - "metadata": { - "ExecuteTime": { - "end_time": "2023-10-27T11:18:11.801945Z", - "start_time": "2023-10-27T11:18:06.718163Z" - } - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "+---------------+----------+--------------------+--------------------+--------+--------+---------+--------------------------------+--------------------------------+---------------------------+---------------------------+--------------+--------------+-------------------------------+-------------+-------------------+---------------+-----------------+--------------------+--------------------+\n", - "| variantId|chromosome| studyId| studyLocusId|position| beta|oddsRatio|oddsRatioConfidenceIntervalLower|oddsRatioConfidenceIntervalUpper|betaConfidenceIntervalLower|betaConfidenceIntervalUpper|pValueMantissa|pValueExponent|effectAlleleFrequencyFromSource|standardError|subStudyDescription|qualityControls|finemappingMethod| locus| ldSet|\n", - "+---------------+----------+--------------------+--------------------+--------+--------+---------+--------------------------------+--------------------------------+---------------------------+---------------------------+--------------+--------------+-------------------------------+-------------+-------------------+---------------+-----------------+--------------------+--------------------+\n", - "|15_27983407_C_T| 15|FINNGEN_R9_C3_BAS...|-8027743839728879857|27983407|0.413866| null| null| null| 0.388762| 0.43897| 4.618| -61| 0.0443583| 0.025104| null| []| null|[{null, null, nul...|[{15_28482553_T_C...|\n", - "+---------------+----------+--------------------+--------------------+--------+--------+---------+--------------------------------+--------------------------------+---------------------------+---------------------------+--------------+--------------+-------------------------------+-------------+-------------------+---------------+-----------------+--------------------+--------------------+\n", - "\n" - ] - } - ], - "source": [ - "study_locus_id = -8027743839728879857\n", - "\n", - "# Running susie for a specific study locus:\n", - "sl = StudyLocus(\n", - " _df= (\n", - " session.spark.read\n", - " .parquet('gs://genetics_etl_python_playground/XX.XX/output/python_etl/parquet/finngen/2023.10.13_ld_clumped_w_locus/')\n", - " .filter(f.col('studyLocusId') == study_locus_id)\n", - " ),\n", - " _schema=StudyLocus.get_schema()\n", - ").persist()\n", - "\n", - "sl.df.show()" - ] - }, - { - "cell_type": "markdown", - "id": "947d112a", - "metadata": {}, - "source": [ - "## Annotating study locus with ld population + Get list of ancestires" - ] - }, - { - "cell_type": "code", - "execution_count": 154, - "id": "8be0fd89", - "metadata": { - "ExecuteTime": { - "end_time": "2023-10-27T11:20:59.482466Z", - "start_time": "2023-10-27T11:20:59.062418Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "-RECORD 0------------------------------------------------\n", - " studyId | FINNGEN_R9_C3_BAS... \n", - " variantId | 15_27983407_C_T \n", - " chromosome | 15 \n", - " studyLocusId | -8027743839728879857 \n", - " position | 27983407 \n", - " beta | 0.413866 \n", - " oddsRatio | null \n", - " oddsRatioConfidenceIntervalLower | null \n", - " oddsRatioConfidenceIntervalUpper | null \n", - " betaConfidenceIntervalLower | 0.388762 \n", - " betaConfidenceIntervalUpper | 0.43897 \n", - " pValueMantissa | 4.618 \n", - " pValueExponent | -61 \n", - " effectAlleleFrequencyFromSource | 0.0443583 \n", - " standardError | 0.025104 \n", - " subStudyDescription | null \n", - " qualityControls | [] \n", - " finemappingMethod | null \n", - " locus | [{null, null, nul... \n", - " ldSet | [{15_28482553_T_C... \n", - " ldPopulation | fin \n", - "\n" - ] - }, - { - "data": { - "text/plain": [ - "['fin']" - ] - }, - "execution_count": 154, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Adding ld population to study locus:\n", - "dl_df = (\n", - " sl.df\n", - " .join(studies, on='studyId', how='left')\n", - " .persist()\n", - ")\n", - "\n", - "dl_df.show(1, vertical=True)\n", - "\n", - "# Extract the required ld populations:\n", - "ld_populations = [row['ldPopulation'] for row in dl_df.select('ldPopulation').distinct().collect()]\n", - "\n", - "ld_populations" - ] - }, - { - "cell_type": "markdown", - "id": "b69aad94", - "metadata": { - "ExecuteTime": { - "end_time": "2023-10-24T10:34:37.443692Z", - "start_time": "2023-10-24T10:34:37.436917Z" - } - }, - "source": [ - "## Read ld index" - ] - }, - { - "cell_type": "code", - "execution_count": 155, - "id": "5465b9d3", - "metadata": { - "ExecuteTime": { - "end_time": "2023-10-27T11:21:03.778148Z", - "start_time": "2023-10-27T11:21:03.770967Z" - }, - "code_folding": [ - 2 - ] - }, - "outputs": [], - "source": [ - "from gentropy.common.utils import _liftover_loci, convert_gnomad_position_to_ensembl\n", - "\n", - "def _process_ld_indices(\n", - " ld_index_raw: hl.Table, \n", - " grch37_to_grch38_chain_path: str\n", - ") -> DataFrame:\n", - " \"\"\"Creates a look up table between variants and their coordinates in the LD Matrix.\n", - "\n", - " !!! info \"Gnomad's LD Matrix and Index are based on GRCh37 coordinates. This function will lift over the coordinates to GRCh38 to build the lookup table.\"\n", - "\n", - " Args:\n", - " ld_index_raw (hl.Table): LD index table from GnomAD\n", - " grch37_to_grch38_chain_path (str): Path to the chain file used to lift over the coordinates\n", - "\n", - " Returns:\n", - " DataFrame: Look up table between variants in build hg38 and their coordinates in the LD Matrix\n", - " \"\"\"\n", - " ld_index_38 = _liftover_loci(\n", - " ld_index_raw, grch37_to_grch38_chain_path, \"GRCh38\"\n", - " )\n", - "\n", - " return (\n", - " ld_index_38.to_spark()\n", - " # Filter out variants where the liftover failed\n", - " .filter(f.col(\"`locus_GRCh38.position`\").isNotNull())\n", - " .withColumn(\n", - " \"chromosome\", f.regexp_replace(\"`locus_GRCh38.contig`\", \"chr\", \"\")\n", - " )\n", - " # Temporary filter:\n", - " .filter(f.col('chromosome').isin(['16', '15']))\n", - " .withColumn(\n", - " \"position\",\n", - " convert_gnomad_position_to_ensembl(\n", - " f.col(\"`locus_GRCh38.position`\"),\n", - " f.col(\"`alleles`\").getItem(0),\n", - " f.col(\"`alleles`\").getItem(1),\n", - " ),\n", - " )\n", - " .select(\n", - " \"chromosome\",\n", - " \"position\",\n", - " f.concat_ws(\n", - " \"_\",\n", - " f.col(\"chromosome\"),\n", - " f.col(\"position\"),\n", - " f.col(\"`alleles`\").getItem(0),\n", - " f.col(\"`alleles`\").getItem(1),\n", - " ).alias(\"variantId\"),\n", - " f.col(\"idx\"),\n", - " )\n", - " # Filter out ambiguous liftover results: multiple indices for the same variant\n", - " .withColumn(\"count\", f.count(\"*\").over(Window.partitionBy([\"variantId\"])))\n", - " .filter(f.col(\"count\") == 1)\n", - " .drop(\"count\")\n", - " )\n" - ] - }, - { - "cell_type": "markdown", - "id": "15eab28a", - "metadata": {}, - "source": [ - "- Full genome: 5min" - ] - }, - { - "cell_type": "code", - "execution_count": 156, - "id": "e231cc9a", - "metadata": { - "ExecuteTime": { - "end_time": "2023-10-27T11:25:47.523343Z", - "start_time": "2023-10-27T11:21:07.729708Z" - } - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "[Stage 975:=================================================>(9996 + 4) / 10000]\r" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "+----------+---------+--------------------+--------+------------+\n", - "|chromosome| position| variantId| idx|ldPopulation|\n", - "+----------+---------+--------------------+--------+------------+\n", - "| 15|100068435| 15_100068435_C_T|11488485| fin|\n", - "| 15|100074914| 15_100074914_T_C|11488528| fin|\n", - "| 15|100082112| 15_100082112_C_G|11488600| fin|\n", - "| 15|100084933| 15_100084933_C_T|11488622| fin|\n", - "| 15|100086055| 15_100086055_C_T|11488643| fin|\n", - "| 15|100102338|15_100102338_CGAA...|11488802| fin|\n", - "| 15|100102474| 15_100102474_A_G|11488806| fin|\n", - "| 15|100140453| 15_100140453_G_GAC|11489087| fin|\n", - "| 15|100141050| 15_100141050_G_A|11489092| fin|\n", - "| 15|100149133| 15_100149133_G_T|11489141| fin|\n", - "| 15|100270659| 15_100270659_G_A|11490053| fin|\n", - "| 15|100317282| 15_100317282_T_C|11490464| fin|\n", - "| 15|100376040| 15_100376040_ACTT_A|11490958| fin|\n", - "| 15|100391254| 15_100391254_CA_C|11491027| fin|\n", - "| 15|100394474| 15_100394474_T_C|11491043| fin|\n", - "| 15|100466861| 15_100466861_T_C|11491614| fin|\n", - "| 15|100516200| 15_100516200_T_C|11492028| fin|\n", - "| 15|100525848| 15_100525848_T_G|11492086| fin|\n", - "| 15|100588385| 15_100588385_A_T|11492713| fin|\n", - "| 15|100605649| 15_100605649_A_T|11492813| fin|\n", - "+----------+---------+--------------------+--------+------------+\n", - "only showing top 20 rows\n", - "\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - } - ], - "source": [ - "grch37_to_grch38_chain_path = 'gs://hail-common/references/grch37_to_grch38.over.chain.gz'\n", - "ld_index_raw_template = 'gs://gcp-public-data--gnomad/release/2.1.1/ld/gnomad.genomes.r2.1.1.{POP}.common.ld.variant_indices.ht'\n", - "ld_matrix_template ='gs://gcp-public-data--gnomad/release/2.1.1/ld/gnomad.genomes.r2.1.1.{POP}.common.adj.ld.bm'\n", - "\n", - "\n", - "ld_population = 'fin'\n", - "ld_index_raw_path = ld_index_raw_template.format(POP=ld_population)\n", - "\n", - "ld_index = (\n", - " _process_ld_indices(\n", - " hl.read_table(ld_index_raw_path),\n", - " grch37_to_grch38_chain_path,\n", - " )\n", - " .withColumn('ldPopulation', f.lit(ld_population))\n", - " .persist()\n", - ")\n", - "\n", - "ld_index.show()" - ] - }, - { - "cell_type": "code", - "execution_count": 157, - "id": "e43d0dbf", - "metadata": { - "ExecuteTime": { - "end_time": "2023-10-27T11:26:04.794300Z", - "start_time": "2023-10-27T11:26:04.691498Z" - } - }, - "outputs": [], - "source": [ - "# how to do the join?\n", - "window_size = 250_000\n", - "tags = (\n", - " # Pre-process study locus:\n", - " f.broadcast(dl_df)\n", - " .select('studyLocusId', 'chromosome', 'position', 'ldPopulation')\n", - " .alias('study_locus')\n", - " .join(\n", - " (\n", - " ld_index\n", - " .selectExpr(*[f\"{col} as ld_index_{col}\" for col in ld_index.columns])\n", - " .alias('ld_index')\n", - " ),\n", - " on = [\n", - " (f.col('ld_index.ld_index_chromosome') == f.col('study_locus.chromosome')) & \n", - " (f.col('ld_index.ld_index_ldPopulation') == f.col('study_locus.ldPopulation')) &\n", - " (f.col('ld_index.ld_index_position') >= f.col('study_locus.position') - window_size) & \n", - " (f.col('ld_index.ld_index_position') <= f.col('study_locus.position') + window_size)\n", - " ],\n", - " how='left'\n", - " )\n", - " .select(\n", - " 'studyLocusId',\n", - " 'chromosome',\n", - " f.col('ld_index_variantId').alias('variantId'),\n", - " f.col('ld_index_idx').alias('idx'),\n", - " f.col('ld_index_position'),\n", - " f.col('ld_index_ldPopulation').alias('ldPopulation')\n", - " )\n", - " .persist()\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 158, - "id": "45fb0df5", - "metadata": { - "ExecuteTime": { - "end_time": "2023-10-27T11:26:08.409160Z", - "start_time": "2023-10-27T11:26:06.312358Z" - } - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "[Stage 979:============================================> (173 + 27) / 200]\r" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "+--------------------+-----+\n", - "| studyLocusId|count|\n", - "+--------------------+-----+\n", - "|-8027743839728879857| 2079|\n", - "+--------------------+-----+\n", - "\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - } - ], - "source": [ - "tags.groupby('studyLocusId').count().show()" - ] - }, - { - "cell_type": "code", - "execution_count": 159, - "id": "858894fc", - "metadata": { - "ExecuteTime": { - "end_time": "2023-10-27T11:26:14.204291Z", - "start_time": "2023-10-27T11:26:12.440937Z" - } - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "+--------------------+----------+--------------+-------------+-------------+---------+--------+--------------+\n", - "|studyLocusId |chromosome|first_position|last_position|window_length|first_idx|last_idx|ldVariantCount|\n", - "+--------------------+----------+--------------+-------------+-------------+---------+--------+--------------+\n", - "|-8027743839728879857|15 |27733460 |28232552 |499092 |11131979 |11134057|2079 |\n", - "+--------------------+----------+--------------+-------------+-------------+---------+--------+--------------+\n", - "\n" - ] - }, - { - "data": { - "text/plain": [ - "1" - ] - }, - "execution_count": 159, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Collecting region:\n", - "ld_windows = (\n", - " tags\n", - " .orderBy('studyLocusId', 'ld_index_position')\n", - " .groupBy('studyLocusId', 'chromosome', 'ldPopulation')\n", - " .agg(\n", - " f.first(f.col('ld_index_position')).alias('first_position'),\n", - " f.first(f.col('variantId')).alias('first_variantId'),\n", - " f.first(f.col('idx')).alias('first_idx'),\n", - " f.last(f.col('ld_index_position')).alias('last_position'),\n", - " f.last(f.col('variantId')).alias('last_variantId'),\n", - " f.last(f.col('idx')).alias('last_idx'),\n", - " f.size(f.collect_list(f.col('variantId'))).alias('ldVariantCount')\n", - " )\n", - " .withColumn('window_length', f.col('last_position') - f.col('first_position'))\n", - " .persist()\n", - ")\n", - "\n", - "(\n", - " ld_windows\n", - " .select(\n", - " 'studyLocusId',\n", - " 'chromosome',\n", - " 'first_position',\n", - " 'last_position',\n", - " 'window_length',\n", - " 'first_idx',\n", - " 'last_idx',\n", - " 'ldVariantCount'\n", - " )\n", - " .show(truncate=False)\n", - ")\n", - "\n", - "\n", - "ld_windows.count()" - ] - }, - { - "cell_type": "code", - "execution_count": 160, - "id": "61d51efe", - "metadata": { - "ExecuteTime": { - "end_time": "2023-10-27T11:26:22.608155Z", - "start_time": "2023-10-27T11:26:22.421535Z" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "Row(studyLocusId=-8027743839728879857, chromosome='15', ldPopulation='fin', first_position=27733460, first_variantId='15_27733460_AGCCAAACTGGCTCATGGCC_A', first_idx=11131979, last_position=28232552, last_variantId='15_28232552_G_GA', last_idx=11134057, ldVariantCount=2079, window_length=499092)" - ] - }, - "execution_count": 160, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "row = ld_windows.collect()[0]\n", - "row" - ] - }, - { - "cell_type": "code", - "execution_count": 161, - "id": "d4d006bd", - "metadata": { - "ExecuteTime": { - "end_time": "2023-10-27T11:26:31.400420Z", - "start_time": "2023-10-27T11:26:30.851547Z" - } - }, - "outputs": [], - "source": [ - "ld_population = row['ldPopulation']\n", - "study_locus_id = row['studyLocusId']\n", - "chromosome = row['chromosome']\n", - "first_index = row['first_idx']\n", - "last_index = row['last_idx']\n", - "\n", - "# For each row, we need to open the gnomad \n", - "half_matrix = (\n", - " BlockMatrix\n", - " .read(ld_matrix_template.format(POP=ld_population))\n", - " .filter(\n", - " range(first_index, last_index),\n", - " range(first_index, last_index)\n", - " )\n", - ")\n", - "\n", - "matrix = half_matrix + half_matrix.T\n" - ] - }, - { - "cell_type": "code", - "execution_count": 162, - "id": "e24da4ca", - "metadata": { - "ExecuteTime": { - "end_time": "2023-10-27T11:27:24.435664Z", - "start_time": "2023-10-27T11:26:35.945855Z" - } - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2023-10-27 11:26:58.169 Hail: INFO: Coerced sorted dataset \n", - " \r" - ] - } - ], - "source": [ - "(\n", - " matrix.entries().to_spark()\n", - " .select(\n", - " (f.col('i')+first_index).alias('idx_i'),\n", - " (f.col('j')+first_index).alias('idx_j'),\n", - " f.when(f.col('i') == f.col('j'), f.col('entry')/2).otherwise(f.col('entry')).alias('r'),\n", - " f.lit(study_locus_id).alias('study_locus_ids')\n", - " )\n", - " # Joining with i:\n", - " .join(\n", - " (\n", - " tags\n", - " .select(\n", - " f.col('variantId').alias('variantIdLeft'), \n", - " f.col('idx').alias('idx_i')\n", - " )\n", - " ), \n", - " on='idx_i', how='outer'\n", - " )\n", - " # Joining with i:\n", - " .join(\n", - " (\n", - " tags\n", - " .select(\n", - " 'chromosome', \n", - " f.col('variantId').alias('variantIdRight'), \n", - " f.col('idx').alias('idx_j')\n", - " )\n", - " ), \n", - " on='idx_j', how='outer'\n", - " )\n", - " .select(\n", - " 'variantIdLeft',\n", - " 'variantIdRight',\n", - " 'study_locus_ids',\n", - " 'r'\n", - " )\n", - " .distinct()\n", - " .write.mode('overwrite').parquet(f'gs://ot-team/dsuveges/ld_matrix-{study_locus_id}')\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 164, - "id": "3cb94848", - "metadata": { - "ExecuteTime": { - "end_time": "2023-10-27T11:28:28.344710Z", - "start_time": "2023-10-27T11:28:27.670811Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "-RECORD 0---------------------------------------------------\n", - " studyId | FINNGEN_R9_C3_BASAL_CELL_CARCINOMA_EXALLC \n", - " variantIdLead | 15_27983407_C_T \n", - " studyLocusId | -8027743839728879857 \n", - " variantId | 15_27733459_AGCCAAACTGGCTCATGGCC_A \n", - " pValueMantissa | 1.937 \n", - " pValueExponent | -2 \n", - " beta | 0.0267247 \n", - " standardError | 0.011429 \n", - "only showing top 1 row\n", - "\n" - ] - }, - { - "data": { - "text/plain": [ - "837" - ] - }, - "execution_count": 164, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "study_locus_id = -8027743839728879857\n", - "\n", - "# Get data:\n", - "ld_matrix = session.spark.read.parquet(f'gs://ot-team/dsuveges/ld_matrix-{study_locus_id}')\n", - "\n", - "# Select one study locus:\n", - "selected_locus = (\n", - " dl_df\n", - " .filter(f.col('studyLocusId') == study_locus_id)\n", - " .select(\n", - " '*',\n", - " f.explode_outer('locus').alias('exploded_locus')\n", - " )\n", - " .select(\n", - " 'studyId',\n", - " f.col('variantId').alias('variantIdLead'),\n", - " f.col('studyLocusId'),\n", - " *[f'exploded_locus.{col}' for col in ['variantId', 'pValueMantissa', 'pValueExponent', 'beta', 'standardError']]\n", - " )\n", - " .persist()\n", - ")\n", - "\n", - "selected_locus.show(1, False, True)\n", - "selected_locus.count()" - ] - }, - { - "cell_type": "code", - "execution_count": 189, - "id": "0e571433", - "metadata": { - "ExecuteTime": { - "end_time": "2023-10-27T13:49:41.356331Z", - "start_time": "2023-10-27T13:49:40.463119Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "+--------------------+--------------------+---------------+---------------+---------------+-------------------+-------------------+----------+------------------+--------------------+\n", - "| studyId| studyLocusId| variantIdLead| variantIdLeft| variantIdRight|pValueMantissaRight|pValueExponentRight| betaRight|standardErrorRight| r|\n", - "+--------------------+--------------------+---------------+---------------+---------------+-------------------+-------------------+----------+------------------+--------------------+\n", - "|FINNGEN_R9_C3_BAS...|-8027743839728879857|15_27983407_C_T|15_27792793_C_T|15_27772290_T_C| 9.979| -6| 0.0730063| 0.0165261| 0.3188276023578284|\n", - "|FINNGEN_R9_C3_BAS...|-8027743839728879857|15_27983407_C_T|15_27950388_C_T|15_27778556_C_T| 1.142| -2| 0.119731| 0.0473309| -0.1845689041174883|\n", - "|FINNGEN_R9_C3_BAS...|-8027743839728879857|15_27983407_C_T|15_28104601_A_T|15_27809200_G_A| 1.397| -2|-0.0286999| 0.0116763| 0.01919714154020592|\n", - "|FINNGEN_R9_C3_BAS...|-8027743839728879857|15_27983407_C_T|15_27970325_G_A|15_27809200_G_A| 1.397| -2|-0.0286999| 0.0116763|-0.12413267238343029|\n", - "|FINNGEN_R9_C3_BAS...|-8027743839728879857|15_27983407_C_T|15_27899878_T_C|15_27851307_A_G| 5.606| -4|-0.0424098| 0.0122927|-0.45516734696600447|\n", - "|FINNGEN_R9_C3_BAS...|-8027743839728879857|15_27983407_C_T|15_27914364_C_T|15_27851307_A_G| 5.606| -4|-0.0424098| 0.0122927| -0.4029686644067302|\n", - "|FINNGEN_R9_C3_BAS...|-8027743839728879857|15_27983407_C_T|15_27828335_G_A|15_27858692_G_A| 3.599| -4| 0.0427448| 0.0119804| 0.09141477739652863|\n", - "|FINNGEN_R9_C3_BAS...|-8027743839728879857|15_27983407_C_T|15_27845815_A_G|15_27858692_G_A| 3.599| -4| 0.0427448| 0.0119804| 0.7803430284267874|\n", - "|FINNGEN_R9_C3_BAS...|-8027743839728879857|15_27983407_C_T|15_27820229_G_A|15_27858692_G_A| 3.599| -4| 0.0427448| 0.0119804|-0.08881336794530735|\n", - "|FINNGEN_R9_C3_BAS...|-8027743839728879857|15_27983407_C_T|15_27825631_G_C|15_27915426_C_A| 1.001| -6| 0.0654293| 0.0133765| 0.13879209804155437|\n", - "|FINNGEN_R9_C3_BAS...|-8027743839728879857|15_27983407_C_T|15_28211160_A_T|15_27915426_C_A| 1.001| -6| 0.0654293| 0.0133765| 0.05996001018362227|\n", - "|FINNGEN_R9_C3_BAS...|-8027743839728879857|15_27983407_C_T|15_28019021_G_T|15_27915426_C_A| 1.001| -6| 0.0654293| 0.0133765| 0.03843623265438152|\n", - "|FINNGEN_R9_C3_BAS...|-8027743839728879857|15_27983407_C_T|15_28081390_A_T|15_27938863_T_A| 2.109| -3| 0.157002| 0.0510665|-0.04189151880774...|\n", - "|FINNGEN_R9_C3_BAS...|-8027743839728879857|15_27983407_C_T|15_27907664_A_T|15_27938914_G_T| 2.725| -2| 0.0355862| 0.0161172|-0.16859090364294946|\n", - "|FINNGEN_R9_C3_BAS...|-8027743839728879857|15_27983407_C_T|15_27819940_C_T|15_27938914_G_T| 2.725| -2| 0.0355862| 0.0161172| 0.11697321459267764|\n", - "|FINNGEN_R9_C3_BAS...|-8027743839728879857|15_27983407_C_T|15_27853556_T_G|15_27938914_G_T| 2.725| -2| 0.0355862| 0.0161172| -0.1404576556679461|\n", - "|FINNGEN_R9_C3_BAS...|-8027743839728879857|15_27983407_C_T|15_28052911_T_C|15_27951206_G_A| 1.437| -2| 0.0695541| 0.0284131| 0.04461220378655805|\n", - "|FINNGEN_R9_C3_BAS...|-8027743839728879857|15_27983407_C_T|15_27790520_G_A|15_27951206_G_A| 1.437| -2| 0.0695541| 0.0284131| 0.04420892575950266|\n", - "|FINNGEN_R9_C3_BAS...|-8027743839728879857|15_27983407_C_T|15_27879868_C_A|15_27989264_G_T| 2.454| -17| 0.147291| 0.0173896| 0.2404542405419156|\n", - "|FINNGEN_R9_C3_BAS...|-8027743839728879857|15_27983407_C_T|15_27822551_G_A|15_27989264_G_T| 2.454| -17| 0.147291| 0.0173896|-0.04613729472121665|\n", - "+--------------------+--------------------+---------------+---------------+---------------+-------------------+-------------------+----------+------------------+--------------------+\n", - "only showing top 20 rows\n", - "\n", - "385641\n", - "621.0\n" - ] - }, - { - "data": { - "text/plain": [ - "621" - ] - }, - "execution_count": 189, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Filtering matrix:\n", - "processed_matrix = (\n", - " ld_matrix\n", - " .join(\n", - " selected_locus.select(f.col('variantId').alias('variantIdLeft')),\n", - " on='variantIdLeft', how='inner'\n", - " )\n", - " .join(\n", - " selected_locus.withColumnRenamed('variantId', 'variantIdRight'), \n", - " on='variantIdRight', how='inner'\n", - " )\n", - " .select(\n", - " 'studyId',\n", - " 'studyLocusId',\n", - " 'variantIdLead',\n", - " 'variantIdLeft',\n", - " 'variantIdRight',\n", - " f.col('pValueMantissa').alias('pValueMantissaRight'),\n", - " f.col('pValueExponent').alias('pValueExponentRight'),\n", - " f.col('beta').alias('betaRight'),\n", - " f.col('standardError').alias('standardErrorRight'),\n", - " 'r'\n", - " )\n", - " .persist()\n", - ")\n", - "\n", - "processed_matrix.show()\n", - "print(processed_matrix.count())\n", - "print(sqrt(processed_matrix.count()))\n", - "processed_matrix.select('variantIdRight').distinct().count()" - ] - }, - { - "cell_type": "code", - "execution_count": 167, - "id": "381f093b", - "metadata": { - "ExecuteTime": { - "end_time": "2023-10-27T11:29:01.779404Z", - "start_time": "2023-10-27T11:28:57.285168Z" - } - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - }, - { - "data": { - "text/plain": [ - "array([[1. , 0.88019644, 0.28333008, 0.25666969, 0.26345801],\n", - " [0.88019644, 1. , 0.26027515, 0.24115952, 0.2442993 ],\n", - " [0.28333008, 0.26027515, 1. , 0.85898573, 0.89168227],\n", - " [0.25666969, 0.24115952, 0.85898573, 1. , 0.96268566],\n", - " [0.26345801, 0.2442993 , 0.89168227, 0.96268566, 1. ]])" - ] - }, - "execution_count": 167, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "\n", - "pivoted_matrix = (\n", - " processed_matrix\n", - " .orderBy(f.col('variantIdLeft'), f.col('variantIdRight'))\n", - " .groupBy('variantIdLeft')\n", - " .pivot(\"variantIdRight\")\n", - " .agg(f.first('r'))\n", - " .orderBy('variantIdLeft')\n", - " # Convert to numpy array ingested by SuSie:\n", - " .toPandas().set_index('variantIdLeft').to_numpy()\n", - ")\n", - "\n", - "pivoted_matrix[0:5, 0:5]" - ] - }, - { - "cell_type": "code", - "execution_count": 90, - "id": "444e2ca2", - "metadata": { - "ExecuteTime": { - "end_time": "2023-10-26T08:49:13.002374Z", - "start_time": "2023-10-26T08:49:12.604741Z" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "array([[ 1. , 0.99851182, 0.85089485, ..., 0.04532387,\n", - " 0.02258468, 0.02476075],\n", - " [ 0.99851182, 1. , 0.85111292, ..., 0.0465783 ,\n", - " 0.02253374, 0.02470884],\n", - " [ 0.85089485, 0.85111292, 1. , ..., 0.04748182,\n", - " 0.01191697, 0.01652519],\n", - " ...,\n", - " [ 0.04532387, 0.0465783 , 0.04748182, ..., 1. ,\n", - " -0.05908013, -0.05417476],\n", - " [ 0.02258468, 0.02253374, 0.01191697, ..., -0.05908013,\n", - " 1. , 0.96019982],\n", - " [ 0.02476075, 0.02470884, 0.01652519, ..., -0.05417476,\n", - " 0.96019982, 1. ]])" - ] - }, - "execution_count": 90, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "pivoted_matrix.toPandas().set_index('variantIdLeft').to_numpy()" - ] - }, - { - "cell_type": "code", - "execution_count": 190, - "id": "8ed590f1", - "metadata": { - "ExecuteTime": { - "end_time": "2023-10-27T13:50:01.812451Z", - "start_time": "2023-10-27T13:49:58.985895Z" - } - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - } - ], - "source": [ - "(\n", - " processed_matrix\n", - " # Convert to numpy array ingested by SuSie:\n", - " .write.mode('overwrite').parquet(f'gs://ot-team/dsuveges/processed-ld-matrix-{study_locus_id}')\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 169, - "id": "5fc2f7ac", - "metadata": { - "ExecuteTime": { - "end_time": "2023-10-27T11:30:11.297300Z", - "start_time": "2023-10-27T11:30:09.400659Z" - } - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - } - ], - "source": [ - "# selected_locus.write.mode('overwrite').parquet('gs://ot-team/dsuveges/selected_studyLocus_2224601896262245870')\n", - "(\n", - " processed_matrix\n", - " .select(\n", - " 'studyId',\n", - " f.col('variantIdRight').alias('variantId'),\n", - " f.col('pValueMantissaRight').alias('pValueMantissa'),\n", - " f.col('pValueExponentRight').alias('pValueExponent'),\n", - " f.col('betaRight').alias('beta'),\n", - " f.col('standardErrorRight').alias('standardError'),\n", - " )\n", - " .distinct()\n", - " .write.mode('overwrite').parquet(f'gs://ot-team/dsuveges/selected_studyLocus_{study_locus_id}')\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 187, - "id": "a4d47348", - "metadata": { - "ExecuteTime": { - "end_time": "2023-10-27T13:33:39.686914Z", - "start_time": "2023-10-27T13:33:39.682284Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1.00, 0.18, 0.18, 0.97, 0.97, 0.15, 0.18, 0.11, 0.13, 0.12\n", - "0.18, 1.00, 0.99, 0.15, 0.15, 0.03, 0.03, 0.02, 0.01, 0.02\n", - "0.18, 0.99, 1.00, 0.15, 0.15, 0.03, 0.03, 0.02, 0.01, 0.02\n", - "0.97, 0.15, 0.15, 1.00, 1.00, 0.14, 0.17, 0.11, 0.12, 0.12\n", - "0.97, 0.15, 0.15, 1.00, 1.00, 0.14, 0.17, 0.11, 0.12, 0.12\n", - "0.15, 0.03, 0.03, 0.14, 0.14, 1.00, 0.32, 0.45, 0.50, 0.25\n", - "0.18, 0.03, 0.03, 0.17, 0.17, 0.32, 1.00, 0.29, 0.33, 0.52\n", - "0.11, 0.02, 0.02, 0.11, 0.11, 0.45, 0.29, 1.00, 0.91, 0.29\n", - "0.13, 0.01, 0.01, 0.12, 0.12, 0.50, 0.33, 0.91, 1.00, 0.33\n", - "0.12, 0.02, 0.02, 0.12, 0.12, 0.25, 0.52, 0.29, 0.33, 1.00\n" - ] - } - ], - "source": [ - "print(\n", - " '\\n'.join(\n", - " [\n", - " ', '.join([f'{value**2:.2f}' for value in row]) \n", - " for row in\n", - " (\n", - " pivoted_matrix\n", - " [[291, 293, 295, 322, 323, 508, 514, 529, 534, 515]]\n", - " [:,[291, 293, 295, 322, 323, 508, 514, 529, 534, 515]]\n", - " )\n", - " ]\n", - " )\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 188, - "id": "f3910534", - "metadata": { - "ExecuteTime": { - "end_time": "2023-10-27T13:45:22.792801Z", - "start_time": "2023-10-27T13:45:22.721043Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "+--------------------+--------------------+---------------+---------------+---------------+-------------------+-------------------+----------+------------------+--------------------+\n", - "| studyId| studyLocusId| variantIdLead| variantIdLeft| variantIdRight|pValueMantissaRight|pValueExponentRight| betaRight|standardErrorRight| r|\n", - "+--------------------+--------------------+---------------+---------------+---------------+-------------------+-------------------+----------+------------------+--------------------+\n", - "|FINNGEN_R9_C3_BAS...|-8027743839728879857|15_27983407_C_T|15_27792793_C_T|15_27772290_T_C| 9.979| -6| 0.0730063| 0.0165261| 0.3188276023578284|\n", - "|FINNGEN_R9_C3_BAS...|-8027743839728879857|15_27983407_C_T|15_27950388_C_T|15_27778556_C_T| 1.142| -2| 0.119731| 0.0473309| -0.1845689041174883|\n", - "|FINNGEN_R9_C3_BAS...|-8027743839728879857|15_27983407_C_T|15_28104601_A_T|15_27809200_G_A| 1.397| -2|-0.0286999| 0.0116763| 0.01919714154020592|\n", - "|FINNGEN_R9_C3_BAS...|-8027743839728879857|15_27983407_C_T|15_27970325_G_A|15_27809200_G_A| 1.397| -2|-0.0286999| 0.0116763|-0.12413267238343029|\n", - "|FINNGEN_R9_C3_BAS...|-8027743839728879857|15_27983407_C_T|15_27899878_T_C|15_27851307_A_G| 5.606| -4|-0.0424098| 0.0122927|-0.45516734696600447|\n", - "|FINNGEN_R9_C3_BAS...|-8027743839728879857|15_27983407_C_T|15_27914364_C_T|15_27851307_A_G| 5.606| -4|-0.0424098| 0.0122927| -0.4029686644067302|\n", - "|FINNGEN_R9_C3_BAS...|-8027743839728879857|15_27983407_C_T|15_27828335_G_A|15_27858692_G_A| 3.599| -4| 0.0427448| 0.0119804| 0.09141477739652863|\n", - "|FINNGEN_R9_C3_BAS...|-8027743839728879857|15_27983407_C_T|15_27845815_A_G|15_27858692_G_A| 3.599| -4| 0.0427448| 0.0119804| 0.7803430284267874|\n", - "|FINNGEN_R9_C3_BAS...|-8027743839728879857|15_27983407_C_T|15_27820229_G_A|15_27858692_G_A| 3.599| -4| 0.0427448| 0.0119804|-0.08881336794530735|\n", - "|FINNGEN_R9_C3_BAS...|-8027743839728879857|15_27983407_C_T|15_27825631_G_C|15_27915426_C_A| 1.001| -6| 0.0654293| 0.0133765| 0.13879209804155437|\n", - "|FINNGEN_R9_C3_BAS...|-8027743839728879857|15_27983407_C_T|15_28211160_A_T|15_27915426_C_A| 1.001| -6| 0.0654293| 0.0133765| 0.05996001018362227|\n", - "|FINNGEN_R9_C3_BAS...|-8027743839728879857|15_27983407_C_T|15_28019021_G_T|15_27915426_C_A| 1.001| -6| 0.0654293| 0.0133765| 0.03843623265438152|\n", - "|FINNGEN_R9_C3_BAS...|-8027743839728879857|15_27983407_C_T|15_28081390_A_T|15_27938863_T_A| 2.109| -3| 0.157002| 0.0510665|-0.04189151880774...|\n", - "|FINNGEN_R9_C3_BAS...|-8027743839728879857|15_27983407_C_T|15_27907664_A_T|15_27938914_G_T| 2.725| -2| 0.0355862| 0.0161172|-0.16859090364294946|\n", - "|FINNGEN_R9_C3_BAS...|-8027743839728879857|15_27983407_C_T|15_27819940_C_T|15_27938914_G_T| 2.725| -2| 0.0355862| 0.0161172| 0.11697321459267764|\n", - "|FINNGEN_R9_C3_BAS...|-8027743839728879857|15_27983407_C_T|15_27853556_T_G|15_27938914_G_T| 2.725| -2| 0.0355862| 0.0161172| -0.1404576556679461|\n", - "|FINNGEN_R9_C3_BAS...|-8027743839728879857|15_27983407_C_T|15_28052911_T_C|15_27951206_G_A| 1.437| -2| 0.0695541| 0.0284131| 0.04461220378655805|\n", - "|FINNGEN_R9_C3_BAS...|-8027743839728879857|15_27983407_C_T|15_27790520_G_A|15_27951206_G_A| 1.437| -2| 0.0695541| 0.0284131| 0.04420892575950266|\n", - "|FINNGEN_R9_C3_BAS...|-8027743839728879857|15_27983407_C_T|15_27879868_C_A|15_27989264_G_T| 2.454| -17| 0.147291| 0.0173896| 0.2404542405419156|\n", - "|FINNGEN_R9_C3_BAS...|-8027743839728879857|15_27983407_C_T|15_27822551_G_A|15_27989264_G_T| 2.454| -17| 0.147291| 0.0173896|-0.04613729472121665|\n", - "+--------------------+--------------------+---------------+---------------+---------------+-------------------+-------------------+----------+------------------+--------------------+\n", - "only showing top 20 rows\n", - "\n" - ] - } - ], - "source": [ - "processed_matrix.show()" - ] - } - ], - "metadata": { - "_draft": { - "nbviewer_url": "https://gist.github.com/DSuveges/df6768b7d5637842e009aa945f3ea062" - }, - "gist": { - "data": { - "description": "Issue-3131-Productionizing_LD_matrix.ipynb", - "public": false - }, - "id": "df6768b7d5637842e009aa945f3ea062" - }, - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.8" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/notebooks/Release_QC_metrics.ipynb b/notebooks/Release_QC_metrics.ipynb index 0052a3cc8..aa0924711 100644 --- a/notebooks/Release_QC_metrics.ipynb +++ b/notebooks/Release_QC_metrics.ipynb @@ -68,9 +68,11 @@ "\"\"\"notebook for release qc metrics.\"\"\"\n", "\n", "import sys\n", - "from gentropy.common.session import Session\n", + "\n", "from pyspark.sql import functions as f\n", "\n", + "from gentropy.common.session import Session\n", + "\n", "sys.path.append(\"../../gentropy/src/\")\n", "release_path=\"../../otg_releases\"\n", "release_ver=\"2403\"\n", @@ -119,7 +121,6 @@ "variant_index=session.spark.read.parquet(variant_index_path, recursiveFileLookup=True)\n", "\n", "# How many variants?\n", - "print(\"Variant index contains \", variant_index.select(f.col(\"variantId\")).distinct().count(), \" unique variants.\")\n", "\n", "# How many variants with MAF>=0.01 for EUR population?\n", "#variant_index.filter(variant_index[\"alleleFrequencies.populationName\"] > 0.05).show(10, False)" @@ -175,9 +176,7 @@ "v2g=session.spark.read.parquet(v2g_path, recursiveFileLookup=True)\n", "\n", "#How many variants?\n", - "print(\"Unique variants in v2g release: \", v2g.select(f.col(\"variantId\")).distinct().count(), \", total variant to gene assignments: \", v2g.count(), \", number of v2g assignments where score > 0.8: \", v2g.filter(v2g[\"score\"] > 0.8).count(), \"(\", round( v2g.filter(v2g[\"score\"] > 0.8).count()/v2g.select(f.col(\"variantId\")).distinct().count(), 3), \"%)\")\n", "sample_size_quartiles = v2g.stat.approxQuantile(\"score\", [0.25, 0.5, 0.75], 0.01)\n", - "print(\"Summary of v2g_score: Mean: \", v2g.select(f.mean(v2g[\"score\"])).collect()[0][0], \"L.quart: \", sample_size_quartiles[0], \"Median: \", sample_size_quartiles[1], \"U.quart: \", sample_size_quartiles[2])\n", "#v2g.select().toPandas().plot.hist()\n", "#v2g.show()" ] @@ -262,22 +261,16 @@ "finngen_susie_path=f\"{release_path}/{release_ver}/credible_set/finngen_susie\"\n", "\n", "finngen_susie=session.spark.read.parquet(finngen_susie_path, recursiveFileLookup=True)\n", - "print(\"Number of unique finngen susie CSs: \", finngen_susie.select(\"studyId\", \"region\", \"credibleSetIndex\").distinct().count())\n", "\n", "# FinnGen:\n", "finngen_index=session.spark.read.parquet(finngen_index_path, recursiveFileLookup=True)\n", "# Number of CSs, studies.\n", - "print(\"Ingested \", finngen_susie.select(\"studyId\", \"region\", \"credibleSetIndex\").distinct().count(), \" Credible sets from\", finngen_index.select(f.col(\"studyId\")).distinct().count(), \"finngen studies\")\n", "sample_size_quartiles = finngen_index.stat.approxQuantile(\"nSamples\", [0.25, 0.5, 0.75], 0.01)\n", - "print(\"Summary of finngen sample sizes: Mean: \", finngen_index.select(f.mean(finngen_index[\"nSamples\"])).collect()[0][0], \"L.quart: \", sample_size_quartiles[0], \"Median: \", sample_size_quartiles[1], \"U.quart: \", sample_size_quartiles[2])\n", "# Number of unique studyids with at leas one CS.\n", - "print(\"Number of finngen studies with at least one CS: \", finngen_susie.select(\"studyId\").distinct().count())\n", "# Number of CSs with at leas one SNP with PIP>0.9\n", - "print(\"Number of CS with top SNP PP > 0.9: \", finngen_susie.select(\"studyId\", \"region\", \"credibleSetIndex\", \"locus.posteriorProbability\").withColumn(\"top_PP\", f.col(\"posteriorProbability\").getItem(0)).filter(f.col(\"top_PP\") > 0.9).count())\n", "# The descriptive summary of 99% CS size and histogram/density plot\n", "\n", "credset_size_quartiles = finngen_susie.select(\"studyId\", \"region\", \"credibleSetIndex\", \"locus.posteriorProbability\").withColumn(\"credset_size\", f.size(f.col(\"posteriorProbability\"))).stat.approxQuantile(\"credset_size\", [0.25, 0.5, 0.75], 0.01)\n", - "print(\"Summary of finngen credible set sizes: L.quart: \", credset_size_quartiles[0], \"Median: \", credset_size_quartiles[1], \"U.quart: \", credset_size_quartiles[2])\n", "\n", "finngen_susie.select(\"studyId\", \"region\", \"credibleSetIndex\", \"locus.posteriorProbability\").withColumn(\"top_PP\", f.col(\"posteriorProbability\").getItem(0)).withColumn(\"credset_size\", f.size(f.col(\"posteriorProbability\"))).toPandas().plot.scatter(x=\"credset_size\", y=\"top_PP\", xlim=[0, 500], alpha=0.05, label=\"finngen susie CSs\", title=\"finngen susie credsets\")\n", "\n", @@ -334,17 +327,13 @@ "# Number of CSs.\n", "finngen_pics=session.spark.read.parquet(finngen_pics_path, recursiveFileLookup=True)\n", "#gwascat_sumstats.printSchema()\n", - "print(\"Number of unique finngen pics CSs: \", finngen_pics.select(\"studyLocusId\").distinct().count(), \" in \", finngen_pics.select(\"studyId\").distinct().count(), \" studies.\")\n", "# keep only credible sets snps\n", "\n", "finngen_pics_fm=finngen_pics.select(\"studyId\", \"studyLocusId\", \"locus.posteriorProbability\").withColumn(\"top_PP\", f.col(\"posteriorProbability\").getItem(0)).withColumn(\"credset_size\", f.size(f.col(\"posteriorProbability\")))\n", "finngen_pics_fm.select(\"credset_size\", \"top_PP\").toPandas().plot.scatter(x=\"credset_size\", y=\"top_PP\", alpha=0.05, xlim=[0, 500], label=\"finngen PICS CS\", title=\"finngen_pics CS\")\n", - "print(\"Number of finngen_pics CS with top SNP PP > 0.9: \", finngen_pics_fm.filter(f.col(\"top_PP\") > 0.9).distinct().count())\n", "sample_size_quartiles = finngen_index.stat.approxQuantile(\"nSamples\", [0.25, 0.5, 0.75], 0.01)\n", - "print(\"Summary of finngen_pics sample sizes: L.quart: \", sample_size_quartiles[0], \"Median: \", sample_size_quartiles[1], \"U.quart: \", sample_size_quartiles[2])\n", "\n", - "sample_size_quartiles = finngen_pics_fm.stat.approxQuantile(\"credset_size\", [0.25, 0.5, 0.75], 0.01)\n", - "print(\"Summary of finngen_pics credset sizes: Mean: \", finngen_pics_fm.select(f.mean(finngen_pics_fm[\"credset_size\"])).collect()[0][0], \"L.quart: \", sample_size_quartiles[0], \"Median: \", sample_size_quartiles[1], \"U.quart: \", sample_size_quartiles[2])" + "sample_size_quartiles = finngen_pics_fm.stat.approxQuantile(\"credset_size\", [0.25, 0.5, 0.75], 0.01)" ] }, { @@ -360,9 +349,7 @@ ] } ], - "source": [ - "print(\"There are \", finngen_susie.join(finngen_pics, on=[\"studyId\", \"studyLocusId\"], how=\"inner\").count(), \" common loci between finngen susie and finngen pics\")" - ] + "source": [] }, { "cell_type": "code", @@ -389,8 +376,7 @@ ], "source": [ "finngen_matching=finngen_pics_fm.withColumnRenamed(\"top_PP\", \"pics_PP\").join(finngen_susie_fm.withColumnRenamed(\"top_PP\", \"susie_PP\"), on=[\"studyId\", \"studyLocusId\"], how=\"inner\")\n", - "finngen_matching.select(\"pics_PP\", \"susie_PP\").toPandas().plot.scatter(x=\"susie_PP\", y=\"pics_PP\", alpha=0.05, title=\"finngen_pics vs finngen_susie CS\")\n", - "print(\"correlation coef: \", finngen_matching.stat.corr(\"pics_PP\", \"susie_PP\"))" + "finngen_matching.select(\"pics_PP\", \"susie_PP\").toPandas().plot.scatter(x=\"susie_PP\", y=\"pics_PP\", alpha=0.05, title=\"finngen_pics vs finngen_susie CS\")" ] }, { @@ -509,9 +495,7 @@ "# eQTLcat:\n", "# Number of studies\n", "eqtl_index=session.spark.read.parquet(eqtl_index_path, recursiveFileLookup=True)\n", - "print(\"Number of unique eQTLcat studies: \", eqtl_index.select(f.col(\"studyId\")).distinct().count())\n", "# Number of tissues, list of tissues\n", - "print(\"Number of unqiue eQTLcat tissues: \", eqtl_index.select(f.col(\"tissueFromSourceId\")).distinct().count())\n", "#eqtl_index.select(f.col(\"tissueFromSourceId\")).distinct().show(truncate=False)\n", "\n", "# Credible_set. Please use Daniels’ notebook as a reference. For each subfolder:\n", @@ -522,17 +506,12 @@ "\n", "\n", "# Number of CSs, studies.\n", - "print(\"Ingested \", eqtlcat_susie.select(\"studyId\", \"region\", \"credibleSetIndex\").distinct().count(), \" Credible sets from\", eqtl_index.select(f.col(\"studyId\")).distinct().count(), \"eQTL catalog studies\")\n", "sample_size_quartiles = eqtl_index.stat.approxQuantile(\"nSamples\", [0.25, 0.5, 0.75], 0.01)\n", - "print(\"Summary of eQTL catalog sample sizes: Mean: \", eqtl_index.select(f.mean(eqtl_index[\"nSamples\"])).collect()[0][0], \"L.quart: \", sample_size_quartiles[0], \"Median: \", sample_size_quartiles[1], \"U.quart: \", sample_size_quartiles[2])\n", "# Number of unique studyids with at leas one CS.\n", - "print(\"Number of eQTL catalog studies with at least one CS: \", eqtlcat_susie.select(\"studyId\").distinct().count())\n", "# Number of CSs with at leas one SNP with PIP>0.9\n", - "print(\"Number of CS with top SNP PP > 0.9: \", eqtlcat_susie.select(\"studyId\", \"region\", \"credibleSetIndex\", \"locus.posteriorProbability\").withColumn(\"top_PP\", f.col(\"posteriorProbability\").getItem(0)).filter(f.col(\"top_PP\") > 0.9).count())\n", "# The descriptive summary of 99% CS size and histogram/density plot\n", "\n", "credset_size_quartiles = eqtlcat_susie.select(\"studyId\", \"region\", \"credibleSetIndex\", \"locus.posteriorProbability\").withColumn(\"credset_size\", f.size(f.col(\"posteriorProbability\"))).stat.approxQuantile(\"credset_size\", [0.25, 0.5, 0.75], 0.01)\n", - "print(\"Summary of eQTL credible set sizes: L.quart: \", credset_size_quartiles[0], \"Median: \", credset_size_quartiles[1], \"U.quart: \", credset_size_quartiles[2])\n", "\n", "# Out of mem error:\n", "#eqtlcat_susie.select(\"studyId\", \"region\", \"credibleSetIndex\", \"locus.posteriorProbability\").withColumn(\"top_PP\", f.col(\"posteriorProbability\").getItem(0)).withColumn(\"credset_size\", f.size(f.col(\"posteriorProbability\"))).toPandas().plot.scatter(x=\"credset_size\", y=\"top_PP\", xlim=[0, 500], alpha=0.05, label=\"finngen susie CSs\", title=\"finngen susie credsets\")\n" @@ -663,9 +642,7 @@ "# Gwas Catalog:\n", "gwascat_index=session.spark.read.parquet(gwascat_path, recursiveFileLookup=True)\n", "# Number of GWAS curated studies\n", - "print(\"Number of unique gwascat studies: \", gwascat_index.select(f.col(\"studyId\")).distinct().count())\n", "# Number of studies with full GWAS sumstats\n", - "print(\"Number of unique SUMSTATS gwascat studies: \", gwascat_index.filter(f.col(\"hasSumstats\") == True).select(f.col(\"studyId\")).distinct().count())\n", "#gwascat_index\n", "# The histogram/density plot for total sample size separately for curated studies and full GWAS\n", "#gwascat_index.filter(f.col(\"hasSumstats\") == True).select(f.col(\"nSamples\")).toPandas().plot.hist(bins=25, alpha=0.5, label=\"Sumstats GWAScat sample size\", title=\"Sumstats GWAScat sample size\")\n", @@ -677,20 +654,15 @@ "# Number of CSs.\n", "gwascat_sumstats=session.spark.read.parquet(gwascat_sumstats_path, recursiveFileLookup=True)\n", "\n", - "print(\"Number of unique gwas catalog sumstats CSs: \", gwascat_sumstats.select(\"studyLocusId\").distinct().count(), \" in \", gwascat_sumstats.select(\"studyId\").distinct().count(), \" studies.\")\n", "\n", "\n", "sample_size_quartiles = gwascat_index.join(gwascat_sumstats, how=\"inner\", on=\"studyId\").stat.approxQuantile(\"nSamples\", [0.25, 0.5, 0.75], 0.01)\n", - "print(\"Summary of SUMSTATS gwas sample sizes: L.quart: \", sample_size_quartiles[0], \"Median: \", sample_size_quartiles[1], \"U.quart: \", sample_size_quartiles[2])\n", - "#\n", "\n", "\n", "gwascat_sumstats_fm=gwascat_sumstats.select(\"studyId\", \"studyLocusId\", \"locus.posteriorProbability\").withColumn(\"top_PP\", f.col(\"posteriorProbability\").getItem(0)).withColumn(\"credset_size\", f.size(f.col(\"posteriorProbability\")))\n", "gwascat_sumstats_fm.select(\"credset_size\", \"top_PP\").toPandas().plot.scatter(x=\"credset_size\", y=\"top_PP\", alpha=0.05, label=\"gwascat sumstats PICS CS\", title=\"gwascat sumstats PICS CS\")\n", - "print(\"Number of SUMSTATS CS with top SNP PP > 0.9: \", gwascat_sumstats_fm.filter(f.col(\"top_PP\") > 0.9).distinct().count())\n", "\n", "sample_size_quartiles = gwascat_sumstats_fm.stat.approxQuantile(\"credset_size\", [0.25, 0.5, 0.75], 0.01)\n", - "print(\"Summary of SUMSTATS gwascat pics credset sizes: Mean: \", gwascat_sumstats_fm.select(f.mean(gwascat_sumstats_fm[\"credset_size\"])).collect()[0][0], \"L.quart: \", sample_size_quartiles[0], \"Median: \", sample_size_quartiles[1], \"U.quart: \", sample_size_quartiles[2])\n", "\n", "\n", "# gwas catalog curated (PICs):\n", @@ -698,17 +670,13 @@ "# Number of CSs.\n", "gwascat_curated=session.spark.read.parquet(gwascat_curated_path, recursiveFileLookup=True)\n", "#gwascat_sumstats.printSchema()\n", - "print(\"Number of unique gwas catalog curated CSs: \", gwascat_curated.select(\"studyLocusId\").distinct().count(), \" in \", gwascat_curated.select(\"studyId\").distinct().count(), \" studies.\")\n", "# keep only credible sets snps\n", "\n", "gwascat_curated_fm=gwascat_curated.select(\"studyId\", \"studyLocusId\", \"locus.posteriorProbability\").withColumn(\"top_PP\", f.col(\"posteriorProbability\").getItem(0)).withColumn(\"credset_size\", f.size(f.col(\"posteriorProbability\")))\n", "gwascat_curated_fm.select(\"credset_size\", \"top_PP\").toPandas().plot.scatter(x=\"credset_size\", y=\"top_PP\", alpha=0.05, label=\"gwascat curated PICS CS\", title=\"gwascat curated PICS CS\")\n", - "print(\"Number of CURATED CS with top SNP PP > 0.9: \", gwascat_curated_fm.filter(f.col(\"top_PP\") > 0.9).distinct().count())\n", "sample_size_quartiles = gwascat_index.join(gwascat_sumstats, how=\"anti\", on=\"studyId\").stat.approxQuantile(\"nSamples\", [0.25, 0.5, 0.75], 0.01)\n", - "print(\"Summary of CURATED gwas sample sizes: L.quart: \", sample_size_quartiles[0], \"Median: \", sample_size_quartiles[1], \"U.quart: \", sample_size_quartiles[2])\n", "\n", - "sample_size_quartiles = gwascat_curated_fm.stat.approxQuantile(\"credset_size\", [0.25, 0.5, 0.75], 0.01)\n", - "print(\"Summary of CURATED gwascat pics credset sizes: Mean: \", gwascat_curated_fm.select(f.mean(gwascat_curated_fm[\"credset_size\"])).collect()[0][0], \"L.quart: \", sample_size_quartiles[0], \"Median: \", sample_size_quartiles[1], \"U.quart: \", sample_size_quartiles[2])" + "sample_size_quartiles = gwascat_curated_fm.stat.approxQuantile(\"credset_size\", [0.25, 0.5, 0.75], 0.01)" ] }, { @@ -758,9 +726,7 @@ "coloc_path=f\"{release_path}/{release_ver}/colocalisation\"\n", "coloc=session.spark.read.parquet(coloc_path, recursiveFileLookup=True)\n", "\n", - "print(\"Number of colocalisations: \", coloc.count(), \" , of which, \", coloc.filter(f.col(\"clpp\") > 0.8).count(), \" > 0.8 clpp (\", round((coloc.filter(f.col(\"clpp\") > 0.8).count()/coloc.count()), 3)*100, \"%)\")\n", "Avg_overlaps=coloc.groupBy(\"leftStudyLocusId\").count().agg(f.avg(\"count\")).collect()[0][0]\n", - "print(\"Average number of overlaps per CS: \", Avg_overlaps)\n", "\n" ] }, @@ -850,10 +816,6 @@ "l2g_path=f\"{release_path}/{release_ver}/locus_to_gene_predictions\"\n", "l2g=session.spark.read.parquet(l2g_path, recursiveFileLookup=True)\n", "l2g.select(\"score\").toPandas().plot.hist(bins=10, alpha=0.5, title=\"l2g scores\")\n", - "print(\"A total of \", l2g.select(\"studyLocusId\", \"geneId\").count(), \"l2g predictions were computed.\")\n", - "print(\"There are\", l2g.select(\"studyLocusId\", \"geneId\").distinct().count(), \" UNIQUE locus to gene predictions for\", l2g.select(\"studyLocusId\").distinct().count(), \" unique studyloci\")\n", - "print(\"Where \", l2g.filter(f.col(\"score\") > 0.5).select(\"studyLocusId\").distinct().count(), \" studyloci contains at least one gene with score > 0.5\")\n", - "print(\"Of these, \", l2g.filter(f.col(\"score\") > 0.5).groupBy(\"studyLocusId\").count().filter(f.col(\"count\") > 1).count(), \" studyloci contains more than one gene with score > 0.5\")\n", "\n", "# There are duplicated l2g predictions studyLocusId with finngen pics and susie" ] @@ -911,9 +873,9 @@ "source": [ "from pyspark.sql import Window\n", "\n", - "window = Window.partitionBy(l2g['studyLocusId']).orderBy(l2g['score'].desc())\n", - "l2g = l2g.withColumn('rn', f.row_number().over(window))\n", - "l2g_max_scores = l2g.filter(l2g['rn'] == 1).drop('rn')\n", + "window = Window.partitionBy(l2g[\"studyLocusId\"]).orderBy(l2g[\"score\"].desc())\n", + "l2g = l2g.withColumn(\"rn\", f.row_number().over(window))\n", + "l2g_max_scores = l2g.filter(l2g[\"rn\"] == 1).drop(\"rn\")\n", "l2g_max_scores.select(\"score\").toPandas().plot.hist(bins=10, alpha=0.5, title=\"l2g scores (top gene assignment)\")" ] }, @@ -960,8 +922,7 @@ "l2g_finngen_pics=l2g_max_scores.join(finngen_pics.select(\"studyLocusId\", \"studyId\"), on=\"studyLocusId\", how=\"inner\")\n", "l2g_finngen_pics.select(\"score\").toPandas().plot.hist(bins=10, alpha=0.5, title=\"l2g scores (top gene assignment), finngen_pics\")\n", "\n", - "sample_size_quartiles = l2g_finngen_pics.stat.approxQuantile(\"score\", [0.25, 0.5, 0.75], 0.01)\n", - "print(\"Summary of finngen PICS l2g scores: mean:\", l2g_finngen_pics.select(f.mean(l2g_finngen_pics[\"score\"])).collect()[0][0], \"L.quart: \", sample_size_quartiles[0], \"Median: \", sample_size_quartiles[1], \"U.quart: \", sample_size_quartiles[2])" + "sample_size_quartiles = l2g_finngen_pics.stat.approxQuantile(\"score\", [0.25, 0.5, 0.75], 0.01)" ] }, { @@ -998,8 +959,7 @@ "l2g_finngen_susie=l2g_max_scores.join(finngen_susie.select(\"studyLocusId\", \"studyId\"), on=\"studyLocusId\", how=\"inner\")\n", "l2g_finngen_susie.select(\"score\").toPandas().plot.hist(bins=10, alpha=0.5, title=\"(top gene assignment), l2g_finngen_susie\")\n", "\n", - "sample_size_quartiles = l2g_finngen_susie.stat.approxQuantile(\"score\", [0.25, 0.5, 0.75], 0.01)\n", - "print(\"Summary of l2g_finngen_susie: mean:\", l2g_finngen_susie.select(f.mean(l2g_finngen_susie[\"score\"])).collect()[0][0], \"L.quart: \", sample_size_quartiles[0], \"Median: \", sample_size_quartiles[1], \"U.quart: \", sample_size_quartiles[2])" + "sample_size_quartiles = l2g_finngen_susie.stat.approxQuantile(\"score\", [0.25, 0.5, 0.75], 0.01)" ] }, { @@ -1036,8 +996,7 @@ "l2g_gwas_curated=l2g_max_scores.join(gwascat_curated.select(\"studyLocusId\", \"studyId\"), on=\"studyLocusId\", how=\"inner\")\n", "l2g_gwas_curated.select(\"score\").toPandas().plot.hist(bins=10, alpha=0.5, title=\"(top gene assignment), l2g_gwas_curated_pics\")\n", "\n", - "sample_size_quartiles = l2g_gwas_curated.stat.approxQuantile(\"score\", [0.25, 0.5, 0.75], 0.01)\n", - "print(\"Summary of l2g_gwas_curated PICS l2g scores: mean:\", l2g_gwas_curated.select(f.mean(l2g_gwas_curated[\"score\"])).collect()[0][0], \"L.quart: \", sample_size_quartiles[0], \"Median: \", sample_size_quartiles[1], \"U.quart: \", sample_size_quartiles[2])" + "sample_size_quartiles = l2g_gwas_curated.stat.approxQuantile(\"score\", [0.25, 0.5, 0.75], 0.01)" ] }, { @@ -1074,8 +1033,7 @@ "l2g_gwas_sumstats=l2g_max_scores.join(gwascat_sumstats.select(\"studyLocusId\", \"studyId\"), on=\"studyLocusId\", how=\"inner\")\n", "l2g_gwas_sumstats.select(\"score\").toPandas().plot.hist(bins=10, alpha=0.5, title=\"(top gene assignment), l2g_gwas_sumstats\")\n", "\n", - "sample_size_quartiles = l2g_gwas_sumstats.stat.approxQuantile(\"score\", [0.25, 0.5, 0.75], 0.01)\n", - "print(\"Summary of l2g_gwas_sumstats PICS l2g scores: mean:\", l2g_gwas_sumstats.select(f.mean(l2g_gwas_sumstats[\"score\"])).collect()[0][0], \"L.quart: \", sample_size_quartiles[0], \"Median: \", sample_size_quartiles[1], \"U.quart: \", sample_size_quartiles[2])" + "sample_size_quartiles = l2g_gwas_sumstats.stat.approxQuantile(\"score\", [0.25, 0.5, 0.75], 0.01)" ] } ], diff --git a/notebooks/gwas_cat_benchmark.ipynb b/notebooks/gwas_cat_benchmark.ipynb index cce01a050..a2ecf5455 100644 --- a/notebooks/gwas_cat_benchmark.ipynb +++ b/notebooks/gwas_cat_benchmark.ipynb @@ -37,6 +37,7 @@ "source": [ "# import matplotlib.pyplot as plt\n", "import pyspark.sql.functions as f\n", + "\n", "from gentropy.common.session import Session\n", "from gentropy.common.spark_helpers import order_array_of_structs_by_field\n", "from gentropy.dataset.ld_index import LDIndex\n", @@ -319,24 +320,24 @@ "source": [ "panda_df = df.select(\"locusSize\", \"locusLength\").toPandas()\n", "\n", - "plt.figure(figsize=(12, 6))\n", + "# plt.figure(figsize=(12, 6))\n", "\n", - "# Histogram for locusLength\n", - "plt.subplot(1, 2, 1) # 1 row, 2 columns, 1st subplot\n", - "plt.hist(panda_df[\"locusLength\"], bins=30, alpha=0.7)\n", - "plt.xlabel(\"Locus Length\")\n", - "plt.ylabel(\"Frequency\")\n", - "plt.title(\"Histogram of Locus Length\")\n", + "# # Histogram for locusLength\n", + "# plt.subplot(1, 2, 1) # 1 row, 2 columns, 1st subplot\n", + "# plt.hist(panda_df[\"locusLength\"], bins=30, alpha=0.7)\n", + "# plt.xlabel(\"Locus Length\")\n", + "# plt.ylabel(\"Frequency\")\n", + "# plt.title(\"Histogram of Locus Length\")\n", "\n", - "# Histogram for locusSize\n", - "plt.subplot(1, 2, 2) # 1 row, 2 columns, 2nd subplot\n", - "plt.hist(panda_df[\"locusSize\"], bins=30, alpha=0.7)\n", - "plt.xlabel(\"Locus Size\")\n", - "plt.ylabel(\"Frequency\")\n", - "plt.title(\"Histogram of Locus Size\")\n", + "# # Histogram for locusSize\n", + "# plt.subplot(1, 2, 2) # 1 row, 2 columns, 2nd subplot\n", + "# plt.hist(panda_df[\"locusSize\"], bins=30, alpha=0.7)\n", + "# plt.xlabel(\"Locus Size\")\n", + "# plt.ylabel(\"Frequency\")\n", + "# plt.title(\"Histogram of Locus Size\")\n", "\n", - "plt.tight_layout()\n", - "plt.show()" + "# plt.tight_layout()\n", + "# plt.show()" ] }, { @@ -356,13 +357,13 @@ } ], "source": [ - "plt.figure(figsize=(10, 6))\n", - "plt.scatter(panda_df[\"locusSize\"], panda_df[\"locusLength\"], alpha=0.5)\n", - "plt.title(\"Scatter Plot of Locus Size vs Locus Length\")\n", - "plt.xlabel(\"Locus Size\")\n", - "plt.ylabel(\"Locus Length\")\n", - "plt.grid(True)\n", - "plt.show()" + "# plt.figure(figsize=(10, 6))\n", + "# plt.scatter(panda_df[\"locusSize\"], panda_df[\"locusLength\"], alpha=0.5)\n", + "# plt.title(\"Scatter Plot of Locus Size vs Locus Length\")\n", + "# plt.xlabel(\"Locus Size\")\n", + "# plt.ylabel(\"Locus Length\")\n", + "# plt.grid(True)\n", + "# plt.show()" ] }, { @@ -458,9 +459,7 @@ ], "source": [ "nan = susie_fm.df.filter(f.isnan(\"credibleSetlog10BF\"))\n", - "null = susie_fm.df.filter(f.isnull(\"credibleSetlog10BF\"))\n", - "print(\"Number of credible sets with 'not a number' as the logBF: \", nan.count())\n", - "print(\"Number of credible sets with 'null' as the logBF: \", null.count())" + "null = susie_fm.df.filter(f.isnull(\"credibleSetlog10BF\"))" ] }, { @@ -639,39 +638,39 @@ ], "source": [ "pdf = susie_results.select(\"purityMinR2\", \"purityMeanR2\", \"topPP\", \"credSetSize\").toPandas()\n", - "plt.figure(figsize=(12, 12))\n", + "# plt.figure(figsize=(12, 12))\n", "\n", - "# Histogram for purityMinR2\n", - "plt.subplot(2, 2, 1)\n", - "plt.hist(pdf[\"purityMinR2\"], bins=30, alpha=0.7)\n", - "plt.title(\"Histogram of purityMinR2\")\n", - "plt.xlabel(\"purityMinR2\")\n", - "plt.ylabel(\"Frequency\")\n", + "# # Histogram for purityMinR2\n", + "# plt.subplot(2, 2, 1)\n", + "# plt.hist(pdf[\"purityMinR2\"], bins=30, alpha=0.7)\n", + "# plt.title(\"Histogram of purityMinR2\")\n", + "# plt.xlabel(\"purityMinR2\")\n", + "# plt.ylabel(\"Frequency\")\n", "\n", - "# Histogram for purityMeanR2\n", - "plt.subplot(2, 2, 2)\n", - "plt.hist(pdf[\"purityMeanR2\"], bins=30, alpha=0.7)\n", - "plt.title(\"Histogram of purityMeanR2\")\n", - "plt.xlabel(\"purityMeanR2\")\n", - "plt.ylabel(\"Frequency\")\n", + "# # Histogram for purityMeanR2\n", + "# plt.subplot(2, 2, 2)\n", + "# plt.hist(pdf[\"purityMeanR2\"], bins=30, alpha=0.7)\n", + "# plt.title(\"Histogram of purityMeanR2\")\n", + "# plt.xlabel(\"purityMeanR2\")\n", + "# plt.ylabel(\"Frequency\")\n", "\n", - "# Histogram for topPP\n", - "plt.subplot(2, 2, 3)\n", - "plt.hist(pdf[\"topPP\"], bins=30, alpha=0.7)\n", - "plt.title(\"Histogram of topPP\")\n", - "plt.xlabel(\"topPP\")\n", - "plt.ylabel(\"Frequency\")\n", + "# # Histogram for topPP\n", + "# plt.subplot(2, 2, 3)\n", + "# plt.hist(pdf[\"topPP\"], bins=30, alpha=0.7)\n", + "# plt.title(\"Histogram of topPP\")\n", + "# plt.xlabel(\"topPP\")\n", + "# plt.ylabel(\"Frequency\")\n", "\n", - "# Histogram for credSetSize\n", - "plt.subplot(2, 2, 4)\n", - "plt.hist(pdf[\"credSetSize\"], bins=30, alpha=0.7)\n", - "plt.title(\"Histogram of credSetSize\")\n", - "plt.xlabel(\"credSetSize\")\n", - "plt.ylabel(\"Frequency\")\n", + "# # Histogram for credSetSize\n", + "# plt.subplot(2, 2, 4)\n", + "# plt.hist(pdf[\"credSetSize\"], bins=30, alpha=0.7)\n", + "# plt.title(\"Histogram of credSetSize\")\n", + "# plt.xlabel(\"credSetSize\")\n", + "# plt.ylabel(\"Frequency\")\n", "\n", - "# Adjust layout to prevent overlap\n", - "plt.tight_layout()\n", - "plt.show()" + "# # Adjust layout to prevent overlap\n", + "# plt.tight_layout()\n", + "# plt.show()" ] }, { @@ -730,9 +729,7 @@ } ], "source": [ - "first_credset = susie_results.filter(f.col(\"credibleSetIndex\") == 1)\n", - "print(\"Number of primary credible sets: \", first_credset.count())\n", - "print(\"Number of unique studyIds in primary credible sets: \", first_credset.select(\"studyId\").distinct().count())" + "first_credset = susie_results.filter(f.col(\"credibleSetIndex\") == 1)" ] }, { @@ -900,39 +897,39 @@ ], "source": [ "pdf = first_credset.select(\"purityMinR2\", \"purityMeanR2\", \"topPP\", \"credSetSize\").toPandas()\n", - "plt.figure(figsize=(12, 12))\n", + "# plt.figure(figsize=(12, 12))\n", "\n", - "# Histogram for purityMinR2\n", - "plt.subplot(2, 2, 1)\n", - "plt.hist(pdf[\"purityMinR2\"], bins=30, alpha=0.7)\n", - "plt.title(\"Histogram of purityMinR2\")\n", - "plt.xlabel(\"purityMinR2\")\n", - "plt.ylabel(\"Frequency\")\n", + "# # Histogram for purityMinR2\n", + "# plt.subplot(2, 2, 1)\n", + "# plt.hist(pdf[\"purityMinR2\"], bins=30, alpha=0.7)\n", + "# plt.title(\"Histogram of purityMinR2\")\n", + "# plt.xlabel(\"purityMinR2\")\n", + "# plt.ylabel(\"Frequency\")\n", "\n", - "# Histogram for purityMeanR2\n", - "plt.subplot(2, 2, 2)\n", - "plt.hist(pdf[\"purityMeanR2\"], bins=30, alpha=0.7)\n", - "plt.title(\"Histogram of purityMeanR2\")\n", - "plt.xlabel(\"purityMeanR2\")\n", - "plt.ylabel(\"Frequency\")\n", + "# # Histogram for purityMeanR2\n", + "# plt.subplot(2, 2, 2)\n", + "# plt.hist(pdf[\"purityMeanR2\"], bins=30, alpha=0.7)\n", + "# plt.title(\"Histogram of purityMeanR2\")\n", + "# plt.xlabel(\"purityMeanR2\")\n", + "# plt.ylabel(\"Frequency\")\n", "\n", - "# Histogram for topPP\n", - "plt.subplot(2, 2, 3)\n", - "plt.hist(pdf[\"topPP\"], bins=30, alpha=0.7)\n", - "plt.title(\"Histogram of topPP\")\n", - "plt.xlabel(\"topPP\")\n", - "plt.ylabel(\"Frequency\")\n", + "# # Histogram for topPP\n", + "# plt.subplot(2, 2, 3)\n", + "# plt.hist(pdf[\"topPP\"], bins=30, alpha=0.7)\n", + "# plt.title(\"Histogram of topPP\")\n", + "# plt.xlabel(\"topPP\")\n", + "# plt.ylabel(\"Frequency\")\n", "\n", - "# Histogram for credSetSize\n", - "plt.subplot(2, 2, 4)\n", - "plt.hist(pdf[\"credSetSize\"], bins=30, alpha=0.7)\n", - "plt.title(\"Histogram of credSetSize\")\n", - "plt.xlabel(\"credSetSize\")\n", - "plt.ylabel(\"Frequency\")\n", + "# # Histogram for credSetSize\n", + "# plt.subplot(2, 2, 4)\n", + "# plt.hist(pdf[\"credSetSize\"], bins=30, alpha=0.7)\n", + "# plt.title(\"Histogram of credSetSize\")\n", + "# plt.xlabel(\"credSetSize\")\n", + "# plt.ylabel(\"Frequency\")\n", "\n", - "# Adjust layout to prevent overlap\n", - "plt.tight_layout()\n", - "plt.show()" + "# # Adjust layout to prevent overlap\n", + "# plt.tight_layout()\n", + "# plt.show()" ] }, { @@ -985,13 +982,7 @@ " )\n", " .withColumn(\"topPP\", f.col(\"locus\").getField(\"posteriorProbability\"))\n", " .filter(~f.isnan(\"topPP\"))\n", - ")\n", - "\n", - "print(\"Number of high quality credible sets: \", qc_credsets.count())\n", - "print(\n", - " \"Number of unique studyIds in high quality credible sets: \",\n", - " qc_credsets.select(\"studyId\").distinct().count(),\n", - ")" + ")\n" ] }, { @@ -1139,39 +1130,39 @@ ], "source": [ "pdf = qc_credsets.select(\"purityMinR2\", \"purityMeanR2\", \"topPP\", \"credSetSize\").toPandas()\n", - "plt.figure(figsize=(12, 12))\n", + "# plt.figure(figsize=(12, 12))\n", "\n", - "# Histogram for purityMinR2\n", - "plt.subplot(2, 2, 1)\n", - "plt.hist(pdf[\"purityMinR2\"], bins=30, alpha=0.7)\n", - "plt.title(\"Histogram of purityMinR2\")\n", - "plt.xlabel(\"purityMinR2\")\n", - "plt.ylabel(\"Frequency\")\n", + "# # Histogram for purityMinR2\n", + "# plt.subplot(2, 2, 1)\n", + "# plt.hist(pdf[\"purityMinR2\"], bins=30, alpha=0.7)\n", + "# plt.title(\"Histogram of purityMinR2\")\n", + "# plt.xlabel(\"purityMinR2\")\n", + "# plt.ylabel(\"Frequency\")\n", "\n", - "# Histogram for purityMeanR2\n", - "plt.subplot(2, 2, 2)\n", - "plt.hist(pdf[\"purityMeanR2\"], bins=30, alpha=0.7)\n", - "plt.title(\"Histogram of purityMeanR2\")\n", - "plt.xlabel(\"purityMeanR2\")\n", - "plt.ylabel(\"Frequency\")\n", + "# # Histogram for purityMeanR2\n", + "# plt.subplot(2, 2, 2)\n", + "# plt.hist(pdf[\"purityMeanR2\"], bins=30, alpha=0.7)\n", + "# plt.title(\"Histogram of purityMeanR2\")\n", + "# plt.xlabel(\"purityMeanR2\")\n", + "# plt.ylabel(\"Frequency\")\n", "\n", - "# Histogram for topPP\n", - "plt.subplot(2, 2, 3)\n", - "plt.hist(pdf[\"topPP\"], bins=30, alpha=0.7)\n", - "plt.title(\"Histogram of topPP\")\n", - "plt.xlabel(\"topPP\")\n", - "plt.ylabel(\"Frequency\")\n", + "# # Histogram for topPP\n", + "# plt.subplot(2, 2, 3)\n", + "# plt.hist(pdf[\"topPP\"], bins=30, alpha=0.7)\n", + "# plt.title(\"Histogram of topPP\")\n", + "# plt.xlabel(\"topPP\")\n", + "# plt.ylabel(\"Frequency\")\n", "\n", - "# Histogram for credSetSize\n", - "plt.subplot(2, 2, 4)\n", - "plt.hist(pdf[\"credSetSize\"], bins=30, alpha=0.7)\n", - "plt.title(\"Histogram of credSetSize\")\n", - "plt.xlabel(\"credSetSize\")\n", - "plt.ylabel(\"Frequency\")\n", + "# # Histogram for credSetSize\n", + "# plt.subplot(2, 2, 4)\n", + "# plt.hist(pdf[\"credSetSize\"], bins=30, alpha=0.7)\n", + "# plt.title(\"Histogram of credSetSize\")\n", + "# plt.xlabel(\"credSetSize\")\n", + "# plt.ylabel(\"Frequency\")\n", "\n", - "# Adjust layout to prevent overlap\n", - "plt.tight_layout()\n", - "plt.show()" + "# # Adjust layout to prevent overlap\n", + "# plt.tight_layout()\n", + "# plt.show()" ] }, { @@ -1436,24 +1427,24 @@ "source": [ "panda_df = df.select(\"locusSize\", \"locusLength\").toPandas()\n", "\n", - "plt.figure(figsize=(12, 6))\n", + "# plt.figure(figsize=(12, 6))\n", "\n", - "# Histogram for locusLength\n", - "plt.subplot(1, 2, 1) # 1 row, 2 columns, 1st subplot\n", - "plt.hist(panda_df[\"locusLength\"], bins=30, alpha=0.7)\n", - "plt.xlabel(\"Locus Length\")\n", - "plt.ylabel(\"Frequency\")\n", - "plt.title(\"Histogram of Locus Length\")\n", + "# # Histogram for locusLength\n", + "# plt.subplot(1, 2, 1) # 1 row, 2 columns, 1st subplot\n", + "# plt.hist(panda_df[\"locusLength\"], bins=30, alpha=0.7)\n", + "# plt.xlabel(\"Locus Length\")\n", + "# plt.ylabel(\"Frequency\")\n", + "# plt.title(\"Histogram of Locus Length\")\n", "\n", - "# Histogram for locusSize\n", - "plt.subplot(1, 2, 2) # 1 row, 2 columns, 2nd subplot\n", - "plt.hist(panda_df[\"locusSize\"], bins=30, alpha=0.7)\n", - "plt.xlabel(\"Locus Size\")\n", - "plt.ylabel(\"Frequency\")\n", - "plt.title(\"Histogram of Locus Size\")\n", + "# # Histogram for locusSize\n", + "# plt.subplot(1, 2, 2) # 1 row, 2 columns, 2nd subplot\n", + "# plt.hist(panda_df[\"locusSize\"], bins=30, alpha=0.7)\n", + "# plt.xlabel(\"Locus Size\")\n", + "# plt.ylabel(\"Frequency\")\n", + "# plt.title(\"Histogram of Locus Size\")\n", "\n", - "plt.tight_layout()\n", - "plt.show()" + "# plt.tight_layout()\n", + "# plt.show()" ] }, { @@ -1473,13 +1464,13 @@ } ], "source": [ - "plt.figure(figsize=(10, 6))\n", - "plt.scatter(panda_df[\"locusSize\"], panda_df[\"locusLength\"], alpha=0.5)\n", - "plt.title(\"Scatter Plot of Locus Size vs Locus Length\")\n", - "plt.xlabel(\"Locus Size\")\n", - "plt.ylabel(\"Locus Length\")\n", - "plt.grid(True)\n", - "plt.show()" + "# plt.figure(figsize=(10, 6))\n", + "# plt.scatter(panda_df[\"locusSize\"], panda_df[\"locusLength\"], alpha=0.5)\n", + "# plt.title(\"Scatter Plot of Locus Size vs Locus Length\")\n", + "# plt.xlabel(\"Locus Size\")\n", + "# plt.ylabel(\"Locus Length\")\n", + "# plt.grid(True)\n", + "# plt.show()" ] } ], diff --git a/notebooks/l2g_benchmark.ipynb b/notebooks/l2g_benchmark.ipynb deleted file mode 100644 index 857d25088..000000000 --- a/notebooks/l2g_benchmark.ipynb +++ /dev/null @@ -1,603 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Benchmarking L2G predictions\n", - "\n", - "The objective of this notebook is to compare the new implementation of L2G with the last results we display in production (22.09.1).\n", - "\n", - "The notebook is divided in 3 parts:\n", - "1. Data preparation\n", - "2. Describe the data\n", - "3. Compare the results\n" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Setting default log level to \"WARN\".\n", - "To adjust logging level use sc.setLogLevel(newLevel). For SparkR, use setLogLevel(newLevel).\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "23/12/11 16:18:49 WARN NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable\n" - ] - } - ], - "source": [ - "from datetime import datetime\n", - "from gentropy.dataset.study_locus import StudyLocus\n", - "from gentropy.dataset.l2g_prediction import L2GPrediction\n", - "from gentropy.common.session import Session\n", - "\n", - "import pyspark.sql.functions as f\n", - "from pyspark.sql import DataFrame\n", - "\n", - "import wandb\n", - "\n", - "%matplotlib inline\n", - "\n", - "session = Session(spark_uri=\"local[*]\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Data preparation" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "def prepare_predictions(credible_set: StudyLocus, predictions: L2GPrediction) -> DataFrame:\n", - " \"\"\"Prepares predictions dataframe for testing and comparison.\"\"\"\n", - " return (\n", - " credible_set.df\n", - " .select(\"studyLocusId\", \"variantId\", \"studyId\").distinct()\n", - " .join(\n", - " predictions.df, on=\"studyLocusId\"\n", - " )\n", - " .select(\"studyLocusId\", \"variantId\", \"studyId\", \"geneId\", \"score\")\n", - " .distinct()\n", - " )\n", - "\n", - "def prepare_production_predictions(old_predictions: DataFrame) -> DataFrame:\n", - " \"\"\"Prepares L2G predictions for testing and comparison.\"\"\"\n", - " return (\n", - " old_predictions\n", - " .select(\n", - " f.col(\"study_id\").alias(\"studyId\"),\n", - " f.concat_ws(\"_\", f.col(\"chrom\"), f.col(\"pos\"), f.col(\"ref\"), f.col(\"alt\")).alias(\"variantId\"),\n", - " f.col(\"gene_id\").alias(\"geneId\"),\n", - " f.col(\"y_proba_full_model\").alias(\"score\"),\n", - " )\n", - " .withColumn(\"studyLocusId\", StudyLocus.assign_study_locus_id(f.col(\"studyId\"), f.col(\"variantId\")))\n", - " .distinct()\n", - " )" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - } - ], - "source": [ - "# RAW DATA\n", - "credible_set_path = \"gs://genetics_etl_python_playground/output/python_etl/parquet/XX.XX/credible_set\"\n", - "predictions_path = \"gs://genetics_etl_python_playground/output/python_etl/parquet/XX.XX/l2g_predictions\"\n", - "old_predictions_path = \"gs://genetics-portal-dev-data/22.09.1/outputs/l2g\"\n", - "\n", - "predictions = L2GPrediction.from_parquet(session, predictions_path)\n", - "old_predictions = session.spark.read.parquet(old_predictions_path)\n", - "credible_set = StudyLocus.from_parquet(session, credible_set_path, recursiveFileLookup=True)" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [], - "source": [ - "predictions_prepared = prepare_predictions(credible_set, predictions).persist()\n", - "old_predictions_prepared = prepare_production_predictions(old_predictions).persist()\n", - "\n", - "joining_cols = [\"studyLocusId\", \"geneId\", \"variantId\", \"studyId\"]\n", - "comparison_df = (\n", - " predictions_prepared.selectExpr(*joining_cols, \"score as new_score\")\n", - " .join(\n", - " old_predictions_prepared.selectExpr(*joining_cols, \"score as old_score\"), on=joining_cols, how=\"inner\"\n", - " )\n", - " .distinct()\n", - " .persist()\n", - " )\n", - "\n", - "comparison_output_path = f\"gs://ot-team/irene/l2g_results_comparison-{datetime.today().strftime('%Y-%m-%d')}\"\n", - "# comparison_df.write.parquet(\"gs://ot-team/irene/l2g_results_comparison\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Data description\n", - "\n", - "Note: Comparison_df is the result of intersecting the L2G datasets with both the production and the new implementation." - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "COUNT PER DATASET\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "predictions_prepared: 9061746\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "old_predictions_prepared: 4083797\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "[Stage 23:====================================================> (196 + 4) / 200]\r" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "comparison_df: 2194371\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - } - ], - "source": [ - "## 1. L2G predicted credible sets count\n", - "\n", - "datasets = {\n", - " \"predictions_prepared\": predictions_prepared,\n", - " \"old_predictions_prepared\": old_predictions_prepared,\n", - " \"comparison_df\": comparison_df\n", - "}\n", - "\n", - "print(\"COUNT PER DATASET\")\n", - "for dataset in datasets.items():\n", - " print(f\"{dataset[0]}: {dataset[1].count()}\")\n" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "AVERAGE SCORES PER DATASET\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "predictions_prepared: 0.20072320074989783\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "old_predictions_prepared: 0.0720378814046517\n", - "MEDIAN SCORE PER DATASET\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "predictions_prepared: 0.023215007036924362\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "[Stage 74:==============================================> (171 + 8) / 200]\r" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "old_predictions_prepared: 0.012324056588113308\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - } - ], - "source": [ - "## 2. Descriptive stats for L2G scores\n", - "\n", - "print(\"AVERAGE SCORES PER DATASET\")\n", - "for dataset in datasets.items():\n", - " if dataset[0] != \"comparison_df\":\n", - " print(f\"{dataset[0]}: {dataset[1].agg(f.avg('score')).collect()[0][0]}\")\n", - "\n", - "print(\"MEDIAN SCORE PER DATASET\")\n", - "for dataset in datasets.items():\n", - " if dataset[0] != \"comparison_df\":\n", - " print(f\"{dataset[0]}: {dataset[1].approxQuantile('score',[0.5],0.1)[0]}\")\n" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "# OF ASSOCIATIONS WITH SCORE > 0.9\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "predictions_prepared: 5275 (0.06 from total)\n", - "old_predictions_prepared: 3942 (0.1 from total)\n" - ] - } - ], - "source": [ - "## How many associations with a score > 0.9\n", - "\n", - "print(\"# OF ASSOCIATIONS WITH SCORE > 0.9\")\n", - "for dataset in datasets.items():\n", - " if dataset[0] != \"comparison_df\":\n", - " print(f\"{dataset[0]}: {dataset[1].filter(f.col('score') >= 0.9).count()} ({round(dataset[1].filter(f.col('score') >= 0.9).count()/dataset[1].count() * 100, 2)} from total)\")\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Results comparison\n", - "\n", - "The comparisons dataset represents the intersection of the predictions of the production and the new implementation. The objective is to compare the L2G scores of both implementations for the same studyLoci." - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - }, - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
studyLocusIdgeneIdvariantIdstudyIdnew_scoreold_score
0-9221872607204368224ENSG0000006571719_3414090_G_AGCST0102410.0018870.008250
1-9219397145747036852ENSG0000016805611_65619907_T_AGCST0072340.0381770.014908
2-9219397145747036852ENSG0000017537611_65619907_T_AGCST0072340.0158460.011380
3-9217975156633736203ENSG000001874756_26325235_T_CGCST0094560.0396680.010985
4-9216978755013122322ENSG0000015761721_41816125_G_AGCST0059450.2710090.024520
\n", - "
" - ], - "text/plain": [ - " studyLocusId geneId variantId studyId \\\n", - "0 -9221872607204368224 ENSG00000065717 19_3414090_G_A GCST010241 \n", - "1 -9219397145747036852 ENSG00000168056 11_65619907_T_A GCST007234 \n", - "2 -9219397145747036852 ENSG00000175376 11_65619907_T_A GCST007234 \n", - "3 -9217975156633736203 ENSG00000187475 6_26325235_T_C GCST009456 \n", - "4 -9216978755013122322 ENSG00000157617 21_41816125_G_A GCST005945 \n", - "\n", - " new_score old_score \n", - "0 0.001887 0.008250 \n", - "1 0.038177 0.014908 \n", - "2 0.015846 0.011380 \n", - "3 0.039668 0.010985 \n", - "4 0.271009 0.024520 " - ] - }, - "execution_count": 27, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "comparison_pdf = comparison_df.toPandas()\n", - "comparison_pdf.head()" - ] - }, - { - "cell_type": "code", - "execution_count": 36, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "SCORES CORRELATION 0.3968047070256464\n", - "Split by chromosome...\n", - "Chromosome 1: 0.4283002148537705\n", - "Chromosome 10: 0.4548083324805242\n", - "Chromosome 11: 0.3952137911268187\n", - "Chromosome 12: 0.4185634370780096\n", - "Chromosome 13: 0.42117917239984404\n", - "Chromosome 14: 0.39845735792304493\n", - "Chromosome 15: 0.40346861517903765\n", - "Chromosome 16: 0.39846240000598415\n", - "Chromosome 17: 0.395304979654295\n", - "Chromosome 18: 0.41437506238370103\n", - "Chromosome 19: 0.4425118135710343\n", - "Chromosome 2: 0.3889598461816933\n", - "Chromosome 20: 0.43686865328167446\n", - "Chromosome 21: 0.3849138600053731\n", - "Chromosome 22: 0.43046292359639526\n", - "Chromosome 3: 0.4111657046267522\n", - "Chromosome 4: 0.4291713768129795\n", - "Chromosome 5: 0.39581618467547613\n", - "Chromosome 6: 0.37446130946623823\n", - "Chromosome 7: 0.4059565003311735\n", - "Chromosome 8: 0.44203370064434944\n", - "Chromosome 9: 0.40815294157407295\n", - "Chromosome X: 0.12625008528673395\n" - ] - } - ], - "source": [ - "## Correlation between old and new scores\n", - "\n", - "overall_corr = comparison_pdf[\"old_score\"].corr(comparison_pdf[\"new_score\"])\n", - "print(\"SCORES CORRELATION\", overall_corr)\n", - "\n", - "print(\"Split by chromosome...\")\n", - "\n", - "comparison_pdf[\"chromosome\"] = comparison_pdf[\"variantId\"].str.split(\"_\", expand=True)[0]\n", - "\n", - "for group in comparison_pdf.sort_values(\"chromosome\").groupby(\"chromosome\"):\n", - " corr = group[1][\"old_score\"].corr(group[1][\"new_score\"])\n", - " print(f\"Chromosome {group[0]}: {corr}\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "## Add correlation coefficient to finished run in W&B\n", - "# See dashboard here to find run ID: https://wandb.ai/open-targets/otg_l2g/table?workspace=user-opentargets\n", - "my_run = \"4cyi1qvz\"\n", - "\n", - "wandb.init(id=my_run, project=\"otg_l2g\", resume=True)\n", - "wandb.log({\"correlationProduction\": overall_corr})\n", - "wandb.finish()" - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 30, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjcAAAHHCAYAAABDUnkqAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8g+/7EAAAACXBIWXMAAA9hAAAPYQGoP6dpAAB7pklEQVR4nO3dd3hUZdoG8HsySSa9kEpCICREpBcp0kFRVBRxdRdxFeQDdRXEFV27YAV210Vc1I+VtYuIoquuIIL0Ji0EUGkhCYSSZNIrqef7gy9jJnPmnHnPnJlJuX/Xlesi5z3nzJtJyHnylucxSJIkgYiIiKiN8PJ0B4iIiIj0xOCGiIiI2hQGN0RERNSmMLghIiKiNoXBDREREbUpDG6IiIioTWFwQ0RERG0KgxsiIiJqUxjcEBERUZvC4IbIhV544QUYDAa3vNbYsWMxduxYy+dbt26FwWDAmjVr3PL69957LxITE93yWlqVl5dj1qxZiI2NhcFgwJ///GdPd4mIXIDBDZGDPvjgAxgMBsuHn58f4uLiMGHCBPzzn/9EWVmZLq9z4cIFvPDCC0hLS9PlfnpqyX1zxMKFC/HBBx/gwQcfxMcff4x77rnH7rmJiYm4+eabFe/31VdfYcqUKUhKSkJAQAC6d++Oxx57DMXFxbLnV1dXY9myZRg5ciTCw8Ph6+uLuLg4TJo0CatWrUJ9fb0zXx4R/T9vT3eAqLV56aWX0LVrV9TW1iInJwdbt27Fn//8ZyxZsgTffvst+vbtazn3ueeew1NPPSV0/wsXLuDFF19EYmIi+vfv7/B1GzZsEHodLZT6tmLFCjQ0NLi8D87YvHkzrr76aixYsECX+91///2Ii4vD3Xffjc6dO+Po0aN48803sW7dOqSmpsLf399yrtlsxo033oiDBw9iwoQJeO6559ChQwfk5OTgxx9/xF133YX09HQ8//zzuvSNqD1jcEMk6MYbb8SgQYMsnz/99NPYvHkzbr75ZkyaNAnHjh2zPNS8vb3h7e3a/2aVlZUICAiAr6+vS19HjY+Pj0df3xF5eXno2bOnbvdbs2aN1VQgAFx11VWYPn06Vq5ciVmzZlmO33PPPTh06BC+/PJL/O53v7O65umnn8aBAwdw4sQJ3frmKg0NDaipqYGfn5+nu0JkF6eliHRwzTXX4Pnnn8eZM2fwySefWI7LrbnZuHEjRo4cibCwMAQFBaF79+545plnAFxeJzN48GAAwIwZMyxTYB988AGAy+tqevfujYMHD2L06NEICAiwXNt8zU2j+vp6PPPMM4iNjUVgYCAmTZqE7Oxsq3MSExNx77332lzb9J5qfZNbc1NRUYHHHnsMCQkJMJlM6N69O1577TVIkmR1nsFgwJw5c/D111+jd+/eMJlM6NWrF9avXy//hjeTl5eHmTNnIiYmBn5+fujXrx8+/PBDS3vj+qPMzEysXbvW0vesrCyH7m+P3Pt92223AQCOHTtmObZnzx788MMPuP/++20Cm0aDBg3CH//4R9XXVPr5aXTp0iW88MILuOKKK+Dn54eOHTvid7/7HU6fPm05R/R7s3LlSvTq1Qsmk8nyfTl//jz+53/+BzExMZbv2XvvvWfT52XLlqFXr14ICAhAeHg4Bg0ahE8//VT1ayXSiiM3RDq555578Mwzz2DDhg247777ZM/55ZdfcPPNN6Nv37546aWXYDKZkJ6ejl27dgEAevTogZdeegnz58/H/fffj1GjRgEAhg8fbrlHQUEBbrzxRtx55524++67ERMTo9ivV199FQaDAU8++STy8vKwdOlSjB8/HmlpaVbTJmoc6VtTkiRh0qRJ2LJlC2bOnIn+/fvjhx9+wF/+8hecP38er7/+utX5O3fuxFdffYWHHnoIwcHB+Oc//4nbb78dZ8+eRUREhN1+VVVVYezYsUhPT8ecOXPQtWtXfPHFF7j33ntRXFyMRx55BD169MDHH3+MRx99FJ06dcJjjz0GAIiKinL463dUTk4OACAyMtJy7L///S8A4O6773bq3mo/P8DlYPbmm2/Gpk2bcOedd+KRRx5BWVkZNm7ciJ9//hnJycnC35vNmzfj888/x5w5cxAZGYnExETk5ubi6quvtgQ/UVFR+P777zFz5kyUlpZaFmuvWLECc+fOxR133IFHHnkEly5dwpEjR7B3717cddddTr0fRHZJROSQ999/XwIg7d+/3+45oaGh0oABAyyfL1iwQGr63+z111+XAEhms9nuPfbv3y8BkN5//32btjFjxkgApOXLl8u2jRkzxvL5li1bJABSfHy8VFpaajn++eefSwCkN954w3KsS5cu0vTp01XvqdS36dOnS126dLF8/vXXX0sApFdeecXqvDvuuEMyGAxSenq65RgAydfX1+rY4cOH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K1ciMTERwOWg6cYbb8SuXbvwySef4Ndff8XixYthNBoBAAcPHsQf/vAH3HnnnTh69CheeOEFPP/88/jggw+sXuO1115Dv379cOjQITz//PM4ffo0brjhBtx+++04cuQIVq9ejZ07d2LOnDn6vLFEJM7TlTuJqPUbM2aMNHLkSKtjgwcPlp588klpx44dUkhIiHTp0iWr9uTkZOlf//qXJEmSNG/ePGnixImSJEnS0qVLpSlTpkj9+vWTvv/+e0mSJKlbt27SO++8o9qPhx9+WLrmmmukhoYGm7YffvhB8vLykk6cOCF77V133SVdd911Vsf+8pe/SD179rR83qVLF2ny5MlW58ycOVO6//77rY7t2LFD8vLykqqqqlT7TET648gNEemib9++Vp937NgReXl5OHz4MMrLyxEREYGgoCDLR2ZmJk6fPg0AGDNmDHbu3In6+nps27YNY8eOxdixY7F161ZcuHAB6enpGDt2rGof7r33XqSlpaF79+6YO3cuNmzYYGlLS0tDp06dcMUVV8hee+zYMYwYMcLq2IgRI3Dq1CnU19dbjg0aNMjqnMOHD+ODDz6w+tomTJiAhoYGZGZmqvaZiPTn7ekOEFHb4OPjY/W5wWBAQ0MDysvL0bFjR8u0U1NhYWEAgNGjR6OsrAypqanYvn07Fi5ciNjYWCxevBj9+vVDXFwcUlJSVPswcOBAZGZm4vvvv8ePP/6IP/zhDxg/fjzWrFkDf39/Pb5MBAYGWn1eXl6OBx54AHPnzrU5t3Pnzrq8JhGJYXBDRC41cOBA5OTkwNvb27L+pbmwsDD07dsXb775Jnx8fHDllVciOjoaU6ZMwXfffefQeptGISEhmDJlCqZMmYI77rgDN9xwAwoLC9G3b1+cO3cOJ0+elB296dGjB3bt2mV1bNeuXbjiiiss63LsfX2//vorunXr5nAfici1OC1FRC41fvx4DBs2DJMnT8aGDRuQlZWF3bt349lnn7XskAIu77hauXKlJZDp0KEDevTogdWrVzsc3CxZsgSrVq3C8ePHcfLkSXzxxReIjY1FWFgYxowZg9GjR+P222/Hxo0bLSM869evBwA89thj2LRpE15++WWcPHkSH374Id588008/vjjiq/55JNPYvfu3ZgzZw7S0tJw6tQpfPPNN1xQTORBDG6IyKUMBgPWrVuH0aNHY8aMGbjiiitw55134syZM4iJibGcN2bMGNTX11utrRk7dqzNMSXBwcH429/+hkGDBmHw4MHIysrCunXr4OV1+Vfdl19+icGDB2Pq1Kno2bMnnnjiCct6moEDB+Lzzz/HZ599ht69e2P+/Pl46aWXcO+99yq+Zt++fbFt2zacPHkSo0aNwoABAzB//nzExcUJvU9EpB+DJEmSpztBREREpBeO3BAREVGbwuCGiFqNhQsXWm25bvpx4403erp7RNRCcFqKiFqNwsJCFBYWyrb5+/sjPj7ezT0iopaIwQ0RERG1KZyWIiIiojaFwQ0RERG1KQxuiIiIqE1hcENERERtCoMbIiIialMY3BAREVGbwuCGiIiI2hQGN0RERNSm/B+aYjrtMdzCDAAAAABJRU5ErkJggg==", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "comparison_pdf.plot.scatter(\n", - " x=\"new_score\",\n", - " y=\"old_score\",\n", - " title=\"Distribution of L2G scores\",\n", - ")" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": ".venv", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.8" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/notebooks/pics_benchmark.ipynb b/notebooks/pics_benchmark.ipynb index d8a2f6e83..0dd05b18b 100644 --- a/notebooks/pics_benchmark.ipynb +++ b/notebooks/pics_benchmark.ipynb @@ -1,904 +1,878 @@ { - "cells": [ - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Benchmarking new PICS implementation\n", - "\n", - "The objective of this notebook is to compare the new implementation of PICS estimated on GWAS Catalog associations using gnomAD LD reference, against the previous implementation using 1000 genomes phase III LD reference. \n", - "\n", - "1. Describe the new dataset\n", - " - Number of signals covered.\n", - " - Number of signals dropped.\n", - "2. Copare with old PICS Dataset.\n", - " - Δ number of covered study (not particularly relevant given updates in GWAS Catalog)\n", - " - Δ number of covered peaks from studies found in the old release - might see increased coverage.\n", - " - Δ in the recovered credible set: number of variants, change in posterior probability.\n", - " - Δ in the average number of credible sets.\n", - "\n", - " " - ] - }, + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Benchmarking new PICS implementation\n", + "\n", + "The objective of this notebook is to compare the new implementation of PICS estimated on GWAS Catalog associations using gnomAD LD reference, against the previous implementation using 1000 genomes phase III LD reference. \n", + "\n", + "1. Describe the new dataset\n", + " - Number of signals covered.\n", + " - Number of signals dropped.\n", + "2. Copare with old PICS Dataset.\n", + " - Δ number of covered study (not particularly relevant given updates in GWAS Catalog)\n", + " - Δ number of covered peaks from studies found in the old release - might see increased coverage.\n", + " - Δ in the recovered credible set: number of variants, change in posterior probability.\n", + " - Δ in the average number of credible sets.\n", + "\n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "import pyspark.sql.functions as f\n", + "from pyspark.sql import SparkSession\n", + "from pyspark.sql.window import Window\n", + "\n", + "spark = SparkSession.builder.getOrCreate()" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 1 Describing the new dataset\n", + "\n", + "1. Study count.\n", + "2. Association count.\n", + "3. Studies split.\n", + "4. Associations not resolved in LD set." + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "import pyspark.sql.functions as f\n", - "import pyspark.sql.types as t\n", - "from pyspark.sql import SparkSession, DataFrame\n", - "from pyspark.sql.window import Window\n", - "\n", - "spark = SparkSession.builder.getOrCreate()" - ] + "name": "stdout", + "output_type": "stream", + "text": [ + "root\n", + " |-- chromosome: string (nullable = true)\n", + " |-- variantId: string (nullable = true)\n", + " |-- studyId: string (nullable = true)\n", + " |-- position: string (nullable = true)\n", + " |-- referenceAllele: string (nullable = true)\n", + " |-- alternateAllele: string (nullable = true)\n", + " |-- pValueMantissa: float (nullable = true)\n", + " |-- pValueExponent: integer (nullable = true)\n", + " |-- beta: string (nullable = true)\n", + " |-- beta_ci_lower: double (nullable = true)\n", + " |-- beta_ci_upper: double (nullable = true)\n", + " |-- odds_ratio: string (nullable = true)\n", + " |-- odds_ratio_ci_lower: double (nullable = true)\n", + " |-- odds_ratio_ci_upper: double (nullable = true)\n", + " |-- qualityControl: array (nullable = true)\n", + " | |-- element: string (containsNull = true)\n", + " |-- sampleSize: double (nullable = true)\n", + " |-- tagVariantId: string (nullable = true)\n", + " |-- R_overall: double (nullable = true)\n", + " |-- pics_mu: double (nullable = true)\n", + " |-- pics_std: double (nullable = true)\n", + " |-- pics_postprob: double (nullable = true)\n", + " |-- pics_95_perc_credset: boolean (nullable = true)\n", + " |-- pics_99_perc_credset: boolean (nullable = true)\n", + " |-- hasResolvedCredibleSet: boolean (nullable = false)\n", + "\n" + ] }, { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 1 Describing the new dataset\n", - "\n", - "1. Study count.\n", - "2. Association count.\n", - "3. Studies split.\n", - "4. Associations not resolved in LD set." - ] + "name": "stderr", + "output_type": "stream", + "text": [ + "[Stage 82:> (0 + 1) / 1]\r" + ] }, { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "root\n", - " |-- chromosome: string (nullable = true)\n", - " |-- variantId: string (nullable = true)\n", - " |-- studyId: string (nullable = true)\n", - " |-- position: string (nullable = true)\n", - " |-- referenceAllele: string (nullable = true)\n", - " |-- alternateAllele: string (nullable = true)\n", - " |-- pValueMantissa: float (nullable = true)\n", - " |-- pValueExponent: integer (nullable = true)\n", - " |-- beta: string (nullable = true)\n", - " |-- beta_ci_lower: double (nullable = true)\n", - " |-- beta_ci_upper: double (nullable = true)\n", - " |-- odds_ratio: string (nullable = true)\n", - " |-- odds_ratio_ci_lower: double (nullable = true)\n", - " |-- odds_ratio_ci_upper: double (nullable = true)\n", - " |-- qualityControl: array (nullable = true)\n", - " | |-- element: string (containsNull = true)\n", - " |-- sampleSize: double (nullable = true)\n", - " |-- tagVariantId: string (nullable = true)\n", - " |-- R_overall: double (nullable = true)\n", - " |-- pics_mu: double (nullable = true)\n", - " |-- pics_std: double (nullable = true)\n", - " |-- pics_postprob: double (nullable = true)\n", - " |-- pics_95_perc_credset: boolean (nullable = true)\n", - " |-- pics_99_perc_credset: boolean (nullable = true)\n", - " |-- hasResolvedCredibleSet: boolean (nullable = false)\n", - "\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "[Stage 82:> (0 + 1) / 1]\r" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "-RECORD 0------------------------------------------\n", - " chromosome | 6 \n", - " variantId | 6_13215826_A_G \n", - " studyId | GCST000101_1 \n", - " position | 13215826 \n", - " referenceAllele | A \n", - " alternateAllele | G \n", - " pValueMantissa | 3.0 \n", - " pValueExponent | -6 \n", - " beta | null \n", - " beta_ci_lower | null \n", - " beta_ci_upper | null \n", - " odds_ratio | null \n", - " odds_ratio_ci_lower | null \n", - " odds_ratio_ci_upper | null \n", - " qualityControl | [Subsignificant p-value] \n", - " sampleSize | 1094.0 \n", - " tagVariantId | 6_13215826_A_G \n", - " R_overall | 1.0 \n", - " pics_mu | 5.522878745280337 \n", - " pics_std | 0.0 \n", - " pics_postprob | 0.12718888994626093 \n", - " pics_95_perc_credset | true \n", - " pics_99_perc_credset | true \n", - " hasResolvedCredibleSet | true \n", - "only showing top 1 row\n", - "\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - } - ], - "source": [ - "new_study_locus = (\n", - " spark.read.parquet(\"gs://genetics_etl_python_playground/XX.XX/output/python_etl/parquet/pics_credible_set/\")\n", - " .withColumn('pics_99_perc_credset', f.when(f.col('tagVariantId').isNull(), False).otherwise(f.col('pics_99_perc_credset')))\n", - " .withColumn(\n", - " 'hasResolvedCredibleSet', \n", - " f.when(\n", - " f.array_contains(\n", - " f.collect_set(f.col('pics_99_perc_credset')).over(Window.partitionBy('studyId', 'variantId')), \n", - " True\n", - " ),\n", - " True\n", - " ).otherwise(False)\n", - " )\n", - " .persist()\n", - ")\n", - "\n", - "\n", - "new_study_locus.printSchema()\n", - "new_study_locus.show(1, False, True)" - ] + "name": "stdout", + "output_type": "stream", + "text": [ + "-RECORD 0------------------------------------------\n", + " chromosome | 6 \n", + " variantId | 6_13215826_A_G \n", + " studyId | GCST000101_1 \n", + " position | 13215826 \n", + " referenceAllele | A \n", + " alternateAllele | G \n", + " pValueMantissa | 3.0 \n", + " pValueExponent | -6 \n", + " beta | null \n", + " beta_ci_lower | null \n", + " beta_ci_upper | null \n", + " odds_ratio | null \n", + " odds_ratio_ci_lower | null \n", + " odds_ratio_ci_upper | null \n", + " qualityControl | [Subsignificant p-value] \n", + " sampleSize | 1094.0 \n", + " tagVariantId | 6_13215826_A_G \n", + " R_overall | 1.0 \n", + " pics_mu | 5.522878745280337 \n", + " pics_std | 0.0 \n", + " pics_postprob | 0.12718888994626093 \n", + " pics_95_perc_credset | true \n", + " pics_99_perc_credset | true \n", + " hasResolvedCredibleSet | true \n", + "only showing top 1 row\n", + "\n" + ] }, { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "22/12/19 11:45:49 WARN org.apache.spark.sql.execution.CacheManager: Asked to cache already cached data.\n", - "[Stage 224:============================================> (173 + 16) / 200]\r" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Study count: 35956\n", - "Association (unique study/variant pairs) count: 433108\n", - "Associations with resolved credible set: 381056 (88.0%)\n", - "Number of good (non-flagged) associations without resolved credible set: 39763 (9.2%)\n", - "Number of good (non-flagged) associations with resolved credible set: 260736 (60.2%)\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - } - ], - "source": [ - "study_count = new_study_locus.select('studyId').distinct().count()\n", - "association_count = new_study_locus.select('studyId', 'variantId').distinct().count()\n", - "association_w_credible_set = new_study_locus.filter(f.col('hasResolvedCredibleSet')).persist()\n", - "credible_set_count = association_w_credible_set.select('studyId', 'variantId').distinct().count()\n", - "failed_w_ld = (\n", - " new_study_locus\n", - " # Selecting good associations without credible sets:\n", - " .filter(\n", - " (~f.col('hasResolvedCredibleSet')) & \n", - " (f.size(f.col('qualityControl'))>0)\n", - " )\n", - " # Get associations:\n", - " .select('studyId', 'variantId')\n", - " .distinct()\n", - " .count()\n", - ")\n", - "good_association_count = (\n", - " association_w_credible_set\n", - " # Drop failed associations:\n", - " .filter(f.size(f.col('qualityControl')) == 0)\n", - " .select('studyId', 'variantId')\n", - " .distinct()\n", - " .count()\n", - ")\n", - "\n", - "print(f'Study count: {study_count}')\n", - "print(f'Association (unique study/variant pairs) count: {association_count}')\n", - "print(f'Associations with resolved credible set: {credible_set_count} ({round(credible_set_count/association_count*100, 1)}%)')\n", - "print(f'Number of good (non-flagged) associations without resolved credible set: {failed_w_ld} ({round(failed_w_ld/association_count*100, 1)}%)')\n", - "print(f'Number of good (non-flagged) associations with resolved credible set: {good_association_count} ({round(good_association_count/association_count*100, 1)}%)')\n" - ] + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + } + ], + "source": [ + "new_study_locus = (\n", + " spark.read.parquet(\"gs://genetics_etl_python_playground/XX.XX/output/python_etl/parquet/pics_credible_set/\")\n", + " .withColumn(\"pics_99_perc_credset\", f.when(f.col(\"tagVariantId\").isNull(), False).otherwise(f.col(\"pics_99_perc_credset\")))\n", + " .withColumn(\n", + " \"hasResolvedCredibleSet\",\n", + " f.when(\n", + " f.array_contains(\n", + " f.collect_set(f.col(\"pics_99_perc_credset\")).over(Window.partitionBy(\"studyId\", \"variantId\")),\n", + " True\n", + " ),\n", + " True\n", + " ).otherwise(False)\n", + " )\n", + " .persist()\n", + ")\n", + "\n", + "\n", + "new_study_locus.printSchema()\n", + "new_study_locus.show(1, False, True)" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "22/12/19 11:45:49 WARN org.apache.spark.sql.execution.CacheManager: Asked to cache already cached data.\n", + "[Stage 224:============================================> (173 + 16) / 200]\r" + ] }, { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Focusing only on the actual credible sets." - ] + "name": "stdout", + "output_type": "stream", + "text": [ + "Study count: 35956\n", + "Association (unique study/variant pairs) count: 433108\n", + "Associations with resolved credible set: 381056 (88.0%)\n", + "Number of good (non-flagged) associations without resolved credible set: 39763 (9.2%)\n", + "Number of good (non-flagged) associations with resolved credible set: 260736 (60.2%)\n" + ] }, { - "cell_type": "code", - "execution_count": 22, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "22/12/19 11:57:56 WARN org.apache.spark.sql.execution.CacheManager: Asked to cache already cached data.\n", - " \r" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Number of resolved credible sets: 381056\n", - "Studies with resolved credible sets: 33723\n", - "Number of lead/tag pairs: 18722043\n" - ] - } - ], - "source": [ - "# Thu\n", - "credible_sets = new_study_locus.filter(f.col('pics_99_perc_credset')).persist()\n", - "resolved_assoc_count = credible_sets.select('studyId', 'variantId').distinct().count()\n", - "resolved_study_count = credible_sets.select('studyId').distinct().count()\n", - "lead_tag_pair_count = credible_sets.select('studyId', 'variantId', 'tagVariantId').distinct().count()\n", - "\n", - "grouped_credset_pdf = credible_sets.groupBy('studyId', 'variantId').count().toPandas()\n", - "\n", - "print(f'Number of resolved credible sets: {resolved_assoc_count}')\n", - "print(f'Studies with resolved credible sets: {resolved_study_count}')\n", - "print(f'Number of lead/tag pairs: {lead_tag_pair_count}')\n", - "\n" - ] + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + } + ], + "source": [ + "study_count = new_study_locus.select(\"studyId\").distinct().count()\n", + "association_count = new_study_locus.select(\"studyId\", \"variantId\").distinct().count()\n", + "association_w_credible_set = new_study_locus.filter(f.col(\"hasResolvedCredibleSet\")).persist()\n", + "credible_set_count = association_w_credible_set.select(\"studyId\", \"variantId\").distinct().count()\n", + "failed_w_ld = (\n", + " new_study_locus\n", + " # Selecting good associations without credible sets:\n", + " .filter(\n", + " (~f.col(\"hasResolvedCredibleSet\")) &\n", + " (f.size(f.col(\"qualityControl\"))>0)\n", + " )\n", + " # Get associations:\n", + " .select(\"studyId\", \"variantId\")\n", + " .distinct()\n", + " .count()\n", + ")\n", + "good_association_count = (\n", + " association_w_credible_set\n", + " # Drop failed associations:\n", + " .filter(f.size(f.col(\"qualityControl\")) == 0)\n", + " .select(\"studyId\", \"variantId\")\n", + " .distinct()\n", + " .count()\n", + ")\n", + "\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Focusing only on the actual credible sets." + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "22/12/19 11:57:56 WARN org.apache.spark.sql.execution.CacheManager: Asked to cache already cached data.\n", + " \r" + ] }, { - "cell_type": "code", - "execution_count": 31, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 31, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "grouped_credset_pdf.query('count < 500')['count'].hist(bins=100)" + "name": "stdout", + "output_type": "stream", + "text": [ + "Number of resolved credible sets: 381056\n", + "Studies with resolved credible sets: 33723\n", + "Number of lead/tag pairs: 18722043\n" + ] + } + ], + "source": [ + "# Thu\n", + "credible_sets = new_study_locus.filter(f.col(\"pics_99_perc_credset\")).persist()\n", + "resolved_assoc_count = credible_sets.select(\"studyId\", \"variantId\").distinct().count()\n", + "resolved_study_count = credible_sets.select(\"studyId\").distinct().count()\n", + "lead_tag_pair_count = credible_sets.select(\"studyId\", \"variantId\", \"tagVariantId\").distinct().count()\n", + "\n", + "grouped_credset_pdf = credible_sets.groupBy(\"studyId\", \"variantId\").count().toPandas()\n", + "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" ] + }, + "execution_count": 31, + "metadata": {}, + "output_type": "execute_result" }, { - "cell_type": "code", - "execution_count": 45, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Credible sets with only one variant: 29536 (7.8)%\n", - "Median size of credible sets: 21.0\n" - ] - } - ], - "source": [ - "median_credset_size = grouped_credset_pdf['count'].median()\n", - "credsets_with_single = len(grouped_credset_pdf.query('count == 1'))\n", - "\n", - "print(f'Credible sets with only one variant: {credsets_with_single} ({round(credsets_with_single/len(grouped_credset_pdf)*100, 1)})%')\n", - "print(f'Median size of credible sets: {median_credset_size}')" + "data": { + "image/png": "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", + "text/plain": [ + "
" ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "grouped_credset_pdf.query(\"count < 500\")[\"count\"].hist(bins=100)" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Credible sets with only one variant: 29536 (7.8)%\n", + "Median size of credible sets: 21.0\n" + ] + } + ], + "source": [ + "median_credset_size = grouped_credset_pdf[\"count\"].median()\n", + "credsets_with_single = len(grouped_credset_pdf.query(\"count == 1\"))\n" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[Stage 285:====================================> (139 + 8) / 200]\r" + ] }, { - "cell_type": "code", - "execution_count": 41, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "[Stage 285:====================================> (139 + 8) / 200]\r" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "+------------+---------------+-----+\n", - "| studyId| variantId|count|\n", - "+------------+---------------+-----+\n", - "|GCST90095125|17_46142465_T_A|11930|\n", - "|GCST90095124|17_46142465_T_A|11221|\n", - "|GCST006483_1|17_45608332_A_G| 9666|\n", - "| GCST011766|17_45846834_C_G| 9566|\n", - "|GCST006481_2|17_45608332_A_G| 9445|\n", - "|GCST006483_1|17_45605039_C_G| 8912|\n", - "|GCST006483_3|17_45605039_C_G| 8602|\n", - "|GCST006481_4|17_45605039_C_G| 8545|\n", - "|GCST006483_1|17_46770468_T_G| 7465|\n", - "|GCST006481_2|17_46770468_T_G| 7396|\n", - "|GCST006483_3|17_46770468_T_G| 7374|\n", - "|GCST006481_4|17_46770468_T_G| 7327|\n", - "|GCST001651_9|17_46257341_G_A| 6926|\n", - "|GCST90134596|17_45707983_T_C| 6748|\n", - "| GCST012099|17_45610951_A_G| 6603|\n", - "|GCST90104034|17_46152620_T_C| 6545|\n", - "| GCST012101|17_45610951_A_G| 6374|\n", - "|GCST90134597|17_45707983_T_C| 6372|\n", - "| GCST007692|17_45846834_C_G| 6331|\n", - "|GCST90013445|17_45996523_A_G| 5668|\n", - "|GCST008675_1|17_45733530_C_T| 5196|\n", - "|GCST004008_1|17_45749271_G_A| 5101|\n", - "|GCST006483_1|17_46785767_T_C| 4913|\n", - "|GCST006481_2|17_46785767_T_C| 4880|\n", - "| GCST007065|11_55736589_G_A| 4071|\n", - "|GCST90100220|10_73256607_T_A| 3897|\n", - "|GCST90095190|17_45913906_A_G| 3858|\n", - "|GCST90095190|17_46055092_G_A| 3855|\n", - "|GCST90095190|17_45609706_G_A| 3764|\n", - "|GCST000996_1|11_55368743_C_T| 3727|\n", - "+------------+---------------+-----+\n", - "only showing top 30 rows\n", - "\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - } - ], - "source": [ - "credible_sets.groupBy('studyId', 'variantId').count().filter(f.col('count') > 1000).orderBy('count', ascending=False).show(30)" - ] + "name": "stdout", + "output_type": "stream", + "text": [ + "+------------+---------------+-----+\n", + "| studyId| variantId|count|\n", + "+------------+---------------+-----+\n", + "|GCST90095125|17_46142465_T_A|11930|\n", + "|GCST90095124|17_46142465_T_A|11221|\n", + "|GCST006483_1|17_45608332_A_G| 9666|\n", + "| GCST011766|17_45846834_C_G| 9566|\n", + "|GCST006481_2|17_45608332_A_G| 9445|\n", + "|GCST006483_1|17_45605039_C_G| 8912|\n", + "|GCST006483_3|17_45605039_C_G| 8602|\n", + "|GCST006481_4|17_45605039_C_G| 8545|\n", + "|GCST006483_1|17_46770468_T_G| 7465|\n", + "|GCST006481_2|17_46770468_T_G| 7396|\n", + "|GCST006483_3|17_46770468_T_G| 7374|\n", + "|GCST006481_4|17_46770468_T_G| 7327|\n", + "|GCST001651_9|17_46257341_G_A| 6926|\n", + "|GCST90134596|17_45707983_T_C| 6748|\n", + "| GCST012099|17_45610951_A_G| 6603|\n", + "|GCST90104034|17_46152620_T_C| 6545|\n", + "| GCST012101|17_45610951_A_G| 6374|\n", + "|GCST90134597|17_45707983_T_C| 6372|\n", + "| GCST007692|17_45846834_C_G| 6331|\n", + "|GCST90013445|17_45996523_A_G| 5668|\n", + "|GCST008675_1|17_45733530_C_T| 5196|\n", + "|GCST004008_1|17_45749271_G_A| 5101|\n", + "|GCST006483_1|17_46785767_T_C| 4913|\n", + "|GCST006481_2|17_46785767_T_C| 4880|\n", + "| GCST007065|11_55736589_G_A| 4071|\n", + "|GCST90100220|10_73256607_T_A| 3897|\n", + "|GCST90095190|17_45913906_A_G| 3858|\n", + "|GCST90095190|17_46055092_G_A| 3855|\n", + "|GCST90095190|17_45609706_G_A| 3764|\n", + "|GCST000996_1|11_55368743_C_T| 3727|\n", + "+------------+---------------+-----+\n", + "only showing top 30 rows\n", + "\n" + ] }, { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Comparing with old dataset\n", - "\n", - "- Data: `gs://genetics-portal-dev-staging/v2d/220210/ld.parquet`" - ] + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + } + ], + "source": [ + "credible_sets.groupBy(\"studyId\", \"variantId\").count().filter(f.col(\"count\") > 1000).orderBy(\"count\", ascending=False).show(30)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Comparing with old dataset\n", + "\n", + "- Data: `gs://genetics-portal-dev-staging/v2d/220210/ld.parquet`" + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[Stage 336:===================================================> (16 + 1) / 17]\r" + ] }, { - "cell_type": "code", - "execution_count": 52, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "[Stage 336:===================================================> (16 + 1) / 17]\r" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Number of lead/tag count: 19406519\n", - "NUmber of studies covered: 18349\n", - "Number of associations covered: 265715\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - } - ], - "source": [ - "old_study_locus = (\n", - " spark.read.parquet(\"gs://genetics-portal-dev-staging/v2d/220210/ld.parquet\")\n", - " .select(\n", - " f.col('study_id').alias(\"studyId\"), \n", - " f.concat_ws(\"_\", f.col(\"lead_chrom\"), f.col(\"lead_pos\"), f.col(\"lead_ref\"), f.col(\"lead_alt\")).alias(\"variantId\"), \n", - " f.concat_ws(\"_\", f.col(\"tag_chrom\"), f.col(\"tag_pos\"), f.col(\"tag_ref\"), f.col(\"tag_alt\")).alias(\"tagVariantId\"),\n", - " 'pics_postprob',\n", - " 'pics_95perc_credset',\n", - " 'pics_99perc_credset'\n", - " )\n", - " .distinct()\n", - ")\n", - "lead_tag_pair_count = old_study_locus.count()\n", - "study_count = old_study_locus.select('studyId').distinct().count()\n", - "association_count = old_study_locus.select('studyId', 'variantId').distinct().count()\n", - "\n", - "print(f'Number of lead/tag count: {lead_tag_pair_count}')\n", - "print(f'NUmber of studies covered: {study_count}')\n", - "print(f'Number of associations covered: {association_count}')\n" - ] + "name": "stdout", + "output_type": "stream", + "text": [ + "Number of lead/tag count: 19406519\n", + "NUmber of studies covered: 18349\n", + "Number of associations covered: 265715\n" + ] }, { - "cell_type": "code", - "execution_count": 57, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "22/12/19 13:53:16 WARN org.apache.spark.sql.execution.CacheManager: Asked to cache already cached data.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The median number of tag size: 21.0\n", - "Number of associations with single credible set: 9231\n", - "Number of associations with more than 1000 tags set: 441\n", - "+-------------+---------------+-----+\n", - "| studyId| variantId|count|\n", - "+-------------+---------------+-----+\n", - "| GCST001482|17_45900461_C_T| 3685|\n", - "| GCST90018953|17_45856424_G_T| 3684|\n", - "| GCST007692|17_45846834_C_G| 3649|\n", - "| GCST90018960|17_45761354_C_T| 3360|\n", - "| GCST90018996|17_46112544_A_G| 3348|\n", - "| GCST90091060|17_45873075_C_A| 3295|\n", - "| GCST002970|17_45846317_A_G| 3294|\n", - "| GCST001548|17_45846853_T_C| 3294|\n", - "| GCST007328|17_45887201_A_C| 3294|\n", - "| GCST007430|17_45887201_A_C| 3294|\n", - "| GCST010701|17_45855805_C_T| 3294|\n", - "| GCST001126|17_45846317_A_G| 3294|\n", - "| GCST012009|17_45862033_A_C| 3294|\n", - "| GCST006941|17_45841739_C_T| 3293|\n", - "| GCST004601|17_45841730_A_G| 3293|\n", - "| GCST010002|17_45895867_C_T| 3293|\n", - "| GCST90025948|17_45834077_T_C| 3293|\n", - "| GCST008733|17_45834077_T_C| 3293|\n", - "| GCST008734|17_45834077_T_C| 3293|\n", - "|GCST009518_66|17_45841730_A_G| 3293|\n", - "+-------------+---------------+-----+\n", - "only showing top 20 rows\n", - "\n" - ] - } - ], - "source": [ - "tag_count = old_study_locus.groupBy('studyId', 'variantId').count().persist()\n", - "median_tag_count = tag_count.toPandas()['count'].median()\n", - "single_count = tag_count.filter(f.col('count') == 1).count()\n", - "over_1000 = tag_count.filter(f.col('count') >= 1000).count()\n", - "\n", - "print(f'The median number of tag size: {median_credset_size}')\n", - "print(f'Number of associations with single credible set: {single_count}')\n", - "print(f'Number of associations with more than 1000 tags set: {over_1000}')\n", - "\n", - "tag_count.orderBy('count',ascending=False).show(20)" - ] + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + } + ], + "source": [ + "old_study_locus = (\n", + " spark.read.parquet(\"gs://genetics-portal-dev-staging/v2d/220210/ld.parquet\")\n", + " .select(\n", + " f.col(\"study_id\").alias(\"studyId\"),\n", + " f.concat_ws(\"_\", f.col(\"lead_chrom\"), f.col(\"lead_pos\"), f.col(\"lead_ref\"), f.col(\"lead_alt\")).alias(\"variantId\"),\n", + " f.concat_ws(\"_\", f.col(\"tag_chrom\"), f.col(\"tag_pos\"), f.col(\"tag_ref\"), f.col(\"tag_alt\")).alias(\"tagVariantId\"),\n", + " \"pics_postprob\",\n", + " \"pics_95perc_credset\",\n", + " \"pics_99perc_credset\"\n", + " )\n", + " .distinct()\n", + ")\n", + "lead_tag_pair_count = old_study_locus.count()\n", + "study_count = old_study_locus.select(\"studyId\").distinct().count()\n", + "association_count = old_study_locus.select(\"studyId\", \"variantId\").distinct().count()\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 57, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "22/12/19 13:53:16 WARN org.apache.spark.sql.execution.CacheManager: Asked to cache already cached data.\n" + ] }, { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Compare credible sets\n", - "\n", - "To make datasets comparable, both datasets need to updated with `studyAccession`: getting the GWAS Catalog study identifier by removing the suffix." - ] + "name": "stdout", + "output_type": "stream", + "text": [ + "The median number of tag size: 21.0\n", + "Number of associations with single credible set: 9231\n", + "Number of associations with more than 1000 tags set: 441\n", + "+-------------+---------------+-----+\n", + "| studyId| variantId|count|\n", + "+-------------+---------------+-----+\n", + "| GCST001482|17_45900461_C_T| 3685|\n", + "| GCST90018953|17_45856424_G_T| 3684|\n", + "| GCST007692|17_45846834_C_G| 3649|\n", + "| GCST90018960|17_45761354_C_T| 3360|\n", + "| GCST90018996|17_46112544_A_G| 3348|\n", + "| GCST90091060|17_45873075_C_A| 3295|\n", + "| GCST002970|17_45846317_A_G| 3294|\n", + "| GCST001548|17_45846853_T_C| 3294|\n", + "| GCST007328|17_45887201_A_C| 3294|\n", + "| GCST007430|17_45887201_A_C| 3294|\n", + "| GCST010701|17_45855805_C_T| 3294|\n", + "| GCST001126|17_45846317_A_G| 3294|\n", + "| GCST012009|17_45862033_A_C| 3294|\n", + "| GCST006941|17_45841739_C_T| 3293|\n", + "| GCST004601|17_45841730_A_G| 3293|\n", + "| GCST010002|17_45895867_C_T| 3293|\n", + "| GCST90025948|17_45834077_T_C| 3293|\n", + "| GCST008733|17_45834077_T_C| 3293|\n", + "| GCST008734|17_45834077_T_C| 3293|\n", + "|GCST009518_66|17_45841730_A_G| 3293|\n", + "+-------------+---------------+-----+\n", + "only showing top 20 rows\n", + "\n" + ] + } + ], + "source": [ + "tag_count = old_study_locus.groupBy(\"studyId\", \"variantId\").count().persist()\n", + "median_tag_count = tag_count.toPandas()[\"count\"].median()\n", + "single_count = tag_count.filter(f.col(\"count\") == 1).count()\n", + "over_1000 = tag_count.filter(f.col(\"count\") >= 1000).count()\n", + "\n", + "\n", + "tag_count.orderBy(\"count\",ascending=False).show(20)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Compare credible sets\n", + "\n", + "To make datasets comparable, both datasets need to updated with `studyAccession`: getting the GWAS Catalog study identifier by removing the suffix." + ] + }, + { + "cell_type": "code", + "execution_count": 97, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[Stage 414:> (0 + 1) / 1][Stage 1072:========> (9 + 7) / 16]\r" + ] + } + ], + "source": [ + "processed_new = (\n", + " credible_sets\n", + " # Dropping leads with sub-significant p-values:\n", + " .filter(f.size(f.col(\"qualityControl\")) == 0)\n", + " .select(\n", + " f.split(f.col(\"studyId\"), \"_\").getItem(0).alias(\"studyAccession\"),\n", + " \"variantId\",\n", + " \"tagVariantId\",\n", + " \"pics_mu\",\n", + " \"pics_postprob\",\n", + " \"pics_95_perc_credset\",\n", + " \"pics_99_perc_credset\"\n", + " )\n", + " .persist()\n", + ")\n", + "\n", + "processed_old = (\n", + " old_study_locus\n", + " .select(\n", + " f.split(f.col(\"studyId\"), \"_\").getItem(0).alias(\"studyAccession\"),\n", + " \"variantId\",\n", + " \"tagVariantId\",\n", + " \"pics_postprob\",\n", + " \"pics_95perc_credset\",\n", + " \"pics_99perc_credset\"\n", + " )\n", + " .persist()\n", + ")\n", + "\n", + "processed_old.show(1, False, True)" + ] + }, + { + "cell_type": "code", + "execution_count": 68, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "22/12/19 14:19:35 WARN org.apache.spark.sql.execution.CacheManager: Asked to cache already cached data.\n", + "22/12/19 14:19:35 WARN org.apache.spark.sql.execution.CacheManager: Asked to cache already cached data.\n", + "[Stage 414:> (0 + 1) / 1][Stage 431:============>(187 + 7) / 200]\r" + ] }, { - "cell_type": "code", - "execution_count": 97, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "[Stage 414:> (0 + 1) / 1][Stage 1072:========> (9 + 7) / 16]\r" - ] - } - ], - "source": [ - "processed_new = (\n", - " credible_sets\n", - " # Dropping leads with sub-significant p-values:\n", - " .filter(f.size(f.col('qualityControl')) == 0)\n", - " .select(\n", - " f.split(f.col('studyId'), '_').getItem(0).alias('studyAccession'),\n", - " 'variantId', \n", - " 'tagVariantId', \n", - " 'pics_mu', \n", - " 'pics_postprob', \n", - " 'pics_95_perc_credset', \n", - " 'pics_99_perc_credset'\n", - " )\n", - " .persist()\n", - ")\n", - "\n", - "processed_old = (\n", - " old_study_locus\n", - " .select(\n", - " f.split(f.col('studyId'), '_').getItem(0).alias('studyAccession'),\n", - " 'variantId', \n", - " 'tagVariantId',\n", - " 'pics_postprob',\n", - " 'pics_95perc_credset',\n", - " 'pics_99perc_credset' \n", - " )\n", - " .persist()\n", - ")\n", - "\n", - "processed_old.show(1, False, True)" - ] + "name": "stdout", + "output_type": "stream", + "text": [ + "+--------------+---------------+---------------------+---------------------+\n", + "|studyAccession| variantId|new_credible_set_size|old_credible_set_size|\n", + "+--------------+---------------+---------------------+---------------------+\n", + "| GCST000114|15_48099968_A_G| 13| 38|\n", + "| GCST000172|3_190632672_A_G| 12| null|\n", + "| GCST000184|18_60217517_G_A| 233| 214|\n", + "| GCST000189|16_81270154_T_C| 6| null|\n", + "| GCST000189|9_105892815_G_T| 26| null|\n", + "| GCST000282|19_11100236_C_T| 34| 69|\n", + "| GCST000425|16_23055939_T_G| 227| null|\n", + "| GCST000452|2_156696348_A_C| 19| null|\n", + "| GCST000679| 10_6056986_C_T| 12| null|\n", + "| GCST000817|9_136220024_G_T| 23| 27|\n", + "| GCST000876|11_18349351_G_C| 2| 6|\n", + "| GCST000943| 20_1960525_G_A| null| 2|\n", + "| GCST000957|22_49692725_G_A| 16| null|\n", + "| GCST000964|13_77957479_G_A| null| 47|\n", + "| GCST000998|10_44280376_C_T| 193| null|\n", + "| GCST000998|21_34226827_C_T| 29| 32|\n", + "| GCST001010| 6_32689801_T_C| 1| 112|\n", + "| GCST001040|17_37738049_G_A| null| 21|\n", + "| GCST001057|13_66393490_A_G| 7| null|\n", + "| GCST001059|2_198123211_C_A| 8| null|\n", + "+--------------+---------------+---------------------+---------------------+\n", + "only showing top 20 rows\n", + "\n" + ] }, { - "cell_type": "code", - "execution_count": 68, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "22/12/19 14:19:35 WARN org.apache.spark.sql.execution.CacheManager: Asked to cache already cached data.\n", - "22/12/19 14:19:35 WARN org.apache.spark.sql.execution.CacheManager: Asked to cache already cached data.\n", - "[Stage 414:> (0 + 1) / 1][Stage 431:============>(187 + 7) / 200]\r" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "+--------------+---------------+---------------------+---------------------+\n", - "|studyAccession| variantId|new_credible_set_size|old_credible_set_size|\n", - "+--------------+---------------+---------------------+---------------------+\n", - "| GCST000114|15_48099968_A_G| 13| 38|\n", - "| GCST000172|3_190632672_A_G| 12| null|\n", - "| GCST000184|18_60217517_G_A| 233| 214|\n", - "| GCST000189|16_81270154_T_C| 6| null|\n", - "| GCST000189|9_105892815_G_T| 26| null|\n", - "| GCST000282|19_11100236_C_T| 34| 69|\n", - "| GCST000425|16_23055939_T_G| 227| null|\n", - "| GCST000452|2_156696348_A_C| 19| null|\n", - "| GCST000679| 10_6056986_C_T| 12| null|\n", - "| GCST000817|9_136220024_G_T| 23| 27|\n", - "| GCST000876|11_18349351_G_C| 2| 6|\n", - "| GCST000943| 20_1960525_G_A| null| 2|\n", - "| GCST000957|22_49692725_G_A| 16| null|\n", - "| GCST000964|13_77957479_G_A| null| 47|\n", - "| GCST000998|10_44280376_C_T| 193| null|\n", - "| GCST000998|21_34226827_C_T| 29| 32|\n", - "| GCST001010| 6_32689801_T_C| 1| 112|\n", - "| GCST001040|17_37738049_G_A| null| 21|\n", - "| GCST001057|13_66393490_A_G| 7| null|\n", - "| GCST001059|2_198123211_C_A| 8| null|\n", - "+--------------+---------------+---------------------+---------------------+\n", - "only showing top 20 rows\n", - "\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "[Stage 414:> (0 + 1) / 1]\r" - ] - } - ], - "source": [ - "aggregated_new = (\n", - " processed_new\n", - " .join(processed_old.select('studyAccession').distinct(), on='studyAccession', how='right')\n", - " .groupBy('studyAccession', 'variantId')\n", - " .agg(f.size(f.collect_list(f.col('tagVariantId'))).alias('new_credible_set_size'))\n", - " .persist()\n", - ")\n", - "\n", - "aggregated_old = (\n", - " processed_old\n", - " .groupBy('studyAccession', 'variantId')\n", - " .agg(f.size(f.collect_list(f.col('tagVariantId'))).alias('old_credible_set_size'))\n", - " .persist()\n", - ")\n", - "\n", - "credset_compare = (\n", - " aggregated_new\n", - " .join(aggregated_old.filter(f.col('studyAccession').startswith('GCST')), on=['studyAccession', 'variantId'], how='outer')\n", - " .persist()\n", - ")\n", - "\n", - "credset_compare.show()" - ] + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] }, { - "cell_type": "code", - "execution_count": 74, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The number of extra credible sets covered by the new dataset: 104508 (53.0%)\n", - "Number of lost credible sets in the new datasets: 49292 (25.0%)\n", - "The number of extra credible sets with more than 1 tags covered by the new dataset: 94745 (48.1%)\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "[Stage 414:> (0 + 1) / 1]\r" - ] - } - ], - "source": [ - "extra_coverage = credset_compare.filter(f.col('old_credible_set_size').isNull()).count()\n", - "lost_coverage = credset_compare.filter(f.col('new_credible_set_size').isNull()).count()\n", - "old_full_count = aggregated_old.filter(f.col('studyAccession').startswith('GCST')).count()\n", - "\n", - "print(f'The number of extra credible sets covered by the new dataset: {extra_coverage} ({round(extra_coverage/old_full_count * 100, 1)}%)')\n", - "print(f'Number of lost credible sets in the new datasets: {lost_coverage} ({round(lost_coverage/old_full_count*100, 1)}%)')\n", - "\n", - "extra_coverage_more = credset_compare.filter(f.col('old_credible_set_size').isNull() & (f.col('new_credible_set_size')>1)).count()\n", - "\n", - "print(f'The number of extra credible sets with more than 1 tags covered by the new dataset: {extra_coverage_more} ({round(extra_coverage_more/old_full_count * 100, 1)}%)')\n" - ] + "name": "stderr", + "output_type": "stream", + "text": [ + "[Stage 414:> (0 + 1) / 1]\r" + ] + } + ], + "source": [ + "aggregated_new = (\n", + " processed_new\n", + " .join(processed_old.select(\"studyAccession\").distinct(), on=\"studyAccession\", how=\"right\")\n", + " .groupBy(\"studyAccession\", \"variantId\")\n", + " .agg(f.size(f.collect_list(f.col(\"tagVariantId\"))).alias(\"new_credible_set_size\"))\n", + " .persist()\n", + ")\n", + "\n", + "aggregated_old = (\n", + " processed_old\n", + " .groupBy(\"studyAccession\", \"variantId\")\n", + " .agg(f.size(f.collect_list(f.col(\"tagVariantId\"))).alias(\"old_credible_set_size\"))\n", + " .persist()\n", + ")\n", + "\n", + "credset_compare = (\n", + " aggregated_new\n", + " .join(aggregated_old.filter(f.col(\"studyAccession\").startswith(\"GCST\")), on=[\"studyAccession\", \"variantId\"], how=\"outer\")\n", + " .persist()\n", + ")\n", + "\n", + "credset_compare.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 74, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] }, { - "cell_type": "code", - "execution_count": 75, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "+--------------+--------------------+---------------------+---------------------+\n", - "|studyAccession| variantId|new_credible_set_size|old_credible_set_size|\n", - "+--------------+--------------------+---------------------+---------------------+\n", - "| GCST000943| 20_1960525_G_A| null| 2|\n", - "| GCST000964| 13_77957479_G_A| null| 47|\n", - "| GCST001040| 17_37738049_G_A| null| 21|\n", - "| GCST002216| 7_73450539_A_G| null| 94|\n", - "| GCST002221| 9_133372523_G_C| null| 20|\n", - "| GCST002223| 8_19973410_C_T| null| 106|\n", - "| GCST002223| 8_20009083_C_T| null| 98|\n", - "| GCST003043| 16_11271643_C_T| null| 14|\n", - "| GCST003191| 20_22824423_G_A| null| 30|\n", - "| GCST003879| 22_23030688_C_G| null| 104|\n", - "| GCST004132| 16_10871740_T_C| null| 74|\n", - "| GCST004365| 3_186755027_C_T| null| 12|\n", - "| GCST004600| 6_35756341_T_C| null| 17|\n", - "| GCST004601| 11_8721318_TC_T| null| 171|\n", - "| GCST004601| 6_27878966_G_C| null| 267|\n", - "| GCST004603|16_88730362_G_GGG...| null| 10|\n", - "| GCST004603| 4_17777672_A_T| null| 9|\n", - "| GCST004605| 6_28489735_CT_C| null| 1|\n", - "| GCST004607| 20_56413821_A_G| null| 15|\n", - "| GCST004607| 2_218258320_T_A| null| 235|\n", - "+--------------+--------------------+---------------------+---------------------+\n", - "only showing top 20 rows\n", - "\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "[Stage 414:> (0 + 1) / 1]\r" - ] - } - ], - "source": [ - "credset_compare.filter(f.col('new_credible_set_size').isNull()).show()" - ] + "name": "stdout", + "output_type": "stream", + "text": [ + "The number of extra credible sets covered by the new dataset: 104508 (53.0%)\n", + "Number of lost credible sets in the new datasets: 49292 (25.0%)\n", + "The number of extra credible sets with more than 1 tags covered by the new dataset: 94745 (48.1%)\n" + ] }, { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Conclusion:**\n", - "- The reason of the disagreement is the fact that the old dataset contains data from summary stats finemapping.\n", - "- To resolve this problem, we exclude those studies which have summary stats. These credible sets should be in a better agreement." - ] + "name": "stderr", + "output_type": "stream", + "text": [ + "[Stage 414:> (0 + 1) / 1]\r" + ] + } + ], + "source": [ + "extra_coverage = credset_compare.filter(f.col(\"old_credible_set_size\").isNull()).count()\n", + "lost_coverage = credset_compare.filter(f.col(\"new_credible_set_size\").isNull()).count()\n", + "old_full_count = aggregated_old.filter(f.col(\"studyAccession\").startswith(\"GCST\")).count()\n", + "\n", + "\n", + "extra_coverage_more = credset_compare.filter(f.col(\"old_credible_set_size\").isNull() & (f.col(\"new_credible_set_size\")>1)).count()\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 75, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "+--------------+--------------------+---------------------+---------------------+\n", + "|studyAccession| variantId|new_credible_set_size|old_credible_set_size|\n", + "+--------------+--------------------+---------------------+---------------------+\n", + "| GCST000943| 20_1960525_G_A| null| 2|\n", + "| GCST000964| 13_77957479_G_A| null| 47|\n", + "| GCST001040| 17_37738049_G_A| null| 21|\n", + "| GCST002216| 7_73450539_A_G| null| 94|\n", + "| GCST002221| 9_133372523_G_C| null| 20|\n", + "| GCST002223| 8_19973410_C_T| null| 106|\n", + "| GCST002223| 8_20009083_C_T| null| 98|\n", + "| GCST003043| 16_11271643_C_T| null| 14|\n", + "| GCST003191| 20_22824423_G_A| null| 30|\n", + "| GCST003879| 22_23030688_C_G| null| 104|\n", + "| GCST004132| 16_10871740_T_C| null| 74|\n", + "| GCST004365| 3_186755027_C_T| null| 12|\n", + "| GCST004600| 6_35756341_T_C| null| 17|\n", + "| GCST004601| 11_8721318_TC_T| null| 171|\n", + "| GCST004601| 6_27878966_G_C| null| 267|\n", + "| GCST004603|16_88730362_G_GGG...| null| 10|\n", + "| GCST004603| 4_17777672_A_T| null| 9|\n", + "| GCST004605| 6_28489735_CT_C| null| 1|\n", + "| GCST004607| 20_56413821_A_G| null| 15|\n", + "| GCST004607| 2_218258320_T_A| null| 235|\n", + "+--------------+--------------------+---------------------+---------------------+\n", + "only showing top 20 rows\n", + "\n" + ] }, { - "cell_type": "code", - "execution_count": 89, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - }, - { - "data": { - "text/plain": [ - "141" - ] - }, - "execution_count": 89, - "metadata": {}, - "output_type": "execute_result" - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "[Stage 414:> (0 + 1) / 1]\r" - ] - } - ], - "source": [ - "(\n", - " spark.read.parquet(\"gs://genetics-portal-dev-staging/v2d/220401/ld.parquet\")\n", - " .filter(f.col('study_id') == 'GCST002223')\n", - " .select('lead_chrom', 'lead_pos', 'lead_ref', 'lead_alt')\n", - " .distinct()\n", - " .count()\n", - ")" - ] + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] }, { - "cell_type": "code", - "execution_count": 96, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "22/12/19 15:57:00 WARN org.apache.spark.sql.execution.CacheManager: Asked to cache already cached data.\n", - " \r" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Number of credible sets in the selected studies (27054): 105658\n", - "The number of extra credible sets covered by the new dataset in the same studies: 73250 (69.3%)\n", - "Number of lost credible sets in the new datasets: 8454 (8.0%)\n", - "The number of extra credible sets with more than 1 tags covered by the new dataset: 67183 (63.6%)\n" - ] - } - ], - "source": [ - "studies_with_no_sumstats = (\n", - " spark.read.parquet('gs://genetics_etl_python_playground/XX.XX/output/python_etl/parquet/gwas_catalog_studies/')\n", - " .filter(~f.col('hasSumstats'))\n", - " .select(f.split(f.col('studyId'), '_').getItem(0).alias('studyAccession'))\n", - " .distinct()\n", - ")\n", - "\n", - "# Dropping studies with summary statistics:\n", - "credset_compare_update = credset_compare.join(studies_with_no_sumstats, on='studyAccession', how='inner').distinct().persist()\n", - "\n", - "old_full_count = credset_compare_update.filter(f.col('old_credible_set_size').isNotNull()).count()\n", - "extra_coverage = credset_compare_update.filter(f.col('old_credible_set_size').isNull()).count()\n", - "lost_coverage = credset_compare_update.filter(f.col('new_credible_set_size').isNull()).count()\n", - "\n", - "print(f'Number of credible sets in the selected studies ({studies_with_no_sumstats.count()}): {old_full_count}')\n", - "print(f'The number of extra credible sets covered by the new dataset in the same studies: {extra_coverage} ({round(extra_coverage/old_full_count * 100, 1)}%)')\n", - "print(f'Number of lost credible sets in the new datasets: {lost_coverage} ({round(lost_coverage/old_full_count*100, 1)}%)')\n", - "\n", - "extra_coverage_more = credset_compare_update.filter(f.col('old_credible_set_size').isNull() & (f.col('new_credible_set_size')>1)).count()\n", - "\n", - "print(f'The number of extra credible sets with more than 1 tags covered by the new dataset: {extra_coverage_more} ({round(extra_coverage_more/old_full_count * 100, 1)}%)')" - ] + "name": "stderr", + "output_type": "stream", + "text": [ + "[Stage 414:> (0 + 1) / 1]\r" + ] + } + ], + "source": [ + "credset_compare.filter(f.col(\"new_credible_set_size\").isNull()).show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Conclusion:**\n", + "- The reason of the disagreement is the fact that the old dataset contains data from summary stats finemapping.\n", + "- To resolve this problem, we exclude those studies which have summary stats. These credible sets should be in a better agreement." + ] + }, + { + "cell_type": "code", + "execution_count": 89, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] }, { - "cell_type": "code", - "execution_count": 91, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "2" - ] - }, - "execution_count": 91, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "1+1" + "data": { + "text/plain": [ + "141" ] + }, + "execution_count": 89, + "metadata": {}, + "output_type": "execute_result" }, { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] + "name": "stderr", + "output_type": "stream", + "text": [ + "[Stage 414:> (0 + 1) / 1]\r" + ] } - ], - "metadata": { - "kernelspec": { - "display_name": "otgenetics-Z1loiStc-py3.8", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.16 (default, Dec 7 2022, 01:39:17) \n[Clang 14.0.0 (clang-1400.0.29.202)]" + ], + "source": [ + "(\n", + " spark.read.parquet(\"gs://genetics-portal-dev-staging/v2d/220401/ld.parquet\")\n", + " .filter(f.col(\"study_id\") == \"GCST002223\")\n", + " .select(\"lead_chrom\", \"lead_pos\", \"lead_ref\", \"lead_alt\")\n", + " .distinct()\n", + " .count()\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 96, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "22/12/19 15:57:00 WARN org.apache.spark.sql.execution.CacheManager: Asked to cache already cached data.\n", + " \r" + ] }, - "orig_nbformat": 4, - "vscode": { - "interpreter": { - "hash": "5a448d06c31dd563cc2d2f896cd972f1626bb3e0fbcfc3d2f2ab4cc41131eab9" - } + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Number of credible sets in the selected studies (27054): 105658\n", + "The number of extra credible sets covered by the new dataset in the same studies: 73250 (69.3%)\n", + "Number of lost credible sets in the new datasets: 8454 (8.0%)\n", + "The number of extra credible sets with more than 1 tags covered by the new dataset: 67183 (63.6%)\n" + ] } + ], + "source": [ + "studies_with_no_sumstats = (\n", + " spark.read.parquet(\"gs://genetics_etl_python_playground/XX.XX/output/python_etl/parquet/gwas_catalog_studies/\")\n", + " .filter(~f.col(\"hasSumstats\"))\n", + " .select(f.split(f.col(\"studyId\"), \"_\").getItem(0).alias(\"studyAccession\"))\n", + " .distinct()\n", + ")\n", + "\n", + "# Dropping studies with summary statistics:\n", + "credset_compare_update = credset_compare.join(studies_with_no_sumstats, on=\"studyAccession\", how=\"inner\").distinct().persist()\n", + "\n", + "old_full_count = credset_compare_update.filter(f.col(\"old_credible_set_size\").isNotNull()).count()\n", + "extra_coverage = credset_compare_update.filter(f.col(\"old_credible_set_size\").isNull()).count()\n", + "lost_coverage = credset_compare_update.filter(f.col(\"new_credible_set_size\").isNull()).count()\n", + "\n", + "\n", + "extra_coverage_more = credset_compare_update.filter(f.col(\"old_credible_set_size\").isNull() & (f.col(\"new_credible_set_size\")>1)).count()\n" + ] + }, + { + "cell_type": "code", + "execution_count": 91, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "2" + ] + }, + "execution_count": 91, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "1+1" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "otgenetics-Z1loiStc-py3.8", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.16 (default, Dec 7 2022, 01:39:17) \n[Clang 14.0.0 (clang-1400.0.29.202)]" }, - "nbformat": 4, - "nbformat_minor": 2 + "orig_nbformat": 4, + "vscode": { + "interpreter": { + "hash": "5a448d06c31dd563cc2d2f896cd972f1626bb3e0fbcfc3d2f2ab4cc41131eab9" + } + } + }, + "nbformat": 4, + "nbformat_minor": 2 } diff --git a/notebooks/susie_inf_benchmark.ipynb b/notebooks/susie_inf_benchmark.ipynb index 21de23b47..d9039d0d1 100644 --- a/notebooks/susie_inf_benchmark.ipynb +++ b/notebooks/susie_inf_benchmark.ipynb @@ -28,8 +28,9 @@ "source": [ "import numpy as np\n", "import pandas as pd\n", - "from gentropy.method.susie_inf import SUSIE_inf\n", - "from scipy.stats import pearsonr\n" + "from scipy.stats import pearsonr\n", + "\n", + "from gentropy.method.susie_inf import SUSIE_inf\n" ] }, { @@ -83,10 +84,10 @@ } ], "source": [ - "plt.scatter(x=first_lbf_susie_r, y=first_lbf_susie_inf)\n", - "plt.xlabel(\"susie_r\")\n", - "plt.ylabel(\"susie_inf\")\n", - "plt.show()\n", + "# plt.scatter(x=first_lbf_susie_r, y=first_lbf_susie_inf)\n", + "# plt.xlabel(\"susie_r\")\n", + "# plt.ylabel(\"susie_inf\")\n", + "# plt.show()\n", "\n", "corr = pearsonr(first_lbf_susie_r, first_lbf_susie_inf)\n", "print(\"Pearson's correlation coefficient: \" + str(corr[0])) # noqa: T201" @@ -116,10 +117,10 @@ } ], "source": [ - "plt.scatter(x=second_lbf_susie_r, y=second_lbf_susie_inf)\n", - "plt.xlabel(\"susie_r\")\n", - "plt.ylabel(\"susie_inf\")\n", - "plt.show()\n", + "# plt.scatter(x=second_lbf_susie_r, y=second_lbf_susie_inf)\n", + "# plt.xlabel(\"susie_r\")\n", + "# plt.ylabel(\"susie_inf\")\n", + "# plt.show()\n", "\n", "corr = pearsonr(second_lbf_susie_r, second_lbf_susie_inf)\n", "print(\"Pearson's correlation coefficient: \" + str(corr[0])) # noqa: T201" @@ -142,7 +143,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.8" + "version": "3.10.14" }, "orig_nbformat": 4 }, diff --git a/notebooks/ukb_ppp_benchmark.ipynb b/notebooks/ukb_ppp_benchmark.ipynb index 4a3e200db..3e2f4a23e 100644 --- a/notebooks/ukb_ppp_benchmark.ipynb +++ b/notebooks/ukb_ppp_benchmark.ipynb @@ -37,6 +37,7 @@ "source": [ "# import matplotlib.pyplot as plt\n", "import pyspark.sql.functions as f\n", + "\n", "from gentropy.common.session import Session\n", "from gentropy.common.spark_helpers import order_array_of_structs_by_field\n", "from gentropy.dataset.ld_index import LDIndex\n", @@ -322,24 +323,24 @@ "source": [ "panda_df = df.select(\"locusSize\", \"locusLength\").toPandas()\n", "\n", - "plt.figure(figsize=(12, 6))\n", + "# plt.figure(figsize=(12, 6))\n", "\n", - "# Histogram for locusLength\n", - "plt.subplot(1, 2, 1) # 1 row, 2 columns, 1st subplot\n", - "plt.hist(panda_df[\"locusLength\"], bins=30, alpha=0.7)\n", - "plt.xlabel(\"Locus Length\")\n", - "plt.ylabel(\"Frequency\")\n", - "plt.title(\"Histogram of Locus Length\")\n", + "# # Histogram for locusLength\n", + "# plt.subplot(1, 2, 1) # 1 row, 2 columns, 1st subplot\n", + "# plt.hist(panda_df[\"locusLength\"], bins=30, alpha=0.7)\n", + "# plt.xlabel(\"Locus Length\")\n", + "# plt.ylabel(\"Frequency\")\n", + "# plt.title(\"Histogram of Locus Length\")\n", "\n", - "# Histogram for locusSize\n", - "plt.subplot(1, 2, 2) # 1 row, 2 columns, 2nd subplot\n", - "plt.hist(panda_df[\"locusSize\"], bins=30, alpha=0.7)\n", - "plt.xlabel(\"Locus Size\")\n", - "plt.ylabel(\"Frequency\")\n", - "plt.title(\"Histogram of Locus Size\")\n", + "# # Histogram for locusSize\n", + "# plt.subplot(1, 2, 2) # 1 row, 2 columns, 2nd subplot\n", + "# plt.hist(panda_df[\"locusSize\"], bins=30, alpha=0.7)\n", + "# plt.xlabel(\"Locus Size\")\n", + "# plt.ylabel(\"Frequency\")\n", + "# plt.title(\"Histogram of Locus Size\")\n", "\n", - "plt.tight_layout()\n", - "plt.show()" + "# plt.tight_layout()\n", + "# plt.show()" ] }, { @@ -359,13 +360,13 @@ } ], "source": [ - "plt.figure(figsize=(10, 6))\n", - "plt.scatter(panda_df[\"locusSize\"], panda_df[\"locusLength\"], alpha=0.5)\n", - "plt.title(\"Scatter Plot of Locus Size vs Locus Length\")\n", - "plt.xlabel(\"Locus Size\")\n", - "plt.ylabel(\"Locus Length\")\n", - "plt.grid(True)\n", - "plt.show()" + "# plt.figure(figsize=(10, 6))\n", + "# plt.scatter(panda_df[\"locusSize\"], panda_df[\"locusLength\"], alpha=0.5)\n", + "# plt.title(\"Scatter Plot of Locus Size vs Locus Length\")\n", + "# plt.xlabel(\"Locus Size\")\n", + "# plt.ylabel(\"Locus Length\")\n", + "# plt.grid(True)\n", + "# plt.show()" ] }, { @@ -480,9 +481,7 @@ ], "source": [ "nan = susie_fm.df.filter(f.isnan(\"credibleSetlog10BF\"))\n", - "null = susie_fm.df.filter(f.isnull(\"credibleSetlog10BF\"))\n", - "print(\"Number of credible sets with 'not a number' as the logBF: \", nan.count())\n", - "print(\"Number of credible sets with 'null' as the logBF: \", null.count())" + "null = susie_fm.df.filter(f.isnull(\"credibleSetlog10BF\"))" ] }, { @@ -662,39 +661,39 @@ "source": [ "\n", "pdf = susie_results.select(\"purityMinR2\", \"purityMeanR2\", \"topPP\", \"credSetSize\").toPandas()\n", - "plt.figure(figsize=(12, 12))\n", + "# plt.figure(figsize=(12, 12))\n", "\n", "# Histogram for purityMinR2\n", - "plt.subplot(2, 2, 1)\n", - "plt.hist(pdf[\"purityMinR2\"], bins=30, alpha=0.7)\n", - "plt.title(\"Histogram of purityMinR2\")\n", - "plt.xlabel(\"purityMinR2\")\n", - "plt.ylabel(\"Frequency\")\n", + "# plt.subplot(2, 2, 1)\n", + "# plt.hist(pdf[\"purityMinR2\"], bins=30, alpha=0.7)\n", + "# plt.title(\"Histogram of purityMinR2\")\n", + "# plt.xlabel(\"purityMinR2\")\n", + "# plt.ylabel(\"Frequency\")\n", "\n", - "# Histogram for purityMeanR2\n", - "plt.subplot(2, 2, 2)\n", - "plt.hist(pdf[\"purityMeanR2\"], bins=30, alpha=0.7)\n", - "plt.title(\"Histogram of purityMeanR2\")\n", - "plt.xlabel(\"purityMeanR2\")\n", - "plt.ylabel(\"Frequency\")\n", + "# # Histogram for purityMeanR2\n", + "# plt.subplot(2, 2, 2)\n", + "# plt.hist(pdf[\"purityMeanR2\"], bins=30, alpha=0.7)\n", + "# plt.title(\"Histogram of purityMeanR2\")\n", + "# plt.xlabel(\"purityMeanR2\")\n", + "# plt.ylabel(\"Frequency\")\n", "\n", - "# Histogram for topPP\n", - "plt.subplot(2, 2, 3)\n", - "plt.hist(pdf[\"topPP\"], bins=30, alpha=0.7)\n", - "plt.title(\"Histogram of topPP\")\n", - "plt.xlabel(\"topPP\")\n", - "plt.ylabel(\"Frequency\")\n", + "# # Histogram for topPP\n", + "# plt.subplot(2, 2, 3)\n", + "# plt.hist(pdf[\"topPP\"], bins=30, alpha=0.7)\n", + "# plt.title(\"Histogram of topPP\")\n", + "# plt.xlabel(\"topPP\")\n", + "# plt.ylabel(\"Frequency\")\n", "\n", - "# Histogram for credSetSize\n", - "plt.subplot(2, 2, 4)\n", - "plt.hist(pdf[\"credSetSize\"], bins=30, alpha=0.7)\n", - "plt.title(\"Histogram of credSetSize\")\n", - "plt.xlabel(\"credSetSize\")\n", - "plt.ylabel(\"Frequency\")\n", + "# # Histogram for credSetSize\n", + "# plt.subplot(2, 2, 4)\n", + "# plt.hist(pdf[\"credSetSize\"], bins=30, alpha=0.7)\n", + "# plt.title(\"Histogram of credSetSize\")\n", + "# plt.xlabel(\"credSetSize\")\n", + "# plt.ylabel(\"Frequency\")\n", "\n", - "# Adjust layout to prevent overlap\n", - "plt.tight_layout()\n", - "plt.show()" + "# # Adjust layout to prevent overlap\n", + "# plt.tight_layout()\n", + "# plt.show()" ] }, { @@ -753,9 +752,7 @@ } ], "source": [ - "first_credset = susie_results.filter(f.col(\"credibleSetIndex\") == 1)\n", - "print(\"Number of primary credible sets: \", first_credset.count())\n", - "print(\"Number of unique studyIds in primary credible sets: \", first_credset.select(\"studyId\").distinct().count())" + "first_credset = susie_results.filter(f.col(\"credibleSetIndex\") == 1)" ] }, { @@ -923,39 +920,39 @@ ], "source": [ "pdf = first_credset.select(\"purityMinR2\", \"purityMeanR2\", \"topPP\", \"credSetSize\").toPandas()\n", - "plt.figure(figsize=(12, 12))\n", + "# plt.figure(figsize=(12, 12))\n", "\n", - "# Histogram for purityMinR2\n", - "plt.subplot(2, 2, 1)\n", - "plt.hist(pdf[\"purityMinR2\"], bins=30, alpha=0.7)\n", - "plt.title(\"Histogram of purityMinR2\")\n", - "plt.xlabel(\"purityMinR2\")\n", - "plt.ylabel(\"Frequency\")\n", + "# # Histogram for purityMinR2\n", + "# plt.subplot(2, 2, 1)\n", + "# plt.hist(pdf[\"purityMinR2\"], bins=30, alpha=0.7)\n", + "# plt.title(\"Histogram of purityMinR2\")\n", + "# plt.xlabel(\"purityMinR2\")\n", + "# plt.ylabel(\"Frequency\")\n", "\n", - "# Histogram for purityMeanR2\n", - "plt.subplot(2, 2, 2)\n", - "plt.hist(pdf[\"purityMeanR2\"], bins=30, alpha=0.7)\n", - "plt.title(\"Histogram of purityMeanR2\")\n", - "plt.xlabel(\"purityMeanR2\")\n", - "plt.ylabel(\"Frequency\")\n", + "# # Histogram for purityMeanR2\n", + "# plt.subplot(2, 2, 2)\n", + "# plt.hist(pdf[\"purityMeanR2\"], bins=30, alpha=0.7)\n", + "# plt.title(\"Histogram of purityMeanR2\")\n", + "# plt.xlabel(\"purityMeanR2\")\n", + "# plt.ylabel(\"Frequency\")\n", "\n", - "# Histogram for topPP\n", - "plt.subplot(2, 2, 3)\n", - "plt.hist(pdf[\"topPP\"], bins=30, alpha=0.7)\n", - "plt.title(\"Histogram of topPP\")\n", - "plt.xlabel(\"topPP\")\n", - "plt.ylabel(\"Frequency\")\n", + "# # Histogram for topPP\n", + "# plt.subplot(2, 2, 3)\n", + "# plt.hist(pdf[\"topPP\"], bins=30, alpha=0.7)\n", + "# plt.title(\"Histogram of topPP\")\n", + "# plt.xlabel(\"topPP\")\n", + "# plt.ylabel(\"Frequency\")\n", "\n", - "# Histogram for credSetSize\n", - "plt.subplot(2, 2, 4)\n", - "plt.hist(pdf[\"credSetSize\"], bins=30, alpha=0.7)\n", - "plt.title(\"Histogram of credSetSize\")\n", - "plt.xlabel(\"credSetSize\")\n", - "plt.ylabel(\"Frequency\")\n", + "# # Histogram for credSetSize\n", + "# plt.subplot(2, 2, 4)\n", + "# plt.hist(pdf[\"credSetSize\"], bins=30, alpha=0.7)\n", + "# plt.title(\"Histogram of credSetSize\")\n", + "# plt.xlabel(\"credSetSize\")\n", + "# plt.ylabel(\"Frequency\")\n", "\n", - "# Adjust layout to prevent overlap\n", - "plt.tight_layout()\n", - "plt.show()" + "# # Adjust layout to prevent overlap\n", + "# plt.tight_layout()\n", + "# plt.show()" ] }, { @@ -1008,13 +1005,7 @@ " )\n", " .withColumn(\"topPP\", f.col(\"locus\").getField(\"posteriorProbability\"))\n", " .filter(~f.isnan(\"topPP\"))\n", - ")\n", - "\n", - "print(\"Number of high quality credible sets: \", qc_credsets.count())\n", - "print(\n", - " \"Number of unique studyIds in high quality credible sets: \",\n", - " qc_credsets.select(\"studyId\").distinct().count(),\n", - ")" + ")\n" ] }, { @@ -1155,39 +1146,39 @@ ], "source": [ "pdf = qc_credsets.select(\"purityMinR2\", \"purityMeanR2\", \"topPP\", \"credSetSize\").toPandas()\n", - "plt.figure(figsize=(12, 12))\n", + "# plt.figure(figsize=(12, 12))\n", "\n", - "# Histogram for purityMinR2\n", - "plt.subplot(2, 2, 1)\n", - "plt.hist(pdf[\"purityMinR2\"], bins=30, alpha=0.7)\n", - "plt.title(\"Histogram of purityMinR2\")\n", - "plt.xlabel(\"purityMinR2\")\n", - "plt.ylabel(\"Frequency\")\n", + "# # Histogram for purityMinR2\n", + "# plt.subplot(2, 2, 1)\n", + "# plt.hist(pdf[\"purityMinR2\"], bins=30, alpha=0.7)\n", + "# plt.title(\"Histogram of purityMinR2\")\n", + "# plt.xlabel(\"purityMinR2\")\n", + "# plt.ylabel(\"Frequency\")\n", "\n", - "# Histogram for purityMeanR2\n", - "plt.subplot(2, 2, 2)\n", - "plt.hist(pdf[\"purityMeanR2\"], bins=30, alpha=0.7)\n", - "plt.title(\"Histogram of purityMeanR2\")\n", - "plt.xlabel(\"purityMeanR2\")\n", - "plt.ylabel(\"Frequency\")\n", + "# # Histogram for purityMeanR2\n", + "# plt.subplot(2, 2, 2)\n", + "# plt.hist(pdf[\"purityMeanR2\"], bins=30, alpha=0.7)\n", + "# plt.title(\"Histogram of purityMeanR2\")\n", + "# plt.xlabel(\"purityMeanR2\")\n", + "# plt.ylabel(\"Frequency\")\n", "\n", - "# Histogram for topPP\n", - "plt.subplot(2, 2, 3)\n", - "plt.hist(pdf[\"topPP\"], bins=30, alpha=0.7)\n", - "plt.title(\"Histogram of topPP\")\n", - "plt.xlabel(\"topPP\")\n", - "plt.ylabel(\"Frequency\")\n", + "# # Histogram for topPP\n", + "# plt.subplot(2, 2, 3)\n", + "# plt.hist(pdf[\"topPP\"], bins=30, alpha=0.7)\n", + "# plt.title(\"Histogram of topPP\")\n", + "# plt.xlabel(\"topPP\")\n", + "# plt.ylabel(\"Frequency\")\n", "\n", - "# Histogram for credSetSize\n", - "plt.subplot(2, 2, 4)\n", - "plt.hist(pdf[\"credSetSize\"], bins=30, alpha=0.7)\n", - "plt.title(\"Histogram of credSetSize\")\n", - "plt.xlabel(\"credSetSize\")\n", - "plt.ylabel(\"Frequency\")\n", + "# # Histogram for credSetSize\n", + "# plt.subplot(2, 2, 4)\n", + "# plt.hist(pdf[\"credSetSize\"], bins=30, alpha=0.7)\n", + "# plt.title(\"Histogram of credSetSize\")\n", + "# plt.xlabel(\"credSetSize\")\n", + "# plt.ylabel(\"Frequency\")\n", "\n", - "# Adjust layout to prevent overlap\n", - "plt.tight_layout()\n", - "plt.show()" + "# # Adjust layout to prevent overlap\n", + "# plt.tight_layout()\n", + "# plt.show()" ] }, { @@ -1397,24 +1388,24 @@ "source": [ "panda_df = df.select(\"locusSize\", \"locusLength\").toPandas()\n", "\n", - "plt.figure(figsize=(12, 6))\n", + "# plt.figure(figsize=(12, 6))\n", "\n", - "# Histogram for locusLength\n", - "plt.subplot(1, 2, 1) # 1 row, 2 columns, 1st subplot\n", - "plt.hist(panda_df[\"locusLength\"], bins=30, alpha=0.7)\n", - "plt.xlabel(\"Locus Length\")\n", - "plt.ylabel(\"Frequency\")\n", - "plt.title(\"Histogram of Locus Length\")\n", + "# # Histogram for locusLength\n", + "# plt.subplot(1, 2, 1) # 1 row, 2 columns, 1st subplot\n", + "# plt.hist(panda_df[\"locusLength\"], bins=30, alpha=0.7)\n", + "# plt.xlabel(\"Locus Length\")\n", + "# plt.ylabel(\"Frequency\")\n", + "# plt.title(\"Histogram of Locus Length\")\n", "\n", - "# Histogram for locusSize\n", - "plt.subplot(1, 2, 2) # 1 row, 2 columns, 2nd subplot\n", - "plt.hist(panda_df[\"locusSize\"], bins=30, alpha=0.7)\n", - "plt.xlabel(\"Locus Size\")\n", - "plt.ylabel(\"Frequency\")\n", - "plt.title(\"Histogram of Locus Size\")\n", + "# # Histogram for locusSize\n", + "# plt.subplot(1, 2, 2) # 1 row, 2 columns, 2nd subplot\n", + "# plt.hist(panda_df[\"locusSize\"], bins=30, alpha=0.7)\n", + "# plt.xlabel(\"Locus Size\")\n", + "# plt.ylabel(\"Frequency\")\n", + "# plt.title(\"Histogram of Locus Size\")\n", "\n", - "plt.tight_layout()\n", - "plt.show()" + "# plt.tight_layout()\n", + "# plt.show()" ] }, { @@ -1434,13 +1425,13 @@ } ], "source": [ - "plt.figure(figsize=(10, 6))\n", - "plt.scatter(panda_df[\"locusSize\"], panda_df[\"locusLength\"], alpha=0.5)\n", - "plt.title(\"Scatter Plot of Locus Size vs Locus Length\")\n", - "plt.xlabel(\"Locus Size\")\n", - "plt.ylabel(\"Locus Length\")\n", - "plt.grid(True)\n", - "plt.show()" + "# plt.figure(figsize=(10, 6))\n", + "# plt.scatter(panda_df[\"locusSize\"], panda_df[\"locusLength\"], alpha=0.5)\n", + "# plt.title(\"Scatter Plot of Locus Size vs Locus Length\")\n", + "# plt.xlabel(\"Locus Size\")\n", + "# plt.ylabel(\"Locus Length\")\n", + "# plt.grid(True)\n", + "# plt.show()" ] } ], diff --git a/poetry.lock b/poetry.lock index 64a192984..04804d728 100644 --- a/poetry.lock +++ b/poetry.lock @@ -7357,29 +7357,29 @@ pyasn1 = ">=0.1.3" [[package]] name = "ruff" -version = "0.5.1" +version = "0.6.1" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.5.1-py3-none-linux_armv6l.whl", hash = "sha256:6ecf968fcf94d942d42b700af18ede94b07521bd188aaf2cd7bc898dd8cb63b6"}, - {file = "ruff-0.5.1-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:204fb0a472f00f2e6280a7c8c7c066e11e20e23a37557d63045bf27a616ba61c"}, - {file = "ruff-0.5.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:d235968460e8758d1e1297e1de59a38d94102f60cafb4d5382033c324404ee9d"}, - {file = "ruff-0.5.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38beace10b8d5f9b6bdc91619310af6d63dd2019f3fb2d17a2da26360d7962fa"}, - {file = "ruff-0.5.1-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e478d2f09cf06add143cf8c4540ef77b6599191e0c50ed976582f06e588c994"}, - {file = "ruff-0.5.1-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f0368d765eec8247b8550251c49ebb20554cc4e812f383ff9f5bf0d5d94190b0"}, - {file = "ruff-0.5.1-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:3a9a9a1b582e37669b0138b7c1d9d60b9edac880b80eb2baba6d0e566bdeca4d"}, - {file = "ruff-0.5.1-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bdd9f723e16003623423affabcc0a807a66552ee6a29f90eddad87a40c750b78"}, - {file = "ruff-0.5.1-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:be9fd62c1e99539da05fcdc1e90d20f74aec1b7a1613463ed77870057cd6bd96"}, - {file = "ruff-0.5.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e216fc75a80ea1fbd96af94a6233d90190d5b65cc3d5dfacf2bd48c3e067d3e1"}, - {file = "ruff-0.5.1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:c4c2112e9883a40967827d5c24803525145e7dab315497fae149764979ac7929"}, - {file = "ruff-0.5.1-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:dfaf11c8a116394da3b65cd4b36de30d8552fa45b8119b9ef5ca6638ab964fa3"}, - {file = "ruff-0.5.1-py3-none-musllinux_1_2_i686.whl", hash = "sha256:d7ceb9b2fe700ee09a0c6b192c5ef03c56eb82a0514218d8ff700f6ade004108"}, - {file = "ruff-0.5.1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:bac6288e82f6296f82ed5285f597713acb2a6ae26618ffc6b429c597b392535c"}, - {file = "ruff-0.5.1-py3-none-win32.whl", hash = "sha256:5c441d9c24ec09e1cb190a04535c5379b36b73c4bc20aa180c54812c27d1cca4"}, - {file = "ruff-0.5.1-py3-none-win_amd64.whl", hash = "sha256:b1789bf2cd3d1b5a7d38397cac1398ddf3ad7f73f4de01b1e913e2abc7dfc51d"}, - {file = "ruff-0.5.1-py3-none-win_arm64.whl", hash = "sha256:2875b7596a740cbbd492f32d24be73e545a4ce0a3daf51e4f4e609962bfd3cd2"}, - {file = "ruff-0.5.1.tar.gz", hash = "sha256:3164488aebd89b1745b47fd00604fb4358d774465f20d1fcd907f9c0fc1b0655"}, + {file = "ruff-0.6.1-py3-none-linux_armv6l.whl", hash = "sha256:b4bb7de6a24169dc023f992718a9417380301b0c2da0fe85919f47264fb8add9"}, + {file = "ruff-0.6.1-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:45efaae53b360c81043e311cdec8a7696420b3d3e8935202c2846e7a97d4edae"}, + {file = "ruff-0.6.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:bc60c7d71b732c8fa73cf995efc0c836a2fd8b9810e115be8babb24ae87e0850"}, + {file = "ruff-0.6.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c7477c3b9da822e2db0b4e0b59e61b8a23e87886e727b327e7dcaf06213c5cf"}, + {file = "ruff-0.6.1-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3a0af7ab3f86e3dc9f157a928e08e26c4b40707d0612b01cd577cc84b8905cc9"}, + {file = "ruff-0.6.1-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:392688dbb50fecf1bf7126731c90c11a9df1c3a4cdc3f481b53e851da5634fa5"}, + {file = "ruff-0.6.1-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:5278d3e095ccc8c30430bcc9bc550f778790acc211865520f3041910a28d0024"}, + {file = "ruff-0.6.1-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fe6d5f65d6f276ee7a0fc50a0cecaccb362d30ef98a110f99cac1c7872df2f18"}, + {file = "ruff-0.6.1-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2e0dd11e2ae553ee5c92a81731d88a9883af8db7408db47fc81887c1f8b672e"}, + {file = "ruff-0.6.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d812615525a34ecfc07fd93f906ef5b93656be01dfae9a819e31caa6cfe758a1"}, + {file = "ruff-0.6.1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:faaa4060f4064c3b7aaaa27328080c932fa142786f8142aff095b42b6a2eb631"}, + {file = "ruff-0.6.1-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:99d7ae0df47c62729d58765c593ea54c2546d5de213f2af2a19442d50a10cec9"}, + {file = "ruff-0.6.1-py3-none-musllinux_1_2_i686.whl", hash = "sha256:9eb18dfd7b613eec000e3738b3f0e4398bf0153cb80bfa3e351b3c1c2f6d7b15"}, + {file = "ruff-0.6.1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:c62bc04c6723a81e25e71715aa59489f15034d69bf641df88cb38bdc32fd1dbb"}, + {file = "ruff-0.6.1-py3-none-win32.whl", hash = "sha256:9fb4c4e8b83f19c9477a8745e56d2eeef07a7ff50b68a6998f7d9e2e3887bdc4"}, + {file = "ruff-0.6.1-py3-none-win_amd64.whl", hash = "sha256:c2ebfc8f51ef4aca05dad4552bbcf6fe8d1f75b2f6af546cc47cc1c1ca916b5b"}, + {file = "ruff-0.6.1-py3-none-win_arm64.whl", hash = "sha256:3bc81074971b0ffad1bd0c52284b22411f02a11a012082a76ac6da153536e014"}, + {file = "ruff-0.6.1.tar.gz", hash = "sha256:af3ffd8c6563acb8848d33cd19a69b9bfe943667f0419ca083f8ebe4224a3436"}, ] [[package]] @@ -8691,4 +8691,4 @@ test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", [metadata] lock-version = "2.0" python-versions = "^3.10, <3.11" -content-hash = "5ebbf7ab3f609d1206d56ff465af3a648b945cb79e8415be61798530943a5911" +content-hash = "622f47ea07bd1c332dcde8368143d533a27eefdd3d8096e8b648432e0dcd0dfb" diff --git a/pyproject.toml b/pyproject.toml index 3a206f4ef..1539cf7ee 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -42,7 +42,7 @@ pep8-naming = "^0.14.1" interrogate = "^1.7.0" isort = "^5.13.2" darglint = "^1.8.1" -ruff = "^0.5.1" +ruff = "^0.6.1" [tool.poetry.group.docs.dependencies] mkdocs = "^1.5.3" From 4169b813bcff4eae01af5c978269b52ae1cc629b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 22 Aug 2024 09:56:27 +0100 Subject: [PATCH 010/188] chore: pre-commit autoupdate (#724) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: pre-commit autoupdate updates: - [github.com/astral-sh/ruff-pre-commit: v0.5.5 → v0.6.1](https://github.com/astral-sh/ruff-pre-commit/compare/v0.5.5...v0.6.1) - [github.com/pre-commit/mirrors-mypy: v1.11.0 → v1.11.1](https://github.com/pre-commit/mirrors-mypy/compare/v1.11.0...v1.11.1) * chore: pre-commit auto fixes [...] --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: David Ochoa --- .pre-commit-config.yaml | 4 ++-- .../howto/python_api/b_create_dataset.py | 1 + src/airflow/dags/common_airflow.py | 3 ++- src/airflow/dags/eqtl_preprocess.py | 1 + src/airflow/dags/finngen_harmonisation.py | 1 + src/airflow/dags/finngen_preprocess.py | 1 + src/airflow/dags/genetics_etl.py | 1 + src/airflow/dags/gnomad_preprocess.py | 1 + .../dags/gwas_catalog_harmonisation.py | 1 + src/airflow/dags/gwas_catalog_preprocess.py | 1 + src/airflow/dags/gwas_curation_update.py | 1 + src/airflow/dags/ukb_ppp_eur.py | 1 + src/airflow/dags/variant_index.py | 15 ++++++++------- tests/airflow/test_dag.py | 1 + tests/gentropy/common/test_spark_helpers.py | 7 ++++--- tests/gentropy/common/test_version_engine.py | 1 + tests/gentropy/conftest.py | 4 ++-- tests/gentropy/dataset/test_dataset.py | 5 +++-- tests/gentropy/dataset/test_gene_index.py | 3 ++- tests/gentropy/dataset/test_l2g.py | 1 + tests/gentropy/dataset/test_pairwise_ld.py | 3 ++- tests/gentropy/dataset/test_study_index.py | 5 +++-- tests/gentropy/dataset/test_study_locus.py | 19 ++++++++++--------- .../dataset/test_study_locus_overlap.py | 3 ++- .../dataset/test_study_locus_overlaps.py | 4 +++- .../dataset/test_summary_statistics.py | 3 ++- tests/gentropy/dataset/test_variant_index.py | 5 +++-- .../datasource/ensembl/test_vep_variants.py | 5 +++-- .../eqtl_catalogue/test_eqtl_catalogue.py | 3 ++- .../finngen/test_finngen_finemapping.py | 3 ++- .../finngen/test_finngen_study_index.py | 3 ++- .../finngen/test_finngen_summary_stats.py | 3 ++- .../datasource/gnomad/test_gnomad_ld.py | 3 ++- .../test_gwas_catalog_associations.py | 7 ++++--- .../test_gwas_catalog_curation.py | 3 ++- .../test_gwas_catalog_study_index.py | 3 ++- .../test_gwas_catalog_study_splitter.py | 1 + .../test_gwas_catalog_summary_statistics.py | 1 + .../datasource/intervals/test_andersson.py | 3 ++- .../datasource/intervals/test_javierre.py | 3 ++- .../datasource/intervals/test_jung.py | 3 ++- .../datasource/intervals/test_thurman.py | 3 ++- .../open_targets/test_l2g_gold_standard.py | 3 ++- .../datasource/open_targets/test_target.py | 3 ++- .../datasource/open_targets/test_variants.py | 3 ++- .../ukbiobank/test_ukbiobank_study_index.py | 3 ++- tests/gentropy/docs/test_applying_methods.py | 4 ++-- tests/gentropy/docs/test_create_dataset.py | 4 ++-- .../docs/test_creating_spark_session.py | 3 +-- tests/gentropy/docs/test_inspect_dataset.py | 2 +- tests/gentropy/method/test_carma.py | 1 + tests/gentropy/method/test_clump.py | 1 + .../method/test_colocalisation_method.py | 7 ++++--- tests/gentropy/method/test_ld.py | 6 ++++-- .../method/test_locus_breaker_clumping.py | 5 +++-- tests/gentropy/method/test_locus_to_gene.py | 6 ++++-- tests/gentropy/method/test_pics.py | 3 ++- tests/gentropy/method/test_qc_of_sumstats.py | 3 ++- .../method/test_sumstat_imputation.py | 1 + tests/gentropy/method/test_susie_inf.py | 1 + .../method/test_window_based_clumping.py | 5 +++-- tests/gentropy/test_cli.py | 3 ++- tests/gentropy/test_schemas.py | 1 + tests/gentropy/test_spark_helpers.py | 3 ++- 64 files changed, 137 insertions(+), 77 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a68850464..17b7a4f6e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -6,7 +6,7 @@ ci: skip: [poetry-lock] repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.5.5 + rev: v0.6.1 hooks: - id: ruff args: @@ -65,7 +65,7 @@ repos: stages: [commit-msg] - repo: https://github.com/pre-commit/mirrors-mypy - rev: "v1.11.0" + rev: "v1.11.1" hooks: - id: mypy args: diff --git a/docs/src_snippets/howto/python_api/b_create_dataset.py b/docs/src_snippets/howto/python_api/b_create_dataset.py index 1a006c97a..61945862e 100644 --- a/docs/src_snippets/howto/python_api/b_create_dataset.py +++ b/docs/src_snippets/howto/python_api/b_create_dataset.py @@ -42,6 +42,7 @@ def create_from_pandas() -> SummaryStatistics: """Create a dataset from a path with Pandas files.""" # --8<-- [start:create_from_pandas_import] import pyspark.pandas as ps + from gentropy.dataset.summary_statistics import SummaryStatistics # --8<-- [end:create_from_pandas_import] diff --git a/src/airflow/dags/common_airflow.py b/src/airflow/dags/common_airflow.py index d3bdc7e29..9c3c2f91c 100644 --- a/src/airflow/dags/common_airflow.py +++ b/src/airflow/dags/common_airflow.py @@ -6,6 +6,8 @@ import pendulum import yaml +from google.cloud import batch_v1, dataproc_v1, storage + from airflow.providers.google.cloud.operators.dataproc import ( ClusterGenerator, DataprocCreateClusterOperator, @@ -13,7 +15,6 @@ DataprocSubmitJobOperator, ) from airflow.utils.trigger_rule import TriggerRule -from google.cloud import batch_v1, dataproc_v1, storage if TYPE_CHECKING: from pathlib import Path diff --git a/src/airflow/dags/eqtl_preprocess.py b/src/airflow/dags/eqtl_preprocess.py index aef70085d..309604e09 100644 --- a/src/airflow/dags/eqtl_preprocess.py +++ b/src/airflow/dags/eqtl_preprocess.py @@ -5,6 +5,7 @@ from pathlib import Path import common_airflow as common + from airflow.models.dag import DAG from airflow.providers.google.cloud.operators.dataflow import ( DataflowTemplatedJobStartOperator, diff --git a/src/airflow/dags/finngen_harmonisation.py b/src/airflow/dags/finngen_harmonisation.py index b40561fd9..18f81a376 100644 --- a/src/airflow/dags/finngen_harmonisation.py +++ b/src/airflow/dags/finngen_harmonisation.py @@ -8,6 +8,7 @@ from typing import Any import common_airflow as common + from airflow.decorators import task from airflow.models.dag import DAG from airflow.providers.google.cloud.operators.gcs import GCSListObjectsOperator diff --git a/src/airflow/dags/finngen_preprocess.py b/src/airflow/dags/finngen_preprocess.py index 3a60a0cfd..fbfab91e5 100644 --- a/src/airflow/dags/finngen_preprocess.py +++ b/src/airflow/dags/finngen_preprocess.py @@ -5,6 +5,7 @@ from pathlib import Path import common_airflow as common + from airflow.models.dag import DAG from airflow.utils.task_group import TaskGroup from airflow.utils.trigger_rule import TriggerRule diff --git a/src/airflow/dags/genetics_etl.py b/src/airflow/dags/genetics_etl.py index 025e4fa0a..aeb87398c 100644 --- a/src/airflow/dags/genetics_etl.py +++ b/src/airflow/dags/genetics_etl.py @@ -5,6 +5,7 @@ from pathlib import Path import common_airflow as common + from airflow.models.dag import DAG from airflow.operators.python import ShortCircuitOperator from airflow.providers.google.cloud.transfers.gcs_to_gcs import GCSToGCSOperator diff --git a/src/airflow/dags/gnomad_preprocess.py b/src/airflow/dags/gnomad_preprocess.py index 03962bec5..54e6b6bf4 100644 --- a/src/airflow/dags/gnomad_preprocess.py +++ b/src/airflow/dags/gnomad_preprocess.py @@ -5,6 +5,7 @@ from pathlib import Path import common_airflow as common + from airflow.models.dag import DAG CLUSTER_NAME = "gnomad-preprocess" diff --git a/src/airflow/dags/gwas_catalog_harmonisation.py b/src/airflow/dags/gwas_catalog_harmonisation.py index 25970fa8a..e6399e957 100644 --- a/src/airflow/dags/gwas_catalog_harmonisation.py +++ b/src/airflow/dags/gwas_catalog_harmonisation.py @@ -8,6 +8,7 @@ from typing import Any import common_airflow as common + from airflow.decorators import task from airflow.models.dag import DAG from airflow.providers.google.cloud.operators.gcs import GCSListObjectsOperator diff --git a/src/airflow/dags/gwas_catalog_preprocess.py b/src/airflow/dags/gwas_catalog_preprocess.py index c4722b83b..7f6280242 100644 --- a/src/airflow/dags/gwas_catalog_preprocess.py +++ b/src/airflow/dags/gwas_catalog_preprocess.py @@ -5,6 +5,7 @@ from pathlib import Path import common_airflow as common + from airflow.models.dag import DAG from airflow.operators.python import PythonOperator from airflow.providers.google.cloud.hooks.gcs import GCSHook diff --git a/src/airflow/dags/gwas_curation_update.py b/src/airflow/dags/gwas_curation_update.py index 830007e6d..d5fd38e35 100644 --- a/src/airflow/dags/gwas_curation_update.py +++ b/src/airflow/dags/gwas_curation_update.py @@ -5,6 +5,7 @@ from pathlib import Path import common_airflow as common + from airflow.models.dag import DAG CLUSTER_NAME = "otg-gwascatalog-curation" diff --git a/src/airflow/dags/ukb_ppp_eur.py b/src/airflow/dags/ukb_ppp_eur.py index f8a7c2342..f0d0e1fe8 100644 --- a/src/airflow/dags/ukb_ppp_eur.py +++ b/src/airflow/dags/ukb_ppp_eur.py @@ -5,6 +5,7 @@ from pathlib import Path import common_airflow as common + from airflow.models.dag import DAG CLUSTER_NAME = "otg-ukb-ppp-eur" diff --git a/src/airflow/dags/variant_index.py b/src/airflow/dags/variant_index.py index f1e402a41..eb102f277 100644 --- a/src/airflow/dags/variant_index.py +++ b/src/airflow/dags/variant_index.py @@ -8,13 +8,6 @@ from pathlib import Path from typing import Any -from airflow.decorators import task -from airflow.models.dag import DAG -from airflow.providers.google.cloud.operators.cloud_batch import ( - CloudBatchSubmitJobOperator, -) -from airflow.providers.google.cloud.operators.gcs import GCSListObjectsOperator -from airflow.utils.trigger_rule import TriggerRule from common_airflow import ( create_batch_job, create_cluster, @@ -28,6 +21,14 @@ ) from google.cloud import batch_v1 +from airflow.decorators import task +from airflow.models.dag import DAG +from airflow.providers.google.cloud.operators.cloud_batch import ( + CloudBatchSubmitJobOperator, +) +from airflow.providers.google.cloud.operators.gcs import GCSListObjectsOperator +from airflow.utils.trigger_rule import TriggerRule + PROJECT_ID = "open-targets-genetics-dev" REGION = "europe-west1" CONFIG_FILE_PATH = Path(__file__).parent / "configs" / "variant_sources.yaml" diff --git a/tests/airflow/test_dag.py b/tests/airflow/test_dag.py index 49edc76ee..e18f91fb1 100644 --- a/tests/airflow/test_dag.py +++ b/tests/airflow/test_dag.py @@ -3,6 +3,7 @@ from __future__ import annotations import pytest + from airflow.models import DagBag diff --git a/tests/gentropy/common/test_spark_helpers.py b/tests/gentropy/common/test_spark_helpers.py index 19ef6a436..bd872ae90 100644 --- a/tests/gentropy/common/test_spark_helpers.py +++ b/tests/gentropy/common/test_spark_helpers.py @@ -3,13 +3,14 @@ from __future__ import annotations import pytest +from pyspark.sql import Column, SparkSession +from pyspark.sql import functions as f +from pyspark.sql import types as t + from gentropy.common.spark_helpers import ( enforce_schema, order_array_of_structs_by_field, ) -from pyspark.sql import Column, SparkSession -from pyspark.sql import functions as f -from pyspark.sql import types as t def test_order_array_of_structs_by_field(spark: SparkSession) -> None: diff --git a/tests/gentropy/common/test_version_engine.py b/tests/gentropy/common/test_version_engine.py index 46a670165..2ee2e12ce 100644 --- a/tests/gentropy/common/test_version_engine.py +++ b/tests/gentropy/common/test_version_engine.py @@ -5,6 +5,7 @@ from pathlib import Path import pytest + from gentropy.common.version_engine import GnomADVersionSeeker, VersionEngine diff --git a/tests/gentropy/conftest.py b/tests/gentropy/conftest.py index c35188466..9ae7ace58 100644 --- a/tests/gentropy/conftest.py +++ b/tests/gentropy/conftest.py @@ -9,6 +9,8 @@ import numpy as np import pandas as pd import pytest +from pyspark.sql import DataFrame, SparkSession + from gentropy.common.Liftover import LiftOverSpark from gentropy.common.session import Session from gentropy.dataset.colocalisation import Colocalisation @@ -28,8 +30,6 @@ from gentropy.datasource.eqtl_catalogue.study_index import EqtlCatalogueStudyIndex from gentropy.datasource.gwas_catalog.associations import StudyLocusGWASCatalog from gentropy.datasource.gwas_catalog.study_index import StudyIndexGWASCatalog -from pyspark.sql import DataFrame, SparkSession - from utils.spark import get_spark_testing_conf diff --git a/tests/gentropy/dataset/test_dataset.py b/tests/gentropy/dataset/test_dataset.py index bddbb4f6a..a152b1ac8 100644 --- a/tests/gentropy/dataset/test_dataset.py +++ b/tests/gentropy/dataset/test_dataset.py @@ -5,8 +5,6 @@ import numpy as np import pyspark.sql.functions as f import pytest -from gentropy.dataset.dataset import Dataset -from gentropy.dataset.study_index import StudyIndex from pyspark.sql import SparkSession from pyspark.sql.types import ( DoubleType, @@ -15,6 +13,9 @@ StructType, ) +from gentropy.dataset.dataset import Dataset +from gentropy.dataset.study_index import StudyIndex + class MockDataset(Dataset): """Concrete subclass of Dataset for testing. Necessary because Dataset is abstract.""" diff --git a/tests/gentropy/dataset/test_gene_index.py b/tests/gentropy/dataset/test_gene_index.py index 999f089b3..e4ae8e581 100644 --- a/tests/gentropy/dataset/test_gene_index.py +++ b/tests/gentropy/dataset/test_gene_index.py @@ -2,9 +2,10 @@ from __future__ import annotations -from gentropy.dataset.gene_index import GeneIndex from pyspark.sql import DataFrame +from gentropy.dataset.gene_index import GeneIndex + def test_gene_index_creation(mock_gene_index: GeneIndex) -> None: """Test gene index creation with mock gene index.""" diff --git a/tests/gentropy/dataset/test_l2g.py b/tests/gentropy/dataset/test_l2g.py index 547c58e51..d0f1c3672 100644 --- a/tests/gentropy/dataset/test_l2g.py +++ b/tests/gentropy/dataset/test_l2g.py @@ -5,6 +5,7 @@ from typing import TYPE_CHECKING import pytest + from gentropy.dataset.l2g_feature_matrix import L2GFeatureMatrix from gentropy.dataset.l2g_gold_standard import L2GGoldStandard from gentropy.dataset.l2g_prediction import L2GPrediction diff --git a/tests/gentropy/dataset/test_pairwise_ld.py b/tests/gentropy/dataset/test_pairwise_ld.py index 11ebf75ca..9a57c129b 100644 --- a/tests/gentropy/dataset/test_pairwise_ld.py +++ b/tests/gentropy/dataset/test_pairwise_ld.py @@ -6,10 +6,11 @@ import numpy as np import pytest -from gentropy.dataset.pairwise_ld import PairwiseLD from pyspark.sql import functions as f from pyspark.sql.window import Window +from gentropy.dataset.pairwise_ld import PairwiseLD + if TYPE_CHECKING: from pyspark.sql import SparkSession diff --git a/tests/gentropy/dataset/test_study_index.py b/tests/gentropy/dataset/test_study_index.py index d693f147c..3bdd7a5cb 100644 --- a/tests/gentropy/dataset/test_study_index.py +++ b/tests/gentropy/dataset/test_study_index.py @@ -3,11 +3,12 @@ from __future__ import annotations import pytest -from gentropy.dataset.gene_index import GeneIndex -from gentropy.dataset.study_index import StudyIndex from pyspark.sql import DataFrame, SparkSession from pyspark.sql import functions as f +from gentropy.dataset.gene_index import GeneIndex +from gentropy.dataset.study_index import StudyIndex + def test_study_index_creation(mock_study_index: StudyIndex) -> None: """Test study index creation with mock data.""" diff --git a/tests/gentropy/dataset/test_study_locus.py b/tests/gentropy/dataset/test_study_locus.py index 9ac58149b..9b40796db 100644 --- a/tests/gentropy/dataset/test_study_locus.py +++ b/tests/gentropy/dataset/test_study_locus.py @@ -7,15 +7,6 @@ import pyspark.sql.functions as f import pyspark.sql.types as t import pytest -from gentropy.dataset.ld_index import LDIndex -from gentropy.dataset.study_index import StudyIndex -from gentropy.dataset.study_locus import ( - CredibleInterval, - StudyLocus, - StudyLocusQualityCheck, -) -from gentropy.dataset.study_locus_overlap import StudyLocusOverlap -from gentropy.dataset.summary_statistics import SummaryStatistics from pyspark.sql import Column, Row, SparkSession from pyspark.sql.types import ( ArrayType, @@ -27,6 +18,16 @@ StructType, ) +from gentropy.dataset.ld_index import LDIndex +from gentropy.dataset.study_index import StudyIndex +from gentropy.dataset.study_locus import ( + CredibleInterval, + StudyLocus, + StudyLocusQualityCheck, +) +from gentropy.dataset.study_locus_overlap import StudyLocusOverlap +from gentropy.dataset.summary_statistics import SummaryStatistics + @pytest.mark.parametrize( "has_overlap, expected", diff --git a/tests/gentropy/dataset/test_study_locus_overlap.py b/tests/gentropy/dataset/test_study_locus_overlap.py index 53d87226c..e26b59c30 100644 --- a/tests/gentropy/dataset/test_study_locus_overlap.py +++ b/tests/gentropy/dataset/test_study_locus_overlap.py @@ -2,9 +2,10 @@ from __future__ import annotations -from gentropy.dataset.study_locus_overlap import StudyLocusOverlap from pyspark.sql import SparkSession +from gentropy.dataset.study_locus_overlap import StudyLocusOverlap + def test_study_locus_overlap_creation( mock_study_locus_overlap: StudyLocusOverlap, diff --git a/tests/gentropy/dataset/test_study_locus_overlaps.py b/tests/gentropy/dataset/test_study_locus_overlaps.py index 8e732fc5c..bd3415959 100644 --- a/tests/gentropy/dataset/test_study_locus_overlaps.py +++ b/tests/gentropy/dataset/test_study_locus_overlaps.py @@ -6,13 +6,15 @@ import pyspark.sql.types as t import pytest + from gentropy.dataset.study_locus import StudyLocus from gentropy.dataset.study_locus_overlap import StudyLocusOverlap if TYPE_CHECKING: - from gentropy.dataset.study_index import StudyIndex from pyspark.sql import SparkSession + from gentropy.dataset.study_index import StudyIndex + def test_study_locus_overlap_creation( mock_study_locus_overlap: StudyLocusOverlap, diff --git a/tests/gentropy/dataset/test_summary_statistics.py b/tests/gentropy/dataset/test_summary_statistics.py index 9885181a8..cf3cfdae7 100644 --- a/tests/gentropy/dataset/test_summary_statistics.py +++ b/tests/gentropy/dataset/test_summary_statistics.py @@ -4,9 +4,10 @@ from typing import TYPE_CHECKING +from pyspark.sql import types as t + from gentropy.dataset.study_locus import StudyLocus from gentropy.dataset.summary_statistics import SummaryStatistics -from pyspark.sql import types as t if TYPE_CHECKING: from pyspark.sql import SparkSession diff --git a/tests/gentropy/dataset/test_variant_index.py b/tests/gentropy/dataset/test_variant_index.py index 9a03308a8..12afba89f 100644 --- a/tests/gentropy/dataset/test_variant_index.py +++ b/tests/gentropy/dataset/test_variant_index.py @@ -5,11 +5,12 @@ from typing import TYPE_CHECKING import pytest +from pyspark.sql import functions as f +from pyspark.sql import types as t + from gentropy.dataset.gene_index import GeneIndex from gentropy.dataset.v2g import V2G from gentropy.dataset.variant_index import VariantIndex -from pyspark.sql import functions as f -from pyspark.sql import types as t if TYPE_CHECKING: from pyspark.sql import SparkSession diff --git a/tests/gentropy/datasource/ensembl/test_vep_variants.py b/tests/gentropy/datasource/ensembl/test_vep_variants.py index 1401f1b6c..e3313a1e5 100644 --- a/tests/gentropy/datasource/ensembl/test_vep_variants.py +++ b/tests/gentropy/datasource/ensembl/test_vep_variants.py @@ -5,11 +5,12 @@ from typing import TYPE_CHECKING import pytest -from gentropy.dataset.variant_index import VariantIndex -from gentropy.datasource.ensembl.vep_parser import VariantEffectPredictorParser from pyspark.sql import DataFrame from pyspark.sql import functions as f +from gentropy.dataset.variant_index import VariantIndex +from gentropy.datasource.ensembl.vep_parser import VariantEffectPredictorParser + if TYPE_CHECKING: from pyspark.sql import SparkSession diff --git a/tests/gentropy/datasource/eqtl_catalogue/test_eqtl_catalogue.py b/tests/gentropy/datasource/eqtl_catalogue/test_eqtl_catalogue.py index a488ab78a..ce892128a 100644 --- a/tests/gentropy/datasource/eqtl_catalogue/test_eqtl_catalogue.py +++ b/tests/gentropy/datasource/eqtl_catalogue/test_eqtl_catalogue.py @@ -3,11 +3,12 @@ from __future__ import annotations import pytest +from pyspark.sql import DataFrame + from gentropy.dataset.study_index import StudyIndex from gentropy.dataset.study_locus import StudyLocus from gentropy.datasource.eqtl_catalogue.finemapping import EqtlCatalogueFinemapping from gentropy.datasource.eqtl_catalogue.study_index import EqtlCatalogueStudyIndex -from pyspark.sql import DataFrame @pytest.fixture diff --git a/tests/gentropy/datasource/finngen/test_finngen_finemapping.py b/tests/gentropy/datasource/finngen/test_finngen_finemapping.py index 089b10f74..56a03fcb7 100644 --- a/tests/gentropy/datasource/finngen/test_finngen_finemapping.py +++ b/tests/gentropy/datasource/finngen/test_finngen_finemapping.py @@ -2,9 +2,10 @@ from __future__ import annotations +from pyspark.sql import SparkSession + from gentropy.dataset.study_locus import StudyLocus from gentropy.datasource.finngen.finemapping import FinnGenFinemapping -from pyspark.sql import SparkSession def test_finngen_finemapping_from_finngen_susie_finemapping( diff --git a/tests/gentropy/datasource/finngen/test_finngen_study_index.py b/tests/gentropy/datasource/finngen/test_finngen_study_index.py index 96a24db94..6fc4665dc 100644 --- a/tests/gentropy/datasource/finngen/test_finngen_study_index.py +++ b/tests/gentropy/datasource/finngen/test_finngen_study_index.py @@ -2,9 +2,10 @@ from __future__ import annotations +from pyspark.sql import SparkSession + from gentropy.dataset.study_index import StudyIndex from gentropy.datasource.finngen.study_index import FinnGenStudyIndex -from pyspark.sql import SparkSession def test_finngen_study_index_from_source(spark: SparkSession) -> None: diff --git a/tests/gentropy/datasource/finngen/test_finngen_summary_stats.py b/tests/gentropy/datasource/finngen/test_finngen_summary_stats.py index 624f66d66..73cffdc9f 100644 --- a/tests/gentropy/datasource/finngen/test_finngen_summary_stats.py +++ b/tests/gentropy/datasource/finngen/test_finngen_summary_stats.py @@ -2,9 +2,10 @@ from __future__ import annotations +from pyspark.sql import SparkSession + from gentropy.dataset.summary_statistics import SummaryStatistics from gentropy.datasource.finngen.summary_stats import FinnGenSummaryStats -from pyspark.sql import SparkSession def test_finngen_summary_stats_from_source(spark: SparkSession) -> None: diff --git a/tests/gentropy/datasource/gnomad/test_gnomad_ld.py b/tests/gentropy/datasource/gnomad/test_gnomad_ld.py index 5fa3b00a4..78b96ad84 100644 --- a/tests/gentropy/datasource/gnomad/test_gnomad_ld.py +++ b/tests/gentropy/datasource/gnomad/test_gnomad_ld.py @@ -7,10 +7,11 @@ import hail as hl import pytest -from gentropy.datasource.gnomad.ld import GnomADLDMatrix from pyspark.sql import DataFrame, SparkSession from pyspark.sql import functions as f +from gentropy.datasource.gnomad.ld import GnomADLDMatrix + @pytest.mark.parametrize( ("observed", "expected"), diff --git a/tests/gentropy/datasource/gwas_catalog/test_gwas_catalog_associations.py b/tests/gentropy/datasource/gwas_catalog/test_gwas_catalog_associations.py index e7067e3d9..2179150cd 100644 --- a/tests/gentropy/datasource/gwas_catalog/test_gwas_catalog_associations.py +++ b/tests/gentropy/datasource/gwas_catalog/test_gwas_catalog_associations.py @@ -2,14 +2,15 @@ from __future__ import annotations +from pyspark.sql import DataFrame +from pyspark.sql import functions as f +from pyspark.sql.types import LongType + from gentropy.dataset.variant_index import VariantIndex from gentropy.datasource.gwas_catalog.associations import ( GWASCatalogCuratedAssociationsParser, StudyLocusGWASCatalog, ) -from pyspark.sql import DataFrame -from pyspark.sql import functions as f -from pyspark.sql.types import LongType def test_study_locus_gwas_catalog_creation( diff --git a/tests/gentropy/datasource/gwas_catalog/test_gwas_catalog_curation.py b/tests/gentropy/datasource/gwas_catalog/test_gwas_catalog_curation.py index 764d003e8..4163531cb 100644 --- a/tests/gentropy/datasource/gwas_catalog/test_gwas_catalog_curation.py +++ b/tests/gentropy/datasource/gwas_catalog/test_gwas_catalog_curation.py @@ -7,9 +7,10 @@ import pyspark.sql.functions as f import pyspark.sql.types as t import pytest -from gentropy.datasource.gwas_catalog.study_index import StudyIndexGWASCatalog from pyspark.sql import DataFrame +from gentropy.datasource.gwas_catalog.study_index import StudyIndexGWASCatalog + if TYPE_CHECKING: from pyspark.sql import SparkSession diff --git a/tests/gentropy/datasource/gwas_catalog/test_gwas_catalog_study_index.py b/tests/gentropy/datasource/gwas_catalog/test_gwas_catalog_study_index.py index 96dccdf9d..b91529b3d 100644 --- a/tests/gentropy/datasource/gwas_catalog/test_gwas_catalog_study_index.py +++ b/tests/gentropy/datasource/gwas_catalog/test_gwas_catalog_study_index.py @@ -2,11 +2,12 @@ from __future__ import annotations +from pyspark.sql import DataFrame + from gentropy.datasource.gwas_catalog.study_index import ( StudyIndexGWASCatalog, StudyIndexGWASCatalogParser, ) -from pyspark.sql import DataFrame def test_annotate_discovery_sample_sizes( diff --git a/tests/gentropy/datasource/gwas_catalog/test_gwas_catalog_study_splitter.py b/tests/gentropy/datasource/gwas_catalog/test_gwas_catalog_study_splitter.py index 58bcb53c8..c6bd03054 100644 --- a/tests/gentropy/datasource/gwas_catalog/test_gwas_catalog_study_splitter.py +++ b/tests/gentropy/datasource/gwas_catalog/test_gwas_catalog_study_splitter.py @@ -6,6 +6,7 @@ import pyspark.sql.functions as f import pytest + from gentropy.datasource.gwas_catalog.associations import StudyLocusGWASCatalog from gentropy.datasource.gwas_catalog.study_index import StudyIndexGWASCatalog from gentropy.datasource.gwas_catalog.study_splitter import GWASCatalogStudySplitter diff --git a/tests/gentropy/datasource/gwas_catalog/test_gwas_catalog_summary_statistics.py b/tests/gentropy/datasource/gwas_catalog/test_gwas_catalog_summary_statistics.py index 4ede62f36..867345455 100644 --- a/tests/gentropy/datasource/gwas_catalog/test_gwas_catalog_summary_statistics.py +++ b/tests/gentropy/datasource/gwas_catalog/test_gwas_catalog_summary_statistics.py @@ -6,6 +6,7 @@ import pyspark.sql.functions as f import pytest + from gentropy.dataset.summary_statistics import SummaryStatistics from gentropy.datasource.gwas_catalog.summary_statistics import ( GWASCatalogSummaryStatistics, diff --git a/tests/gentropy/datasource/intervals/test_andersson.py b/tests/gentropy/datasource/intervals/test_andersson.py index 09204967d..69575b7c3 100644 --- a/tests/gentropy/datasource/intervals/test_andersson.py +++ b/tests/gentropy/datasource/intervals/test_andersson.py @@ -3,11 +3,12 @@ from __future__ import annotations import pytest +from pyspark.sql import DataFrame, SparkSession + from gentropy.common.Liftover import LiftOverSpark from gentropy.dataset.gene_index import GeneIndex from gentropy.dataset.intervals import Intervals from gentropy.datasource.intervals.andersson import IntervalsAndersson -from pyspark.sql import DataFrame, SparkSession @pytest.fixture(scope="module") diff --git a/tests/gentropy/datasource/intervals/test_javierre.py b/tests/gentropy/datasource/intervals/test_javierre.py index a6a74e94e..886a28c52 100644 --- a/tests/gentropy/datasource/intervals/test_javierre.py +++ b/tests/gentropy/datasource/intervals/test_javierre.py @@ -3,11 +3,12 @@ from __future__ import annotations import pytest +from pyspark.sql import DataFrame, SparkSession + from gentropy.common.Liftover import LiftOverSpark from gentropy.dataset.gene_index import GeneIndex from gentropy.dataset.intervals import Intervals from gentropy.datasource.intervals.javierre import IntervalsJavierre -from pyspark.sql import DataFrame, SparkSession @pytest.fixture(scope="module") diff --git a/tests/gentropy/datasource/intervals/test_jung.py b/tests/gentropy/datasource/intervals/test_jung.py index 44062f680..e391b8f96 100644 --- a/tests/gentropy/datasource/intervals/test_jung.py +++ b/tests/gentropy/datasource/intervals/test_jung.py @@ -3,11 +3,12 @@ from __future__ import annotations import pytest +from pyspark.sql import DataFrame, SparkSession + from gentropy.common.Liftover import LiftOverSpark from gentropy.dataset.gene_index import GeneIndex from gentropy.dataset.intervals import Intervals from gentropy.datasource.intervals.jung import IntervalsJung -from pyspark.sql import DataFrame, SparkSession @pytest.fixture(scope="module") diff --git a/tests/gentropy/datasource/intervals/test_thurman.py b/tests/gentropy/datasource/intervals/test_thurman.py index 853adb380..616e1abec 100644 --- a/tests/gentropy/datasource/intervals/test_thurman.py +++ b/tests/gentropy/datasource/intervals/test_thurman.py @@ -3,11 +3,12 @@ from __future__ import annotations import pytest +from pyspark.sql import DataFrame, SparkSession + from gentropy.common.Liftover import LiftOverSpark from gentropy.dataset.gene_index import GeneIndex from gentropy.dataset.intervals import Intervals from gentropy.datasource.intervals.thurman import IntervalsThurman -from pyspark.sql import DataFrame, SparkSession @pytest.fixture(scope="module") diff --git a/tests/gentropy/datasource/open_targets/test_l2g_gold_standard.py b/tests/gentropy/datasource/open_targets/test_l2g_gold_standard.py index 0690781f5..6f91d32a9 100644 --- a/tests/gentropy/datasource/open_targets/test_l2g_gold_standard.py +++ b/tests/gentropy/datasource/open_targets/test_l2g_gold_standard.py @@ -5,12 +5,13 @@ from typing import TYPE_CHECKING import pytest +from pyspark.sql import DataFrame + from gentropy.dataset.l2g_gold_standard import L2GGoldStandard from gentropy.dataset.v2g import V2G from gentropy.datasource.open_targets.l2g_gold_standard import ( OpenTargetsL2GGoldStandard, ) -from pyspark.sql import DataFrame if TYPE_CHECKING: from pyspark.sql.session import SparkSession diff --git a/tests/gentropy/datasource/open_targets/test_target.py b/tests/gentropy/datasource/open_targets/test_target.py index c0a92fcd7..091dcea53 100644 --- a/tests/gentropy/datasource/open_targets/test_target.py +++ b/tests/gentropy/datasource/open_targets/test_target.py @@ -2,9 +2,10 @@ from __future__ import annotations +from pyspark.sql import DataFrame + from gentropy.dataset.gene_index import GeneIndex from gentropy.datasource.open_targets.target import OpenTargetsTarget -from pyspark.sql import DataFrame def test_open_targets_as_gene_index(sample_target_index: DataFrame) -> None: diff --git a/tests/gentropy/datasource/open_targets/test_variants.py b/tests/gentropy/datasource/open_targets/test_variants.py index f75fd8860..9d2c56e73 100644 --- a/tests/gentropy/datasource/open_targets/test_variants.py +++ b/tests/gentropy/datasource/open_targets/test_variants.py @@ -8,9 +8,10 @@ from gentropy.datasource.open_targets.variants import OpenTargetsVariant if TYPE_CHECKING: - from gentropy.common.session import Session from pyspark.sql import SparkSession + from gentropy.common.session import Session + class TestOpenTargetsVariant: """Test suite for the OpenTargetsVariant class.""" diff --git a/tests/gentropy/datasource/ukbiobank/test_ukbiobank_study_index.py b/tests/gentropy/datasource/ukbiobank/test_ukbiobank_study_index.py index ff07db5db..9f48ebef2 100644 --- a/tests/gentropy/datasource/ukbiobank/test_ukbiobank_study_index.py +++ b/tests/gentropy/datasource/ukbiobank/test_ukbiobank_study_index.py @@ -2,9 +2,10 @@ from __future__ import annotations +from pyspark.sql import DataFrame + from gentropy.dataset.study_index import StudyIndex from gentropy.datasource.ukbiobank.study_index import UKBiobankStudyIndex -from pyspark.sql import DataFrame def test_ukbiobank_study_index_from_source( diff --git a/tests/gentropy/docs/test_applying_methods.py b/tests/gentropy/docs/test_applying_methods.py index cbfdb9155..14bd70fd7 100644 --- a/tests/gentropy/docs/test_applying_methods.py +++ b/tests/gentropy/docs/test_applying_methods.py @@ -3,14 +3,14 @@ from typing import Any import pytest -from gentropy.dataset.study_locus import StudyLocus -from gentropy.dataset.summary_statistics import SummaryStatistics from docs.src_snippets.howto.python_api.c_applying_methods import ( apply_class_method_clumping, apply_class_method_pics, apply_instance_method, ) +from gentropy.dataset.study_locus import StudyLocus +from gentropy.dataset.summary_statistics import SummaryStatistics @pytest.mark.parametrize( diff --git a/tests/gentropy/docs/test_create_dataset.py b/tests/gentropy/docs/test_create_dataset.py index 2daae0c6a..256f11251 100644 --- a/tests/gentropy/docs/test_create_dataset.py +++ b/tests/gentropy/docs/test_create_dataset.py @@ -3,14 +3,14 @@ from typing import Any import pytest -from gentropy.common.session import Session -from gentropy.dataset.summary_statistics import SummaryStatistics from docs.src_snippets.howto.python_api.b_create_dataset import ( create_from_pandas, create_from_parquet, create_from_source, ) +from gentropy.common.session import Session +from gentropy.dataset.summary_statistics import SummaryStatistics @pytest.mark.parametrize( diff --git a/tests/gentropy/docs/test_creating_spark_session.py b/tests/gentropy/docs/test_creating_spark_session.py index 197d22d56..088f23d38 100644 --- a/tests/gentropy/docs/test_creating_spark_session.py +++ b/tests/gentropy/docs/test_creating_spark_session.py @@ -1,11 +1,10 @@ """Testing creating spark session docs.""" -from gentropy.common.session import Session - from docs.src_snippets.howto.python_api.a_creating_spark_session import ( custom_session, default_session, ) +from gentropy.common.session import Session def test_default_session() -> None: diff --git a/tests/gentropy/docs/test_inspect_dataset.py b/tests/gentropy/docs/test_inspect_dataset.py index 38e258158..ecfb6d85b 100644 --- a/tests/gentropy/docs/test_inspect_dataset.py +++ b/tests/gentropy/docs/test_inspect_dataset.py @@ -1,6 +1,5 @@ """Testing inspecting dataset docs.""" -from gentropy.dataset.summary_statistics import SummaryStatistics from pyspark.sql.types import StructType from docs.src_snippets.howto.python_api.d_inspect_dataset import ( @@ -8,6 +7,7 @@ get_dataset_schema, interact_w_dataframe, ) +from gentropy.dataset.summary_statistics import SummaryStatistics def test_filter_dataset(mock_summary_statistics: SummaryStatistics) -> None: diff --git a/tests/gentropy/method/test_carma.py b/tests/gentropy/method/test_carma.py index b3aecf6c8..8db2abe47 100644 --- a/tests/gentropy/method/test_carma.py +++ b/tests/gentropy/method/test_carma.py @@ -3,6 +3,7 @@ from __future__ import annotations import numpy as np + from gentropy.method.carma import CARMA diff --git a/tests/gentropy/method/test_clump.py b/tests/gentropy/method/test_clump.py index af4e2d141..4616c5c6f 100644 --- a/tests/gentropy/method/test_clump.py +++ b/tests/gentropy/method/test_clump.py @@ -7,6 +7,7 @@ import pyspark.sql.functions as f import pyspark.sql.types as t import pytest + from gentropy.dataset.study_locus import StudyLocus from gentropy.method.clump import LDclumping diff --git a/tests/gentropy/method/test_colocalisation_method.py b/tests/gentropy/method/test_colocalisation_method.py index e58b0e562..d6798d831 100644 --- a/tests/gentropy/method/test_colocalisation_method.py +++ b/tests/gentropy/method/test_colocalisation_method.py @@ -5,13 +5,14 @@ from typing import Any import pytest -from gentropy.dataset.colocalisation import Colocalisation -from gentropy.dataset.study_locus_overlap import StudyLocusOverlap -from gentropy.method.colocalisation import Coloc, ECaviar from pandas.testing import assert_frame_equal from pyspark.sql import SparkSession from pyspark.sql.types import DoubleType, LongType, StringType, StructField, StructType +from gentropy.dataset.colocalisation import Colocalisation +from gentropy.dataset.study_locus_overlap import StudyLocusOverlap +from gentropy.method.colocalisation import Coloc, ECaviar + def test_coloc(mock_study_locus_overlap: StudyLocusOverlap) -> None: """Test coloc.""" diff --git a/tests/gentropy/method/test_ld.py b/tests/gentropy/method/test_ld.py index db0b5aba4..8fb86ff31 100644 --- a/tests/gentropy/method/test_ld.py +++ b/tests/gentropy/method/test_ld.py @@ -7,14 +7,16 @@ import pyspark.sql.functions as f import pyspark.sql.types as t import pytest +from pyspark.sql import Row + from gentropy.dataset.study_locus import StudyLocus from gentropy.method.ld import LDAnnotator -from pyspark.sql import Row if TYPE_CHECKING: + from pyspark.sql import SparkSession + from gentropy.dataset.ld_index import LDIndex from gentropy.dataset.study_index import StudyIndex - from pyspark.sql import SparkSession class TestLDAnnotator: diff --git a/tests/gentropy/method/test_locus_breaker_clumping.py b/tests/gentropy/method/test_locus_breaker_clumping.py index fd3476ded..c2c23eca5 100644 --- a/tests/gentropy/method/test_locus_breaker_clumping.py +++ b/tests/gentropy/method/test_locus_breaker_clumping.py @@ -5,11 +5,12 @@ from typing import TYPE_CHECKING import pytest -from gentropy.dataset.study_locus import StudyLocus -from gentropy.dataset.summary_statistics import SummaryStatistics from pyspark.sql import functions as f from pyspark.sql import types as t +from gentropy.dataset.study_locus import StudyLocus +from gentropy.dataset.summary_statistics import SummaryStatistics + if TYPE_CHECKING: from pyspark.sql import SparkSession diff --git a/tests/gentropy/method/test_locus_to_gene.py b/tests/gentropy/method/test_locus_to_gene.py index 35f736d1f..460d65062 100644 --- a/tests/gentropy/method/test_locus_to_gene.py +++ b/tests/gentropy/method/test_locus_to_gene.py @@ -5,18 +5,20 @@ from typing import TYPE_CHECKING import pytest +from sklearn.ensemble import RandomForestClassifier + from gentropy.dataset.colocalisation import Colocalisation from gentropy.dataset.l2g_feature import L2GFeature from gentropy.dataset.study_index import StudyIndex from gentropy.dataset.study_locus import StudyLocus from gentropy.method.l2g.feature_factory import ColocalisationFactory, StudyLocusFactory from gentropy.method.l2g.model import LocusToGeneModel -from sklearn.ensemble import RandomForestClassifier if TYPE_CHECKING: - from gentropy.dataset.v2g import V2G from pyspark.sql import SparkSession + from gentropy.dataset.v2g import V2G + @pytest.fixture(scope="module") def model() -> LocusToGeneModel: diff --git a/tests/gentropy/method/test_pics.py b/tests/gentropy/method/test_pics.py index ee0425b61..ff6f115dc 100644 --- a/tests/gentropy/method/test_pics.py +++ b/tests/gentropy/method/test_pics.py @@ -3,9 +3,10 @@ from __future__ import annotations import pyspark.sql.functions as f +from pyspark.sql import Row + from gentropy.dataset.study_locus import StudyLocus from gentropy.method.pics import PICS -from pyspark.sql import Row class TestFinemap: diff --git a/tests/gentropy/method/test_qc_of_sumstats.py b/tests/gentropy/method/test_qc_of_sumstats.py index 6c2d23f65..d734fcaef 100644 --- a/tests/gentropy/method/test_qc_of_sumstats.py +++ b/tests/gentropy/method/test_qc_of_sumstats.py @@ -6,10 +6,11 @@ import pandas as pd import pyspark.sql.functions as f import pytest +from pyspark.sql.functions import rand, when + from gentropy.common.session import Session from gentropy.dataset.summary_statistics import SummaryStatistics from gentropy.method.sumstat_quality_controls import SummaryStatisticsQC -from pyspark.sql.functions import rand, when def test_qc_functions( diff --git a/tests/gentropy/method/test_sumstat_imputation.py b/tests/gentropy/method/test_sumstat_imputation.py index aea59f76b..93df23abc 100644 --- a/tests/gentropy/method/test_sumstat_imputation.py +++ b/tests/gentropy/method/test_sumstat_imputation.py @@ -3,6 +3,7 @@ from __future__ import annotations import numpy as np + from gentropy.method.sumstat_imputation import SummaryStatisticsImputation diff --git a/tests/gentropy/method/test_susie_inf.py b/tests/gentropy/method/test_susie_inf.py index 45d79bcae..91227af0f 100644 --- a/tests/gentropy/method/test_susie_inf.py +++ b/tests/gentropy/method/test_susie_inf.py @@ -4,6 +4,7 @@ import numpy as np import pyspark.sql.functions as f + from gentropy.common.session import Session from gentropy.dataset.study_locus import StudyLocus from gentropy.dataset.summary_statistics import SummaryStatistics diff --git a/tests/gentropy/method/test_window_based_clumping.py b/tests/gentropy/method/test_window_based_clumping.py index cd583bac2..382dce1e9 100644 --- a/tests/gentropy/method/test_window_based_clumping.py +++ b/tests/gentropy/method/test_window_based_clumping.py @@ -4,14 +4,15 @@ from typing import TYPE_CHECKING -from gentropy.dataset.study_locus import StudyLocus -from gentropy.method.window_based_clumping import WindowBasedClumping from pyspark.ml import functions as fml from pyspark.ml.linalg import VectorUDT from pyspark.sql import SparkSession from pyspark.sql import functions as f from pyspark.sql.window import Window +from gentropy.dataset.study_locus import StudyLocus +from gentropy.method.window_based_clumping import WindowBasedClumping + if TYPE_CHECKING: from gentropy.dataset.summary_statistics import SummaryStatistics diff --git a/tests/gentropy/test_cli.py b/tests/gentropy/test_cli.py index 5675713ce..dbb5a8cac 100644 --- a/tests/gentropy/test_cli.py +++ b/tests/gentropy/test_cli.py @@ -3,10 +3,11 @@ from unittest.mock import patch import pytest -from gentropy.cli import main from hydra.errors import ConfigCompositionException from omegaconf.errors import MissingMandatoryValue +from gentropy.cli import main + def test_main_no_step() -> None: """Test the main function of the CLI without a valid step.""" diff --git a/tests/gentropy/test_schemas.py b/tests/gentropy/test_schemas.py index 630abd0ab..1af72c149 100644 --- a/tests/gentropy/test_schemas.py +++ b/tests/gentropy/test_schemas.py @@ -14,6 +14,7 @@ if TYPE_CHECKING: from _pytest.fixtures import FixtureRequest + from gentropy.dataset.gene_index import GeneIndex from gentropy.dataset.v2g import V2G diff --git a/tests/gentropy/test_spark_helpers.py b/tests/gentropy/test_spark_helpers.py index a3790c62e..1adb686cd 100644 --- a/tests/gentropy/test_spark_helpers.py +++ b/tests/gentropy/test_spark_helpers.py @@ -6,12 +6,13 @@ import pyspark.sql.functions as f import pytest +from pyspark.sql.types import ArrayType, DoubleType, StructField, StructType + from gentropy.common.spark_helpers import ( get_record_with_maximum_value, get_record_with_minimum_value, order_array_of_structs_by_field, ) -from pyspark.sql.types import ArrayType, DoubleType, StructField, StructType if TYPE_CHECKING: from pyspark.sql import DataFrame, SparkSession From 02b006d523d932830565876296513ec6dfc0aefb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 22 Aug 2024 14:07:03 +0100 Subject: [PATCH 011/188] build(deps-dev): bump deptry from 0.18.0 to 0.19.1 (#728) Bumps [deptry](https://github.com/fpgmaas/deptry) from 0.18.0 to 0.19.1. - [Release notes](https://github.com/fpgmaas/deptry/releases) - [Changelog](https://github.com/fpgmaas/deptry/blob/main/CHANGELOG.md) - [Commits](https://github.com/fpgmaas/deptry/compare/0.18.0...0.19.1) --- updated-dependencies: - dependency-name: deptry dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: David Ochoa --- poetry.lock | 27 ++++++++++++++------------- pyproject.toml | 2 +- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/poetry.lock b/poetry.lock index 04804d728..dd0c9718b 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1667,22 +1667,23 @@ dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "sphinx (<2)", "tox"] [[package]] name = "deptry" -version = "0.18.0" +version = "0.19.1" description = "A command line utility to check for unused, missing and transitive dependencies in a Python project." optional = false python-versions = ">=3.8" files = [ - {file = "deptry-0.18.0-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:aac16b9825c67887f84795d3fe3c5a676376cd6cc8555f6f7b57bfd45603e421"}, - {file = "deptry-0.18.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:b1440d2fab960e224b542726e6fcb0d3065635cfa8233c14f6c578faa2766e02"}, - {file = "deptry-0.18.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5764d6b484d488ce0f7085dc1767d99069b476383857aafd3bbc912128892dd"}, - {file = "deptry-0.18.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee0a916d78ba8db092a9454d5bc20fccbadb6ed0e8fb81fc020ba7e0df3578ed"}, - {file = "deptry-0.18.0-cp38-abi3-win_amd64.whl", hash = "sha256:7d1b561a4477ab130e1cb277b3d3aa25743b3005e1bb60076031ec3926b47541"}, - {file = "deptry-0.18.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:e73d5c2676a1f49a954baa59c248b56bc940ab87d6070cb164f1394c24e07cf3"}, - {file = "deptry-0.18.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:7343bb4948ad625ac1b3109279665004e6790ce01c8dc6a8a2ef1e4424c29773"}, - {file = "deptry-0.18.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdf6da66e31ef8bdace3bb34a86c4f066b5c5296776dd61b76802c72b0b3f5f4"}, - {file = "deptry-0.18.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c7590966832f5222d2277612e07e67285d92123ad96cf7713cda579d420d63d1"}, - {file = "deptry-0.18.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:57e09ca29e98c4782197dc959849498941b5c4fc53178e9fe1fa30025e608bfd"}, - {file = "deptry-0.18.0.tar.gz", hash = "sha256:9cf8e398ea394f90ccfa8e11d7dcfba8ed485f6a33270ee2b024475b72a00d11"}, + {file = "deptry-0.19.1-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:3a20ef0dd1c737fb05553d1b9c2fa9f185d0c9d3d881d255334cef401ffdc599"}, + {file = "deptry-0.19.1-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:2c6b2df353e5113fd2f787c2f7e694657548d388929e988e8644bd178e19fc5c"}, + {file = "deptry-0.19.1-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a407bab3486e3844f93d702f1a381942873b2a46056c693b5634bbde219bb056"}, + {file = "deptry-0.19.1-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:43f33789b97b47313609e92b62fabf8a71bba0d35a7476806da5d3d152e32345"}, + {file = "deptry-0.19.1-cp38-abi3-win_amd64.whl", hash = "sha256:0bad85a77b31360d0f52383b14783fdae4a201b597c0158fe10e91a779c67079"}, + {file = "deptry-0.19.1-cp38-abi3-win_arm64.whl", hash = "sha256:c59142d9dca8873325692fbb7aa1d2902fde87020dcc8102f75120ba95515172"}, + {file = "deptry-0.19.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a1abc119f9c8536b8ab1ee2122d4130665f33225d00d8615256ce354eb2c11ba"}, + {file = "deptry-0.19.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:7344c6cea032b549d86e156aa1e679fb94cd44deb7e93f25cb6d9c0ded5ea06f"}, + {file = "deptry-0.19.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ff7d8954265c48ea334fdd508339c51d3fba05e2d4a8be47712c69d1c8d35c94"}, + {file = "deptry-0.19.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:023073247e5dac21254bf7b600ca2e2b71560652d2dfbe11535445ee912ca059"}, + {file = "deptry-0.19.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:af8a0a9c42f8f92dfbc048e724fa89b9131f032f7e245812260560c214395abf"}, + {file = "deptry-0.19.1.tar.gz", hash = "sha256:1c12fea1d2301f42c7035c5636e4b9421457fde256fe7a241245662d20b4c841"}, ] [package.dependencies] @@ -8691,4 +8692,4 @@ test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", [metadata] lock-version = "2.0" python-versions = "^3.10, <3.11" -content-hash = "622f47ea07bd1c332dcde8368143d533a27eefdd3d8096e8b648432e0dcd0dfb" +content-hash = "e88c1cae723d94139b4ed7d1308004a63d6c4a87076bc393638d977974661797" diff --git a/pyproject.toml b/pyproject.toml index 1539cf7ee..3050f7b6e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -75,7 +75,7 @@ apache-airflow = "^2.8.0" apache-airflow-providers-google = "^10.13.1" pydoclint = ">=0.3.8,<0.6.0" prettier = "^0.0.7" -deptry = ">=0.12,<0.19" +deptry = ">=0.12,<0.20" yamllint = "^1.33.0" [tool.semantic_release] From 5984de958b9c6c4681243f917a87061d061d0426 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 23 Aug 2024 11:32:52 +0100 Subject: [PATCH 012/188] build(deps-dev): bump lxml from 5.2.2 to 5.3.0 (#727) Bumps [lxml](https://github.com/lxml/lxml) from 5.2.2 to 5.3.0. - [Release notes](https://github.com/lxml/lxml/releases) - [Changelog](https://github.com/lxml/lxml/blob/master/CHANGES.txt) - [Commits](https://github.com/lxml/lxml/compare/lxml-5.2.2...lxml-5.3.0) --- updated-dependencies: - dependency-name: lxml dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- poetry.lock | 284 ++++++++++++++++++++++++++-------------------------- 1 file changed, 140 insertions(+), 144 deletions(-) diff --git a/poetry.lock b/poetry.lock index dd0c9718b..fe8793398 100644 --- a/poetry.lock +++ b/poetry.lock @@ -4424,153 +4424,149 @@ typing-extensions = ">=4.1.1" [[package]] name = "lxml" -version = "5.2.2" +version = "5.3.0" description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." optional = false python-versions = ">=3.6" files = [ - {file = "lxml-5.2.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:364d03207f3e603922d0d3932ef363d55bbf48e3647395765f9bfcbdf6d23632"}, - {file = "lxml-5.2.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:50127c186f191b8917ea2fb8b206fbebe87fd414a6084d15568c27d0a21d60db"}, - {file = "lxml-5.2.2-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:74e4f025ef3db1c6da4460dd27c118d8cd136d0391da4e387a15e48e5c975147"}, - {file = "lxml-5.2.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:981a06a3076997adf7c743dcd0d7a0415582661e2517c7d961493572e909aa1d"}, - {file = "lxml-5.2.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aef5474d913d3b05e613906ba4090433c515e13ea49c837aca18bde190853dff"}, - {file = "lxml-5.2.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1e275ea572389e41e8b039ac076a46cb87ee6b8542df3fff26f5baab43713bca"}, - {file = "lxml-5.2.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5b65529bb2f21ac7861a0e94fdbf5dc0daab41497d18223b46ee8515e5ad297"}, - {file = "lxml-5.2.2-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:bcc98f911f10278d1daf14b87d65325851a1d29153caaf146877ec37031d5f36"}, - {file = "lxml-5.2.2-cp310-cp310-manylinux_2_28_ppc64le.whl", hash = "sha256:b47633251727c8fe279f34025844b3b3a3e40cd1b198356d003aa146258d13a2"}, - {file = "lxml-5.2.2-cp310-cp310-manylinux_2_28_s390x.whl", hash = "sha256:fbc9d316552f9ef7bba39f4edfad4a734d3d6f93341232a9dddadec4f15d425f"}, - {file = "lxml-5.2.2-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:13e69be35391ce72712184f69000cda04fc89689429179bc4c0ae5f0b7a8c21b"}, - {file = "lxml-5.2.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3b6a30a9ab040b3f545b697cb3adbf3696c05a3a68aad172e3fd7ca73ab3c835"}, - {file = "lxml-5.2.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:a233bb68625a85126ac9f1fc66d24337d6e8a0f9207b688eec2e7c880f012ec0"}, - {file = "lxml-5.2.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:dfa7c241073d8f2b8e8dbc7803c434f57dbb83ae2a3d7892dd068d99e96efe2c"}, - {file = "lxml-5.2.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1a7aca7964ac4bb07680d5c9d63b9d7028cace3e2d43175cb50bba8c5ad33316"}, - {file = "lxml-5.2.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ae4073a60ab98529ab8a72ebf429f2a8cc612619a8c04e08bed27450d52103c0"}, - {file = "lxml-5.2.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:ffb2be176fed4457e445fe540617f0252a72a8bc56208fd65a690fdb1f57660b"}, - {file = "lxml-5.2.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:e290d79a4107d7d794634ce3e985b9ae4f920380a813717adf61804904dc4393"}, - {file = "lxml-5.2.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:96e85aa09274955bb6bd483eaf5b12abadade01010478154b0ec70284c1b1526"}, - {file = "lxml-5.2.2-cp310-cp310-win32.whl", hash = "sha256:f956196ef61369f1685d14dad80611488d8dc1ef00be57c0c5a03064005b0f30"}, - {file = "lxml-5.2.2-cp310-cp310-win_amd64.whl", hash = "sha256:875a3f90d7eb5c5d77e529080d95140eacb3c6d13ad5b616ee8095447b1d22e7"}, - {file = "lxml-5.2.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:45f9494613160d0405682f9eee781c7e6d1bf45f819654eb249f8f46a2c22545"}, - {file = "lxml-5.2.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b0b3f2df149efb242cee2ffdeb6674b7f30d23c9a7af26595099afaf46ef4e88"}, - {file = "lxml-5.2.2-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d28cb356f119a437cc58a13f8135ab8a4c8ece18159eb9194b0d269ec4e28083"}, - {file = "lxml-5.2.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:657a972f46bbefdbba2d4f14413c0d079f9ae243bd68193cb5061b9732fa54c1"}, - {file = "lxml-5.2.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b74b9ea10063efb77a965a8d5f4182806fbf59ed068b3c3fd6f30d2ac7bee734"}, - {file = "lxml-5.2.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:07542787f86112d46d07d4f3c4e7c760282011b354d012dc4141cc12a68cef5f"}, - {file = "lxml-5.2.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:303f540ad2dddd35b92415b74b900c749ec2010e703ab3bfd6660979d01fd4ed"}, - {file = "lxml-5.2.2-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:2eb2227ce1ff998faf0cd7fe85bbf086aa41dfc5af3b1d80867ecfe75fb68df3"}, - {file = "lxml-5.2.2-cp311-cp311-manylinux_2_28_ppc64le.whl", hash = "sha256:1d8a701774dfc42a2f0b8ccdfe7dbc140500d1049e0632a611985d943fcf12df"}, - {file = "lxml-5.2.2-cp311-cp311-manylinux_2_28_s390x.whl", hash = "sha256:56793b7a1a091a7c286b5f4aa1fe4ae5d1446fe742d00cdf2ffb1077865db10d"}, - {file = "lxml-5.2.2-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:eb00b549b13bd6d884c863554566095bf6fa9c3cecb2e7b399c4bc7904cb33b5"}, - {file = "lxml-5.2.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1a2569a1f15ae6c8c64108a2cd2b4a858fc1e13d25846be0666fc144715e32ab"}, - {file = "lxml-5.2.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:8cf85a6e40ff1f37fe0f25719aadf443686b1ac7652593dc53c7ef9b8492b115"}, - {file = "lxml-5.2.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:d237ba6664b8e60fd90b8549a149a74fcc675272e0e95539a00522e4ca688b04"}, - {file = "lxml-5.2.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0b3f5016e00ae7630a4b83d0868fca1e3d494c78a75b1c7252606a3a1c5fc2ad"}, - {file = "lxml-5.2.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:23441e2b5339bc54dc949e9e675fa35efe858108404ef9aa92f0456929ef6fe8"}, - {file = "lxml-5.2.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:2fb0ba3e8566548d6c8e7dd82a8229ff47bd8fb8c2da237607ac8e5a1b8312e5"}, - {file = "lxml-5.2.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:79d1fb9252e7e2cfe4de6e9a6610c7cbb99b9708e2c3e29057f487de5a9eaefa"}, - {file = "lxml-5.2.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6dcc3d17eac1df7859ae01202e9bb11ffa8c98949dcbeb1069c8b9a75917e01b"}, - {file = "lxml-5.2.2-cp311-cp311-win32.whl", hash = "sha256:4c30a2f83677876465f44c018830f608fa3c6a8a466eb223535035fbc16f3438"}, - {file = "lxml-5.2.2-cp311-cp311-win_amd64.whl", hash = "sha256:49095a38eb333aaf44c06052fd2ec3b8f23e19747ca7ec6f6c954ffea6dbf7be"}, - {file = "lxml-5.2.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:7429e7faa1a60cad26ae4227f4dd0459efde239e494c7312624ce228e04f6391"}, - {file = "lxml-5.2.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:50ccb5d355961c0f12f6cf24b7187dbabd5433f29e15147a67995474f27d1776"}, - {file = "lxml-5.2.2-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc911208b18842a3a57266d8e51fc3cfaccee90a5351b92079beed912a7914c2"}, - {file = "lxml-5.2.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:33ce9e786753743159799fdf8e92a5da351158c4bfb6f2db0bf31e7892a1feb5"}, - {file = "lxml-5.2.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ec87c44f619380878bd49ca109669c9f221d9ae6883a5bcb3616785fa8f94c97"}, - {file = "lxml-5.2.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08ea0f606808354eb8f2dfaac095963cb25d9d28e27edcc375d7b30ab01abbf6"}, - {file = "lxml-5.2.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75a9632f1d4f698b2e6e2e1ada40e71f369b15d69baddb8968dcc8e683839b18"}, - {file = "lxml-5.2.2-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:74da9f97daec6928567b48c90ea2c82a106b2d500f397eeb8941e47d30b1ca85"}, - {file = "lxml-5.2.2-cp312-cp312-manylinux_2_28_ppc64le.whl", hash = "sha256:0969e92af09c5687d769731e3f39ed62427cc72176cebb54b7a9d52cc4fa3b73"}, - {file = "lxml-5.2.2-cp312-cp312-manylinux_2_28_s390x.whl", hash = "sha256:9164361769b6ca7769079f4d426a41df6164879f7f3568be9086e15baca61466"}, - {file = "lxml-5.2.2-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:d26a618ae1766279f2660aca0081b2220aca6bd1aa06b2cf73f07383faf48927"}, - {file = "lxml-5.2.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ab67ed772c584b7ef2379797bf14b82df9aa5f7438c5b9a09624dd834c1c1aaf"}, - {file = "lxml-5.2.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:3d1e35572a56941b32c239774d7e9ad724074d37f90c7a7d499ab98761bd80cf"}, - {file = "lxml-5.2.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:8268cbcd48c5375f46e000adb1390572c98879eb4f77910c6053d25cc3ac2c67"}, - {file = "lxml-5.2.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e282aedd63c639c07c3857097fc0e236f984ceb4089a8b284da1c526491e3f3d"}, - {file = "lxml-5.2.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6dfdc2bfe69e9adf0df4915949c22a25b39d175d599bf98e7ddf620a13678585"}, - {file = "lxml-5.2.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4aefd911793b5d2d7a921233a54c90329bf3d4a6817dc465f12ffdfe4fc7b8fe"}, - {file = "lxml-5.2.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:8b8df03a9e995b6211dafa63b32f9d405881518ff1ddd775db4e7b98fb545e1c"}, - {file = "lxml-5.2.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f11ae142f3a322d44513de1018b50f474f8f736bc3cd91d969f464b5bfef8836"}, - {file = "lxml-5.2.2-cp312-cp312-win32.whl", hash = "sha256:16a8326e51fcdffc886294c1e70b11ddccec836516a343f9ed0f82aac043c24a"}, - {file = "lxml-5.2.2-cp312-cp312-win_amd64.whl", hash = "sha256:bbc4b80af581e18568ff07f6395c02114d05f4865c2812a1f02f2eaecf0bfd48"}, - {file = "lxml-5.2.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:e3d9d13603410b72787579769469af730c38f2f25505573a5888a94b62b920f8"}, - {file = "lxml-5.2.2-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:38b67afb0a06b8575948641c1d6d68e41b83a3abeae2ca9eed2ac59892b36706"}, - {file = "lxml-5.2.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c689d0d5381f56de7bd6966a4541bff6e08bf8d3871bbd89a0c6ab18aa699573"}, - {file = "lxml-5.2.2-cp36-cp36m-manylinux_2_28_x86_64.whl", hash = "sha256:cf2a978c795b54c539f47964ec05e35c05bd045db5ca1e8366988c7f2fe6b3ce"}, - {file = "lxml-5.2.2-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:739e36ef7412b2bd940f75b278749106e6d025e40027c0b94a17ef7968d55d56"}, - {file = "lxml-5.2.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:d8bbcd21769594dbba9c37d3c819e2d5847656ca99c747ddb31ac1701d0c0ed9"}, - {file = "lxml-5.2.2-cp36-cp36m-musllinux_1_2_x86_64.whl", hash = "sha256:2304d3c93f2258ccf2cf7a6ba8c761d76ef84948d87bf9664e14d203da2cd264"}, - {file = "lxml-5.2.2-cp36-cp36m-win32.whl", hash = "sha256:02437fb7308386867c8b7b0e5bc4cd4b04548b1c5d089ffb8e7b31009b961dc3"}, - {file = "lxml-5.2.2-cp36-cp36m-win_amd64.whl", hash = "sha256:edcfa83e03370032a489430215c1e7783128808fd3e2e0a3225deee278585196"}, - {file = "lxml-5.2.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:28bf95177400066596cdbcfc933312493799382879da504633d16cf60bba735b"}, - {file = "lxml-5.2.2-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3a745cc98d504d5bd2c19b10c79c61c7c3df9222629f1b6210c0368177589fb8"}, - {file = "lxml-5.2.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b590b39ef90c6b22ec0be925b211298e810b4856909c8ca60d27ffbca6c12e6"}, - {file = "lxml-5.2.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b336b0416828022bfd5a2e3083e7f5ba54b96242159f83c7e3eebaec752f1716"}, - {file = "lxml-5.2.2-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:c2faf60c583af0d135e853c86ac2735ce178f0e338a3c7f9ae8f622fd2eb788c"}, - {file = "lxml-5.2.2-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:4bc6cb140a7a0ad1f7bc37e018d0ed690b7b6520ade518285dc3171f7a117905"}, - {file = "lxml-5.2.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7ff762670cada8e05b32bf1e4dc50b140790909caa8303cfddc4d702b71ea184"}, - {file = "lxml-5.2.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:57f0a0bbc9868e10ebe874e9f129d2917750adf008fe7b9c1598c0fbbfdde6a6"}, - {file = "lxml-5.2.2-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:a6d2092797b388342c1bc932077ad232f914351932353e2e8706851c870bca1f"}, - {file = "lxml-5.2.2-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:60499fe961b21264e17a471ec296dcbf4365fbea611bf9e303ab69db7159ce61"}, - {file = "lxml-5.2.2-cp37-cp37m-win32.whl", hash = "sha256:d9b342c76003c6b9336a80efcc766748a333573abf9350f4094ee46b006ec18f"}, - {file = "lxml-5.2.2-cp37-cp37m-win_amd64.whl", hash = "sha256:b16db2770517b8799c79aa80f4053cd6f8b716f21f8aca962725a9565ce3ee40"}, - {file = "lxml-5.2.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7ed07b3062b055d7a7f9d6557a251cc655eed0b3152b76de619516621c56f5d3"}, - {file = "lxml-5.2.2-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f60fdd125d85bf9c279ffb8e94c78c51b3b6a37711464e1f5f31078b45002421"}, - {file = "lxml-5.2.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8a7e24cb69ee5f32e003f50e016d5fde438010c1022c96738b04fc2423e61706"}, - {file = "lxml-5.2.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:23cfafd56887eaed93d07bc4547abd5e09d837a002b791e9767765492a75883f"}, - {file = "lxml-5.2.2-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:19b4e485cd07b7d83e3fe3b72132e7df70bfac22b14fe4bf7a23822c3a35bff5"}, - {file = "lxml-5.2.2-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:7ce7ad8abebe737ad6143d9d3bf94b88b93365ea30a5b81f6877ec9c0dee0a48"}, - {file = "lxml-5.2.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:e49b052b768bb74f58c7dda4e0bdf7b79d43a9204ca584ffe1fb48a6f3c84c66"}, - {file = "lxml-5.2.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d14a0d029a4e176795cef99c056d58067c06195e0c7e2dbb293bf95c08f772a3"}, - {file = "lxml-5.2.2-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:be49ad33819d7dcc28a309b86d4ed98e1a65f3075c6acd3cd4fe32103235222b"}, - {file = "lxml-5.2.2-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:a6d17e0370d2516d5bb9062c7b4cb731cff921fc875644c3d751ad857ba9c5b1"}, - {file = "lxml-5.2.2-cp38-cp38-win32.whl", hash = "sha256:5b8c041b6265e08eac8a724b74b655404070b636a8dd6d7a13c3adc07882ef30"}, - {file = "lxml-5.2.2-cp38-cp38-win_amd64.whl", hash = "sha256:f61efaf4bed1cc0860e567d2ecb2363974d414f7f1f124b1df368bbf183453a6"}, - {file = "lxml-5.2.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:fb91819461b1b56d06fa4bcf86617fac795f6a99d12239fb0c68dbeba41a0a30"}, - {file = "lxml-5.2.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d4ed0c7cbecde7194cd3228c044e86bf73e30a23505af852857c09c24e77ec5d"}, - {file = "lxml-5.2.2-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:54401c77a63cc7d6dc4b4e173bb484f28a5607f3df71484709fe037c92d4f0ed"}, - {file = "lxml-5.2.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:625e3ef310e7fa3a761d48ca7ea1f9d8718a32b1542e727d584d82f4453d5eeb"}, - {file = "lxml-5.2.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:519895c99c815a1a24a926d5b60627ce5ea48e9f639a5cd328bda0515ea0f10c"}, - {file = "lxml-5.2.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c7079d5eb1c1315a858bbf180000757db8ad904a89476653232db835c3114001"}, - {file = "lxml-5.2.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:343ab62e9ca78094f2306aefed67dcfad61c4683f87eee48ff2fd74902447726"}, - {file = "lxml-5.2.2-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:cd9e78285da6c9ba2d5c769628f43ef66d96ac3085e59b10ad4f3707980710d3"}, - {file = "lxml-5.2.2-cp39-cp39-manylinux_2_28_ppc64le.whl", hash = "sha256:546cf886f6242dff9ec206331209db9c8e1643ae642dea5fdbecae2453cb50fd"}, - {file = "lxml-5.2.2-cp39-cp39-manylinux_2_28_s390x.whl", hash = "sha256:02f6a8eb6512fdc2fd4ca10a49c341c4e109aa6e9448cc4859af5b949622715a"}, - {file = "lxml-5.2.2-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:339ee4a4704bc724757cd5dd9dc8cf4d00980f5d3e6e06d5847c1b594ace68ab"}, - {file = "lxml-5.2.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0a028b61a2e357ace98b1615fc03f76eb517cc028993964fe08ad514b1e8892d"}, - {file = "lxml-5.2.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:f90e552ecbad426eab352e7b2933091f2be77115bb16f09f78404861c8322981"}, - {file = "lxml-5.2.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:d83e2d94b69bf31ead2fa45f0acdef0757fa0458a129734f59f67f3d2eb7ef32"}, - {file = "lxml-5.2.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a02d3c48f9bb1e10c7788d92c0c7db6f2002d024ab6e74d6f45ae33e3d0288a3"}, - {file = "lxml-5.2.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:6d68ce8e7b2075390e8ac1e1d3a99e8b6372c694bbe612632606d1d546794207"}, - {file = "lxml-5.2.2-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:453d037e09a5176d92ec0fd282e934ed26d806331a8b70ab431a81e2fbabf56d"}, - {file = "lxml-5.2.2-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:3b019d4ee84b683342af793b56bb35034bd749e4cbdd3d33f7d1107790f8c472"}, - {file = "lxml-5.2.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:cb3942960f0beb9f46e2a71a3aca220d1ca32feb5a398656be934320804c0df9"}, - {file = "lxml-5.2.2-cp39-cp39-win32.whl", hash = "sha256:ac6540c9fff6e3813d29d0403ee7a81897f1d8ecc09a8ff84d2eea70ede1cdbf"}, - {file = "lxml-5.2.2-cp39-cp39-win_amd64.whl", hash = "sha256:610b5c77428a50269f38a534057444c249976433f40f53e3b47e68349cca1425"}, - {file = "lxml-5.2.2-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:b537bd04d7ccd7c6350cdaaaad911f6312cbd61e6e6045542f781c7f8b2e99d2"}, - {file = "lxml-5.2.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4820c02195d6dfb7b8508ff276752f6b2ff8b64ae5d13ebe02e7667e035000b9"}, - {file = "lxml-5.2.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2a09f6184f17a80897172863a655467da2b11151ec98ba8d7af89f17bf63dae"}, - {file = "lxml-5.2.2-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:76acba4c66c47d27c8365e7c10b3d8016a7da83d3191d053a58382311a8bf4e1"}, - {file = "lxml-5.2.2-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:b128092c927eaf485928cec0c28f6b8bead277e28acf56800e972aa2c2abd7a2"}, - {file = "lxml-5.2.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ae791f6bd43305aade8c0e22f816b34f3b72b6c820477aab4d18473a37e8090b"}, - {file = "lxml-5.2.2-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a2f6a1bc2460e643785a2cde17293bd7a8f990884b822f7bca47bee0a82fc66b"}, - {file = "lxml-5.2.2-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e8d351ff44c1638cb6e980623d517abd9f580d2e53bfcd18d8941c052a5a009"}, - {file = "lxml-5.2.2-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bec4bd9133420c5c52d562469c754f27c5c9e36ee06abc169612c959bd7dbb07"}, - {file = "lxml-5.2.2-pp37-pypy37_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:55ce6b6d803890bd3cc89975fca9de1dff39729b43b73cb15ddd933b8bc20484"}, - {file = "lxml-5.2.2-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:8ab6a358d1286498d80fe67bd3d69fcbc7d1359b45b41e74c4a26964ca99c3f8"}, - {file = "lxml-5.2.2-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:06668e39e1f3c065349c51ac27ae430719d7806c026fec462e5693b08b95696b"}, - {file = "lxml-5.2.2-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:9cd5323344d8ebb9fb5e96da5de5ad4ebab993bbf51674259dbe9d7a18049525"}, - {file = "lxml-5.2.2-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:89feb82ca055af0fe797a2323ec9043b26bc371365847dbe83c7fd2e2f181c34"}, - {file = "lxml-5.2.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e481bba1e11ba585fb06db666bfc23dbe181dbafc7b25776156120bf12e0d5a6"}, - {file = "lxml-5.2.2-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:9d6c6ea6a11ca0ff9cd0390b885984ed31157c168565702959c25e2191674a14"}, - {file = "lxml-5.2.2-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:3d98de734abee23e61f6b8c2e08a88453ada7d6486dc7cdc82922a03968928db"}, - {file = "lxml-5.2.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:69ab77a1373f1e7563e0fb5a29a8440367dec051da6c7405333699d07444f511"}, - {file = "lxml-5.2.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:34e17913c431f5ae01d8658dbf792fdc457073dcdfbb31dc0cc6ab256e664a8d"}, - {file = "lxml-5.2.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05f8757b03208c3f50097761be2dea0aba02e94f0dc7023ed73a7bb14ff11eb0"}, - {file = "lxml-5.2.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a520b4f9974b0a0a6ed73c2154de57cdfd0c8800f4f15ab2b73238ffed0b36e"}, - {file = "lxml-5.2.2-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:5e097646944b66207023bc3c634827de858aebc226d5d4d6d16f0b77566ea182"}, - {file = "lxml-5.2.2-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:b5e4ef22ff25bfd4ede5f8fb30f7b24446345f3e79d9b7455aef2836437bc38a"}, - {file = "lxml-5.2.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:ff69a9a0b4b17d78170c73abe2ab12084bdf1691550c5629ad1fe7849433f324"}, - {file = "lxml-5.2.2.tar.gz", hash = "sha256:bb2dc4898180bea79863d5487e5f9c7c34297414bad54bcd0f0852aee9cfdb87"}, + {file = "lxml-5.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:dd36439be765e2dde7660212b5275641edbc813e7b24668831a5c8ac91180656"}, + {file = "lxml-5.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ae5fe5c4b525aa82b8076c1a59d642c17b6e8739ecf852522c6321852178119d"}, + {file = "lxml-5.3.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:501d0d7e26b4d261fca8132854d845e4988097611ba2531408ec91cf3fd9d20a"}, + {file = "lxml-5.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb66442c2546446944437df74379e9cf9e9db353e61301d1a0e26482f43f0dd8"}, + {file = "lxml-5.3.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9e41506fec7a7f9405b14aa2d5c8abbb4dbbd09d88f9496958b6d00cb4d45330"}, + {file = "lxml-5.3.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f7d4a670107d75dfe5ad080bed6c341d18c4442f9378c9f58e5851e86eb79965"}, + {file = "lxml-5.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41ce1f1e2c7755abfc7e759dc34d7d05fd221723ff822947132dc934d122fe22"}, + {file = "lxml-5.3.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:44264ecae91b30e5633013fb66f6ddd05c006d3e0e884f75ce0b4755b3e3847b"}, + {file = "lxml-5.3.0-cp310-cp310-manylinux_2_28_ppc64le.whl", hash = "sha256:3c174dc350d3ec52deb77f2faf05c439331d6ed5e702fc247ccb4e6b62d884b7"}, + {file = "lxml-5.3.0-cp310-cp310-manylinux_2_28_s390x.whl", hash = "sha256:2dfab5fa6a28a0b60a20638dc48e6343c02ea9933e3279ccb132f555a62323d8"}, + {file = "lxml-5.3.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:b1c8c20847b9f34e98080da785bb2336ea982e7f913eed5809e5a3c872900f32"}, + {file = "lxml-5.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:2c86bf781b12ba417f64f3422cfc302523ac9cd1d8ae8c0f92a1c66e56ef2e86"}, + {file = "lxml-5.3.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:c162b216070f280fa7da844531169be0baf9ccb17263cf5a8bf876fcd3117fa5"}, + {file = "lxml-5.3.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:36aef61a1678cb778097b4a6eeae96a69875d51d1e8f4d4b491ab3cfb54b5a03"}, + {file = "lxml-5.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f65e5120863c2b266dbcc927b306c5b78e502c71edf3295dfcb9501ec96e5fc7"}, + {file = "lxml-5.3.0-cp310-cp310-win32.whl", hash = "sha256:ef0c1fe22171dd7c7c27147f2e9c3e86f8bdf473fed75f16b0c2e84a5030ce80"}, + {file = "lxml-5.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:052d99051e77a4f3e8482c65014cf6372e61b0a6f4fe9edb98503bb5364cfee3"}, + {file = "lxml-5.3.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:74bcb423462233bc5d6066e4e98b0264e7c1bed7541fff2f4e34fe6b21563c8b"}, + {file = "lxml-5.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a3d819eb6f9b8677f57f9664265d0a10dd6551d227afb4af2b9cd7bdc2ccbf18"}, + {file = "lxml-5.3.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5b8f5db71b28b8c404956ddf79575ea77aa8b1538e8b2ef9ec877945b3f46442"}, + {file = "lxml-5.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c3406b63232fc7e9b8783ab0b765d7c59e7c59ff96759d8ef9632fca27c7ee4"}, + {file = "lxml-5.3.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2ecdd78ab768f844c7a1d4a03595038c166b609f6395e25af9b0f3f26ae1230f"}, + {file = "lxml-5.3.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:168f2dfcfdedf611eb285efac1516c8454c8c99caf271dccda8943576b67552e"}, + {file = "lxml-5.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa617107a410245b8660028a7483b68e7914304a6d4882b5ff3d2d3eb5948d8c"}, + {file = "lxml-5.3.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:69959bd3167b993e6e710b99051265654133a98f20cec1d9b493b931942e9c16"}, + {file = "lxml-5.3.0-cp311-cp311-manylinux_2_28_ppc64le.whl", hash = "sha256:bd96517ef76c8654446fc3db9242d019a1bb5fe8b751ba414765d59f99210b79"}, + {file = "lxml-5.3.0-cp311-cp311-manylinux_2_28_s390x.whl", hash = "sha256:ab6dd83b970dc97c2d10bc71aa925b84788c7c05de30241b9e96f9b6d9ea3080"}, + {file = "lxml-5.3.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:eec1bb8cdbba2925bedc887bc0609a80e599c75b12d87ae42ac23fd199445654"}, + {file = "lxml-5.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6a7095eeec6f89111d03dabfe5883a1fd54da319c94e0fb104ee8f23616b572d"}, + {file = "lxml-5.3.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:6f651ebd0b21ec65dfca93aa629610a0dbc13dbc13554f19b0113da2e61a4763"}, + {file = "lxml-5.3.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:f422a209d2455c56849442ae42f25dbaaba1c6c3f501d58761c619c7836642ec"}, + {file = "lxml-5.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:62f7fdb0d1ed2065451f086519865b4c90aa19aed51081979ecd05a21eb4d1be"}, + {file = "lxml-5.3.0-cp311-cp311-win32.whl", hash = "sha256:c6379f35350b655fd817cd0d6cbeef7f265f3ae5fedb1caae2eb442bbeae9ab9"}, + {file = "lxml-5.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:9c52100e2c2dbb0649b90467935c4b0de5528833c76a35ea1a2691ec9f1ee7a1"}, + {file = "lxml-5.3.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:e99f5507401436fdcc85036a2e7dc2e28d962550afe1cbfc07c40e454256a859"}, + {file = "lxml-5.3.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:384aacddf2e5813a36495233b64cb96b1949da72bef933918ba5c84e06af8f0e"}, + {file = "lxml-5.3.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:874a216bf6afaf97c263b56371434e47e2c652d215788396f60477540298218f"}, + {file = "lxml-5.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:65ab5685d56914b9a2a34d67dd5488b83213d680b0c5d10b47f81da5a16b0b0e"}, + {file = "lxml-5.3.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aac0bbd3e8dd2d9c45ceb82249e8bdd3ac99131a32b4d35c8af3cc9db1657179"}, + {file = "lxml-5.3.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b369d3db3c22ed14c75ccd5af429086f166a19627e84a8fdade3f8f31426e52a"}, + {file = "lxml-5.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c24037349665434f375645fa9d1f5304800cec574d0310f618490c871fd902b3"}, + {file = "lxml-5.3.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:62d172f358f33a26d6b41b28c170c63886742f5b6772a42b59b4f0fa10526cb1"}, + {file = "lxml-5.3.0-cp312-cp312-manylinux_2_28_ppc64le.whl", hash = "sha256:c1f794c02903c2824fccce5b20c339a1a14b114e83b306ff11b597c5f71a1c8d"}, + {file = "lxml-5.3.0-cp312-cp312-manylinux_2_28_s390x.whl", hash = "sha256:5d6a6972b93c426ace71e0be9a6f4b2cfae9b1baed2eed2006076a746692288c"}, + {file = "lxml-5.3.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:3879cc6ce938ff4eb4900d901ed63555c778731a96365e53fadb36437a131a99"}, + {file = "lxml-5.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:74068c601baff6ff021c70f0935b0c7bc528baa8ea210c202e03757c68c5a4ff"}, + {file = "lxml-5.3.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:ecd4ad8453ac17bc7ba3868371bffb46f628161ad0eefbd0a855d2c8c32dd81a"}, + {file = "lxml-5.3.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:7e2f58095acc211eb9d8b5771bf04df9ff37d6b87618d1cbf85f92399c98dae8"}, + {file = "lxml-5.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e63601ad5cd8f860aa99d109889b5ac34de571c7ee902d6812d5d9ddcc77fa7d"}, + {file = "lxml-5.3.0-cp312-cp312-win32.whl", hash = "sha256:17e8d968d04a37c50ad9c456a286b525d78c4a1c15dd53aa46c1d8e06bf6fa30"}, + {file = "lxml-5.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:c1a69e58a6bb2de65902051d57fde951febad631a20a64572677a1052690482f"}, + {file = "lxml-5.3.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8c72e9563347c7395910de6a3100a4840a75a6f60e05af5e58566868d5eb2d6a"}, + {file = "lxml-5.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e92ce66cd919d18d14b3856906a61d3f6b6a8500e0794142338da644260595cd"}, + {file = "lxml-5.3.0-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d04f064bebdfef9240478f7a779e8c5dc32b8b7b0b2fc6a62e39b928d428e51"}, + {file = "lxml-5.3.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c2fb570d7823c2bbaf8b419ba6e5662137f8166e364a8b2b91051a1fb40ab8b"}, + {file = "lxml-5.3.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0c120f43553ec759f8de1fee2f4794452b0946773299d44c36bfe18e83caf002"}, + {file = "lxml-5.3.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:562e7494778a69086f0312ec9689f6b6ac1c6b65670ed7d0267e49f57ffa08c4"}, + {file = "lxml-5.3.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:423b121f7e6fa514ba0c7918e56955a1d4470ed35faa03e3d9f0e3baa4c7e492"}, + {file = "lxml-5.3.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:c00f323cc00576df6165cc9d21a4c21285fa6b9989c5c39830c3903dc4303ef3"}, + {file = "lxml-5.3.0-cp313-cp313-manylinux_2_28_ppc64le.whl", hash = "sha256:1fdc9fae8dd4c763e8a31e7630afef517eab9f5d5d31a278df087f307bf601f4"}, + {file = "lxml-5.3.0-cp313-cp313-manylinux_2_28_s390x.whl", hash = "sha256:658f2aa69d31e09699705949b5fc4719cbecbd4a97f9656a232e7d6c7be1a367"}, + {file = "lxml-5.3.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:1473427aff3d66a3fa2199004c3e601e6c4500ab86696edffdbc84954c72d832"}, + {file = "lxml-5.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a87de7dd873bf9a792bf1e58b1c3887b9264036629a5bf2d2e6579fe8e73edff"}, + {file = "lxml-5.3.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:0d7b36afa46c97875303a94e8f3ad932bf78bace9e18e603f2085b652422edcd"}, + {file = "lxml-5.3.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:cf120cce539453ae086eacc0130a324e7026113510efa83ab42ef3fcfccac7fb"}, + {file = "lxml-5.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:df5c7333167b9674aa8ae1d4008fa4bc17a313cc490b2cca27838bbdcc6bb15b"}, + {file = "lxml-5.3.0-cp313-cp313-win32.whl", hash = "sha256:c802e1c2ed9f0c06a65bc4ed0189d000ada8049312cfeab6ca635e39c9608957"}, + {file = "lxml-5.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:406246b96d552e0503e17a1006fd27edac678b3fcc9f1be71a2f94b4ff61528d"}, + {file = "lxml-5.3.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:8f0de2d390af441fe8b2c12626d103540b5d850d585b18fcada58d972b74a74e"}, + {file = "lxml-5.3.0-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1afe0a8c353746e610bd9031a630a95bcfb1a720684c3f2b36c4710a0a96528f"}, + {file = "lxml-5.3.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56b9861a71575f5795bde89256e7467ece3d339c9b43141dbdd54544566b3b94"}, + {file = "lxml-5.3.0-cp36-cp36m-manylinux_2_28_x86_64.whl", hash = "sha256:9fb81d2824dff4f2e297a276297e9031f46d2682cafc484f49de182aa5e5df99"}, + {file = "lxml-5.3.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:2c226a06ecb8cdef28845ae976da407917542c5e6e75dcac7cc33eb04aaeb237"}, + {file = "lxml-5.3.0-cp36-cp36m-musllinux_1_2_x86_64.whl", hash = "sha256:7d3d1ca42870cdb6d0d29939630dbe48fa511c203724820fc0fd507b2fb46577"}, + {file = "lxml-5.3.0-cp36-cp36m-win32.whl", hash = "sha256:094cb601ba9f55296774c2d57ad68730daa0b13dc260e1f941b4d13678239e70"}, + {file = "lxml-5.3.0-cp36-cp36m-win_amd64.whl", hash = "sha256:eafa2c8658f4e560b098fe9fc54539f86528651f61849b22111a9b107d18910c"}, + {file = "lxml-5.3.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cb83f8a875b3d9b458cada4f880fa498646874ba4011dc974e071a0a84a1b033"}, + {file = "lxml-5.3.0-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:25f1b69d41656b05885aa185f5fdf822cb01a586d1b32739633679699f220391"}, + {file = "lxml-5.3.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23e0553b8055600b3bf4a00b255ec5c92e1e4aebf8c2c09334f8368e8bd174d6"}, + {file = "lxml-5.3.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ada35dd21dc6c039259596b358caab6b13f4db4d4a7f8665764d616daf9cc1d"}, + {file = "lxml-5.3.0-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:81b4e48da4c69313192d8c8d4311e5d818b8be1afe68ee20f6385d0e96fc9512"}, + {file = "lxml-5.3.0-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:2bc9fd5ca4729af796f9f59cd8ff160fe06a474da40aca03fcc79655ddee1a8b"}, + {file = "lxml-5.3.0-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:07da23d7ee08577760f0a71d67a861019103e4812c87e2fab26b039054594cc5"}, + {file = "lxml-5.3.0-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:ea2e2f6f801696ad7de8aec061044d6c8c0dd4037608c7cab38a9a4d316bfb11"}, + {file = "lxml-5.3.0-cp37-cp37m-win32.whl", hash = "sha256:5c54afdcbb0182d06836cc3d1be921e540be3ebdf8b8a51ee3ef987537455f84"}, + {file = "lxml-5.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:f2901429da1e645ce548bf9171784c0f74f0718c3f6150ce166be39e4dd66c3e"}, + {file = "lxml-5.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c56a1d43b2f9ee4786e4658c7903f05da35b923fb53c11025712562d5cc02753"}, + {file = "lxml-5.3.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ee8c39582d2652dcd516d1b879451500f8db3fe3607ce45d7c5957ab2596040"}, + {file = "lxml-5.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fdf3a3059611f7585a78ee10399a15566356116a4288380921a4b598d807a22"}, + {file = "lxml-5.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:146173654d79eb1fc97498b4280c1d3e1e5d58c398fa530905c9ea50ea849b22"}, + {file = "lxml-5.3.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:0a7056921edbdd7560746f4221dca89bb7a3fe457d3d74267995253f46343f15"}, + {file = "lxml-5.3.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:9e4b47ac0f5e749cfc618efdf4726269441014ae1d5583e047b452a32e221920"}, + {file = "lxml-5.3.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:f914c03e6a31deb632e2daa881fe198461f4d06e57ac3d0e05bbcab8eae01945"}, + {file = "lxml-5.3.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:213261f168c5e1d9b7535a67e68b1f59f92398dd17a56d934550837143f79c42"}, + {file = "lxml-5.3.0-cp38-cp38-win32.whl", hash = "sha256:218c1b2e17a710e363855594230f44060e2025b05c80d1f0661258142b2add2e"}, + {file = "lxml-5.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:315f9542011b2c4e1d280e4a20ddcca1761993dda3afc7a73b01235f8641e903"}, + {file = "lxml-5.3.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:1ffc23010330c2ab67fac02781df60998ca8fe759e8efde6f8b756a20599c5de"}, + {file = "lxml-5.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2b3778cb38212f52fac9fe913017deea2fdf4eb1a4f8e4cfc6b009a13a6d3fcc"}, + {file = "lxml-5.3.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4b0c7a688944891086ba192e21c5229dea54382f4836a209ff8d0a660fac06be"}, + {file = "lxml-5.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:747a3d3e98e24597981ca0be0fd922aebd471fa99d0043a3842d00cdcad7ad6a"}, + {file = "lxml-5.3.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:86a6b24b19eaebc448dc56b87c4865527855145d851f9fc3891673ff97950540"}, + {file = "lxml-5.3.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b11a5d918a6216e521c715b02749240fb07ae5a1fefd4b7bf12f833bc8b4fe70"}, + {file = "lxml-5.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68b87753c784d6acb8a25b05cb526c3406913c9d988d51f80adecc2b0775d6aa"}, + {file = "lxml-5.3.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:109fa6fede314cc50eed29e6e56c540075e63d922455346f11e4d7a036d2b8cf"}, + {file = "lxml-5.3.0-cp39-cp39-manylinux_2_28_ppc64le.whl", hash = "sha256:02ced472497b8362c8e902ade23e3300479f4f43e45f4105c85ef43b8db85229"}, + {file = "lxml-5.3.0-cp39-cp39-manylinux_2_28_s390x.whl", hash = "sha256:6b038cc86b285e4f9fea2ba5ee76e89f21ed1ea898e287dc277a25884f3a7dfe"}, + {file = "lxml-5.3.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:7437237c6a66b7ca341e868cda48be24b8701862757426852c9b3186de1da8a2"}, + {file = "lxml-5.3.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:7f41026c1d64043a36fda21d64c5026762d53a77043e73e94b71f0521939cc71"}, + {file = "lxml-5.3.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:482c2f67761868f0108b1743098640fbb2a28a8e15bf3f47ada9fa59d9fe08c3"}, + {file = "lxml-5.3.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:1483fd3358963cc5c1c9b122c80606a3a79ee0875bcac0204149fa09d6ff2727"}, + {file = "lxml-5.3.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2dec2d1130a9cda5b904696cec33b2cfb451304ba9081eeda7f90f724097300a"}, + {file = "lxml-5.3.0-cp39-cp39-win32.whl", hash = "sha256:a0eabd0a81625049c5df745209dc7fcef6e2aea7793e5f003ba363610aa0a3ff"}, + {file = "lxml-5.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:89e043f1d9d341c52bf2af6d02e6adde62e0a46e6755d5eb60dc6e4f0b8aeca2"}, + {file = "lxml-5.3.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7b1cd427cb0d5f7393c31b7496419da594fe600e6fdc4b105a54f82405e6626c"}, + {file = "lxml-5.3.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:51806cfe0279e06ed8500ce19479d757db42a30fd509940b1701be9c86a5ff9a"}, + {file = "lxml-5.3.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee70d08fd60c9565ba8190f41a46a54096afa0eeb8f76bd66f2c25d3b1b83005"}, + {file = "lxml-5.3.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:8dc2c0395bea8254d8daebc76dcf8eb3a95ec2a46fa6fae5eaccee366bfe02ce"}, + {file = "lxml-5.3.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:6ba0d3dcac281aad8a0e5b14c7ed6f9fa89c8612b47939fc94f80b16e2e9bc83"}, + {file = "lxml-5.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:6e91cf736959057f7aac7adfc83481e03615a8e8dd5758aa1d95ea69e8931dba"}, + {file = "lxml-5.3.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:94d6c3782907b5e40e21cadf94b13b0842ac421192f26b84c45f13f3c9d5dc27"}, + {file = "lxml-5.3.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c300306673aa0f3ed5ed9372b21867690a17dba38c68c44b287437c362ce486b"}, + {file = "lxml-5.3.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78d9b952e07aed35fe2e1a7ad26e929595412db48535921c5013edc8aa4a35ce"}, + {file = "lxml-5.3.0-pp37-pypy37_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:01220dca0d066d1349bd6a1726856a78f7929f3878f7e2ee83c296c69495309e"}, + {file = "lxml-5.3.0-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:2d9b8d9177afaef80c53c0a9e30fa252ff3036fb1c6494d427c066a4ce6a282f"}, + {file = "lxml-5.3.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:20094fc3f21ea0a8669dc4c61ed7fa8263bd37d97d93b90f28fc613371e7a875"}, + {file = "lxml-5.3.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ace2c2326a319a0bb8a8b0e5b570c764962e95818de9f259ce814ee666603f19"}, + {file = "lxml-5.3.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:92e67a0be1639c251d21e35fe74df6bcc40cba445c2cda7c4a967656733249e2"}, + {file = "lxml-5.3.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd5350b55f9fecddc51385463a4f67a5da829bc741e38cf689f38ec9023f54ab"}, + {file = "lxml-5.3.0-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:4c1fefd7e3d00921c44dc9ca80a775af49698bbfd92ea84498e56acffd4c5469"}, + {file = "lxml-5.3.0-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:71a8dd38fbd2f2319136d4ae855a7078c69c9a38ae06e0c17c73fd70fc6caad8"}, + {file = "lxml-5.3.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:97acf1e1fd66ab53dacd2c35b319d7e548380c2e9e8c54525c6e76d21b1ae3b1"}, + {file = "lxml-5.3.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:68934b242c51eb02907c5b81d138cb977b2129a0a75a8f8b60b01cb8586c7b21"}, + {file = "lxml-5.3.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b710bc2b8292966b23a6a0121f7a6c51d45d2347edcc75f016ac123b8054d3f2"}, + {file = "lxml-5.3.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18feb4b93302091b1541221196a2155aa296c363fd233814fa11e181adebc52f"}, + {file = "lxml-5.3.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:3eb44520c4724c2e1a57c0af33a379eee41792595023f367ba3952a2d96c2aab"}, + {file = "lxml-5.3.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:609251a0ca4770e5a8768ff902aa02bf636339c5a93f9349b48eb1f606f7f3e9"}, + {file = "lxml-5.3.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:516f491c834eb320d6c843156440fe7fc0d50b33e44387fcec5b02f0bc118a4c"}, + {file = "lxml-5.3.0.tar.gz", hash = "sha256:4e109ca30d1edec1ac60cdbe341905dc3b8f55b16855e03a54aaf59e51ec8c6f"}, ] [package.extras] @@ -4578,7 +4574,7 @@ cssselect = ["cssselect (>=0.7)"] html-clean = ["lxml-html-clean"] html5 = ["html5lib"] htmlsoup = ["BeautifulSoup4"] -source = ["Cython (>=3.0.10)"] +source = ["Cython (>=3.0.11)"] [[package]] name = "mako" From 4db64a3eb5cd3f2cd2bd2026dd5b05191f4d0292 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 23 Aug 2024 12:29:20 +0100 Subject: [PATCH 013/188] build(deps-dev): bump pre-commit from 3.7.1 to 3.8.0 (#719) * build(deps-dev): bump pre-commit from 3.7.1 to 3.8.0 Bumps [pre-commit](https://github.com/pre-commit/pre-commit) from 3.7.1 to 3.8.0. - [Release notes](https://github.com/pre-commit/pre-commit/releases) - [Changelog](https://github.com/pre-commit/pre-commit/blob/main/CHANGELOG.md) - [Commits](https://github.com/pre-commit/pre-commit/compare/v3.7.1...v3.8.0) --- updated-dependencies: - dependency-name: pre-commit dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * fix: update lock --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Szymon Szyszkowski <69353402+project-defiant@users.noreply.github.com> Co-authored-by: David Ochoa Co-authored-by: David Ochoa --- poetry.lock | 11 +++++------ pyproject.toml | 2 +- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/poetry.lock b/poetry.lock index fe8793398..46d0cf279 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. [[package]] name = "aiodns" @@ -6052,13 +6052,13 @@ tests = ["pytest (>=5.4.1)", "pytest-cov (>=2.8.1)", "pytest-mypy (>=0.8.0)", "p [[package]] name = "pre-commit" -version = "3.7.1" +version = "3.8.0" description = "A framework for managing and maintaining multi-language pre-commit hooks." optional = false python-versions = ">=3.9" files = [ - {file = "pre_commit-3.7.1-py2.py3-none-any.whl", hash = "sha256:fae36fd1d7ad7d6a5a1c0b0d5adb2ed1a3bda5a21bf6c3e5372073d7a11cd4c5"}, - {file = "pre_commit-3.7.1.tar.gz", hash = "sha256:8ca3ad567bc78a4972a3f1a477e94a79d4597e8140a6e0b651c5e33899c3654a"}, + {file = "pre_commit-3.8.0-py2.py3-none-any.whl", hash = "sha256:9a90a53bf82fdd8778d58085faf8d83df56e40dfe18f45b19446e26bf1b3a63f"}, + {file = "pre_commit-3.8.0.tar.gz", hash = "sha256:8bb6494d4a20423842e198980c9ecf9f96607a07ea29549e180eef9ae80fe7af"}, ] [package.dependencies] @@ -6879,7 +6879,6 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, @@ -8688,4 +8687,4 @@ test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", [metadata] lock-version = "2.0" python-versions = "^3.10, <3.11" -content-hash = "e88c1cae723d94139b4ed7d1308004a63d6c4a87076bc393638d977974661797" +content-hash = "04bc80689794ab41c58a2daf8f7841a36b6f34bed3b74069b6e0e8c30f32d24b" diff --git a/pyproject.toml b/pyproject.toml index 3050f7b6e..3dbf9f8ff 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,7 +36,7 @@ skops = ">=0.9,<0.11" google-cloud-secret-manager = "^2.20.0" [tool.poetry.dev-dependencies] -pre-commit = "^3.7.0" +pre-commit = "^3.8.0" mypy = "^1.11" pep8-naming = "^0.14.1" interrogate = "^1.7.0" From dc8c9dc63376bdc353771d7158060494a8a62434 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Irene=20L=C3=B3pez=20Santiago?= <45119610+ireneisdoomed@users.noreply.github.com> Date: Tue, 27 Aug 2024 15:59:23 +0100 Subject: [PATCH 014/188] feat(variant_index): changes for a successful run (#735) * feat: update variant sources for variant idx and drop rsid mapping * chore: remove variant_index step from etl dag * chore: move gnomad annotation from dev to static assets * chore: change gentropy docker image * feat(convert_to_vcf): write data partitioned * feat: add vcf merging step * chore: assert merge is succesful * fix: remove non canonical variants from vcfs * chore: pass vcf types to merging rule * fix: match vep parser order of columns to variant index schema * fix: ditch `assign_variant_id` in favour of `hash_long_variant_ids` * chore: update `test_as_vcf_df_without_variant_id` * fix: correct test mock data * chore: pre-commit auto fixes [...] * chore: merge from dev * chore: pre-commit auto fixes [...] --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Szymon Szyszkowski <69353402+project-defiant@users.noreply.github.com> --- config/datasets/ot_gcp.yaml | 2 +- src/airflow/dags/configs/dag.yaml | 4 - src/airflow/dags/configs/variant_sources.yaml | 6 +- src/airflow/dags/variant_index.py | 93 ++++++++++++++++--- src/gentropy/dataset/variant_index.py | 23 ----- src/gentropy/datasource/ensembl/vep_parser.py | 2 +- .../datasource/open_targets/variants.py | 19 ++-- src/gentropy/variant_index.py | 13 ++- .../datasource/open_targets/test_variants.py | 17 +--- 9 files changed, 106 insertions(+), 73 deletions(-) diff --git a/config/datasets/ot_gcp.yaml b/config/datasets/ot_gcp.yaml index c61863b86..d169f7c08 100644 --- a/config/datasets/ot_gcp.yaml +++ b/config/datasets/ot_gcp.yaml @@ -55,7 +55,7 @@ finngen_finemapping_results_path: ${datasets.inputs}/Finngen_susie_finemapping_r finngen_finemapping_summaries_path: ${datasets.inputs}/Finngen_susie_finemapping_r10/Finngen_susie_credset_summary_r10.tsv # Dev output datasets -gnomad_variants: ${datasets.outputs}/gnomad_variants +gnomad_variants: ${datasets.static_assets}/gnomad_variants study_locus: ${datasets.outputs}/study_locus summary_statistics: ${datasets.outputs}/summary_statistics study_locus_overlap: ${datasets.outputs}/study_locus_overlap diff --git a/src/airflow/dags/configs/dag.yaml b/src/airflow/dags/configs/dag.yaml index b6d343343..24d185c1e 100644 --- a/src/airflow/dags/configs/dag.yaml +++ b/src/airflow/dags/configs/dag.yaml @@ -1,21 +1,17 @@ - id: "ot_gene_index" -- id: "ot_variant_index" - id: "ot_variant_to_gene" prerequisites: - - "ot_variant_index" - "ot_gene_index" - id: "ot_colocalisation_ecaviar" - id: "ot_colocalisation_coloc" - id: "ot_locus_to_gene_train" prerequisites: - - "ot_variant_index" - "ot_variant_to_gene" - "ot_colocalisation_ecaviar" - "ot_colocalisation_coloc" - id: "ot_locus_to_gene_predict" prerequisites: - "ot_locus_to_gene_train" - - "ot_variant_index" - "ot_variant_to_gene" - "ot_colocalisation_ecaviar" - "ot_colocalisation_coloc" diff --git a/src/airflow/dags/configs/variant_sources.yaml b/src/airflow/dags/configs/variant_sources.yaml index e8914b8aa..233eb0ccf 100644 --- a/src/airflow/dags/configs/variant_sources.yaml +++ b/src/airflow/dags/configs/variant_sources.yaml @@ -1,12 +1,12 @@ sources_inclusion_list: - name: uniprot - location: gs://open-targets-pre-data-releases/24.06/input/evidence-files/uniprot.json.gz ## input + location: gs://open-targets-pre-data-releases/24.09/input/evidence-files/uniprot.json.gz ## input format: json - name: clinvar - location: gs://open-targets-pre-data-releases/24.06/input/evidence-files/eva.json.gz + location: gs://open-targets-pre-data-releases/24.09/input/evidence-files/eva.json.gz format: json - name: pharmgkb - location: gs://open-targets-pre-data-releases/24.06/input/pharmacogenomics-inputs/pharmacogenomics.json.gz + location: gs://open-targets-pre-data-releases/24.09/input/pharmacogenomics-inputs/pharmacogenomics.json.gz format: json - name: gentropy_credible_sets location: gs://genetics_etl_python_playground/releases/24.06/credible_set diff --git a/src/airflow/dags/variant_index.py b/src/airflow/dags/variant_index.py index eb102f277..9d0736632 100644 --- a/src/airflow/dags/variant_index.py +++ b/src/airflow/dags/variant_index.py @@ -8,6 +8,7 @@ from pathlib import Path from typing import Any +import pandas as pd from common_airflow import ( create_batch_job, create_cluster, @@ -31,14 +32,19 @@ PROJECT_ID = "open-targets-genetics-dev" REGION = "europe-west1" +GCS_BUCKET = "genetics_etl_python_playground" CONFIG_FILE_PATH = Path(__file__).parent / "configs" / "variant_sources.yaml" -GENTROPY_DOCKER_IMAGE = "europe-west1-docker.pkg.dev/open-targets-genetics-dev/gentropy-app/gentropy:il-3333" +GENTROPY_DOCKER_IMAGE = "europe-west1-docker.pkg.dev/open-targets-genetics-dev/gentropy-app/gentropy:il-variant-idx" # TODO: change to dev VEP_DOCKER_IMAGE = "europe-west1-docker.pkg.dev/open-targets-genetics-dev/gentropy-app/custom_ensembl_vep:dev" -VCF_DST_PATH = "gs://genetics_etl_python_playground/il-3333" -VEP_OUTPUT_BUCKET = "gs://genetics_etl_python_playground/il-3333/vep_output" -VEP_CACHE_BUCKET = "gs://genetics_etl_python_playground/vep/cache" -VARIANT_INDEX_BUCKET = "gs://genetics_etl_python_playground/il-3333/variant_index" -GNOMAD_ANNOTATION_PATH = "gs://genetics_etl_python_playground/output/python_etl/parquet/24.06/gnomad_variants" +VEP_CACHE_BUCKET = f"gs://{GCS_BUCKET}/vep/cache" + +RELEASE = "XX.XX" # This needs to be updated to the latest release + +VCF_DST_PATH = f"gs://{GCS_BUCKET}/{RELEASE}/variant_vcf" +VCF_MERGED_DST_PATH = f"{VCF_DST_PATH}/merged" +VEP_OUTPUT_BUCKET = f"gs://{GCS_BUCKET}/{RELEASE}/vep_output" +VARIANT_INDEX_BUCKET = f"gs://{GCS_BUCKET}/{RELEASE}/variant_index" +GNOMAD_ANNOTATION_PATH = f"gs://{GCS_BUCKET}/static_assets/gnomad_variants" # Internal parameters for the docker image: MOUNT_DIR = "/mnt/disks/share" @@ -67,7 +73,7 @@ def create_vcf(**kwargs: Any) -> None: commands = [ "-c", - rf"poetry run gentropy step=variant_to_vcf step.source_path=$SOURCE_PATH step.source_format=$SOURCE_FORMAT step.vcf_path={VCF_DST_PATH}/$SOURCE_NAME.vcf +step.session.extended_spark_conf={{spark.jars:https://storage.googleapis.com/hadoop-lib/gcs/gcs-connector-hadoop3-latest.jar}}", + rf"poetry run gentropy step=variant_to_vcf step.source_path=$SOURCE_PATH step.source_format=$SOURCE_FORMAT step.vcf_path={VCF_DST_PATH}/$SOURCE_NAME +step.session.extended_spark_conf={{spark.jars:https://storage.googleapis.com/hadoop-lib/gcs/gcs-connector-hadoop3-latest.jar}}", ] task = create_task_spec( GENTROPY_DOCKER_IMAGE, commands, options="-e HYDRA_FULL_ERROR=1" @@ -89,6 +95,59 @@ def create_vcf(**kwargs: Any) -> None: batch_task.execute(context=kwargs) +@task(task_id="merge_vcfs") +def merge_vcfs(chunk_size: int = 2000, **kwargs: Any) -> None: + """Task that merges the information from all the VCF files into a single one so that we only submit one VEP job. + + Args: + chunk_size (int): Partition size of the merged file. Defaults to 2000. + **kwargs (Any): Keyword arguments + """ + ti = kwargs["ti"] + input_vcfs = [ + f"gs://{GCS_BUCKET}/{listed_file}" + for listed_file in ti.xcom_pull( + task_ids="get_vcf_per_source", key="return_value" + ) + ] + merged_df = ( + pd.concat( + pd.read_csv( + file, + sep="\t", + dtype={ + "#CHROM": str, + "POS": int, + "ID": str, + "REF": str, + "ALT": str, + "QUAL": str, + "FILTER": str, + "INFO": str, + }, + ) + for file in input_vcfs + ) + .drop_duplicates(subset=["#CHROM", "POS", "REF", "ALT"]) + .sort_values(by=["#CHROM", "POS"]) + .reset_index(drop=True) + ) + # Partition the merged file into chunks of 2000 variants to run the VEP jobs in parallel + chunks = 0 + for i in range(0, len(merged_df), chunk_size): + merged_df[i : i + chunk_size].to_csv( + f"{VCF_MERGED_DST_PATH}/chunk_{i + 1}-{i + chunk_size}.vcf", + index=False, + header=True, + sep="\t", + ) + chunks += 1 + expected_chunks_count = len(merged_df) // chunk_size + 1 + assert ( + chunks == expected_chunks_count + ), f"Expected {expected_chunks_count} chunks but got {chunks} chunks" + + @dataclass class PathManager: """It is quite complicated to keep track of all the input/output buckets, the corresponding mounting points prefixes etc...""" @@ -147,7 +206,7 @@ def get_mount_config(self) -> list[dict[str, str]]: @task(task_id="vep_annotation") def vep_annotation(pm: PathManager, **kwargs: Any) -> None: - """Submit a Batch job to download cache for VEP. + """Submit a Batch job to annotate VCFs with a local VEP docker image. Args: pm (PathManager): The path manager with all the required path related information. @@ -166,7 +225,7 @@ def vep_annotation(pm: PathManager, **kwargs: Any) -> None: task_env = [ batch_v1.Environment( variables={ - "INPUT_FILE": f"{filename}.tsv", + "INPUT_FILE": f"{filename}.vcf", "OUTPUT_FILE": f"{filename}.json", } ) @@ -210,19 +269,27 @@ def vep_annotation(pm: PathManager, **kwargs: Any) -> None: **shared_dag_kwargs, ) as dag: pm = PathManager( - VCF_DST_PATH, + VCF_MERGED_DST_PATH, VEP_OUTPUT_BUCKET, VEP_CACHE_BUCKET, MOUNT_DIR, ) ( create_vcf() + >> GCSListObjectsOperator( + task_id="get_vcf_per_source", + bucket=GCS_BUCKET, + prefix=VCF_DST_PATH.replace(f"gs://{GCS_BUCKET}/", ""), + trigger_rule=TriggerRule.ALL_SUCCESS, + match_glob="**.csv", + ) + >> merge_vcfs() >> GCSListObjectsOperator( task_id="get_vep_todo_list", - bucket=pm.input_bucket, - prefix=pm.input_path, - match_glob="**vcf", + bucket=GCS_BUCKET, + prefix=VCF_MERGED_DST_PATH.replace(f"gs://{GCS_BUCKET}/", ""), trigger_rule=TriggerRule.ALL_SUCCESS, + match_glob="**.vcf", ) >> vep_annotation(pm) >> create_cluster( diff --git a/src/gentropy/dataset/variant_index.py b/src/gentropy/dataset/variant_index.py index fa110a2d4..1cc1eac1b 100644 --- a/src/gentropy/dataset/variant_index.py +++ b/src/gentropy/dataset/variant_index.py @@ -59,29 +59,6 @@ def get_schema(cls: type[VariantIndex]) -> StructType: """ return parse_spark_schema("variant_index.json") - @classmethod - def assign_variant_id( - cls: type[VariantIndex], - ) -> Column: - """Creates a column with the variant ID that will be used to index the variant index. - - This is to ensure that the variant ID is unique and not too long. - - Returns: - Column: Column with the variant ID containing the hash if the variant ID is longer than 100 characters - """ - return ( - f.when( - f.length(f.col("variantId")) >= 100, - f.concat( - f.lit("otvar_"), - f.xxhash64(f.col("variantId")).cast("string"), - ), - ) - .otherwise(f.col("variantId")) - .alias("variantId") - ) - @staticmethod def hash_long_variant_ids( variant_id: Column, chromosome: Column, position: Column, threshold: int = 100 diff --git a/src/gentropy/datasource/ensembl/vep_parser.py b/src/gentropy/datasource/ensembl/vep_parser.py index 9cde1c44b..2259ef34e 100644 --- a/src/gentropy/datasource/ensembl/vep_parser.py +++ b/src/gentropy/datasource/ensembl/vep_parser.py @@ -738,7 +738,6 @@ def process_vep_output( transcript.distance.alias("distance"), transcript.gene_id.alias("targetId"), transcript.impact.alias("impact"), - transcript.transcript_id.alias("transcriptId"), transcript.lof.cast(t.StringType()).alias( "lofteePrediction" ), @@ -746,6 +745,7 @@ def process_vep_output( transcript.lof.cast(t.FloatType()).alias( "polyphenPrediction" ), + transcript.transcript_id.alias("transcriptId"), ), ), ).alias("transcriptConsequences"), diff --git a/src/gentropy/datasource/open_targets/variants.py b/src/gentropy/datasource/open_targets/variants.py index a50cc04ae..03018438b 100644 --- a/src/gentropy/datasource/open_targets/variants.py +++ b/src/gentropy/datasource/open_targets/variants.py @@ -96,15 +96,6 @@ def as_vcf_df( col, create_empty_column_if_not_exists(col) ) - variant_df = cls.map_rsids_to_variant_ids(session, variant_df) - - variant_df = variant_df.withColumn( - "variantId", - f.when(f.col("variantId").isNull(), f.lit(".")).otherwise( - f.col("variantId") - ), - ) - return ( variant_df.filter(f.col("variantId").isNotNull()) .withColumn( @@ -135,6 +126,12 @@ def as_vcf_df( f.lit(".").alias("FILTER"), f.lit(".").alias("INFO"), ) - .filter(f.col("#CHROM") != ".") + .distinct() + .filter( + (f.col("#CHROM") != ".") + & (f.col("POS").isNotNull()) + & (f.col("REF").rlike("^[GCTA.]*$")) + & (f.col("ALT").rlike("^[GCTA.]*$")) + ) .orderBy(f.col("#CHROM").asc(), f.col("POS").asc()) - ).distinct() + ) diff --git a/src/gentropy/variant_index.py b/src/gentropy/variant_index.py index a3dbdbcda..f6d555f07 100644 --- a/src/gentropy/variant_index.py +++ b/src/gentropy/variant_index.py @@ -2,6 +2,8 @@ from __future__ import annotations +from pyspark.sql.functions import col + from gentropy.common.session import Session from gentropy.config import VariantIndexConfig from gentropy.dataset.variant_index import VariantIndex @@ -51,7 +53,12 @@ def __init__( variant_index = variant_index.add_annotation(annotations) ( - variant_index.df.withColumn("variantId", VariantIndex.assign_variant_id()) + variant_index.df.withColumn( + "variantId", + VariantIndex.hash_long_variant_ids( + col("variantId"), col("chromosome"), col("position") + ), + ) .write.partitionBy("chromosome") .mode(session.write_mode) .parquet(variant_index_path) @@ -77,8 +84,8 @@ def __init__( vcf_path (str): Output VCF file path. """ # Load - df = session.load_data(source_path, source_format).limit(100) + df = session.load_data(source_path, source_format) # Extract vcf_df = OpenTargetsVariant.as_vcf_df(session, df) # Write - vcf_df.toPandas().to_csv(vcf_path, sep="\t", index=False) + vcf_df.write.csv(vcf_path, sep="\t", header=True) diff --git a/tests/gentropy/datasource/open_targets/test_variants.py b/tests/gentropy/datasource/open_targets/test_variants.py index 9d2c56e73..247a9d81e 100644 --- a/tests/gentropy/datasource/open_targets/test_variants.py +++ b/tests/gentropy/datasource/open_targets/test_variants.py @@ -66,18 +66,7 @@ def test_as_vcf_df_without_variant_id( session, df_without_variant_id_df ).orderBy(*["#CHROM", "POS", "REF", "ALT"]) - vcf_cols = ["#CHROM", "POS", "ID", "REF", "ALT", "QUAL", "FILTER", "INFO"] - df_without_variant_id_expected_df = spark.createDataFrame( - [ - ("17", 7041768, "rs75493593", "G", "C", ".", ".", "."), - ("17", 7041768, "rs75493593", "G", "T", ".", ".", "."), - ], - vcf_cols, - ) - - assert ( - observed_df.collect() == df_without_variant_id_expected_df.collect() - ), "Unexpected VCF dataframe." + assert observed_df.count() == 0, "A variant ID should be present for VCF step." def test_as_vcf_df_without_rs_id( self: TestOpenTargetsVariant, @@ -85,13 +74,13 @@ def test_as_vcf_df_without_rs_id( session: Session, ) -> None: """Test the as_vcf_df method with a dataframe of variants without an annotated variantRsId.""" - df_without_rs_id_df = spark.createDataFrame([("1_2_x_y",)], ["variantId"]) + df_without_rs_id_df = spark.createDataFrame([("1_2_G_GA",)], ["variantId"]) observed_df = OpenTargetsVariant.as_vcf_df(session, df_without_rs_id_df) vcf_cols = ["#CHROM", "POS", "ID", "REF", "ALT", "QUAL", "FILTER", "INFO"] df_without_rs_id_expected_df = spark.createDataFrame( [ - ("1", 2, ".", "x", "y", ".", ".", "."), + ("1", 2, ".", "G", "GA", ".", ".", "."), ], vcf_cols, ) From 348b6f0804988449398d335b2201dccbe1b75c41 Mon Sep 17 00:00:00 2001 From: Szymon Szyszkowski <69353402+project-defiant@users.noreply.github.com> Date: Wed, 28 Aug 2024 11:18:03 +0200 Subject: [PATCH 015/188] fix: update cluster creation command (#739) Co-authored-by: Szymon Szyszkowski --- Makefile | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index f1caf887f..b83075558 100644 --- a/Makefile +++ b/Makefile @@ -38,18 +38,19 @@ build-documentation: ## Create local server with documentation create-dev-cluster: build ## Spin up a simple dataproc cluster with all dependencies for development purposes @echo "Creating Dataproc Dev Cluster" @gcloud config set project ${PROJECT_ID} - @gcloud dataproc clusters create "ot-genetics-dev-${CLEAN_VERSION_NO}" \ + @gcloud dataproc clusters create "ot-genetics-dev-${CLEAN_VERSION_NO}-$(USER)" \ --image-version 2.1 \ --region ${REGION} \ --master-machine-type n1-standard-16 \ --initialization-actions=gs://genetics_etl_python_playground/initialisation/${VERSION_NO}/install_dependencies_on_cluster.sh \ --metadata="PACKAGE=gs://genetics_etl_python_playground/initialisation/${VERSION_NO}/gentropy-${VERSION_NO}-py3-none-any.whl,CONFIGTAR=gs://genetics_etl_python_playground/initialisation/${VERSION_NO}/config.tar.gz" \ - --primary-worker-type n1-standard-8 \ + --secondary-worker-type spot \ --worker-machine-type n1-standard-4 \ --worker-boot-disk-size 500 \ - --autoscaling_policy=f"projects/${PROJECT_ID}/regions/${REGION}/autoscalingPolicies/eqtl-preprocess", \ + --autoscaling-policy="projects/${PROJECT_ID}/regions/${REGION}/autoscalingPolicies/otg-etl" \ --optional-components=JUPYTER \ - --enable-component-gateway + --enable-component-gateway \ + --max-idle=30m make update-dev-cluster: build ## Reinstalls the package on the dev-cluster @echo "Updating Dataproc Dev Cluster" From b6746fb17fcef46791d00dbb7de28ced52fedd66 Mon Sep 17 00:00:00 2001 From: Szymon Szyszkowski <69353402+project-defiant@users.noreply.github.com> Date: Wed, 28 Aug 2024 16:18:14 +0200 Subject: [PATCH 016/188] fix: revert recursiveFileLookup to False (#738) Co-authored-by: Szymon Szyszkowski --- src/gentropy/common/session.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/gentropy/common/session.py b/src/gentropy/common/session.py index f618cd722..297903629 100644 --- a/src/gentropy/common/session.py +++ b/src/gentropy/common/session.py @@ -134,11 +134,13 @@ def load_data( ) -> DataFrame: """Generic function to read a file or folder into a Spark dataframe. + The `recursiveFileLookup` flag when set to True will skip all partition columns, but read files from all subdirectories. + Args: path (str | list[str]): path to the dataset format (str): file format. Defaults to parquet. schema (StructType | str | None): Schema to use when reading the data. - **kwargs (bool | float | int | str | None): Additional arguments to pass to spark.read.load. `recursiveFileLookup` and `mergeSchema` are set to True by default. + **kwargs (bool | float | int | str | None): Additional arguments to pass to spark.read.load. `mergeSchema` is set to True, `recursiveFileLookup` is set to False by default. Returns: DataFrame: Dataframe @@ -147,7 +149,7 @@ def load_data( if schema is None: kwargs["inferSchema"] = kwargs.get("inferSchema", True) kwargs["mergeSchema"] = kwargs.get("mergeSchema", True) - kwargs["recursiveFileLookup"] = kwargs.get("recursiveFileLookup", True) + kwargs["recursiveFileLookup"] = kwargs.get("recursiveFileLookup", False) return self.spark.read.load(path, format=format, schema=schema, **kwargs) From cf1ec24577580243f513aadd42676b863e2ffe8f Mon Sep 17 00:00:00 2001 From: Szymon Szyszkowski <69353402+project-defiant@users.noreply.github.com> Date: Thu, 29 Aug 2024 13:55:35 +0200 Subject: [PATCH 017/188] feat: Finngen r11 ingestion (#733) * feat: finngen r11 study index paths * feat: simplification of finngen susie finemapping ingestion * feat: efos in finngne study index * docs: updated docstring * fix: pass spark_session not gentropy session to step * fix: read uploaded file requires file:/// * fix: parallelize csv from url * fix: typo in docstring * chore: pre-commit auto fixes [...] --------- Co-authored-by: Szymon Szyszkowski Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Daniel Suveges --- config/datasets/ot_gcp.yaml | 3 - .../ot_finngen_finemapping_ingestion.yaml | 7 - src/airflow/dags/finngen_harmonisation.py | 79 ------- src/airflow/dags/finngen_preprocess.py | 76 ------- src/gentropy/config.py | 41 ++-- .../datasource/finngen/finemapping.py | 203 ++++++++++++++++-- .../datasource/finngen/study_index.py | 80 +++++-- src/gentropy/finngen_finemapping_ingestion.py | 17 +- src/gentropy/finngen_studies.py | 45 +++- .../data_samples/finngen_R9_AB1_EBV.SUSIE.snp | 90 ++++++++ .../finngen_R9_AB1_EBV.SUSIE.snp.bgz | Bin 0 -> 35105 bytes .../finngen_credset_summary_sample.tsv.bgz | Bin 0 -> 1338 bytes .../finngen/test_finngen_finemapping.py | 29 ++- .../finngen/test_finngen_study_index.py | 73 +++++++ 14 files changed, 518 insertions(+), 225 deletions(-) delete mode 100644 config/step/ot_finngen_finemapping_ingestion.yaml delete mode 100644 src/airflow/dags/finngen_harmonisation.py delete mode 100644 src/airflow/dags/finngen_preprocess.py create mode 100644 tests/gentropy/data_samples/finngen_R9_AB1_EBV.SUSIE.snp create mode 100644 tests/gentropy/data_samples/finngen_R9_AB1_EBV.SUSIE.snp.bgz create mode 100644 tests/gentropy/data_samples/finngen_credset_summary_sample.tsv.bgz diff --git a/config/datasets/ot_gcp.yaml b/config/datasets/ot_gcp.yaml index d169f7c08..a8d8886bb 100644 --- a/config/datasets/ot_gcp.yaml +++ b/config/datasets/ot_gcp.yaml @@ -51,9 +51,6 @@ thurman: ${datasets.static_assets}/thurman2012/genomewideCorrs_above0.7_promoter target_index: ${datasets.static_assets}/targets # OTP 23.12 data gene_interactions: ${datasets.static_assets}/interaction # OTP 23.12 data -finngen_finemapping_results_path: ${datasets.inputs}/Finngen_susie_finemapping_r10/full -finngen_finemapping_summaries_path: ${datasets.inputs}/Finngen_susie_finemapping_r10/Finngen_susie_credset_summary_r10.tsv - # Dev output datasets gnomad_variants: ${datasets.static_assets}/gnomad_variants study_locus: ${datasets.outputs}/study_locus diff --git a/config/step/ot_finngen_finemapping_ingestion.yaml b/config/step/ot_finngen_finemapping_ingestion.yaml deleted file mode 100644 index 46aa497fa..000000000 --- a/config/step/ot_finngen_finemapping_ingestion.yaml +++ /dev/null @@ -1,7 +0,0 @@ -defaults: - - finngen_finemapping_ingestion - -finngen_finemapping_results_path: ${datasets.finngen_finemapping_results_path} -finngen_finemapping_summaries_path: ${datasets.finngen_finemapping_summaries_path} -finngen_release_prefix: ${datasets.finngen_release_prefix} -finngen_finemapping_out: ${datasets.finngen_finemapping_out} diff --git a/src/airflow/dags/finngen_harmonisation.py b/src/airflow/dags/finngen_harmonisation.py deleted file mode 100644 index 18f81a376..000000000 --- a/src/airflow/dags/finngen_harmonisation.py +++ /dev/null @@ -1,79 +0,0 @@ -"""Airflow DAG for the harmonisation part of the pipeline.""" - -from __future__ import annotations - -import re -import time -from pathlib import Path -from typing import Any - -import common_airflow as common - -from airflow.decorators import task -from airflow.models.dag import DAG -from airflow.providers.google.cloud.operators.gcs import GCSListObjectsOperator - -CLUSTER_NAME = "otg-finngen-harmonisation" -AUTOSCALING = "gwascatalog-harmonisation" # same as GWAS Catalog harmonisation -SUMMARY_STATS_BUCKET_NAME = "finngen-public-data-r10" -RELEASEBUCKET = "gs://genetics_etl_python_playground/output/python_etl/parquet/XX.XX" -SUMSTATS_PARQUET = f"{RELEASEBUCKET}/summary_statistics/finngen" - -with DAG( - dag_id=Path(__file__).stem, - description="Open Targets Genetics — Finngen harmonisation", - default_args=common.shared_dag_args, - **common.shared_dag_kwargs, -): - # List raw harmonised files from GWAS Catalog - list_inputs = GCSListObjectsOperator( - task_id="list_raw_sumstats", - bucket=SUMMARY_STATS_BUCKET_NAME, - prefix="summary_stats", - match_glob="**/*.gz", - ) - - # Submit jobs to dataproc - @task(task_id="submit_jobs") - def submit_jobs(**kwargs: Any) -> None: - """Submit jobs to dataproc. - - Args: - **kwargs (Any): Keyword arguments. - """ - ti = kwargs["ti"] - todo = ti.xcom_pull(task_ids="list_raw_sumstats", key="return_value") - print("Number of jobs to submit: ", len(todo)) # noqa: T201 - for i in range(len(todo)): - # Not to exceed default quota 400 jobs per minute - if i > 0 and i % 399 == 0: - time.sleep(60) - input_path = todo[i] - match_result = re.search(r"summary_stats/finngen_(.*).gz", input_path) - if match_result: - study_id = match_result.group(1) - print("Submitting job for study: ", study_id) # noqa: T201 - common.submit_pyspark_job_no_operator( - cluster_name=CLUSTER_NAME, - step_id="finngen_sumstat_preprocess", - other_args=[ - f"step.raw_sumstats_path=gs://{SUMMARY_STATS_BUCKET_NAME}/{input_path}", - f"step.out_sumstats_path={SUMSTATS_PARQUET}/{study_id}.parquet", - ], - ) - - # list_inputs >> - ( - list_inputs - >> common.create_cluster( - CLUSTER_NAME, - autoscaling_policy=AUTOSCALING, - num_workers=8, - # num_preemptible_workers=8, - master_machine_type="n1-highmem-32", - worker_machine_type="n1-standard-2", - ) - >> common.install_dependencies(CLUSTER_NAME) - >> submit_jobs() - >> common.delete_cluster(CLUSTER_NAME) - ) diff --git a/src/airflow/dags/finngen_preprocess.py b/src/airflow/dags/finngen_preprocess.py deleted file mode 100644 index fbfab91e5..000000000 --- a/src/airflow/dags/finngen_preprocess.py +++ /dev/null @@ -1,76 +0,0 @@ -"""Airflow DAG for the Preprocess part of the pipeline.""" - -from __future__ import annotations - -from pathlib import Path - -import common_airflow as common - -from airflow.models.dag import DAG -from airflow.utils.task_group import TaskGroup -from airflow.utils.trigger_rule import TriggerRule - -CLUSTER_NAME = "otg-preprocess-finngen" -AUTOSCALING = "finngen-preprocess" - -# Get all parameters for the DAG: -FINNGEN_VERSION = "r10" -FINNGEN_BUCKET = f"gs://finngen_data/{FINNGEN_VERSION}" - -STUDY_INDEX = f"{FINNGEN_BUCKET}/study_index" -SUMMARY_STATISTICS = f"{FINNGEN_BUCKET}/harmonised_summary_statistics" -WINDOW_BASED_CLUMPED = f"{FINNGEN_BUCKET}/study_locus_datasets/finngen_window_clumped" -LD_CLUMPED = f"{FINNGEN_BUCKET}/study_locus_datasets/finngen_ld_clumped" -PICSED_CREDIBLE_SET = f"{FINNGEN_BUCKET}/credible_set_datasets/finngen_pics" - -FINNGEN_FINEMAPPING = ( - "gs://genetics_etl_python_playground/input/Finngen_susie_finemapping_r10/full" -) -FINNGEN_FM_SUMMARIES = "gs://genetics_etl_python_playground/input/Finngen_susie_finemapping_r10/Finngen_susie_credset_summary_r10.tsv" -FINNGEN_PREFIX = "FINNGEN_R10_" -FINNGEN_FM_OUT = f"{FINNGEN_BUCKET}/credible_set_datasets/finngen_susie" - -with DAG( - dag_id=Path(__file__).stem, - description="Open Targets Genetics — Finngen preprocess", - default_args=common.shared_dag_args, - **common.shared_dag_kwargs, -): - finngen_finemapping_ingestion = common.submit_step( - cluster_name=CLUSTER_NAME, - step_id="ot_finngen_finemapping_ingestion", - task_id="finngen_finemapping_ingestion", - other_args=[ - f"step.finngen_finemapping_out={FINNGEN_FM_OUT}", - f"step.finngen_release_prefix={FINNGEN_PREFIX}", - f"step.finngen_finemapping_results_path={FINNGEN_FINEMAPPING}", - f"step.finngen_finemapping_summaries_path={FINNGEN_FM_SUMMARIES}", - ], - # This allows to attempt running the task when above step fails do to failifexists - trigger_rule=TriggerRule.ALL_DONE, - ) - with TaskGroup( - group_id="finngen_summary_stats_preprocess" - ) as finngen_summary_stats_preprocess: - study_index = common.submit_step( - cluster_name=CLUSTER_NAME, - step_id="finngen_studies", - task_id="finngen_studies", - other_args=[ - f"step.finngen_study_index_out={STUDY_INDEX}", - ], - ) - - # Define order of steps: - (study_index) - ( - common.create_cluster( - CLUSTER_NAME, - autoscaling_policy=AUTOSCALING, - master_disk_size=2000, - num_workers=6, - ) - >> common.install_dependencies(CLUSTER_NAME) - >> [finngen_summary_stats_preprocess, finngen_finemapping_ingestion] - >> common.delete_cluster(CLUSTER_NAME) - ) diff --git a/src/gentropy/config.py b/src/gentropy/config.py index 90160e962..2d0cf5b8e 100644 --- a/src/gentropy/config.py +++ b/src/gentropy/config.py @@ -123,26 +123,38 @@ class EqtlCatalogueConfig(StepConfig): class FinngenStudiesConfig(StepConfig): """FinnGen study index step configuration.""" + session: Any = field( + default_factory=lambda: { + "start_hail": True, + } + ) finngen_study_index_out: str = MISSING + finngen_phenotype_table_url: str = "https://r11.finngen.fi/api/phenos" + finngen_release_prefix: str = "FINNGEN_R11_" + finngen_summary_stats_url_prefix: str = ( + "gs://finngen-public-data-r11/summary_stats/finngen_R11_" + ) + finngen_summary_stats_url_suffix: str = ".gz" + efo_curation_mapping_url: str = "https://raw.githubusercontent.com/opentargets/curation/24.09.1/mappings/disease/manual_string.tsv" _target_: str = "gentropy.finngen_studies.FinnGenStudiesStep" -@dataclass -class FinngenSumstatPreprocessConfig(StepConfig): - """FinnGen study index step configuration.""" - - raw_sumstats_path: str = MISSING - out_sumstats_path: str = MISSING - _target_: str = "gentropy.finngen_sumstat_preprocess.FinnGenSumstatPreprocessStep" - - @dataclass class FinngenFinemappingConfig(StepConfig): """FinnGen fine mapping ingestion step configuration.""" - finngen_finemapping_results_path: str = MISSING - finngen_finemapping_summaries_path: str = MISSING - finngen_release_prefix: str = MISSING + session: Any = field( + default_factory=lambda: { + "start_hail": True, + } + ) + finngen_susie_finemapping_snp_files: str = ( + "gs://finngen-public-data-r11/finemap/full/susie/*.snp.bgz" + ) + finngen_susie_finemapping_cs_summary_files: str = ( + "gs://finngen-public-data-r11/finemap/summary/*.cred.summary.tsv" + ) + finngen_release_prefix: str = "FINNGEN_R11_" finngen_finemapping_out: str = MISSING _target_: str = ( "gentropy.finngen_finemapping_ingestion.FinnGenFinemappingIngestionStep" @@ -510,11 +522,6 @@ def register_config() -> None: cs.store(group="step", name="ld_index", node=LDIndexConfig) cs.store(group="step", name="locus_to_gene", node=LocusToGeneConfig) cs.store(group="step", name="finngen_studies", node=FinngenStudiesConfig) - cs.store( - group="step", - name="finngen_sumstat_preprocess", - node=FinngenSumstatPreprocessConfig, - ) cs.store( group="step", diff --git a/src/gentropy/datasource/finngen/finemapping.py b/src/gentropy/datasource/finngen/finemapping.py index a31ddf511..340b1d3c9 100644 --- a/src/gentropy/datasource/finngen/finemapping.py +++ b/src/gentropy/datasource/finngen/finemapping.py @@ -5,6 +5,7 @@ from dataclasses import dataclass +import hail as hl import pyspark.sql.functions as f import pyspark.sql.types as t from pyspark.sql import SparkSession, Window @@ -21,7 +22,7 @@ class FinnGenFinemapping: Credible sets from SuSIE are extracted and transformed into StudyLocus objects: - - Study ID in the special format (e.g. FINNGEN_R10_*) + - Study ID in the special format (e.g. FINNGEN_R11*) - Credible set specific finemapping statistics (e.g. LogBayesFactors, Alphas/Posterior) - Additional credible set level BayesFactor filtering is applied (LBF > 2) - StudyLocusId is annotated for each credible set. @@ -109,34 +110,189 @@ class FinnGenFinemapping: ] ) + raw_hail_shema: hl.tstruct = hl.tstruct( + trait=hl.tstr, + region=hl.tstr, + v=hl.tstr, + rsid=hl.tstr, + chromosome=hl.tstr, + position=hl.tstr, + allele1=hl.tstr, + allele2=hl.tstr, + maf=hl.tstr, + beta=hl.tstr, + se=hl.tstr, + p=hl.tstr, + mean=hl.tstr, + sd=hl.tstr, + prob=hl.tstr, + cs=hl.tstr, + cs_specific_prob=hl.tfloat64, + low_purity=hl.tstr, + lead_r2=hl.tstr, + mean_99=hl.tstr, + sd_99=hl.tstr, + prob_99=hl.tstr, + cs_99=hl.tstr, + cs_specific_prob_99=hl.tstr, + low_purity_99=hl.tstr, + lead_r2_99=hl.tstr, + alpha1=hl.tfloat64, + alpha2=hl.tfloat64, + alpha3=hl.tfloat64, + alpha4=hl.tfloat64, + alpha5=hl.tfloat64, + alpha6=hl.tfloat64, + alpha7=hl.tfloat64, + alpha8=hl.tfloat64, + alpha9=hl.tfloat64, + alpha10=hl.tfloat64, + mean1=hl.tstr, + mean2=hl.tstr, + mean3=hl.tstr, + mean4=hl.tstr, + mean5=hl.tstr, + mean6=hl.tstr, + mean7=hl.tstr, + mean8=hl.tstr, + mean9=hl.tstr, + mean10=hl.tstr, + sd1=hl.tstr, + sd2=hl.tstr, + sd3=hl.tstr, + sd4=hl.tstr, + sd5=hl.tstr, + sd6=hl.tstr, + sd7=hl.tstr, + sd8=hl.tstr, + sd9=hl.tstr, + sd10=hl.tstr, + lbf_variable1=hl.tfloat64, + lbf_variable2=hl.tfloat64, + lbf_variable3=hl.tfloat64, + lbf_variable4=hl.tfloat64, + lbf_variable5=hl.tfloat64, + lbf_variable6=hl.tfloat64, + lbf_variable7=hl.tfloat64, + lbf_variable8=hl.tfloat64, + lbf_variable9=hl.tfloat64, + lbf_variable10=hl.tfloat64, + ) + + summary_hail_schema: hl.tstruct = hl.tstruct( + trait=hl.tstr, + region=hl.tstr, + cs=hl.tstr, + cs_log10bf=hl.tfloat64, + ) + + @staticmethod + def _infer_block_gzip_compression(paths: str | list[str]) -> bool: + """Naively infer compression type based on the file extension. + + Args: + paths (str | list[str]): File path(s). + + Returns: + bool: True if block gzipped, False otherwise. + """ + if isinstance(paths, str): + return paths.endswith(".bgz") + return all(path.endswith(".bgz") for path in paths) + @classmethod def from_finngen_susie_finemapping( cls: type[FinnGenFinemapping], spark: SparkSession, - finngen_finemapping_df: (str | list[str]), - finngen_finemapping_summaries: (str | list[str]), + finngen_susie_finemapping_snp_files: (str | list[str]), + finngen_susie_finemapping_cs_summary_files: (str | list[str]), finngen_release_prefix: str, credset_lbf_threshold: float = 0.8685889638065036, ) -> StudyLocus: """Process the SuSIE finemapping output for FinnGen studies. + The finngen_susue_finemapping_snp_files are files that contain variant summaries with credible set information with following shema: + - trait: phenotype + - region: region for which the fine-mapping was run. + - v, rsid: variant ids + - chromosome + - position + - allele1 + - allele2 + - maf: minor allele frequency + - beta: original marginal beta + - se: original se + - p: original p + - mean: posterior mean beta after fine-mapping + - sd: posterior standard deviation after fine-mapping. + - prob: posterior inclusion probability + - cs: credible set index within region + - lead_r2: r2 value to a lead variant (the one with maximum PIP) in a credible set + - alphax: posterior inclusion probability for the x-th single effect (x := 1..L where L is the number of single effects (causal variants) specified; default: L = 10). + - lbfx: log-Bayes Factor for each variable and single effect (i.e credible set). + - meanx: posterior mean for each variable and single effect (i.e credible set). + - sdx: posterior sd of mean for each variable and single effect (i.e credible set). + As for r11 finngen release these files are ingested from `https://console.cloud.google.com/storage/browser/finngen-public-data-r11/finemap/full/susie/` by + - *.snp.bgz + - *.snp.bgz.tbi + Each file contains index (.tbi) file that is required to read the block gzipped compressed snp file. These files needs to be + downloaded, transfromed from block gzipped to plain gzipped and then uploaded to the storage bucket, before they can be read by spark or read by hail directly as import table. + + The finngen_susie_finemapping_cs_summary_files are files that Contains credible set summaries from SuSiE fine-mapping for all genome-wide significant regions with following schema: + - trait: phenotype + - region: region for which the fine-mapping was run. + - cs: running number for independent credible sets in a region + - cs_log10bf: Log10 bayes factor of comparing the solution of this model (cs independent credible sets) to cs -1 credible sets + - cs_avg_r2: Average correlation R2 between variants in the credible set + - cs_min_r2: minimum r2 between variants in the credible set + - low_purity: boolean (TRUE,FALSE) indicator if the CS is low purity (low min r2) + - cs_size: how many snps does this credible set contain + - good_cs: boolean (TRUE,FALSE) indicator if this CS is considered reliable. IF this is FALSE then top variant reported for the CS will be chosen based on minimum p-value in the credible set, otherwise top variant is chosen by maximum PIP + - cs_id: + - v: top variant (chr:pos:ref:alt) + - p: top variant p-value + - beta: top variant beta + - sd: top variant standard deviation + - prob: overall PIP of the variant in the region + - cs_specific_prob: PIP of the variant in the current credible set (this and previous are typically almost identical) + - 0..n: configured annotation columns. Typical default most_severe,gene_most_severe giving consequence and gene of top variant + These files needs to be downloaded from the `https://console.cloud.google.com/storage/browser/finngen-public-data-r11/finemap/summary/` by *.cred.summary.tsv pattern, + Args: - spark (SparkSession): Spark session object. - finngen_finemapping_df (str | list[str]): SuSIE finemapping output filename(s). - finngen_finemapping_summaries (str | list[str]): filename of SuSIE finemapping summaries. + spark (SparkSession): SparkSession object. + finngen_susie_finemapping_snp_files (str | list[str]): SuSIE finemapping output filename(s). + finngen_susie_finemapping_cs_summary_files (str | list[str]): filename of SuSIE finemapping credible set summaries. finngen_release_prefix (str): FinnGen study prefix. credset_lbf_threshold (float, optional): Filter out credible sets below, Default 0.8685889638065036 == np.log10(np.exp(2)), this is threshold from publication. Returns: StudyLocus: Processed SuSIE finemapping output in StudyLocus format. """ + # NOTE: hail allows for importing block gzipped files, spark does not without external libraries. + # check https://github.com/projectglow/glow/blob/36bf6121fbc4ccc33a13b028deb87b63faeba7a9/core/src/main/scala/io/projectglow/vcf/VCFFileFormat.scala#L274 + # how it could be implemented with spark. + bgzip_compressed_snps = cls._infer_block_gzip_compression( + finngen_susie_finemapping_snp_files + ) + + # NOTE: fallback to spark read if not block gzipped file in the input + if bgzip_compressed_snps: + snps_df = hl.import_table( + finngen_susie_finemapping_snp_files, + delimiter="\t", + types=cls.raw_hail_shema, + ).to_spark() + else: + snps_df = ( + spark.read.schema(cls.raw_schema) + .option("delimiter", "\t") + .option("compression", "gzip") + .csv(finngen_susie_finemapping_snp_files, header=True) + ) + processed_finngen_finemapping_df = ( - spark.read.schema(cls.raw_schema) - .option("delimiter", "\t") - .option("compression", "gzip") - .csv(finngen_finemapping_df, header=True) # Drop rows which don't have proper position. - .filter(f.col("position").cast(t.IntegerType()).isNotNull()) + snps_df.filter(f.col("position").cast(t.IntegerType()).isNotNull()) # Drop non credible set SNPs: .filter(f.col("cs").cast(t.IntegerType()) > 0) .select( @@ -222,14 +378,31 @@ def from_finngen_susie_finemapping( ) ) + bgzip_compressed_cs_summaries = cls._infer_block_gzip_compression( + finngen_susie_finemapping_cs_summary_files + ) + + # NOTE: fallback to spark read if not block gzipped file in the input + # in case we want to use the raw files from the + # https://console.cloud.google.com/storage/browser/finngen-public-data-r11/finemap/full/susie/*.cred.gz + if bgzip_compressed_cs_summaries: + cs_summary_df = hl.import_table( + finngen_susie_finemapping_cs_summary_files, + delimiter="\t", + types=cls.summary_hail_schema, + ).to_spark() + else: + cs_summary_df = ( + spark.read.schema(cls.summary_schema) + .option("delimiter", "\t") + .csv(finngen_susie_finemapping_cs_summary_files, header=True) + ) + # drop credible sets where logbf > 2. Except when there's only one credible set in region: # 0.8685889638065036 corresponds to np.log10(np.exp(2)), to match the orginal threshold in publication. finngen_finemapping_summaries_df = ( # Read credible set level lbf, it is output as a different file which is not ideal. - spark.read.schema(cls.summary_schema) - .option("delimiter", "\t") - .csv(finngen_finemapping_summaries, header=True) - .select( + cs_summary_df.select( f.col("region"), f.col("trait"), f.col("cs").cast("integer").alias("credibleSetIndex"), diff --git a/src/gentropy/datasource/finngen/study_index.py b/src/gentropy/datasource/finngen/study_index.py index 872c25dee..71dce10d4 100644 --- a/src/gentropy/datasource/finngen/study_index.py +++ b/src/gentropy/datasource/finngen/study_index.py @@ -2,11 +2,13 @@ from __future__ import annotations +import re from urllib.request import urlopen import pyspark.sql.functions as f -from pyspark.sql import SparkSession +from pyspark.sql import DataFrame, SparkSession +from gentropy.config import FinngenStudiesConfig from gentropy.dataset.study_index import StudyIndex @@ -15,35 +17,89 @@ class FinnGenStudyIndex: The following information is aggregated/extracted: - - Study ID in the special format (e.g. FINNGEN_R10_*) + - Study ID in the special format (e.g. FINNGEN_R11_*) - Trait name (for example, Amoebiasis) - Number of cases and controls - Link to the summary statistics location + - EFO mapping from curated EFO mapping file Some fields are also populated as constants, such as study type and the initial sample size. """ - finngen_phenotype_table_url: str = "https://r10.finngen.fi/api/phenos" - finngen_release_prefix: str = "FINNGEN_R10" - finngen_summary_stats_url_prefix: str = ( - "gs://finngen-public-data-r10/summary_stats/finngen_R10_" - ) - finngen_summary_stats_url_suffix: str = ".gz" + @staticmethod + def join_efo_mapping( + study_index: StudyIndex, + efo_curation_mapping: DataFrame, + finngen_release_prefix: str = FinngenStudiesConfig().finngen_release_prefix, + ) -> StudyIndex: + """Add EFO mapping to the Finngen study index table. + + This function performs inner join on table of EFO mappings to the study index table by trait name. + All studies without EFO traits are dropped. The EFO mappings are then aggregated into lists per + studyId. + + Args: + study_index (StudyIndex): Study index table. + efo_curation_mapping (DataFrame): Dataframe with EFO mappings. + finngen_release_prefix (str): FinnGen release prefix. + + Returns: + StudyIndex: Study index table with added EFO mappings. + + Raises: + ValueError: when incorrect release prefix is provided. + """ + finngen_release_prefix_regex = re.compile(r"FINNGEN_(?PR\d+){1}_?") + finngen_release_prefix_match = finngen_release_prefix_regex.match( + finngen_release_prefix + ) + if not finngen_release_prefix_match: + raise ValueError( + f"Invalid FinnGen release prefix: {finngen_release_prefix}, use the format FINNGEN_R*_" + ) + finngen_release = finngen_release_prefix_match.group("release").upper() + + efo_mappings = ( + efo_curation_mapping.withColumn("STUDY", f.upper(f.col("STUDY"))) + .filter(f.col("STUDY").contains("FINNGEN")) + .filter(f.upper(f.col("STUDY")).contains(finngen_release)) + .select( + f.regexp_replace(f.col("SEMANTIC_TAG"), r"^.*/", "").alias( + "traitFromSourceMappedId" + ), + f.col("PROPERTY_VALUE").alias("traitFromSource"), + ) + ) + # NOTE: inner join to keep only the studies with EFO mappings + si_df = study_index.df.join(efo_mappings, on="traitFromSource", how="inner") + common_cols = [c for c in si_df.columns if c != "traitFromSourceMappedId"] + si_df = si_df.groupby(common_cols).agg( + f.collect_list("traitFromSourceMappedId").alias("traitFromSourceMappedIds") + ) + return StudyIndex(_df=si_df, _schema=StudyIndex.get_schema()) @classmethod def from_source( cls: type[FinnGenStudyIndex], spark: SparkSession, + finngen_phenotype_table_url: str = FinngenStudiesConfig().finngen_phenotype_table_url, + finngen_release_prefix: str = FinngenStudiesConfig().finngen_release_prefix, + finngen_summary_stats_url_prefix: str = FinngenStudiesConfig().finngen_summary_stats_url_prefix, + finngen_summary_stats_url_suffix: str = FinngenStudiesConfig().finngen_summary_stats_url_suffix, ) -> StudyIndex: """This function ingests study level metadata from FinnGen. Args: spark (SparkSession): Spark session object. + finngen_phenotype_table_url (str): URL to the FinnGen phenotype table. + finngen_release_prefix (str): FinnGen release prefix. + finngen_summary_stats_url_prefix (str): FinnGen summary stats URL prefix. + finngen_summary_stats_url_suffix (str): FinnGen summary stats URL suffix. Returns: StudyIndex: Parsed and annotated FinnGen study table. """ - json_data = urlopen(cls.finngen_phenotype_table_url).read().decode("utf-8") + json_data = urlopen(finngen_phenotype_table_url).read().decode("utf-8") rdd = spark.sparkContext.parallelize([json_data]) raw_df = spark.read.json(rdd) return StudyIndex( @@ -55,7 +111,7 @@ def from_source( (f.col("num_cases") + f.col("num_controls")) .cast("integer") .alias("nSamples"), - f.lit(cls.finngen_release_prefix).alias("projectId"), + f.lit(finngen_release_prefix).alias("projectId"), f.lit("gwas").alias("studyType"), f.lit(True).alias("hasSumstats"), f.lit("377,277 (210,870 females and 166,407 males)").alias( @@ -70,9 +126,9 @@ def from_source( # Cohort label is consistent with GWAS Catalog curation. f.array(f.lit("FinnGen")).alias("cohorts"), f.concat( - f.lit(cls.finngen_summary_stats_url_prefix), + f.lit(finngen_summary_stats_url_prefix), f.col("phenocode"), - f.lit(cls.finngen_summary_stats_url_suffix), + f.lit(finngen_summary_stats_url_suffix), ).alias("summarystatsLocation"), ).withColumn( "ldPopulationStructure", diff --git a/src/gentropy/finngen_finemapping_ingestion.py b/src/gentropy/finngen_finemapping_ingestion.py index d70316b5e..e85508023 100644 --- a/src/gentropy/finngen_finemapping_ingestion.py +++ b/src/gentropy/finngen_finemapping_ingestion.py @@ -6,6 +6,7 @@ from dataclasses import dataclass from gentropy.common.session import Session +from gentropy.config import FinngenFinemappingConfig from gentropy.datasource.finngen.finemapping import FinnGenFinemapping @@ -16,26 +17,26 @@ class FinnGenFinemappingIngestionStep(FinnGenFinemapping): def __init__( self, session: Session, - finngen_finemapping_results_path: str, - finngen_finemapping_summaries_path: str, - finngen_release_prefix: str, finngen_finemapping_out: str, + finngen_susie_finemapping_snp_files: str = FinngenFinemappingConfig().finngen_susie_finemapping_snp_files, + finngen_susie_finemapping_cs_summary_files: str = FinngenFinemappingConfig().finngen_susie_finemapping_cs_summary_files, + finngen_release_prefix: str = FinngenFinemappingConfig().finngen_release_prefix, ) -> None: """Run FinnGen finemapping ingestion step. Args: session (Session): Session object. - finngen_finemapping_results_path (str): Path to the FinnGen SuSIE finemapping results. - finngen_finemapping_summaries_path (str): FinnGen SuSIE summaries for CS filters(LBF>2). - finngen_release_prefix (str): Release prefix for FinnGen. finngen_finemapping_out (str): Output path for the finemapping results in StudyLocus format. + finngen_susie_finemapping_snp_files(str): Path to the FinnGen SuSIE finemapping results. + finngen_susie_finemapping_cs_summary_files (str): FinnGen SuSIE summaries for CS filters(LBF>2). + finngen_release_prefix (str): Release prefix for FinnGen. """ # Read finemapping outputs from the input paths. finngen_finemapping_df = FinnGenFinemapping.from_finngen_susie_finemapping( spark=session.spark, - finngen_finemapping_df=finngen_finemapping_results_path, - finngen_finemapping_summaries=finngen_finemapping_summaries_path, + finngen_susie_finemapping_snp_files=finngen_susie_finemapping_snp_files, + finngen_susie_finemapping_cs_summary_files=finngen_susie_finemapping_cs_summary_files, finngen_release_prefix=finngen_release_prefix, ) diff --git a/src/gentropy/finngen_studies.py b/src/gentropy/finngen_studies.py index c1869b736..706fa3d39 100644 --- a/src/gentropy/finngen_studies.py +++ b/src/gentropy/finngen_studies.py @@ -2,21 +2,56 @@ from __future__ import annotations +from urllib.request import urlopen + from gentropy.common.session import Session +from gentropy.config import FinngenStudiesConfig from gentropy.datasource.finngen.study_index import FinnGenStudyIndex class FinnGenStudiesStep: """FinnGen study index generation step.""" - def __init__(self, session: Session, finngen_study_index_out: str) -> None: + def __init__( + self, + session: Session, + finngen_study_index_out: str, + finngen_phenotype_table_url: str = FinngenStudiesConfig().finngen_phenotype_table_url, + finngen_release_prefix: str = FinngenStudiesConfig().finngen_release_prefix, + finngen_summary_stats_url_prefix: str = FinngenStudiesConfig().finngen_summary_stats_url_prefix, + finngen_summary_stats_url_suffix: str = FinngenStudiesConfig().finngen_summary_stats_url_suffix, + efo_curation_mapping_url: str = FinngenStudiesConfig().efo_curation_mapping_url, + ) -> None: """Run FinnGen study index generation step. Args: session (Session): Session object. finngen_study_index_out (str): Output FinnGen study index path. + finngen_phenotype_table_url (str): URL to the FinnGen phenotype table. + finngen_release_prefix (str): FinnGen release prefix. + finngen_summary_stats_url_prefix (str): FinnGen summary stats URL prefix. + finngen_summary_stats_url_suffix (str): FinnGen summary stats URL suffix. + efo_curation_mapping_url (str): URL to the EFO curation mapping file """ - # Fetch study index. - FinnGenStudyIndex.from_source(session.spark).df.write.mode( - session.write_mode - ).parquet(finngen_study_index_out) + study_index = FinnGenStudyIndex.from_source( + session.spark, + finngen_phenotype_table_url, + finngen_release_prefix, + finngen_summary_stats_url_prefix, + finngen_summary_stats_url_suffix, + ) + + # NOTE: hack to allow spark to read directly from the URL. + csv_data = urlopen(efo_curation_mapping_url).readlines() + csv_rows = [row.decode("utf8") for row in csv_data] + rdd = session.spark.sparkContext.parallelize(csv_rows) + efo_curation_mapping = session.spark.read.csv(rdd, header=True, sep="\t") + + study_index_with_efo = FinnGenStudyIndex.join_efo_mapping( + study_index, + efo_curation_mapping, + finngen_release_prefix, + ) + study_index_with_efo.df.write.mode(session.write_mode).parquet( + finngen_study_index_out + ) diff --git a/tests/gentropy/data_samples/finngen_R9_AB1_EBV.SUSIE.snp b/tests/gentropy/data_samples/finngen_R9_AB1_EBV.SUSIE.snp new file mode 100644 index 000000000..052399388 --- /dev/null +++ b/tests/gentropy/data_samples/finngen_R9_AB1_EBV.SUSIE.snp @@ -0,0 +1,90 @@ +trait region v rsid chromosome position allele1 allele2 maf beta se p mean sd prob cs cs_specific_prob low_purity lead_r2 mean_99 sd_99 prob_99 cs_99 cs_specific_prob_99 low_purity_99 lead_r2_99 alpha1 alpha2 alpha3 alpha4 alpha5 alpha6 alpha7 alpha8 alpha9 alpha10 mean1 mean2 mean3 mean4 mean5 mean6 mean7 mean8 mean9 mean10 sd1 sd2 sd3 sd4 sd5 sd6 sd7 sd8 sd9 sd10 lbf_variable1 lbf_variable2 lbf_variable3 lbf_variable4 lbf_variable5 lbf_variable6 lbf_variable7 lbf_variable8 lbf_variable9 lbf_variable10 +AB1_EBV chr6:1412516-4412516 6:2898066:G:T chr6_2898066_G_T chr6 2898066 G T 0.413765 0.192277 0.0298155 1.12676e-10 0.0329796138322914 0.0726322608911893 0.175343223649957 1 0.17509358936193 0 0.829216035769 0.0329796138322914 0.0726322608911893 0.175343223649957 1 0.17509358936193 0 0.829216035769 0.17509358936193 1.43993284524406e-05 3.60778561866872e-05 3.60648003884279e-05 3.60463349785855e-05 3.60278897859947e-05 3.60134896639449e-05 3.60060022461947e-05 3.60073664773458e-05 3.60187793017426e-05 0.0329766994994914 2.57161576786077e-07 3.31357531479788e-07 3.31581920897055e-07 3.31896507403073e-07 3.32212185390434e-07 3.32463786669888e-07 3.32605524722194e-07 3.32606528595316e-07 3.3244723805964e-07 0.0726311826236639 0.000126488575709164 0.000132387886331515 0.000132445000681512 0.000132525304968958 0.00013260558503703 0.000132668849958987 0.000132703150483526 0.000132700432413816 0.000132655610635964 18.5528693035569 -0.907607419163184 -0.195319530537169 -0.195641777295255 -0.196097663493068 -0.196552998035164 -0.196908246717843 -0.197092464695888 -0.197057687849098 -0.196774385008403 +AB1_EBV chr6:1412516-4412516 6:2898362:A:G chr6_2898362_A_G chr6 2898362 A G 0.443219 0.194397 0.0300071 9.27257e-11 0.0241861868176693 0.0638457314593366 0.128984802300941 1 0.128501831150163 0 0.468032488641 0.0241861868176693 0.0638457314593366 0.128984802300941 1 0.128501831150163 0 0.468032488641 0.128501831150163 4.5718571259867e-05 6.35067335181723e-05 6.35268204571264e-05 6.35549284123062e-05 6.35828685460672e-05 6.36046221942562e-05 6.36159391721562e-05 6.36139574209168e-05 6.35968920726836e-05 0.0241721312923613 2.13319750249321e-06 1.48299548305333e-06 1.48511049788324e-06 1.48808727845368e-06 1.49105919339296e-06 1.49338558929439e-06 1.49461138816016e-06 1.49442930680649e-06 1.49264906846324e-06 0.0638408505215491 0.000369070254874925 0.000245869167457302 0.000246119260779774 0.000246471397738596 0.000246822988506741 0.000247098297537043 0.000247243598398107 0.000247222620317828 0.000247012843232762 18.2434918306617 0.247715599243637 0.370147134295912 0.37050307766634 0.371001689249645 0.371497718747115 0.371884315841652 0.372085936546344 0.372051672829573 0.371749767645852 +AB1_EBV chr6:1412516-4412516 6:2898390:T:C chr6_2898390_T_C chr6 2898390 T C 0.0759868 0.063491 0.056021 0.25707 4.31960345414416e-05 0.00196441267952157 0.00075046097081477 -1 NA NA NA 4.31960345414416e-05 0.00196441267952157 0.00075046097081477 -1 NA NA NA 3.93838174054942e-10 8.09816386834445e-05 8.35285041586315e-05 8.358390349547e-05 8.36617711445916e-05 8.37390173140435e-05 8.37985885393119e-05 8.38283740382775e-05 8.38201989302556e-05 8.37690030828716e-05 2.21782417886126e-11 8.40987313953194e-06 4.32181362915771e-06 4.32953616230941e-06 4.34041881168691e-06 4.35126272348911e-06 4.35969622337004e-06 4.36402915653852e-06 4.36311925498564e-06 4.35626326213054e-06 1.56709910069891e-06 0.00104868422604798 0.000584775010658085 0.000585504251701282 0.000586531786129352 0.000587555924454652 0.000588353554304855 0.000588766075105534 0.00058868635013728 0.000588048090257165 -1.35977706153615 0.819433456645043 0.644189135136349 0.644891851168843 0.645879279429021 0.646858672726141 0.647614336265917 0.647993424205583 0.647892786053872 0.647248212724249 +AB1_EBV chr6:1412516-4412516 6:2898544:G:A chr6_2898544_G_A chr6 2898544 G A 0.000162658 -1.06485 1.263 0.399165 -0.000142307972554879 0.0174158850922084 0.000311180806728872 -1 NA NA NA -0.000142307972554879 0.0174158850922084 0.000311180806728872 -1 NA NA NA 3.3135651989527e-10 1.52689507421236e-05 3.70370646643062e-05 3.70247425398274e-05 3.70073367344066e-05 3.69899109471804e-05 3.69762228369255e-05 3.69689522016209e-05 3.69699116314651e-05 3.6980218847936e-05 -3.43352664772061e-10 -1.31256485573238e-05 -1.61079999492037e-05 -1.6119506258209e-05 -1.6135711269742e-05 -1.61518735029245e-05 -1.61645243654611e-05 -1.61712251774856e-05 -1.61703323205355e-05 -1.6160807801329e-05 2.95278730463148e-05 0.00574326803029291 0.00580365618281197 0.00580635729320344 0.00581016191629574 0.00581395759104792 0.00581692952751578 0.00581850423125729 0.00581829515872435 0.00581605883240119 -1.53252226561108 -0.848967586219725 -0.169079646723388 -0.169372702017943 -0.169786674000275 -0.17020115447332 -0.170526747831395 -0.170699687623306 -0.170676847074374 -0.17043169077503 +AB1_EBV chr6:1412516-4412516 6:2898634:A:G chr6_2898634_A_G chr6 2898634 A G 0.00990053 -0.0578846 0.155065 0.708929 3.36036046428797e-06 0.00177237672153217 0.00027298259335895 -1 NA NA NA 3.36036046428797e-06 0.00177237672153217 0.00027298259335895 -1 NA NA NA 2.45728985394081e-10 1.18511459605607e-05 3.26983764410425e-05 3.26831287402668e-05 3.26616014503584e-05 3.26400678296922e-05 3.26231695999668e-05 3.26142077268511e-05 3.26154135009179e-05 3.26281696699098e-05 -1.13844933399768e-11 1.98687927513989e-07 3.94710720255768e-07 3.94852414729217e-07 3.95050128659409e-07 3.95248276157307e-07 3.95406902746122e-07 3.95498447227266e-07 3.95504388775756e-07 3.95412642716477e-07 2.50933551331188e-06 0.000507185455541354 0.000599816995638025 0.00059999301326225 0.000600240532874255 0.00060048710965031 0.000600680011385158 0.000600782359514579 0.000600769347073544 0.000600625192283742 -1.83148791747326 -1.10236442097249 -0.29367337908761 -0.294100104367622 -0.294702736769016 -0.295305744621835 -0.295779068020591 -0.29603010504238 -0.295996246331836 -0.295638819167599 +AB1_EBV chr6:1412516-4412516 6:2898644:T:C chr6_2898644_T_C chr6 2898644 T C 0.118276 0.0617586 0.0458201 0.177706 0.000125511810900469 0.0034159962920344 0.00182190717924902 -1 NA NA NA 0.000125511810900469 0.0034159962920344 0.00182190717924902 -1 NA NA NA 4.99625110164512e-10 0.000374713090516501 0.000180149143340477 0.000180420738438503 0.000180804029116973 0.000181186404788696 0.000181484208566077 0.000181637677334594 0.000181606348560438 0.000181365328632569 2.78040407063015e-11 4.2635373091066e-05 1.02671877785273e-05 1.02939763337702e-05 1.03318266007943e-05 1.03696614548733e-05 1.03992204262546e-05 1.04145817520178e-05 1.04117330753764e-05 1.03882225837485e-05 1.60359727996177e-06 0.00235589933186244 0.000869385262846467 0.000870883775241722 0.000872998948126608 0.000875111357562359 0.000876761378346027 0.000877621128059248 0.000877468732854278 0.000876167427429173 -1.12185912318842 2.35137165177169 1.41278627628876 1.41433245064316 1.41651087554207 1.41868000920298 1.42036681690019 1.4212358006416 1.42106019484617 1.4196985525637 +AB1_EBV chr6:1412516-4412516 6:2898830:A:G chr6_2898830_A_G chr6 2898830 A G 0.000489288 -0.517711 0.741123 0.484834 -7.05337249388736e-05 0.00977642959411629 0.000301195614534455 -1 NA NA NA -7.05337249388736e-05 0.00977642959411629 0.000301195614534455 -1 NA NA NA 2.97764493146971e-10 1.43401826588032e-05 3.59071858643746e-05 3.58941405813954e-05 3.58757109199825e-05 3.58572625522856e-05 3.5842773584086e-05 3.58350787098728e-05 3.58360952711092e-05 3.584700788488e-05 -1.50380125009478e-10 -6.30023739860649e-06 -8.01001018220035e-06 -8.01556149521334e-06 -8.02337146677288e-06 -8.03115738911102e-06 -8.03725003519927e-06 -8.04047655572757e-06 -8.04004705958623e-06 -8.03546297633142e-06 1.53506655570811e-05 0.00312826418533324 0.00326989814640512 0.00327130492779428 0.00327328536956076 0.00327526049902121 0.00327680659330808 0.0032776256749774 0.00327751699993004 0.00327635402345175 -1.63941427810691 -0.911723416607235 -0.200061366819909 -0.20038504129272 -0.200842366638393 -0.2013002246487 -0.201659854812704 -0.201850852419317 -0.201825596480631 -0.201554733229527 +AB1_EBV chr6:1412516-4412516 6:2898852:T:C chr6_2898852_T_C chr6 2898852 T C 0.0024569 -0.0135518 0.324193 0.966657 -1.90309295779787e-05 0.00392799672003962 0.000283694464996431 -1 NA NA NA -1.90309295779787e-05 0.00392799672003962 0.000283694464996431 -1 NA NA NA 2.34840617180525e-10 1.28335944565251e-05 3.39111799170108e-05 3.38970129876025e-05 3.38770069576382e-05 3.3856987559621e-05 3.3841267667435e-05 3.38329164730246e-05 3.38340098433433e-05 3.38458341753585e-05 -2.09651795148505e-12 -1.63067161461712e-06 -2.16968783989117e-06 -2.17123876945852e-06 -2.17342034713896e-06 -2.17559432396506e-06 -2.17729339929383e-06 -2.17818917940871e-06 -2.17806108789175e-06 -2.17677091979559e-06 4.91110635777357e-06 0.0011870206897283 0.00132217297406661 0.001322651864879 0.00132332577835033 0.00132399749839758 0.00132452293088544 0.00132480093897028 0.00132476346769777 0.00132436755008538 -1.87681010143231 -1.02272268973018 -0.257254054557634 -0.257632210418853 -0.258166333679878 -0.25870094760849 -0.259120833215976 -0.259343929571735 -0.259314724759633 -0.258998910137287 +AB1_EBV chr6:1412516-4412516 6:2899158:A:C chr6_2899158_A_C chr6 2899158 A C 0.0385391 -0.0845606 0.0783558 0.280505 -1.06305709374504e-06 0.000890585228214677 0.000271879605582837 -1 NA NA NA -1.06305709374504e-06 0.000890585228214677 0.000271879605582837 -1 NA NA NA 3.89971767959007e-10 1.18853024263449e-05 3.25560426474199e-05 3.25408385949403e-05 3.25193782421875e-05 3.2497910462905e-05 3.24810583812967e-05 3.24721091331244e-05 3.24732843530629e-05 3.24859607402584e-05 -3.04216196484357e-11 -1.20773208732576e-07 -1.17467876151092e-07 -1.17558562261101e-07 -1.17689048444265e-07 -1.17819396074175e-07 -1.1792032044286e-07 -1.17971037817629e-07 -1.17957314252656e-07 -1.17869907949035e-07 2.17049329642282e-06 0.000257383025890685 0.000301128541857739 0.000301216604637751 0.000301340511307874 0.000301463928398313 0.000301560402178935 0.000301611424323912 0.000301604540952648 0.000301531828463628 -1.36964281405956 -1.09948644286867 -0.298035812202123 -0.298463235801365 -0.299066691853802 -0.299670559011449 -0.300144727480335 -0.300396577946486 -0.300363498356908 -0.300006815940666 +AB1_EBV chr6:1412516-4412516 6:2899177:C:T chr6_2899177_C_T chr6 2899177 C T 0.00149376 0.210318 0.395069 0.594478 1.1087286785856e-05 0.00454796513625276 0.000274177154775179 -1 NA NA NA 1.1087286785856e-05 0.00454796513625276 0.000274177154775179 -1 NA NA NA 2.67372961757553e-10 1.20357475324825e-05 3.28237946821668e-05 3.28087983026664e-05 3.27876271505826e-05 3.27664482961326e-05 3.27498248649085e-05 3.27410018608325e-05 3.27421727690368e-05 3.27546968813631e-05 5.32485539737573e-11 9.41836094528548e-07 1.26508166244442e-06 1.26597518122759e-06 1.26723377472505e-06 1.268490108755e-06 1.26947525977421e-06 1.26999997624907e-06 1.26993668153731e-06 1.26920479806084e-06 7.16606946438526e-06 0.0013219318002017 0.00153689317083669 0.00153736560443222 0.00153803021717581 0.00153869238437754 0.00153921027711139 0.00153948458599627 0.00153944848834106 0.00153905955204809 -1.74707261650093 -1.0869078068944 -0.289845105629987 -0.29026238810814 -0.29085163390118 -0.291441278779356 -0.291904213443387 -0.292149946326287 -0.292117295645589 -0.291768466701535 +AB1_EBV chr6:1412516-4412516 6:2899240:C:G chr6_2899240_C_G chr6 2899240 C G 0.0666566 -0.0741942 0.0595902 0.213105 -2.35036062319914e-06 0.00069660721485727 0.000277034829564426 -1 NA NA NA -2.35036062319914e-06 0.00069660721485727 0.000277034829564426 -1 NA NA NA 5.29478798776676e-10 1.2187859861444e-05 3.31625006174758e-05 3.31473453882313e-05 3.31259462375983e-05 3.31045519310923e-05 3.30877873025634e-05 3.30789417366297e-05 3.30802378336914e-05 3.30930509408374e-05 -3.97653759915523e-11 -1.80278726260054e-07 -2.7087361447815e-07 -2.70978473752448e-07 -2.71125234085206e-07 -2.71274104665597e-07 -2.71396403440742e-07 -2.71472184299646e-07 -2.71487842059741e-07 -2.71434274781564e-07 2.19598734227066e-06 0.000203049208153187 0.000235341514858765 0.000235413753819564 0.000235515338999907 0.000235616680522203 0.000235696231531389 0.000235738912010994 0.000235734565442074 0.000235676718860371 -1.06382403655627 -1.07434862642961 -0.279579067553628 -0.279996473824015 -0.28058600754497 -0.281175559326416 -0.281637577243573 -0.281881239704408 -0.281845169961472 -0.281491515746687 +AB1_EBV chr6:1412516-4412516 6:2899287:G:A chr6_2899287_G_A chr6 2899287 G A 0.000973672 0.986415 0.535162 0.065298 0.000205637050101746 0.0126007782851599 0.000497212565959249 -1 NA NA NA 0.000205637050101746 0.0126007782851599 0.000497212565959249 -1 NA NA NA 1.21738607486518e-09 3.6312730369849e-05 5.75982567906221e-05 5.76063163334434e-05 5.76176058640543e-05 5.76288416022498e-05 5.76376454787103e-05 5.76423596489159e-05 5.76418647761721e-05 5.76354359891861e-05 1.1680419720311e-09 2.75315948481859e-05 2.21712096584771e-05 2.21977200026116e-05 2.22350866021457e-05 2.22724309351061e-05 2.23017363944456e-05 2.23173233289229e-05 2.2315353047048e-05 2.22934272428311e-05 3.82248679592031e-05 0.00548996456467016 0.00399781093087686 0.00400131834219449 0.00400626261432472 0.00401120330696571 0.00401507928280891 0.00401713908431259 0.00401687504406763 0.00401397001993241 -0.231255883141779 0.0173793892737324 0.272493497554994 0.272673111793488 0.272925321253496 0.273176811812416 0.273374093684475 0.273479589676235 0.273467892984359 0.273322751959984 +AB1_EBV chr6:1412516-4412516 6:2899309:C:T chr6_2899309_C_T chr6 2899309 C T 0.00201975 -0.222409 0.355153 0.531161 -5.69774573358679e-05 0.00551697685252187 0.00034144100434419 -1 NA NA NA -5.69774573358679e-05 0.00551697685252187 0.00034144100434419 -1 NA NA NA 2.8470006636764e-10 1.81775181581979e-05 4.04492007225223e-05 4.04391980402028e-05 4.04250432914032e-05 4.0410845371332e-05 4.03996652542573e-05 4.03936943770997e-05 4.03944168669415e-05 4.04027431440506e-05 -6.20618320233197e-11 -5.67953826532967e-06 -6.39495570484508e-06 -6.39996837016291e-06 -6.40702208170669e-06 -6.41405240374765e-06 -6.41954772365366e-06 -6.42244442944812e-06 -6.42202579005806e-06 -6.41784050508404e-06 6.97085070922511e-06 0.00195382940556986 0.00182064312290325 0.00182165207819596 0.00182307294576125 0.00182449032343091 0.00182559954701346 0.00182618589315656 0.00182610460264635 0.00182526475596744 -1.68428093331602 -0.674603424930791 -0.0809519219688912 -0.0811595453629046 -0.0814533807374165 -0.0817481541047984 -0.0819803287269014 -0.0821044253045882 -0.0820896506889417 -0.0819171524572564 +AB1_EBV chr6:1412516-4412516 6:2899314:G:A chr6_2899314_G_A chr6 2899314 G A 0.00135432 -0.0619992 0.437623 0.887339 -2.43115488702986e-05 0.0052673935976394 0.000282464733497689 -1 NA NA NA -2.43115488702986e-05 0.0052673935976394 0.000282464733497689 -1 NA NA NA 2.3761345399726e-10 1.26853254402591e-05 3.37776612443965e-05 3.37629959130597e-05 3.37422920681702e-05 3.37215779436554e-05 3.3705316942895e-05 3.36966852850623e-05 3.36978302318604e-05 3.37100809368494e-05 -1.60019770592677e-11 -2.02382570470464e-06 -2.78067427247183e-06 -2.78220489258914e-06 -2.78436135757928e-06 -2.78651083235294e-06 -2.78819262804003e-06 -2.78908448212784e-06 -2.78896942551408e-06 -2.78770927294178e-06 6.74620903076303e-06 0.00157718883328219 0.00177478256886408 0.00177538443340019 0.00177623154657695 0.00177707582465066 0.001777736310445 0.00177808617502091 0.00177804004370986 0.00177754378462498 -1.86507195026131 -1.0343431411693 -0.261199131574553 -0.261593701171978 -0.262150849036905 -0.262708425310302 -0.26314623017427 -0.263378645288213 -0.263347779268952 -0.263017904506943 +AB1_EBV chr6:1412516-4412516 6:2899350:T:C chr6_2899350_T_C chr6 2899350 T C 0.0355572 -0.000819206 0.0800958 0.991839 7.32864915311251e-06 0.0010478896155351 0.000299176292555825 -1 NA NA NA 7.32864915311251e-06 0.0010478896155351 0.000299176292555825 -1 NA NA NA 2.35265856190137e-10 1.43878771095247e-05 3.56470650085047e-05 3.56345405861951e-05 3.56168563699093e-05 3.55991379878365e-05 3.55851838546828e-05 3.55776997009629e-05 3.55785165932683e-05 3.55887681763074e-05 -1.23441442927995e-12 6.88880582696483e-07 8.27671568238661e-07 8.28342793131389e-07 8.29288982520426e-07 8.30230315026994e-07 8.30961543885504e-07 8.31338047714907e-07 8.31262512882923e-07 8.30674041429651e-07 1.21663962920582e-06 0.000339449598993973 0.000349968305915352 0.000350124878355504 0.000350345466973101 0.000350565296261939 0.000350736897475 0.000350826848316304 0.000350812640677258 0.00035068013845627 -1.87500098307431 -0.908403004792035 -0.207331990118194 -0.207643699799531 -0.208083837774638 -0.208524929091143 -0.208872460501747 -0.209059089630061 -0.209039240525643 -0.208784747312844 +AB1_EBV chr6:1412516-4412516 6:2899430:C:T chr6_2899430_C_T chr6 2899430 C T 0.000430113 0.554905 0.722716 0.442603 5.99156548867282e-05 0.00925033668662987 0.000294727962604879 -1 NA NA NA 5.99156548867282e-05 0.00925033668662987 0.000294727962604879 -1 NA NA NA 3.11709759048175e-10 1.37827163651308e-05 3.51696672118842e-05 3.51561909498981e-05 3.51371577219624e-05 3.51181105109568e-05 3.51031565024186e-05 3.50952206845135e-05 3.50962811425252e-05 3.51075610491758e-05 1.67637675055622e-10 5.27800908307061e-06 6.81350052228466e-06 6.81818455565397e-06 6.82477697793433e-06 6.83135208246479e-06 6.83650155819372e-06 6.83923579239388e-06 6.83888830119467e-06 6.83503837586246e-06 1.57838568324735e-05 0.00290440207718282 0.00310074207519064 0.00310200196189509 0.00310377565859856 0.00310554461097979 0.00310692951042729 0.00310766375394084 0.00310756776217689 0.00310652822535614 -1.59364466532564 -0.951373619511788 -0.220814821468332 -0.221158376272983 -0.221643662025386 -0.222129386452423 -0.22251077260167 -0.222713159948769 -0.222686055239937 -0.22239831294462 +AB1_EBV chr6:1412516-4412516 6:2899448:A:G chr6_2899448_A_G chr6 2899448 A G 0.00026419 0.82525 0.994775 0.406774 0.000105775492105234 0.0134979386420686 0.00030746990816144 -1 NA NA NA 0.000105775492105234 0.0134979386420686 0.00030746990816144 -1 NA NA NA 3.28071092823362e-10 1.4927362759166e-05 3.66168144960311e-05 3.66041907262449e-05 3.65863580856004e-05 3.65685066985302e-05 3.65544866637575e-05 3.65470429953807e-05 3.65480326160835e-05 3.65586017273023e-05 2.63854267004587e-10 9.65701937130248e-06 1.19857159185444e-05 1.19941284407886e-05 1.20059722797453e-05 1.20177841993937e-05 1.20270313207347e-05 1.20319336962253e-05 1.20312923835425e-05 1.20243506406901e-05 2.30045101988549e-05 0.00440559444046247 0.00450385284642857 0.0045058870612298 0.00450875179867735 0.00451160956843206 0.00451384716570932 0.00451503315975474 0.00451487684830838 0.00451319510196308 -1.54248682940356 -0.871593033839509 -0.180491258267593 -0.180796373893336 -0.181227416082072 -0.18165895556074 -0.181997895073484 -0.182177838391413 -0.182153872189501 -0.18189833484089 +AB1_EBV chr6:1412516-4412516 6:2899745:G:A chr6_2899745_G_A chr6 2899745 G A 0.000117045 -1.36897 1.53632 0.372891 -0.000214482894300735 0.0226752228956154 0.000327842170640524 -1 NA NA NA -0.000214482894300735 0.0226752228956154 0.000327842170640524 -1 NA NA NA 3.4598841215619e-10 1.68188102648398e-05 3.8921837227274e-05 3.89108912347048e-05 3.88954221464638e-05 3.88799280587529e-05 3.88677527068588e-05 3.88612850417718e-05 3.88621420421056e-05 3.88713185192388e-05 -4.62627639678193e-10 -2.05989778749332e-05 -2.41715975197179e-05 -2.41900701729451e-05 -2.42160880585753e-05 -2.42420440626695e-05 -2.42623674480377e-05 -2.42731382353883e-05 -2.42717148466788e-05 -2.42564334541495e-05 3.76293905253514e-05 0.00778454364442189 0.00751610979510354 0.00752002589184257 0.00752554294920676 0.00753104868167867 0.00753536087793154 0.007537646547676 0.007537344158716 0.00753410079872939 -1.48931187709545 -0.752291070730094 -0.119443344210645 -0.119684916699199 -0.120026296017635 -0.120368223581343 -0.120636900301013 -0.120779606416229 -0.120760665282574 -0.120558169179215 +AB1_EBV chr6:1412516-4412516 6:2900248:C:A chr6_2900248_C_A chr6 2900248 C A 0.0666209 -0.0745332 0.0595208 0.210489 -2.40599263449429e-06 0.000696875971842839 0.0002773208531206 -1 NA NA NA -2.40599263449429e-06 0.000696875971842839 0.0002773208531206 -1 NA NA NA 5.34239928424041e-10 1.22100123955882e-05 3.31954458722522e-05 3.3180303528717e-05 3.3158922412406e-05 3.31375463876293e-05 3.31207967544259e-05 3.31119604398682e-05 3.31132583693554e-05 3.3126064771795e-05 -4.02961574085908e-11 -1.85072747193858e-07 -2.77214528631182e-07 -2.77323368982149e-07 -2.77475730133333e-07 -2.77630186771891e-07 -2.77756864285653e-07 -2.77834980447318e-07 -2.77850367011055e-07 -2.7779356488044e-07 2.21076556571287e-06 0.000203341460822337 0.000235408256271966 0.000235480799123452 0.000235582812396303 0.000235684585134965 0.000235764481250163 0.000235807357421787 0.000235803014119548 0.000235744951193583 -1.05487211849611 -1.07253268608871 -0.278586111646277 -0.279002675800522 -0.279591023977834 -0.280179381363973 -0.280640442051281 -0.280883558606506 -0.280847472595501 -0.280494406880535 +AB1_EBV chr6:1412516-4412516 6:2900335:G:A chr6_2900335_G_A chr6 2900335 G A 0.0141425 0.0871561 0.128692 0.49825 -4.8508851812967e-06 0.00150079197313381 0.000276535291099278 -1 NA NA NA -4.8508851812967e-06 0.00150079197313381 0.000276535291099278 -1 NA NA NA 2.9118904773619e-10 1.22127022947677e-05 3.30969532069184e-05 3.30818377973087e-05 3.30604993683275e-05 3.30391480522195e-05 3.30223804765177e-05 3.30134663789116e-05 3.30146157602308e-05 3.30271970744514e-05 2.43074616704319e-11 -4.01449309932804e-07 -5.55372192291594e-07 -5.55610515295359e-07 -5.55946267795425e-07 -5.56278692320696e-07 -5.56535030480033e-07 -5.56664687226849e-07 -5.56633503268646e-07 -5.56419290146967e-07 2.59576698269183e-06 0.000439789713479433 0.000506778882168131 0.000506934685916685 0.000507153885835485 0.000507372164401548 0.000507542686144415 0.000507632676254687 0.00050762007726774 0.000507490860118933 -1.6617444558951 -1.07231240761235 -0.28155757562021 -0.281974683704746 -0.282563659917823 -0.283153189855267 -0.283616300020534 -0.283862567999277 -0.283830864503621 -0.283483458915005 +AB1_EBV chr6:1412516-4412516 6:2900414:T:A chr6_2900414_T_A chr6 2900414 T A 0.000665535 -0.139883 0.716694 0.845254 -3.82750989083661e-05 0.00859039307097078 0.000281652410816347 -1 NA NA NA -3.82750989083661e-05 0.00859039307097078 0.000281652410816347 -1 NA NA NA 2.39508370320693e-10 1.26326017337332e-05 3.36824589320091e-05 3.36678668884519e-05 3.36472607420992e-05 3.3626640591405e-05 3.36104486317959e-05 3.36018459573805e-05 3.36029700713173e-05 3.36151449528514e-05 -3.39828253445488e-11 -3.20715310728596e-06 -4.3744647901316e-06 -4.37709079805373e-06 -4.38078008181301e-06 -4.38445091094579e-06 -4.3873144802804e-06 -4.38881848885003e-06 -4.38859190152779e-06 -4.38640036665243e-06 1.11779046586714e-05 0.00256822572033681 0.00289485122527406 0.00289583737532278 0.0028972246820386 0.00289860691148584 0.00289968767710333 0.00290025922613081 0.00290018176576873 0.00289936678143994 -1.85712879532708 -1.03850807792568 -0.264021610257959 -0.264415230773286 -0.264971208724758 -0.265527725276927 -0.265964838061926 -0.266197113647407 -0.26616677170098 -0.265838126664907 +AB1_EBV chr6:1412516-4412516 6:2900482:G:A chr6_2900482_G_A chr6 2900482 G A 0.00263659 -0.148118 0.285531 0.603939 -7.81711333268456e-06 0.00328394972541939 0.000274033837365906 -1 NA NA NA -7.81711333268456e-06 0.00328394972541939 0.000274033837365906 -1 NA NA NA 2.65623587561404e-10 1.19997776301267e-05 3.28099467075179e-05 3.2795070836965e-05 3.27740673447991e-05 3.27530575777528e-05 3.27365702526763e-05 3.27278256360016e-05 3.2729000636728e-05 3.27414447134073e-05 -3.725607632674e-11 -6.3084943095232e-07 -8.95451470538984e-07 -8.96264942137871e-07 -8.97407813111108e-07 -8.98550900264671e-07 -8.99452015723433e-07 -8.99940070338565e-07 -8.99899885363641e-07 -8.99259548177639e-07 5.13525367516566e-06 0.000951241529523494 0.00111007623869679 0.00111042320525827 0.00111091123194518 0.00111139758053865 0.00111177816708481 0.00111198007054922 0.00111195422561528 0.00111166951609209 -1.75363693846563 -1.08990087061697 -0.290267082941084 -0.290680883726823 -0.29126528416087 -0.291850033955015 -0.292309018514408 -0.29255246537276 -0.2925196752518 -0.292173136894739 +AB1_EBV chr6:1412516-4412516 6:2900706:G:A chr6_2900706_G_A chr6 2900706 G A 0.0666048 -0.0748309 0.059488 0.208422 -2.4505317402585e-06 0.000697356259738811 0.000277550020485684 -1 NA NA NA -2.4505317402585e-06 0.000697356259738811 0.000277550020485684 -1 NA NA NA 5.38086030734586e-10 1.22277846647579e-05 3.32218387383518e-05 3.32067068942862e-05 3.31853404764832e-05 3.31639793445744e-05 3.31472419094258e-05 3.31384130878286e-05 3.31397124354581e-05 3.31525132685726e-05 -4.07404343673439e-11 -1.88905566542675e-07 -2.82291734212634e-07 -2.82403759486555e-07 -2.82560601359849e-07 -2.82719528341308e-07 -2.82849712802439e-07 -2.82929704285372e-07 -2.82944884411671e-07 -2.82885508381631e-07 2.22349317817976e-06 0.000203652812363333 0.000235551223885542 0.000235624038880583 0.00023572643548321 0.000235828593919897 0.000235908797992618 0.000235951847624438 0.000235947504759349 0.000235889244887071 -1.04769870490789 -1.07107819555023 -0.277791352642094 -0.2782072380547 -0.278794630610174 -0.279382025404102 -0.279842315022417 -0.280084992562041 -0.280048895046835 -0.279696305926548 +AB1_EBV chr6:1412516-4412516 6:2900779:G:T chr6_2900779_G_T chr6 2900779 G T 0.000293308 0.222851 0.892501 0.802825 3.93278283454109e-05 0.0105165019832976 0.000278429524439683 -1 NA NA NA 3.93278283454109e-05 0.0105165019832976 0.000278429524439683 -1 NA NA NA 2.42119911334643e-10 1.23805452883762e-05 3.33120134147895e-05 3.32971316570212e-05 3.32761196029438e-05 3.32550934598933e-05 3.32385807075095e-05 3.32298022254387e-05 3.32309351934593e-05 3.32433277153777e-05 5.30951482486496e-11 3.30691633667144e-06 4.49426732413003e-06 4.49670771714816e-06 4.50013763168623e-06 4.50354268658721e-06 4.50618537893779e-06 4.50754993946109e-06 4.50728872163161e-06 4.50517951400913e-06 1.41407276088693e-05 0.00310971365275386 0.00354793619288009 0.00354907774513592 0.00355068362647631 0.00355228303996116 0.00355353284435313 0.00355419270368656 0.00355410085553536 0.0035531545954489 -1.84628405589504 -1.0586626772132 -0.275080710503293 -0.275487851612368 -0.276062846421069 -0.276638410697475 -0.277090557128362 -0.277330987653494 -0.277300004725495 -0.276960757973803 +AB1_EBV chr6:1412516-4412516 6:2901299:T:A chr6_2901299_T_A chr6 2901299 T A 0.000160786 -1.26096 1.47459 0.392483 -0.000170522636125533 0.0204851026808546 0.000312954617270877 -1 NA NA NA -0.000170522636125533 0.0204851026808546 0.000312954617270877 -1 NA NA NA 3.35255518153791e-10 1.53990054822489e-05 3.7241766909278e-05 3.72296882854881e-05 3.72126196025097e-05 3.71955283613543e-05 3.71821013619481e-05 3.71749684918958e-05 3.7175909131918e-05 3.71860208911237e-05 -4.12416769738376e-10 -1.57052145928113e-05 -1.93033337994492e-05 -1.93174668113558e-05 -1.93373577642266e-05 -1.93571929576123e-05 -1.93727175786129e-05 -1.93809394925251e-05 -1.93798430306353e-05 -1.93681576815342e-05 3.49162021266074e-05 0.00677140504927717 0.00682423602985352 0.00682747911755856 0.00683204596431248 0.00683660189556094 0.00684016907512273 0.00684205909989392 0.00684180805236277 0.00683912400865881 -1.52082417887053 -0.840486061150979 -0.163567907810423 -0.163852593283656 -0.164254916728738 -0.164657804117231 -0.164974328567028 -0.165142473531004 -0.165120282230847 -0.164881926566009 +AB1_EBV chr6:1412516-4412516 6:2901437:T:C chr6_2901437_T_C chr6 2901437 T C 0.00243636 0.160119 0.310196 0.605724 2.96061315937843e-05 0.00409536289602358 0.000301337566358306 -1 NA NA NA 2.96061315937843e-05 0.00409536289602358 0.000301337566358306 -1 NA NA NA 2.66812142111886e-10 1.43959073204915e-05 3.59189719774459e-05 3.59056435298025e-05 3.58868259382378e-05 3.58679869005927e-05 3.58531811787001e-05 3.58452976161622e-05 3.58462883764916e-05 3.58573568471173e-05 4.13834474904866e-11 2.67310651563078e-06 3.35915900741316e-06 3.36132554446077e-06 3.36437932025667e-06 3.36742138929354e-06 3.36979562569709e-06 3.3710412365638e-06 3.37084698290736e-06 3.36901458811364e-06 5.61130019692742e-06 0.00131551545531481 0.00136920959834915 0.00136978442111869 0.00137059415886078 0.00137140149547561 0.00137203287982255 0.00137236629721574 0.00137231946856703 0.00137184035323422 -1.74917233754388 -0.907845037079717 -0.199733182394312 -0.200064623936376 -0.200532594469493 -0.201001184952951 -0.201369528957596 -0.201565728180789 -0.201541200093894 -0.201266076817944 +AB1_EBV chr6:1412516-4412516 6:2901740:C:T chr6_2901740_C_T chr6 2901740 C T 0.00113492 -0.660862 0.469182 0.158971 -0.000104368763391992 0.00837225553970323 0.00038399391514754 -1 NA NA NA -0.000104368763391992 0.00837225553970323 0.00038399391514754 -1 NA NA NA 6.27557957401794e-10 2.23904185497478e-05 4.52285784811251e-05 4.52228368637095e-05 4.52146905460237e-05 4.52064991309838e-05 4.52000393455772e-05 4.51965963634224e-05 4.51970426383519e-05 4.52019040545982e-05 -4.08017420349811e-10 -1.12431861891166e-05 -1.16039623831258e-05 -1.1614574853731e-05 -1.16295246741969e-05 -1.16444459722166e-05 -1.16561338320443e-05 -1.16623272812409e-05 -1.16615012891556e-05 -1.16526988997442e-05 2.00042363984756e-05 0.00316816247511648 0.00273361515849696 0.00273543568248955 0.00273800114071713 0.00274056251299853 0.00274256942538591 0.00274363323642256 0.00274349175815446 0.00274198074860733 -0.893881131580187 -0.466155865372607 0.0307303486857835 0.0306430911317879 0.030519189006661 0.0303945097545189 0.0302961294412096 0.0302436639934607 0.0302504265993964 0.0303243763281786 +AB1_EBV chr6:1412516-4412516 6:2901779:C:T chr6_2901779_C_T chr6 2901779 C T 0.000474125 0.464259 0.713054 0.514991 7.42781689841096e-05 0.00962408463873327 0.000306219320683976 -1 NA NA NA 7.42781689841096e-05 0.00962408463873327 0.000306219320683976 -1 NA NA NA 2.86243935440098e-10 1.48599589426249e-05 3.64684340513584e-05 3.64559467233702e-05 3.64383065447139e-05 3.64206442766831e-05 3.64067651396288e-05 3.63993818493059e-05 3.6400330025449e-05 3.64107439124906e-05 1.27023445979675e-10 6.82486782147636e-06 8.41039220824134e-06 8.41655434299846e-06 8.42523035358088e-06 8.43387953285573e-06 8.44064190143476e-06 8.44420944646573e-06 8.44370167347457e-06 8.43856468013581e-06 1.40881940768886e-05 0.00314110358222158 0.00321124072749791 0.00321270312520817 0.00321476262578972 0.00321681678949376 0.00321842434512764 0.00321927474243777 0.00321915878472844 0.00321794486437146 -1.67887279230573 -0.876118713070541 -0.184551739732469 -0.184854515897884 -0.185282258223097 -0.185710588499166 -0.186047215015958 -0.186226325978645 -0.186203388508407 -0.185950941202606 +AB1_EBV chr6:1412516-4412516 6:2901780:G:C chr6_2901780_G_C chr6 2901780 G C 0.0602314 -0.0252196 0.0618397 0.683405 8.57138514535798e-06 0.000910498237234011 0.000327196293954057 -1 NA NA NA 8.57138514535798e-06 0.000910498237234011 0.000327196293954057 -1 NA NA NA 2.57933295715376e-10 1.67770980844004e-05 3.88435654164233e-05 3.88334085586811e-05 3.88190914231861e-05 3.8804753336167e-05 3.87934701671027e-05 3.87874356121324e-05 3.87881299708099e-05 3.87964586105363e-05 -6.84061171967653e-12 8.24205140773222e-07 9.65577315271994e-07 9.66393292140342e-07 9.67546441330625e-07 9.68697563004973e-07 9.6959771249865e-07 9.70071031874967e-07 9.69998525976611e-07 9.69304963098313e-07 1.06983434732419e-06 0.000312499195642551 0.000301785553703583 0.000301950290219811 0.000302182775581074 0.000302414863899145 0.000302596525548325 0.000302692435916132 0.000302678731690022 0.000302540389994796 -1.78301615295971 -0.754774242278217 -0.121456368887976 -0.121678186993833 -0.121990684503573 -0.1223036050414 -0.122549890070179 -0.122681748558017 -0.122666958507057 -0.122485865185222 +AB1_EBV chr6:1412516-4412516 6:2901784:T:C chr6_2901784_T_C chr6 2901784 T C 0.000474114 0.464262 0.713054 0.514988 7.4278229790865e-05 0.00962408661564884 0.000306219369939686 -1 NA NA NA 7.4278229790865e-05 0.00962408661564884 0.000306219369939686 -1 NA NA NA 2.86244808138723e-10 1.48599605837659e-05 3.64684400314365e-05 3.64559526953849e-05 3.64383125054799e-05 3.64206502263469e-05 3.64067710808445e-05 3.63993877865356e-05 3.6400335964364e-05 3.64107498594699e-05 1.27024809591101e-10 6.82487019409241e-06 8.41039954058659e-06 8.4165616667619e-06 8.42523766538765e-06 8.43388683287977e-06 8.44064919253504e-06 8.44421673344543e-06 8.44370896243587e-06 8.43857197793072e-06 1.40882463064968e-05 0.00314110399239066 0.00321124141832974 0.00321270381557033 0.00321476331550199 0.00321681747857059 0.00321842503373471 0.00321927543085274 0.00321915947330345 0.00321794555349866 -1.67886974351696 -0.876118602630065 -0.184551575752915 -0.184854352083343 -0.185282094637956 -0.185710425139527 -0.186047051826089 -0.186226162865182 -0.186203225352894 -0.185950777872275 +AB1_EBV chr6:1412516-4412516 6:2901906:G:T chr6_2901906_G_T chr6 2901906 G T 0.000732806 -0.514416 0.561698 0.35976 -0.000114028330580257 0.00962161397599455 0.000370399667817156 -1 NA NA NA -0.000114028330580257 0.00962161397599455 0.000370399667817156 -1 NA NA NA 3.52125777245866e-10 2.11518692151745e-05 4.36868584718273e-05 4.36801706901131e-05 4.3670704489078e-05 4.36611964857497e-05 4.36536971131505e-05 4.36496837702575e-05 4.36501604902728e-05 4.36557399258389e-05 -1.7600131130793e-10 -1.21396951826313e-05 -1.26963525001502e-05 -1.27078425352357e-05 -1.27240367061852e-05 -1.27401984318054e-05 -1.27528498983887e-05 -1.27595380654515e-05 -1.27586100625871e-05 -1.27490311965107e-05 1.40160216167457e-05 0.00359352235404155 0.00314855773213012 0.00315059007537553 0.00315345483706459 0.00315631482545548 0.0031585548423876 0.00315974055082775 0.0031595791217589 0.0031578873594886 -1.47172872721918 -0.523060708855343 -0.00395147022989217 -0.00406486929332406 -0.00422535763315501 -0.00438659746392567 -0.00451385013387107 -0.00458208072348754 -0.00457427071126393 -0.0044800622103649 +AB1_EBV chr6:1412516-4412516 6:2901927:C:A chr6_2901927_C_A chr6 2901927 C A 0.000122246 -1.13981 1.35456 0.40009 -0.000159865798488725 0.0189320928496257 0.000314385192374811 -1 NA NA NA -0.000159865798488725 0.0189320928496257 0.000314385192374811 -1 NA NA NA 3.31831868939229e-10 1.55355647665652e-05 3.74034876093184e-05 3.73914278597979e-05 3.73743921275384e-05 3.73573359212473e-05 3.73439376908123e-05 3.73368215672707e-05 3.73377627028184e-05 3.73478552980006e-05 -3.69538033917271e-10 -1.47921828239582e-05 -1.80888781861212e-05 -1.81019823473878e-05 -1.81204396926077e-05 -1.81388504163526e-05 -1.81532633341475e-05 -1.81608999283469e-05 -1.81598876287449e-05 -1.81490445930246e-05 3.17180559629383e-05 0.00628352839668168 0.00630368303904831 0.00630668925041208 0.00631092398764079 0.00631514915690365 0.00631845770904774 0.0063202110540328 0.00631997875775944 0.00631748983560914 -1.53108873892888 -0.831657092764422 -0.159234853978305 -0.159517631922922 -0.159917089674251 -0.160317050330861 -0.160631240290594 -0.160798105215386 -0.160776010328358 -0.160539346534644 +AB1_EBV chr6:1412516-4412516 6:2901956:C:G chr6_2901956_C_G chr6 2901956 C G 0.00422977 -0.169267 0.237368 0.475785 -1.62815035121505e-05 0.00293764001846143 0.000287893968729858 -1 NA NA NA -1.62815035121505e-05 0.00293764001846143 0.000287893968729858 -1 NA NA NA 3.00922682592311e-10 1.31499796504163e-05 3.43960612222218e-05 3.4382081817001e-05 3.4362329904722e-05 3.43425610815575e-05 3.4327038236061e-05 3.43187958648315e-05 3.43198858566079e-05 3.43315780105471e-05 -4.97429504469612e-11 -1.38546252123471e-06 -1.85768974678648e-06 -1.85894190280673e-06 -1.8606983796764e-06 -1.86244754062533e-06 -1.86381550540057e-06 -1.86453972766464e-06 -1.86444344328619e-06 -1.86341500171895e-06 4.97775331539796e-06 0.000897851438327447 0.000987627332533439 0.000987999491806122 0.000988522889854285 0.000989044558694027 0.000989452722598915 0.000989668899040274 0.00098964024095878 0.000989333352109394 -1.62886379742584 -0.998368778284787 -0.243056747167402 -0.243423557200197 -0.243941953653876 -0.244460920015889 -0.244868497471278 -0.245084929834525 -0.245056280985397 -0.244749262376344 +AB1_EBV chr6:1412516-4412516 6:2902097:A:C chr6_2902097_A_C chr6 2902097 A C 0.381506 0.171729 0.0305523 1.90055e-08 0.000152423497918228 0.00495139434682274 0.0013570758271243 -1 NA NA NA 0.000152423497918228 0.00495139434682274 0.0013570758271243 -1 NA NA NA 0.000843526188656871 3.91741028318361e-05 5.93126743663999e-05 5.93282533599584e-05 5.93500295728665e-05 5.93716631818064e-05 5.93884955045684e-05 5.93972332518681e-05 5.93956532569341e-05 5.93823609924639e-05 0.000139928800104302 1.7518564521159e-06 1.33642690192504e-06 1.3382905777224e-06 1.34091346719012e-06 1.34353208568464e-06 1.3455820506066e-06 1.34666229599662e-06 1.34650175732951e-06 1.3449322253552e-06 0.00489504602054235 0.000333052358433822 0.000234759365008444 0.000234991037227334 0.00023531723633409 0.000235642941485097 0.000235898001954203 0.000236032634770317 0.0002360132076357 0.000235818808107556 13.2173843463615 0.093226897020803 0.301824210520419 0.302126531966772 0.302549762227976 0.302970708901167 0.303298701362282 0.303469528717203 0.30343981645509 0.303182394556006 +AB1_EBV chr6:1412516-4412516 6:2902159:A:G chr6_2902159_A_G chr6 2902159 A G 0.199925 -0.0167221 0.036845 0.649937 1.27910315514759e-05 0.000823906046209054 0.000470625668141822 -1 NA NA NA 1.27910315514759e-05 0.000823906046209054 0.000470625668141822 -1 NA NA NA 2.7512128114274e-10 3.45131117258491e-05 5.44921382732307e-05 5.45025758305991e-05 5.45172433642999e-05 5.45316126904354e-05 5.4542362454444e-05 5.4547147694049e-05 5.45443895335381e-05 5.45331019684047e-05 -5.64309864838996e-12 1.76043634854507e-06 1.37247712640654e-06 1.37433592409176e-06 1.37695732716769e-06 1.37956536863081e-06 1.38158671720971e-06 1.38261411351815e-06 1.38237255902427e-06 1.38069170998055e-06 6.93135129452434e-07 0.000362684329388557 0.00026070914685714 0.000260955264477976 0.000261302336434109 0.00026164802637794 0.000261916803312259 0.000262055077651312 0.00026202666807898 0.000261809108603266 -1.71850513793224 -0.0334496875492922 0.217057633759386 0.21728885503609 0.217614186526596 0.217934230040226 0.218175864601768 0.218287304678361 0.218233627265473 0.217993058133872 +AB1_EBV chr6:1412516-4412516 6:2912043:G:A chr6_2912043_G_A chr6 2912043 G A 0.379836 0.195819 0.0298776 5.60015e-11 0.0627098030382369 0.0914758405630092 0.327483481692081 1 0.327287739668512 0 0.988626524209 0.0627098030382369 0.0914758405630092 0.327483481692081 1 0.327287739668512 0 0.988626524209 0.327287739668512 1.34116556674083e-05 3.47479906129698e-05 3.47341023926405e-05 3.47144673802213e-05 3.46948481583097e-05 3.46795126959479e-05 3.46714989293944e-05 3.46728600996272e-05 3.46848650779766e-05 0.0627075544730858 1.93070115154659e-07 2.56351789036658e-07 2.56517545891351e-07 2.56749448141219e-07 2.56982473311057e-07 2.57169098245676e-07 2.57275938042434e-07 2.57280452181013e-07 2.57168291095261e-07 0.0914750699783512 0.000115965451802635 0.000126090501441368 0.000126139059796606 0.000126207301983071 0.000126275491956345 0.000126329203768056 0.000126358304086684 0.000126355963029962 0.000126317856103039 19.1783883980353 -0.978664834606986 -0.232877059385462 -0.233237126234329 -0.233746329660068 -0.234255144961051 -0.234652727503607 -0.234860125362074 -0.234823978507148 -0.234511407819073 +AB1_EBV chr6:1412516-4412516 6:2912091:T:C chr6_2912091_T_C chr6 2912091 T C 0.0014968 0.849767 0.39658 0.0321336 0.000467799155561597 0.0178107769162849 0.000999898076620487 -1 NA NA NA 0.000467799155561597 0.0178107769162849 0.000999898076620487 -1 NA NA NA 2.14748023589044e-09 0.000129030020977694 0.000108607514244686 0.000108695992067434 0.000108820817330923 0.000108945579309375 0.000109043388481492 0.00010909516101071 0.000109088003495295 0.000109013906271378 1.7706840523719e-09 0.000105696396775546 4.49708995093949e-05 4.50550210557385e-05 4.5173821756935e-05 4.52927095848752e-05 4.53860323694479e-05 4.54355104110357e-05 4.5428780052821e-05 4.53582133617496e-05 4.23059122786113e-05 0.0102300083056357 0.00513146611005017 0.0051381716493634 0.00514763567977716 0.0051570999330498 0.00516452473746057 0.00516846065280203 0.00516792812105516 0.00516231993799184 0.336333289791154 1.28525610863321 0.90674179140902 0.907595813479623 0.908799794774941 0.910002132328979 0.910944034613751 0.911442419834467 0.91137369825334 0.910660619838302 +AB1_EBV chr6:1412516-4412516 6:2912215:A:C chr6_2912215_A_C chr6 2912215 A C 0.000455488 0.61666 0.755233 0.414205 0.000112004643456391 0.0113904316010689 0.000333457603954423 -1 NA NA NA 0.000112004643456391 0.0113904316010689 0.000333457603954423 -1 NA NA NA 3.24538856818094e-10 1.7385629796308e-05 3.95513804269452e-05 3.95409324142499e-05 3.95261701037205e-05 3.95113845208808e-05 3.94997674441308e-05 3.94936005032933e-05 3.94944279729676e-05 3.95031985094307e-05 1.94930595906053e-10 1.09430535165028e-05 1.25985989515895e-05 1.26084517781145e-05 1.26223360989094e-05 1.263619241875e-05 1.26470466233653e-05 1.26528047819961e-05 1.26520552817327e-05 1.2643909074835e-05 1.72577400195345e-05 0.00396527667424546 0.00376819718924355 0.00377022680744795 0.00377308699655655 0.00377594195077436 0.00377817858479035 0.0037793647338638 0.00377920899661583 0.00377752828442837 -1.55331188807753 -0.719144998187052 -0.103398208696467 -0.103622709454589 -0.103939870307167 -0.104257506731746 -0.104507043474584 -0.104639472108447 -0.104621631762101 -0.104433191173421 +AB1_EBV chr6:1412516-4412516 6:2912223:A:G chr6_2912223_A_G chr6 2912223 A G 0.000327161 -0.974896 0.897826 0.277549 -0.000143823315763218 0.0139369815289686 0.000341294746581511 -1 NA NA NA -0.000143823315763218 0.0139369815289686 0.000341294746581511 -1 NA NA NA 4.15651617156049e-10 1.81159684822268e-05 4.04369439533612e-05 4.04273931742459e-05 4.0413883888316e-05 4.0400344441517e-05 4.03897002915185e-05 4.03840447014201e-05 4.03847944480235e-05 4.0392817733862e-05 -3.94185719873914e-10 -1.42532764371269e-05 -1.61503880112751e-05 -1.6163647332254e-05 -1.61823187080979e-05 -1.62009487904163e-05 -1.62155396124606e-05 -1.62232739594452e-05 -1.62222517278753e-05 -1.62112769985464e-05 2.64761296927553e-05 0.00492195420313575 0.00460091996559752 0.00460353106509021 0.00460720952302008 0.00461088108504921 0.00461375733109938 0.00461528214251335 0.00461508042144129 0.00461291664214722 -1.305869710077 -0.677995203493559 -0.0812549842375656 -0.0814515043997215 -0.0817294705755023 -0.0820080421202665 -0.0822270186896716 -0.0823433444879065 -0.0823278906719001 -0.0821628444267333 +AB1_EBV chr6:1412516-4412516 6:2912235:C:A chr6_2912235_C_A chr6 2912235 C A 0.000894445 0.0390669 0.502805 0.938068 1.64477341850827e-05 0.00582199394394285 0.000275236633743181 -1 NA NA NA 1.64477341850827e-05 0.00582199394394285 0.000275236633743181 -1 NA NA NA 2.35335244481712e-10 1.2109466439747e-05 3.2946910297286e-05 3.29319569945197e-05 3.29108465588616e-05 3.28897269237278e-05 3.28731475226994e-05 3.28643438621222e-05 3.2865502937009e-05 3.28779796697682e-05 8.25512316693382e-12 1.36304292983158e-06 1.88139085922139e-06 1.88260803746861e-06 1.88432243632932e-06 1.88603061134145e-06 1.88736476632332e-06 1.88806645059385e-06 1.88796128625787e-06 1.88693855259211e-06 7.64087884500099e-06 0.0016974102170611 0.00196684251598381 0.00196745566043838 0.00196831827899032 0.00196917766387594 0.00196984963868014 0.00197020521959275 0.00197015760253611 0.00196965166777194 -1.87470609089502 -1.08080149229204 -0.28610131851516 -0.286515584914988 -0.287100571028592 -0.287685995378918 -0.28814568808312 -0.288389821438491 -0.288357665025673 -0.288011711991038 +AB1_EBV chr6:1412516-4412516 6:2912261:G:A chr6_2912261_G_A chr6 2912261 G A 0.0199092 -0.220904 0.106552 0.0381531 -2.97706349596775e-05 0.00212370411917391 0.000423874556068071 -1 NA NA NA -2.97706349596775e-05 0.00212370411917391 0.000423874556068071 -1 NA NA NA 1.98958362816542e-09 2.7132197094122e-05 4.96130716799048e-05 4.96100894958993e-05 4.96057801356657e-05 4.96014037623309e-05 4.95979392558906e-05 4.95961163167247e-05 4.95964347585059e-05 4.95991841555843e-05 -4.3309240151892e-10 -3.52624448591988e-06 -3.26979385529758e-06 -3.2728905431541e-06 -3.27724678792719e-06 -3.28159386611135e-06 -3.28500081535703e-06 -3.28681127681543e-06 -3.28658270906846e-06 -3.28403752762494e-06 1.07857201849781e-05 0.000856007676657065 0.000685441550967017 0.0006859315780635 0.000686621517047654 0.000687310284091608 0.000687850150940657 0.000688136832127493 0.000688099988781492 0.00068769557453296 0.259963503034496 -0.274067882084955 0.123255535306186 0.123235121837409 0.123204504827758 0.123172782159143 0.123147457733531 0.123134412284021 0.123137721535353 0.123159550394981 +AB1_EBV chr6:1412516-4412516 6:2912516:CCA:C chr6_2912516_CCA_C chr6 2912516 CCA C 0.379568 0.196413 0.0298788 4.90908e-11 0.0705334503762503 0.0943211787286286 0.367291808726716 1 0.367106415849495 0 1 0.0705334503762503 0.0943211787286286 0.367291808726716 1 0.367106415849495 0 1 0.367106415849495 1.35826756661766e-05 3.49703766940184e-05 3.49566673877352e-05 3.49372826355214e-05 3.49179144495213e-05 3.4902779017062e-05 3.48948777422873e-05 3.48962391873188e-05 3.4908116627254e-05 0.0705310811656966 2.04829896721797e-07 2.69918706751321e-07 2.70097089742913e-07 2.703467265568e-07 2.70597474615109e-07 2.70798048480558e-07 2.70912405770814e-07 2.7091621239132e-07 2.70793992636531e-07 0.0943204169456985 0.000117874520944068 0.000127207470188182 0.000127257707273328 0.000127328309993585 0.00012739886603438 0.000127454449709537 0.000127484572709491 0.000127482165069385 0.000127442752777842 19.2932004436988 -0.965993856777881 -0.226497482700605 -0.226849888657321 -0.227348327734282 -0.227846347311053 -0.228235373839683 -0.228438069440508 -0.228402166017004 -0.228095464439732 +AB1_EBV chr6:1412516-4412516 6:2912529:A:G chr6_2912529_A_G chr6 2912529 A G 0.000327219 -0.97546 0.897843 0.277281 -0.000143953079553094 0.0139419926770435 0.0003413887961905 -1 NA NA NA -0.000143953079553094 0.0139419926770435 0.0003413887961905 -1 NA NA NA 4.15918375867138e-10 1.81252741493716e-05 4.04475101763738e-05 4.04379681637341e-05 4.0424471223517e-05 4.0410944096783e-05 4.04003095978191e-05 4.03946591265783e-05 4.03954082031063e-05 4.0403424239079e-05 -3.94667582594136e-10 -1.42693628376224e-05 -1.61645419108553e-05 -1.61778173275889e-05 -1.6196511395159e-05 -1.62151641464748e-05 -1.62297727421942e-05 -1.62375165200616e-05 -1.62364930492056e-05 -1.62255049563498e-05 2.64930551234239e-05 0.00492466914772154 0.00460244397516612 0.00460505719958363 0.00460873865501266 0.0046124132135329 0.00461529181034602 0.00461681786950121 0.00461661598421526 0.00461445043652855 -1.30522813156292 -0.67748166330158 -0.0809937171452315 -0.0811899588040905 -0.0814675321615681 -0.0817457110643343 -0.0819643796238738 -0.0820805419244524 -0.0820651095746605 -0.0819002949561405 +AB1_EBV chr6:1412516-4412516 6:2912588:C:T chr6_2912588_C_T chr6 2912588 C T 0.0254686 0.216313 0.0955807 0.0236265 1.47824004154632e-05 0.00146431229272919 0.000337611425283768 -1 NA NA NA 1.47824004154632e-05 0.00146431229272919 0.000337611425283768 -1 NA NA NA 2.72685699254245e-09 1.78248894962867e-05 4.00108805539477e-05 4.00017784606194e-05 3.99888907079696e-05 3.99759826507461e-05 3.99658550555137e-05 3.99605097334193e-05 3.99613013955271e-05 3.99690615313357e-05 5.70381630748495e-10 1.46467314122321e-06 1.65960336828124e-06 1.66106000252363e-06 1.66310974647536e-06 1.66515656502215e-06 1.66676273894097e-06 1.66761930038806e-06 1.66751779919677e-06 1.66632737178103e-06 1.19846816026332e-05 0.000515215638913325 0.000483618358084242 0.00048389907275914 0.000484294387774508 0.000484689129467184 0.000484998689925372 0.00048516333488638 0.000485142766776561 0.000484911717134194 0.575187779444314 -0.694193222496162 -0.0918473746636161 -0.0920351938219852 -0.0923011738682922 -0.0925675127810841 -0.0927763619162958 -0.092886408524647 -0.0928697090375366 -0.092709141603013 +AB1_EBV chr6:1412516-4412516 6:2912610:T:A chr6_2912610_T_A chr6 2912610 T A 0.000546427 0.109603 0.608951 0.857163 -1.7075059345342e-06 0.00689201795132011 0.000271185931488116 -1 NA NA NA -1.7075059345342e-06 0.00689201795132011 0.000271185931488116 -1 NA NA NA 2.37990235015101e-10 1.17752178586987e-05 3.24833629428342e-05 3.24680806295094e-05 3.24465064204478e-05 3.24249247619617e-05 3.2407984976631e-05 3.23989929381462e-05 3.24001832167821e-05 3.24129409677569e-05 2.37142738719595e-11 -1.10061281359889e-07 -1.99916178590291e-07 -1.99847078568636e-07 -1.99750046290116e-07 -1.99653339751115e-07 -1.99578768359799e-07 -1.99542536537732e-07 -1.99555699429243e-07 -1.99624719921246e-07 9.40928980680266e-06 0.00197272591095902 0.00233243168230848 0.00233310172729173 0.0023340440487014 0.00233498253666501 0.00233571624093277 0.00233610464497459 0.00233605323933057 0.0023355018923268 -1.86348751723285 -1.10879184787886 -0.300270756823125 -0.300701636214049 -0.301310080139224 -0.301918943002603 -0.302396985543454 -0.302650778155976 -0.302617152121965 -0.302257079085101 +AB1_EBV chr6:1412516-4412516 6:2912748:A:G chr6_2912748_A_G chr6 2912748 A G 0.00233851 0.432498 0.310772 0.164016 5.15277704475579e-05 0.00489060027618745 0.000345015214635036 -1 NA NA NA 5.15277704475579e-05 0.00489060027618745 0.000345015214635036 -1 NA NA NA 5.99956963572397e-10 1.85725654097157e-05 4.08444675074e-05 4.08350760770347e-05 4.08218020645658e-05 4.08085011268683e-05 4.0798045921e-05 4.07924931202076e-05 4.07932351053201e-05 4.08011247074387e-05 2.52393731776312e-10 5.20198836606858e-06 5.77436514648892e-06 5.77908582942781e-06 5.7857384974689e-06 5.79237838581503e-06 5.79757978057528e-06 5.8003381874085e-06 5.79997622281808e-06 5.79606763775497e-06 1.27576077926897e-05 0.0017479247396613 0.00161168129135818 0.00161260430278 0.00161390516855485 0.00161520381422027 0.0016162212837495 0.00161676081838625 0.00161668971463515 0.00161592466322812 -0.938859235450003 -0.65310347551445 -0.071227427838604 -0.0714176886195066 -0.0716865540907756 -0.0719559321725098 -0.0721676417039498 -0.072280045985508 -0.072264968322628 -0.0721051873355378 +AB1_EBV chr6:1412516-4412516 6:2913008:C:T chr6_2913008_C_T chr6 2913008 C T 0.0024573 0.210031 0.306679 0.493435 3.92406011765618e-05 0.00439665175954045 0.000320463764927226 -1 NA NA NA 3.92406011765618e-05 0.00439665175954045 0.000320463764927226 -1 NA NA NA 2.94217037452583e-10 1.61738961036959e-05 3.80830747887176e-05 3.80712201708452e-05 3.8054480217481e-05 3.80377114807026e-05 3.80245222278381e-05 3.80174874673335e-05 3.80183473959848e-05 3.80281706575051e-05 5.99168022206555e-11 3.7312241576727e-06 4.42780444533946e-06 4.43095386156343e-06 4.43539335038771e-06 4.43981828187131e-06 4.44327482738013e-06 4.4450921744079e-06 4.44481732150604e-06 4.44216283963094e-06 6.26270446596284e-06 0.00148867738379177 0.00146017212945563 0.00146088436225525 0.00146188805981231 0.00146288920935577 0.00146367244969592 0.00146408612234863 0.00146402790663259 0.00146343325414789 -1.65139944310006 -0.791390398419185 -0.141228853471726 -0.141500487863944 -0.14188403419878 -0.142268277828509 -0.142570554492937 -0.142731867937992 -0.142712360329771 -0.142487616557522 +AB1_EBV chr6:1412516-4412516 6:2913068:GGTTA:G chr6_2913068_GGTTA_G chr6 2913068 GGTTA G 0.00870822 -0.212726 0.162239 0.189793 -2.37283424156391e-05 0.00243803334876037 0.000332005245500255 -1 NA NA NA -2.37283424156391e-05 0.00243803334876037 0.000332005245500255 -1 NA NA NA 5.06606768772462e-10 1.77032100225915e-05 3.93273587257883e-05 3.93177261339309e-05 3.93041069449291e-05 3.9290448887226e-05 3.92796864739962e-05 3.92739177867756e-05 3.92745660964864e-05 3.9282510890253e-05 -1.0073654079631e-10 -2.44868290682411e-06 -2.6520195225503e-06 -2.65431910644349e-06 -2.65755833349504e-06 -2.660787970917e-06 -2.6633110343195e-06 -2.66463612161047e-06 -2.66443261042391e-06 -2.66249407251444e-06 5.74903715846843e-06 0.000868265459189036 0.000803893013679785 0.00080434590358937 0.000804984014857361 0.00080562066225268 0.000806118736528231 0.000806381510540053 0.00080634382910633 0.000805964947295852 -1.10798206205858 -0.701043009065389 -0.10907837817911 -0.109283644613869 -0.109573841275992 -0.10986489435211 -0.110094326242466 -0.110217489313817 -0.110204093492312 -0.110035430413266 +AB1_EBV chr6:1412516-4412516 6:2913328:C:T chr6_2913328_C_T chr6 2913328 C T 0.00154494 -0.519913 0.394744 0.187808 -0.000161875377546235 0.00962934039254081 0.00051506802660084 -1 NA NA NA -0.000161875377546235 0.00962934039254081 0.00051506802660084 -1 NA NA NA 5.4587505222394e-10 3.87066516912138e-05 5.95239253736136e-05 5.95343368544001e-05 5.95489780746768e-05 5.95635596947194e-05 5.95749601233526e-05 5.95809961611447e-05 5.95801979507378e-05 5.95716287271369e-05 -2.76619917891995e-10 -2.22515297726671e-05 -1.73788721996806e-05 -1.74002600883788e-05 -1.74304291144383e-05 -1.74605810644305e-05 -1.74842285353933e-05 -1.74967743770226e-05 -1.74951137467133e-05 -1.74773120275926e-05 1.49409272427542e-05 0.00426209489159326 0.00304332489050872 0.00304607056877729 0.00304994306445174 0.00305381280763353 0.00305684735233557 0.00305845712540929 0.00305824402669091 0.00305595981473945 -1.03332705323842 0.0812224741817866 0.305379533210553 0.305594127626087 0.305896277752671 0.306197619731943 0.306433525758578 0.306558548553959 0.306542039972419 0.306364597941301 +AB1_EBV chr6:1412516-4412516 6:2913533:T:C chr6_2913533_T_C chr6 2913533 T C 0.0012859 -0.294808 0.424332 0.487208 -6.72214334167609e-05 0.00655757133201166 0.000340136198118679 -1 NA NA NA -6.72214334167609e-05 0.00655757133201166 0.000340136198118679 -1 NA NA NA 2.97030235883492e-10 1.79362995702231e-05 4.03144028679426e-05 4.0304892078558e-05 4.02914423661257e-05 4.02779649470781e-05 4.02673714613803e-05 4.02617452136461e-05 4.02624971379401e-05 4.02704935005059e-05 -8.54411777701489e-11 -6.59200715981395e-06 -7.55700070228509e-06 -7.56326851622423e-06 -7.5720966468441e-06 -7.58090683326348e-06 -7.58780813207615e-06 -7.59146793888667e-06 -7.59098800441846e-06 -7.58580404177101e-06 8.76352213705461e-06 0.00230223142130359 0.00216660864196398 0.00216784043660966 0.00216957596391961 0.00217130839872426 0.00217266569311009 0.00217338540816428 0.00217329058718609 0.00217227022799917 -1.64188322277177 -0.687962421044489 -0.0842900092695089 -0.0844862553502468 -0.0847637589382444 -0.0850418089214982 -0.0852603280145701 -0.0853763504676799 -0.0853607861709023 -0.0851958051434307 +AB1_EBV chr6:1412516-4412516 6:2913796:C:T chr6_2913796_C_T chr6 2913796 C T 0.00941746 0.335343 0.157435 0.0331681 4.55657828344948e-05 0.00318684629739834 0.000431444673078984 -1 NA NA NA 4.55657828344948e-05 0.00318684629739834 0.000431444673078984 -1 NA NA NA 2.30538610436447e-09 2.6805498999232e-05 5.059013531817e-05 5.05900962554694e-05 5.05899572315649e-05 5.05897803915044e-05 5.05896517792012e-05 5.0589656828871e-05 5.05898513725928e-05 5.05902415684262e-05 7.66614930776059e-10 5.10995658072454e-06 5.03852061861102e-06 5.04382160905973e-06 5.05128657355206e-06 5.05874533200358e-06 5.06460140973759e-06 5.06772529294742e-06 5.06735321256222e-06 5.06300559036585e-06 1.76272160940659e-05 0.00125143232076605 0.00103343253982729 0.00103422980064459 0.00103535302842997 0.00103647526981979 0.0010373559353431 0.00103782480336434 0.00103776684453523 0.00103710997247525 0.407286288005157 -0.286181936403061 0.142757797463833 0.142796722497035 0.142850225803715 0.142903234516531 0.142945217211903 0.142969026586909 0.142969760675168 0.142943868591193 +AB1_EBV chr6:1412516-4412516 6:2913933:G:A chr6_2913933_G_A chr6 2913933 G A 0.002884 -0.0552494 0.28875 0.848259 -2.61276804153581e-06 0.0032733607704216 0.000271474463967358 -1 NA NA NA -2.61276804153581e-06 0.0032733607704216 0.000271474463967358 -1 NA NA NA 2.39012529715526e-10 1.17947687710751e-05 3.2516816670443e-05 3.25015864228945e-05 3.24800841838334e-05 3.24585740548146e-05 3.24416903315117e-05 3.24327282233183e-05 3.24339151204045e-05 3.2446631739486e-05 -1.29384107884142e-11 -1.92414475066341e-07 -3.01585412168728e-07 -3.01865121378649e-07 -3.02253440974626e-07 -3.02639599248237e-07 -3.02942240776185e-07 -3.0310396405733e-07 -3.03086152715454e-07 -3.02864696739472e-07 4.48984746872096e-06 0.000937747091442122 0.00110769083204224 0.00110801250403537 0.00110846483835581 0.00110891534026423 0.00110926755788719 0.00110945402956772 0.00110942937943025 0.00110916474980723 -1.85920118456897 -1.10713288072139 -0.299241414111716 -0.299670207306508 -0.300275749949801 -0.300881721012933 -0.301357493587462 -0.301610075005957 -0.301576591443828 -0.301218195436843 +AB1_EBV chr6:1412516-4412516 6:2914065:C:T chr6_2914065_C_T chr6 2914065 C T 0.068155 -0.0898974 0.0585507 0.124691 -4.55635943984205e-06 0.000739866387618746 0.000292226090615189 -1 NA NA NA -4.55635943984205e-06 0.000739866387618746 0.000292226090615189 -1 NA NA NA 7.9672360969625e-10 1.33992478416794e-05 3.49075399455961e-05 3.48931938639127e-05 3.48729310299871e-05 3.48526823296835e-05 3.4836842233479e-05 3.48285391892714e-05 3.48298863700927e-05 3.48421872513886e-05 -7.20626698041368e-11 -3.76640606337197e-07 -5.21489879796873e-07 -5.21762991004918e-07 -5.22146662381582e-07 -5.22532208711195e-07 -5.22840636116295e-07 -5.23016665719313e-07 -5.23022840888174e-07 -5.22834886216702e-07 3.03066573362912e-06 0.000226971358502165 0.000248648293365666 0.000248740065882767 0.000248869189393097 0.00024899818088449 0.000249099682591987 0.000249154498042909 0.000249149679517198 0.000249076993648462 -0.655209330404995 -0.979590415247006 -0.228295955476589 -0.228667316499166 -0.229191944030024 -0.229716250733307 -0.230126316235066 -0.230340975980472 -0.230305407785422 -0.229985904820172 +AB1_EBV chr6:1412516-4412516 6:2914194:A:T chr6_2914194_A_T chr6 2914194 A T 0.00109866 0.110877 0.477429 0.816353 2.7396613039195e-05 0.00576889745077796 0.000283171893704526 -1 NA NA NA 2.7396613039195e-05 0.00576889745077796 0.000283171893704526 -1 NA NA NA 2.41209623129335e-10 1.27864463223858e-05 3.38532563572749e-05 3.38386411599051e-05 3.38180096087545e-05 3.37973688864156e-05 3.37811670182675e-05 3.37725691856805e-05 3.37737148124725e-05 3.37859275631042e-05 2.65158009872724e-11 2.34098095477853e-06 3.12591812671548e-06 3.12766098049386e-06 3.13011841781008e-06 3.13256955050937e-06 3.13448944903574e-06 3.13551052109538e-06 3.13538478299653e-06 3.13395373995902e-06 7.5232896894886e-06 0.00173938842606516 0.00194239563817294 0.0019430608545397 0.00194399730246343 0.00194493075990924 0.00194566117493293 0.00194604829464393 0.00194599767055386 0.00194544938818315 -1.85005079976932 -1.02640326055915 -0.258963611281714 -0.259355729380369 -0.259909367859147 -0.260463396969321 -0.260898369481019 -0.261129207875246 -0.261098398065117 -0.260770463217731 +AB1_EBV chr6:1412516-4412516 6:2914212:A:G chr6_2914212_A_G chr6 2914212 A G 0.000394946 -0.38577 0.705803 0.584676 -7.44339347826138e-05 0.00955359514397322 0.000306979642194949 -1 NA NA NA -7.44339347826138e-05 0.00955359514397322 0.000306979642194949 -1 NA NA NA 2.72783652698342e-10 1.48189846981526e-05 3.65695054388094e-05 3.65567584070366e-05 3.6538753489373e-05 3.65207283449848e-05 3.65065684534308e-05 3.6499044020748e-05 3.65000288380522e-05 3.65106793034488e-05 -1.04259352605892e-10 -6.69676778652577e-06 -8.44708051792153e-06 -8.45288940020747e-06 -8.46106900742361e-06 -8.46922407475e-06 -8.47560366041431e-06 -8.47897779681471e-06 -8.47851789772401e-06 -8.47370038147977e-06 1.31352569982239e-05 0.00309901695153985 0.00319013108056283 0.00319155667504451 0.00319356441400493 0.00319556700346377 0.00319713453525078 0.00319796460227068 0.0031978534339785 0.00319667259720857 -1.72703816066681 -0.878879880785989 -0.181784097253166 -0.182093030823458 -0.182529420330056 -0.182966353574209 -0.183309625847713 -0.18349204928215 -0.183468179071459 -0.183210033274174 +AB1_EBV chr6:1412516-4412516 6:2914375:A:C chr6_2914375_A_C chr6 2914375 A C 0.449913 0.073551 0.029878 0.0138277 1.32216141683604e-05 0.000761528659714504 0.000536628417467266 -1 NA NA NA 1.32216141683604e-05 0.000761528659714504 0.000536628417467266 -1 NA NA NA 3.83151076045243e-09 4.30887802086399e-05 6.16439638151432e-05 6.1662884637203e-05 6.16893492695819e-05 6.17155657828099e-05 6.17358050208852e-05 6.17460236951692e-05 6.17435083053162e-05 6.17265813132754e-05 2.67335670903368e-10 1.95755214840349e-06 1.40105574913152e-06 1.40306874183386e-06 1.40590161913239e-06 1.40872631846429e-06 1.41093060082874e-06 1.41207967234115e-06 1.41188033327313e-06 1.4101516492809e-06 4.68962630555799e-06 0.000351002342680615 0.000238095951014486 0.000238338134818822 0.000238679108788393 0.000239019238319394 0.000239284959287019 0.000239424093383826 0.000239401448933722 0.000239195231478321 0.915297298109937 0.188473653824918 0.340376508638551 0.340723095858899 0.341208437665329 0.341689827993623 0.342062243003785 0.342251461519015 0.342207611579621 0.34189981886268 +AB1_EBV chr6:1412516-4412516 6:2914401:G:A chr6_2914401_G_A chr6 2914401 G A 0.0503909 0.0677083 0.0674605 0.315536 3.37903989382671e-05 0.00184438530310166 0.000575749305072093 -1 NA NA NA 3.37903989382671e-05 0.00184438530310166 0.000575749305072093 -1 NA NA NA 3.50376911289106e-10 4.96758289149142e-05 6.56915862278989e-05 6.57172605597296e-05 6.57532207183963e-05 6.57887312841917e-05 6.58158891851144e-05 6.58290990600566e-05 6.58245890958145e-05 6.58000155287485e-05 2.09034212952765e-11 5.36761997901145e-06 3.53441819355873e-06 3.53981002719482e-06 3.54739911063546e-06 3.55495242620422e-06 3.5608180386453e-06 3.56382125348346e-06 3.56316872122301e-06 3.55837028488939e-06 1.67453037152077e-06 0.000883963392274344 0.000570211614939072 0.000570825147685962 0.000571688993428737 0.000572549442921174 0.00057321911261408 0.000573564973504713 0.000573497202384529 0.000572960109854784 -1.47670769626281 0.330729485650394 0.40397204815025 0.404402500327367 0.405005797061682 0.405602213754799 0.406059458283852 0.406283857214265 0.406212233246936 0.405805239605961 +AB1_EBV chr6:1412516-4412516 6:2914502:C:G chr6_2914502_C_G chr6 2914502 C G 0.00245766 0.209088 0.306687 0.495389 3.9047537953121e-05 0.00438973837463217 0.000320070210425683 -1 NA NA NA 3.9047537953121e-05 0.00438973837463217 0.000320070210425683 -1 NA NA NA 2.93611457820829e-10 1.6136632346308e-05 3.80386339173337e-05 3.80267475798636e-05 3.80099629270098e-05 3.79931496362746e-05 3.79799255720913e-05 3.79728724915218e-05 3.7973735146357e-05 3.79835850669857e-05 5.95215988605005e-11 3.70917890764339e-06 4.40649934645662e-06 4.40962790391042e-06 4.41403798711645e-06 4.41843356693725e-06 4.42186713149864e-06 4.42367232750498e-06 4.42339916298949e-06 4.42076209746486e-06 6.24753246060531e-06 0.00148490108672485 0.00145806488870796 0.0014587742047661 0.00145977378640281 0.00146077082315774 0.001461550840378 0.00146196280796287 0.0014619048298717 0.00146131262253826 -1.65345983946009 -0.793697000984798 -0.142396480346853 -0.142669312665948 -0.143054549454361 -0.143440482085462 -0.143744082152327 -0.143906095325838 -0.143886489351122 -0.143660740246291 +AB1_EBV chr6:1412516-4412516 6:2914521:C:A chr6_2914521_C_A chr6 2914521 C A 0.20614 0.0703608 0.0371003 0.0578935 -6.93534828254422e-06 0.000613286361002598 0.000359322953560004 -1 NA NA NA -6.93534828254422e-06 0.000613286361002598 0.000359322953560004 -1 NA NA NA 1.43860220089813e-09 2.00500835682009e-05 4.24379611194419e-05 4.24317697338114e-05 4.24229792199924e-05 4.24141112696858e-05 4.2407050279112e-05 4.24031542841006e-05 4.24033531754856e-05 4.24082265653458e-05 1.00425433816151e-10 -7.24534959424452e-07 -7.73748294791053e-07 -7.74509417674381e-07 -7.75580896950382e-07 -7.76648408012684e-07 -7.7748073561931e-07 -7.77914685709095e-07 -7.77840636185839e-07 -7.77190673610843e-07 2.99064346024811e-06 0.000225325439176917 0.000201202997636832 0.00020133605363049 0.000201523476548863 0.000201710396361092 0.000201856448338797 0.000201933123478497 0.000201921237009441 0.0002018088618075 -0.0642899333933222 -0.576555667676539 -0.0329555345288934 -0.0330617406250537 -0.0332126789418901 -0.0333652329989018 -0.0334871992913355 -0.0335553653514253 -0.0335537863048128 -0.0334724685389816 +AB1_EBV chr6:1412516-4412516 6:2914554:C:T chr6_2914554_C_T chr6 2914554 C T 0.135995 0.038435 0.0429496 0.370848 6.47053539247435e-05 0.00223777734319599 0.00118259558244027 -1 NA NA NA 6.47053539247435e-05 0.00223777734319599 0.00118259558244027 -1 NA NA NA 3.18689749020099e-10 0.000179061771950524 0.000125039542732018 0.000125179499792941 0.000125376975572424 0.000125573802098581 0.000125726856413785 0.000125805389205695 0.000125788588193547 0.000125663596335013 1.05757319394502e-11 1.69376568691927e-05 5.92538130863974e-06 5.93861193914095e-06 5.95730092452391e-06 5.97597060943443e-06 5.99054552494914e-06 5.99811035205237e-06 5.99669074573156e-06 5.98507507534674e-06 9.6175766833845e-07 0.00137701733722103 0.000620409140951185 0.000621347699584995 0.00062267242076679 0.000623995031064763 0.000625027784623004 0.000625565655334832 0.000625469940626079 0.000624654936818488 -1.57149910479072 1.61294185159444 1.04763122349573 1.04878959712318 1.05042214635872 1.05204729742902 1.05330991974445 1.05395806450647 1.0538213965256 1.05279363140955 +AB1_EBV chr6:1412516-4412516 6:2914711:C:CCT chr6_2914711_C_CCT chr6 2914711 C CCT 0.320268 0.107084 0.0314276 0.000656009 1.00794454196126e-05 0.000672864308448527 0.000452688558775338 -1 NA NA NA 1.00794454196126e-05 0.000672864308448527 0.000452688558775338 -1 NA NA NA 6.11914659554838e-08 3.08908269105225e-05 5.27123673074265e-05 5.27172540270212e-05 5.27239006708949e-05 5.27303941178295e-05 5.27353567648797e-05 5.27378404526941e-05 5.27372196452797e-05 5.27331031379703e-05 6.3388208695703e-09 1.27285056200579e-06 1.09552090789256e-06 1.09683247897076e-06 1.0986735500374e-06 1.10050887668888e-06 1.10194389643366e-06 1.10269929246762e-06 1.10258691219298e-06 1.10149012205341e-06 2.67517074212337e-05 0.000282191907234753 0.000215119636993929 0.0002153036373749 0.000215562279839644 0.000215820285181988 0.000216022181983816 0.000216128707906801 0.000216113399346476 0.000215959815439381 3.68604585289092 -0.144329713316701 0.18385129614376 0.18398369439256 0.184166018796946 0.184345674945186 0.184484309070744 0.184555114723677 0.18454023165196 0.184428566659044 +AB1_EBV chr6:1412516-4412516 6:2914809:ATT:A chr6_2914809_ATT_A chr6 2914809 ATT A 0.000447573 -0.408113 0.842956 0.628283 -7.51047265041005e-05 0.0109514034494035 0.00029793787915644 -1 NA NA NA -7.51047265041005e-05 0.0109514034494035 0.00029793787915644 -1 NA NA NA 2.64208065930658e-10 1.40086248601729e-05 3.5542574882971e-05 3.55291586107761e-05 3.55102126508247e-05 3.54912513681538e-05 3.54763622448605e-05 3.54684571175488e-05 3.54695050079257e-05 3.54807223963272e-05 -1.07011080440611e-10 -6.57193498994277e-06 -8.54707725731676e-06 -8.5527244378763e-06 -8.5606772789815e-06 -8.56860768545149e-06 -8.57481477742161e-06 -8.57810429112542e-06 -8.57767155549499e-06 -8.57300721940919e-06 1.50551291235237e-05 0.00345722524180414 0.0036686736517724 0.00367018759650938 0.00367231949345491 0.00367444568572225 0.0036761100317613 0.00367699193386601 0.00367687539704228 0.0036756240603886 -1.75898023945295 -0.935115788042269 -0.210267535254518 -0.210605379803196 -0.211082521692463 -0.211560127054884 -0.211935205428116 -0.212134348712334 -0.212107916286927 -0.211825316827286 +AB1_EBV chr6:1412516-4412516 6:2914984:C:T chr6_2914984_C_T chr6 2914984 C T 0.000287449 0.354267 0.999662 0.723049 2.703077715997e-05 0.0114938828249797 0.00027396398143209 -1 NA NA NA 2.703077715997e-05 0.0114938828249797 0.00027396398143209 -1 NA NA NA 2.49377474437249e-10 1.20122914886385e-05 3.28004061135531e-05 3.27853154081789e-05 3.2764010103102e-05 3.27426964355368e-05 3.27259666666453e-05 3.27170867158878e-05 3.27182643369172e-05 3.2730867781985e-05 8.56525709482312e-11 2.27070858295486e-06 3.08874315563543e-06 3.09055516420125e-06 3.09310137612001e-06 3.09563882057952e-06 3.09762571652866e-06 3.09868271811578e-06 3.09855490771735e-06 3.09708106554615e-06 1.65152603369177e-05 0.00333543589553106 0.00388477309447274 0.00388594889741285 0.00388760268835554 0.00388925012559928 0.00389053841161184 0.00389122064397984 0.00389113073047462 0.00389016315885473 -1.81674945056399 -1.08885857313042 -0.290557908812972 -0.290978394291082 -0.291572197093555 -0.29216642522216 -0.292632977426566 -0.292880647345178 -0.292847765353393 -0.292496233211677 +AB1_EBV chr6:1412516-4412516 6:2915098:G:A chr6_2915098_G_A chr6 2915098 G A 0.00527826 0.0543171 0.215615 0.801105 -9.76874223221042e-06 0.00254577990784939 0.000278829707978434 -1 NA NA NA -9.76874223221042e-06 0.00254577990784939 0.000278829707978434 -1 NA NA NA 2.42262873180657e-10 1.23875645887906e-05 3.33603046810113e-05 3.33456713272467e-05 3.33250067920336e-05 3.330432922802e-05 3.32880930729057e-05 3.32794671508043e-05 3.32805938368856e-05 3.32928003399584e-05 1.295652743051e-11 -8.03849430033876e-07 -1.11801393012677e-06 -1.11877089860112e-06 -1.11983380012676e-06 -1.12089149424497e-06 -1.12171656441473e-06 -1.12214929538475e-06 -1.12208221811762e-06 -1.12144755768726e-06 3.41909754540966e-06 0.000751860547074559 0.000858931641245195 0.000859218031145905 0.000859620868089426 0.000860022209225979 0.000860336005987524 0.000860501937197444 0.000860479407270481 0.00086024269987228 -1.84569377129065 -1.05809587573848 -0.273632095064505 -0.274031139810482 -0.274594787229997 -0.275158957447462 -0.27560206020752 -0.275837513584008 -0.275806770292984 -0.275473667121246 +AB1_EBV chr6:1412516-4412516 6:2915224:C:T chr6_2915224_C_T chr6 2915224 C T 0.0682216 -0.0937519 0.0584923 0.108977 -5.20821122150971e-06 0.000759432459797402 0.000297929467887204 -1 NA NA NA -5.20821122150971e-06 0.000759432459797402 0.000297929467887204 -1 NA NA NA 8.86204646290237e-10 1.38755065518203e-05 3.55598635899948e-05 3.55458691901148e-05 3.55261005201324e-05 3.55063481147054e-05 3.5490904371254e-05 3.54828262789226e-05 3.54841786182658e-05 3.54962335818677e-05 -8.34908632156713e-11 -4.3910943201162e-07 -5.94966695873379e-07 -5.95295798613142e-07 -5.9575829500644e-07 -5.96222632316608e-07 -5.96593086246553e-07 -5.96802610781167e-07 -5.96805807681173e-07 -5.96573372116411e-07 3.29034782342141e-06 0.000237055757649994 0.000254735053338896 0.000254834640236507 0.000254974779840339 0.000255114813479599 0.000255225044981329 0.000255284621984149 0.000255279476045557 0.000255200670056554 -0.548769259026239 -0.944663822205111 -0.209781231050728 -0.21013515614902 -0.210635204852288 -0.211134852203649 -0.211525379115496 -0.211729305677665 -0.211694305328359 -0.211388240157156 +AB1_EBV chr6:1412516-4412516 6:2915401:C:T chr6_2915401_C_T chr6 2915401 C T 0.0200603 0.111735 0.106574 0.294442 2.65891628161913e-05 0.0020077713393796 0.00040294679285513 -1 NA NA NA 2.65891628161913e-05 0.0020077713393796 0.00040294679285513 -1 NA NA NA 4.07700965734278e-10 2.44724106421007e-05 4.73314047000324e-05 4.73276541540497e-05 4.73223445037227e-05 4.7316985754982e-05 4.73127293219974e-05 4.73104211616356e-05 4.73106421248228e-05 4.73137418639691e-05 4.51133110511089e-11 2.97815421029617e-06 2.94157430655294e-06 2.94440721491119e-06 2.94840324770975e-06 2.95239262933605e-06 2.95551581206691e-06 2.95716627297094e-06 2.95693551488462e-06 2.95456849415166e-06 3.08439022087468e-06 0.000781076959890063 0.000652341106383485 0.000652801889347646 0.000653451763617018 0.000654100709838075 0.000654609010407683 0.000654877985192742 0.000654841122017456 0.000654456890573819 -1.32518318215438 -0.377242602623381 0.0761752166918708 0.0761356706107117 0.0760797265014599 0.0760229850739513 0.075977550276229 0.0759524734576429 0.0759540325158889 0.0759859442442865 +AB1_EBV chr6:1412516-4412516 6:2915430:G:T chr6_2915430_G_T chr6 2915430 G T 0.246598 0.100933 0.0338728 0.0028847 1.43993571296611e-06 0.000398239121275289 0.000277947681035617 -1 NA NA NA 1.43993571296611e-06 0.000398239121275289 0.000277947681035617 -1 NA NA NA 1.95359444118897e-08 1.22955320476787e-05 3.32598606505559e-05 3.32449896815547e-05 3.32239748206454e-05 3.32029577224263e-05 3.31864839176995e-05 3.31777877703217e-05 3.317905715224e-05 3.31916490750607e-05 1.94451230905899e-09 1.15787296945157e-07 1.64947440322177e-07 1.6504072388084e-07 1.6516985957693e-07 1.6529933656796e-07 1.65403292068897e-07 1.65463735006879e-07 1.65468712156058e-07 1.65410804132149e-07 1.46776813293119e-05 0.000116878731773104 0.000134349021559498 0.000134392183985858 0.000134452796106265 0.000134513232529988 0.000134560645405559 0.000134586041806141 0.000134583378036163 0.000134548827726025 2.54429419021292 -1.06555304117893 -0.276647521581845 -0.277055038984506 -0.277631108644985 -0.278207392851923 -0.278659145756337 -0.278897509364558 -0.27886236153174 -0.278516524325726 +AB1_EBV chr6:1412516-4412516 6:2915652:C:G chr6_2915652_C_G chr6 2915652 C G 0.00124761 -0.701166 0.415776 0.091717 -0.00027199989545806 0.0132006112124618 0.000678245680799772 -1 NA NA NA -0.00027199989545806 0.0132006112124618 0.000678245680799772 -1 NA NA NA 9.39384588742169e-10 6.37939353453445e-05 7.671516910991e-05 7.67489388243181e-05 7.67965239366717e-05 7.68440271393261e-05 7.68812340125626e-05 7.69009327205877e-05 7.6898261707839e-05 7.68701825591455e-05 -6.42735476372314e-10 -4.60272210722758e-05 -2.81010998919438e-05 -2.81430624371292e-05 -2.82022796605134e-05 -2.82614948535306e-05 -2.83079517080839e-05 -2.8332590368358e-05 -2.83292911595377e-05 -2.82942615712114e-05 2.44607892199364e-05 0.00655992902413388 0.00403496960382416 0.00403931933825822 0.004045455705724 0.00405158954622103 0.00405640032779591 0.00405895155185838 0.00405861086096073 0.00405498528629517 -0.490492192682643 0.580869139139011 0.559100655149265 0.559580451515449 0.560256520781342 0.560931393109285 0.561459987811208 0.561739887129169 0.56170204193343 0.561303223541298 +AB1_EBV chr6:1412516-4412516 6:2915708:C:T chr6_2915708_C_T chr6 2915708 C T 0.268358 0.0578417 0.0337544 0.0866024 -1.55092260036492e-06 0.000399053682974076 0.000279038690448874 -1 NA NA NA -1.55092260036492e-06 0.000399053682974076 0.000279038690448874 -1 NA NA NA 9.99918434915411e-10 1.243560802191e-05 3.3379819889901e-05 3.33653505888417e-05 3.33449084962539e-05 3.33244451596598e-05 3.33083654268511e-05 3.32998042428375e-05 3.33008838108988e-05 3.33129225685633e-05 5.67792470097502e-11 -1.31052851840977e-07 -1.77031336788425e-07 -1.77166611653612e-07 -1.77355750962205e-07 -1.77543235607044e-07 -1.77688395240212e-07 -1.77762765137038e-07 -1.77747460064138e-07 -1.77630972318274e-07 2.08244294300018e-06 0.000118345449793908 0.000134579726341672 0.000134625602728603 0.000134690086743743 0.000134754291173147 0.000134804427965216 0.000134830835004099 0.000134827025019115 0.000134788913447476 -0.428043450143346 -1.05422501733844 -0.273047283166974 -0.273441154479705 -0.273997765178134 -0.27455513627753 -0.274993248416976 -0.275226599939566 -0.275197292241188 -0.274869447893877 +AB1_EBV chr6:1412516-4412516 6:2915966:T:A chr6_2915966_T_A chr6 2915966 T A 0.00245882 0.210171 0.306692 0.493166 3.92701027237077e-05 0.00439785149583809 0.000320520194884821 -1 NA NA NA 3.92701027237077e-05 0.00439785149583809 0.000320520194884821 -1 NA NA NA 2.94292097139502e-10 1.61795668167075e-05 3.80894059344709e-05 3.80775558887321e-05 3.80608224057336e-05 3.80440601186295e-05 3.80308758920353e-05 3.80238437443115e-05 3.80247031979213e-05 3.80345224615323e-05 5.99684729433109e-11 3.73475040204798e-06 4.43104049842842e-06 4.43419305617215e-06 4.43863698689777e-06 4.44306635199132e-06 4.44652636209089e-06 4.44834552482554e-06 4.44807037697052e-06 4.44541319581013e-06 6.26486940101891e-06 0.00148932064238078 0.00146053952541834 0.00146125220886662 0.00146225654360647 0.00146325832977999 0.0014640420683366 0.00146445600294546 0.00146439774651902 0.00146380270883261 -1.65114435891219 -0.791039850900761 -0.141062621632935 -0.141334084193934 -0.141717387334125 -0.142101387972814 -0.142403474591471 -0.142564688408347 -0.142545197074177 -0.1423206015918 +AB1_EBV chr6:1412516-4412516 6:2916048:T:C chr6_2916048_T_C chr6 2916048 T C 0.0131298 0.210555 0.133103 0.113674 1.16850326021304e-05 0.00172479358807696 0.000297227997039795 -1 NA NA NA 1.16850326021304e-05 0.00172479358807696 0.000297227997039795 -1 NA NA NA 7.32208667558176e-10 1.41088836751237e-05 3.54387090129078e-05 3.54260275712218e-05 3.54080972950051e-05 3.53901497406694e-05 3.5376061220974e-05 3.53685893673649e-05 3.53695947911179e-05 3.53802223669006e-05 1.4525943007589e-10 1.06636629333676e-06 1.32361564115894e-06 1.32468806841809e-06 1.32619359643205e-06 1.32769517608615e-06 1.32887230721187e-06 1.32949842177912e-06 1.32941971911649e-06 1.32853811916089e-06 6.44078982806224e-06 0.000550740041603564 0.000577003314918781 0.000577256969646812 0.00057761377192192 0.000577969673755596 0.000578248449890955 0.000578396376971511 0.000578377155963118 0.000578167815871085 -0.739651622406083 -0.927984342542101 -0.213194107964821 -0.213512316356463 -0.213962325976297 -0.214412827325076 -0.214766473181057 -0.214953998071122 -0.214928682878758 -0.214661860910844 +AB1_EBV chr6:1412516-4412516 6:2916260:G:GT chr6_2916260_G_GT chr6 2916260 G GT 0.341792 0.130362 0.0314309 3.36008e-05 4.16354152320501e-06 0.000467766307919146 0.000321953196178781 -1 NA NA NA 4.16354152320501e-06 0.000467766307919146 0.000321953196178781 -1 NA NA NA 8.59497209082973e-07 1.63936356890018e-05 3.81301738872002e-05 3.81196184125329e-05 3.81046546470492e-05 3.80896300407893e-05 3.80777742469636e-05 3.80713916328134e-05 3.80720403650775e-05 3.80806788282489e-05 1.08143809015176e-07 3.95760299744966e-07 4.56128958390794e-07 4.56516363030521e-07 4.57059793071343e-07 4.57600210214348e-07 4.58020975083182e-07 4.58239807917504e-07 4.58201176240885e-07 4.57870130496292e-07 0.000120149912259846 0.000154870439427054 0.000149886260903151 0.000149965833929052 0.000150077714409609 0.000150189190849025 0.000150276261048877 0.0001503219935621 0.000150314966550464 0.000150248004591374 6.32838569594526 -0.777895797641916 -0.13999287140045 -0.140230039891527 -0.140566413222216 -0.140904285152593 -0.141171069056003 -0.141314994010152 -0.141301065694943 -0.141107798588142 +AB1_EBV chr6:1412516-4412516 6:2916310:C:T chr6_2916310_C_T chr6 2916310 C T 0.017997 0.104869 0.112272 0.350269 -2.06608058363164e-06 0.00127991421863132 0.00027246801160119 -1 NA NA NA -2.06608058363164e-06 0.00127991421863132 0.00027246801160119 -1 NA NA NA 3.49143165505881e-10 1.18679125238671e-05 3.2632254549013e-05 3.26169189667467e-05 3.25952710097641e-05 3.2573613882791e-05 3.25566114476792e-05 3.25475803654816e-05 3.25487625120573e-05 3.25615472502304e-05 3.45132787067508e-11 -1.58827418440601e-07 -2.38338489475163e-07 -2.38361809245648e-07 -2.38395479473152e-07 -2.38427362863984e-07 -2.38449401383151e-07 -2.38456508572611e-07 -2.38445317959044e-07 -2.3841330949699e-07 2.77649313724686e-06 0.000367990900120619 0.000432980305550763 0.000433105021681782 0.000433280448304889 0.000433455130915465 0.000433591631112812 0.00043366377644883 0.000433653963752813 0.00043355098836745 -1.48023510627835 -1.10095065776515 -0.295697603057446 -0.296127968007364 -0.296735640306601 -0.297343782289945 -0.297821363172618 -0.298075088353595 -0.298041879874098 -0.297682774748979 +AB1_EBV chr6:1412516-4412516 6:2916347:C:T chr6_2916347_C_T chr6 2916347 C T 0.00234823 -0.472653 0.319524 0.139076 -7.30572554286086e-05 0.00577508239019442 0.000388321169953576 -1 NA NA NA -7.30572554286086e-05 0.00577508239019442 0.000388321169953576 -1 NA NA NA 6.85520808868472e-10 2.2868798622248e-05 4.57069624728122e-05 4.57020544071268e-05 4.56950926405767e-05 4.56880889393967e-05 4.56825623082732e-05 4.56796131516313e-05 4.56799871004238e-05 4.56841289950174e-05 -3.16876086277397e-10 -7.94803449252908e-06 -8.11205163551567e-06 -8.11973214656119e-06 -8.130556928672e-06 -8.14136422670553e-06 -8.14983138284861e-06 -8.15431809887712e-06 -8.15371694660398e-06 -8.14733269420916e-06 1.46564883619148e-05 0.00220059709444493 0.00188328457825256 0.001884574271071 0.00188639223184881 0.00188820763332014 0.00188963024641197 0.00189038432858177 0.00189028374688367 0.00188921187334649 -0.805538306419943 -0.445015513483716 0.0412518323613069 0.041184142630815 0.0410880529833104 0.040991275198154 0.0409148284635545 0.0408739783371201 0.0408790532144785 0.0409361160965389 +AB1_EBV chr6:1412516-4412516 6:2916373:AG:A chr6_2916373_AG_A chr6 2916373 AG A 0.000633458 0.378783 0.6089 0.533891 6.80076325399599e-05 0.00837578208513209 0.000310595076911557 -1 NA NA NA 6.80076325399599e-05 0.00837578208513209 0.000310595076911557 -1 NA NA NA 2.82344029787875e-10 1.52314386571413e-05 3.69681347368441e-05 3.6955920892769e-05 3.69386700840338e-05 3.69214017424662e-05 3.69078399003114e-05 3.69006400664021e-05 3.69015986878916e-05 3.6911824259152e-05 1.03225036954902e-10 6.28247035175782e-06 7.6961275257194e-06 7.70176953384914e-06 7.7097180876155e-06 7.71764860272493e-06 7.72385925292066e-06 7.72715284259484e-06 7.7267227077645e-06 7.72206040997617e-06 1.1830194013809e-05 0.00276098092003172 0.00279124475241787 0.00279255308801732 0.00279439618701084 0.00279623524135786 0.00279767548721564 0.00279843899835864 0.00279833846850423 0.00279725601392684 -1.69259086954052 -0.851427364906821 -0.170942487387372 -0.171233233235637 -0.171643885040182 -0.17205497689485 -0.172377835971572 -0.172549221446217 -0.172526354760116 -0.172282894380725 +AB1_EBV chr6:1412516-4412516 6:2917032:A:AGT chr6_2917032_A_AGT chr6 2917032 A AGT 0.0680982 -0.0965194 0.0586032 0.0995589 -5.67228412404672e-06 0.00077565669488866 0.00030211835616889 -1 NA NA NA -5.67228412404672e-06 0.00077565669488866 0.00030211835616889 -1 NA NA NA 9.52600995304864e-10 1.42308031348723e-05 3.6038247010799e-05 3.60245211065824e-05 3.60051298055076e-05 3.59857562531494e-05 3.59706146822702e-05 3.59627073189676e-05 3.59640618618359e-05 3.59759265813746e-05 -9.23290858444292e-11 -4.84690774651301e-07 -6.47133510036717e-07 -6.47503854785806e-07 -6.48024417118163e-07 -6.48546824271423e-07 -6.48963039774495e-07 -6.49197352402227e-07 -6.49198512506053e-07 -6.48933509414694e-07 3.48472222779747e-06 0.000245061586619285 0.000259819386500546 0.000259924962621006 0.000260073545200983 0.00026022203960888 0.000260338956286304 0.00026040217319824 0.000260396762721103 0.000260313248205561 -0.476521027518269 -0.919380139346068 -0.196418014179931 -0.196759260029226 -0.197241434204558 -0.197723152303706 -0.198099481564319 -0.198295624588887 -0.198261071517732 -0.197964826024948 +AB1_EBV chr6:1412516-4412516 6:2917176:C:T chr6_2917176_C_T chr6 2917176 C T 0.00910822 -0.09442 0.158339 0.550964 -5.41421170898064e-06 0.00183684381811164 0.0002756075401944 -1 NA NA NA -5.41421170898064e-06 0.00183684381811164 0.0002756075401944 -1 NA NA NA 2.84232871122056e-10 1.21041071443067e-05 3.29944702128207e-05 3.29793530034869e-05 3.29580109574804e-05 3.29366660533178e-05 3.29199227122373e-05 3.29110558340144e-05 3.29122790564568e-05 3.29249636459084e-05 -2.75059829382995e-11 -4.25657770042768e-07 -6.22568345957953e-07 -6.22850021454831e-07 -6.23246251132018e-07 -6.23644423514365e-07 -6.23962855072759e-07 -6.24144638057899e-07 -6.24151420349237e-07 -6.23958477415872e-07 3.10160324945875e-06 0.000534191677338166 0.000620696835564093 0.000620886366756455 0.000621152978432888 0.000621418734081884 0.000621626868351387 0.000621737656185905 0.000621724366873825 0.000621570005169982 -1.68592328980415 -1.08124416098852 -0.284658827520475 -0.285077409368548 -0.285668501050224 -0.28625984591446 -0.286723799812775 -0.286969473406826 -0.286935418001979 -0.286583691244332 +AB1_EBV chr6:1412516-4412516 6:2917233:T:C chr6_2917233_T_C chr6 2917233 T C 0.24434 0.0999066 0.0339502 0.00325327 1.17275027333658e-06 0.000394264827547286 0.000275700504050569 -1 NA NA NA 1.17275027333658e-06 0.000394264827547286 0.000275700504050569 -1 NA NA NA 1.75632579654595e-08 1.21147943333276e-05 3.30022108794099e-05 3.29872041986018e-05 3.29660016367499e-05 3.29447963476298e-05 3.29281712886146e-05 3.29193868298062e-05 3.29206481604014e-05 3.293332313767e-05 1.73093484856806e-09 9.27937305938899e-08 1.34512791773872e-07 1.34587916993572e-07 1.34691492371402e-07 1.34795501405842e-07 1.34879543304851e-07 1.34929456975357e-07 1.34935875093499e-07 1.34893029975727e-07 1.37970324369143e-05 0.000114686143418646 0.00013313386124762 0.000133175189798825 0.000133233233124206 0.000133291095415736 0.00013333646639927 0.000133360733104092 0.000133358107471219 0.000133324921510813 2.43784722260616 -1.08036161148688 -0.284424250069105 -0.284839373749135 -0.28542608014791 -0.286013030071064 -0.286473266322151 -0.286716368748884 -0.286681165173086 -0.286329828223755 +AB1_EBV chr6:1412516-4412516 6:2917240:G:T chr6_2917240_G_T chr6 2917240 G T 0.019097 -0.159466 0.109105 0.143855 -1.06007158704344e-05 0.0014462718648323 0.000302294232483735 -1 NA NA NA -1.06007158704344e-05 0.0014462718648323 0.000302294232483735 -1 NA NA NA 6.26153740838257e-10 1.44071633015345e-05 3.60294952601571e-05 3.60183204861313e-05 3.60025374024845e-05 3.59867629945237e-05 3.5974414300767e-05 3.59679229569778e-05 3.59689346483901e-05 3.5978469812833e-05 -9.45614227094562e-11 -9.42774140466601e-07 -1.20310496862918e-06 -1.2042899547144e-06 -1.20596013986471e-06 -1.20763224967048e-06 -1.20895012347198e-06 -1.20966170492439e-06 -1.20959718085394e-06 -1.20865084641601e-06 4.64312917459456e-06 0.000463145208134987 0.000483564555405223 0.000483806510448037 0.000484147448334549 0.000484488181541861 0.000484755810549468 0.000484898864214593 0.000484882652700948 0.00048468546985797 -0.896121227373675 -0.907063455021076 -0.196660889852437 -0.196931397061284 -0.19731343773209 -0.197695176587837 -0.19799385596227 -0.198150606034225 -0.198125590256057 -0.1978941359327 +AB1_EBV chr6:1412516-4412516 6:2917276:C:T chr6_2917276_C_T chr6 2917276 C T 0.322012 0.110478 0.0313368 0.000422698 1.16203311784586e-05 0.00072476971171035 0.000487556916038523 -1 NA NA NA 1.16203311784586e-05 0.00072476971171035 0.000487556916038523 -1 NA NA NA 9.07661742481001e-08 3.54577585259985e-05 5.64822031250835e-05 5.64917294193233e-05 5.65048911449434e-05 5.65178814771113e-05 5.65279262925007e-05 5.65330884422946e-05 5.65320761040156e-05 5.65240852900257e-05 9.70184583297669e-09 1.55745503383001e-06 1.25118072636648e-06 1.25276882573555e-06 1.25499911161245e-06 1.25722326398891e-06 1.25896298292562e-06 1.25987939423479e-06 1.25974414810072e-06 1.25841584583106e-06 3.35268268988337e-05 0.00031533030047395 0.000229694983463847 0.000229904152209295 0.000230198240225988 0.000230491662996154 0.00023072132284593 0.000230842536310908 0.000230825180163132 0.000230650554226152 4.08032480416118 -0.00644690209912024 0.2529267939592 0.253135137015608 0.253424346235863 0.253710721570567 0.253932958830646 0.254047984566061 0.254026965973055 0.253852000911881 +AB1_EBV chr6:1412516-4412516 6:2917284:G:A chr6_2917284_G_A chr6 2917284 G A 0.000185896 2.17343 1.33618 0.103821 0.000613554969808555 0.0347133916275768 0.000548510584581052 -1 NA NA NA 0.000613554969808555 0.0347133916275768 0.000548510584581052 -1 NA NA NA 8.4773204979451e-10 4.37818021334355e-05 6.30578137241499e-05 6.30722778698699e-05 6.30926174150932e-05 6.31128835806283e-05 6.3128733630544e-05 6.31371227967198e-05 6.31360029299488e-05 6.31240802836088e-05 1.79370456202886e-09 8.949699191577e-05 6.52179650543132e-05 6.53014400084777e-05 6.54191687976645e-05 6.55368291330057e-05 6.56291037498186e-05 6.56780492507771e-05 6.567155176552e-05 6.56020764286465e-05 7.26163392126802e-05 0.0158929736566894 0.0108758088609039 0.0108860145849345 0.010900406902664 0.0109147885991464 0.0109260658449788 0.0109320473330933 0.0109312538622067 0.01092276412053 -0.593152553870173 0.20442926523208 0.363053178106279 0.36332222809547 0.363700907419618 0.364078573063729 0.364374204594942 0.364530795146633 0.364509946503933 0.364287483000271 +AB1_EBV chr6:1412516-4412516 6:2917286:G:A chr6_2917286_G_A chr6 2917286 G A 0.00245976 0.211607 0.306676 0.490192 3.95662131838167e-05 0.00440843832881892 0.000321126231617619 -1 NA NA NA 3.95662131838167e-05 0.00440843832881892 0.000321126231617619 -1 NA NA NA 2.95218797816824e-10 1.62372798357836e-05 3.81578001835832e-05 3.8145998770834e-05 3.81293338499226e-05 3.81126398975393e-05 3.80995090421955e-05 3.80925049378021e-05 3.80933601060031e-05 3.81031383111853e-05 6.0571039331081e-11 3.76880877656163e-06 4.46368651768963e-06 4.4668710239593e-06 4.47136000792566e-06 4.4758343419471e-06 4.47932955082859e-06 4.48116730343495e-06 4.48088951852954e-06 4.47820557190098e-06 6.28796818169363e-06 0.0014951406154105 0.00146376129947197 0.00146447844632928 0.00146548908090669 0.00146649716193881 0.00146728583268409 0.00146770237436583 0.00146764374925418 0.00146704496098117 -1.64800039177406 -0.787479166502865 -0.139268607899495 -0.139538237731458 -0.139918953887551 -0.140300369876369 -0.140600431855955 -0.140760576327229 -0.140741238231277 -0.14051818561178 +AB1_EBV chr6:1412516-4412516 6:2917318:G:A chr6_2917318_G_A chr6 2917318 G A 0.058009 -0.131377 0.0635492 0.0387035 -7.99509123567877e-06 0.00090682772847784 0.000319083731836756 -1 NA NA NA -7.99509123567877e-06 0.00090682772847784 0.000319083731836756 -1 NA NA NA 1.72502156829369e-09 1.62653333570556e-05 3.78964433213557e-05 3.78853134403692e-05 3.78695978162394e-05 3.7853849576543e-05 3.78414495824049e-05 3.7834809455084e-05 3.78355596771822e-05 3.78447033793833e-05 -2.16350082937035e-10 -7.84421219436232e-07 -8.9882425130246e-07 -8.99544960274532e-07 -9.00561224799436e-07 -9.01574155145299e-07 -9.02364627045751e-07 -9.02778153844284e-07 -9.02710464096011e-07 -9.02095829651832e-07 5.82552481850122e-06 0.000310416825672205 0.000300705351122607 0.000300858991487216 0.000301075549948497 0.000301291560771109 0.000301460471977938 0.000301549460046424 0.000301536383244006 0.000301407317389571 0.117277672031676 -0.785752934333665 -0.146141541716107 -0.146395579645013 -0.146754235364545 -0.147113672002027 -0.147396776220942 -0.147548554389052 -0.147531837128308 -0.147323801769661 +AB1_EBV chr6:1412516-4412516 6:2917351:C:T chr6_2917351_C_T chr6 2917351 C T 0.0551008 -0.0252723 0.0655198 0.699705 8.76563114378706e-06 0.000953081915894028 0.000324133599466037 -1 NA NA NA 8.76563114378706e-06 0.000953081915894028 0.000324133599466037 -1 NA NA NA 2.55308349576141e-10 1.64770820887932e-05 3.8498544760935e-05 3.84882018246528e-05 3.84736412993685e-05 3.84590928995726e-05 3.8447696457833e-05 3.84416897867099e-05 3.84425830315233e-05 3.84513011942451e-05 -6.77317053600951e-12 8.35503496407967e-07 9.88349177806006e-07 9.89186716492214e-07 9.90372368094158e-07 9.91559209796093e-07 9.92492417400822e-07 9.92991882622889e-07 9.92935723200553e-07 9.92246925136894e-07 1.11796892423137e-06 0.000324638038118916 0.000316223270509299 0.000316393706294589 0.000316634430626803 0.000316875070328934 0.000317063943593495 0.000317164552651642 0.00031715224106143 0.000317011488610749 -1.79324513204221 -0.772818538324604 -0.130378363475097 -0.130607360246403 -0.130929491861886 -0.131251198503196 -0.131503043786358 -0.131635576107759 -0.131615451449086 -0.131422298142715 +AB1_EBV chr6:1412516-4412516 6:2917734:C:G chr6_2917734_C_G chr6 2917734 C G 0.00245994 0.211399 0.306657 0.490594 3.9524191170592e-05 0.00440673010071969 0.000321045681277887 -1 NA NA NA 3.9524191170592e-05 0.00440673010071969 0.000321045681277887 -1 NA NA NA 2.95091129039371e-10 1.62296994164451e-05 3.81486982592076e-05 3.81368904147737e-05 3.81202164335897e-05 3.81035134521812e-05 3.80903755433228e-05 3.80833677277856e-05 3.80842234498353e-05 3.80940070589232e-05 6.04839396679464e-11 3.76407889292354e-06 4.45904038663407e-06 4.46222044321167e-06 4.46670315578475e-06 4.47117123112336e-06 4.47466154078533e-06 4.47649670406267e-06 4.47621928120657e-06 4.47353905092034e-06 6.28435419419683e-06 0.00149427406313861 0.00146323196856338 0.00146394847452663 0.00146495820496947 0.00146596538275929 0.00146675334579134 0.00146716951316541 0.00146711094031488 0.00146651268904095 -1.64843294008008 -0.787946128299184 -0.13950717013481 -0.139777042428051 -0.140158100645596 -0.140539858357503 -0.140840188064173 -0.141000474072818 -0.140981116047954 -0.140757860005393 +AB1_EBV chr6:1412516-4412516 6:2917881:C:A chr6_2917881_C_A chr6 2917881 C A 0.00116755 0.370974 0.425921 0.383759 3.53736518553954e-05 0.00545300435877033 0.000294806223373634 -1 NA NA NA 3.53736518553954e-05 0.00545300435877033 0.000294806223373634 -1 NA NA NA 3.40527758013535e-10 1.37669358643734e-05 3.51818012726602e-05 3.51682166763565e-05 3.51490289628559e-05 3.51298263665128e-05 3.51147499283518e-05 3.51067488721605e-05 3.51078174978935e-05 3.51191886372793e-05 1.23616403503735e-10 3.09563226436544e-06 4.02551039150873e-06 4.02818215912796e-06 4.03194076257432e-06 4.03568836199183e-06 4.03862275252425e-06 4.04018062501683e-06 4.03998251792172e-06 4.03778840396079e-06 1.02563779922254e-05 0.00170919184224034 0.00182823169391561 0.00182896711066571 0.00183000229100878 0.00183103458991319 0.0018318426997936 0.00183227111349744 0.00183221507839199 0.00183160844974472 -1.50522051711543 -0.952519223989972 -0.220469866027951 -0.22081636908141 -0.221305864754931 -0.221795829164183 -0.222180559793347 -0.222384730765843 -0.222357403332269 -0.222067168807617 +AB1_EBV chr6:1412516-4412516 6:2917970:G:A chr6_2917970_G_A chr6 2917970 G A 0.062377 -0.00141246 0.0610677 0.981547 1.27354036804579e-05 0.00105882371419752 0.00037421893669809 -1 NA NA NA 1.27354036804579e-05 0.00105882371419752 0.00037421893669809 -1 NA NA NA 2.35118899459539e-10 2.16104077010826e-05 4.41025022891234e-05 4.40971333598514e-05 4.40895829848684e-05 4.40820023943699e-05 4.40760067470158e-05 4.40727569685085e-05 4.40730346409258e-05 4.40773046136013e-05 -7.95686349561399e-13 1.37289483938082e-06 1.41555781180205e-06 1.41693236704312e-06 1.41887466937707e-06 1.42081459579131e-06 1.42233290866819e-06 1.42313298367922e-06 1.42301415005418e-06 1.42185015034832e-06 9.26739669098075e-07 0.000398779291250974 0.000345973236210372 0.000346207904069368 0.000346539213308086 0.000346870131954123 0.00034712928751056 0.000347266191582495 0.000347246721450257 0.000347049466693444 -1.87562581937529 -0.50161395275396 0.00551771645585486 0.00543566869900669 0.00532068394824137 0.00520523735131473 0.00511374182841173 0.00506371743170675 0.0050669063026163 0.00513018064624138 +AB1_EBV chr6:1412516-4412516 6:2917981:C:T chr6_2917981_C_T chr6 2917981 C T 0.0106991 -0.179925 0.144395 0.212743 -1.46565807176174e-05 0.00193638244665908 0.000304691406547875 -1 NA NA NA -1.46565807176174e-05 0.00193638244665908 0.000304691406547875 -1 NA NA NA 4.83699583433394e-10 1.47995421524578e-05 3.62857206053768e-05 3.62729810870845e-05 3.62550074572633e-05 3.62370233763348e-05 3.6222902803972e-05 3.62154049104344e-05 3.62163926891588e-05 3.62270121787056e-05 -8.29883274842750e-11 -1.36433698015565e-06 -1.65744443378711e-06 -1.6586210465356e-06 -1.66028304758396e-06 -1.66194249736079e-06 -1.66324242346387e-06 -1.66393134904925e-06 -1.66383901756174e-06 -1.66285693379194e-06 4.90772202982209e-06 0.000633019966572649 0.000646002662206916 0.000646290010074167 0.000646695172156275 0.00064709951297063 0.000647416170251992 0.000647583981357366 0.000647561655030434 0.000647323077262763 -1.15425314209433 -0.880192744763693 -0.189574513510048 -0.189885967007717 -0.190325348593937 -0.190765011444355 -0.191110234953281 -0.191293539992217 -0.191269376694 -0.191009801374269 +AB1_EBV chr6:1412516-4412516 6:2918284:C:A chr6_2918284_C_A chr6 2918284 C A 0.000833908 -0.556691 0.523047 0.287183 -7.44030003889521e-05 0.00777112881458192 0.00032953541860814 -1 NA NA NA -7.44030003889521e-05 0.00777112881458192 0.00032953541860814 -1 NA NA NA 4.06846382975239e-10 1.69954040133585e-05 3.91104286633995e-05 3.90998019339285e-05 3.90847734770854e-05 3.90697107981359e-05 3.90578611687294e-05 3.90515458445335e-05 3.90523375456124e-05 3.90612055195211e-05 -2.20524022350319e-10 -7.18967998108677e-06 -8.37893111831845e-06 -8.38551510128346e-06 -8.39478151687654e-06 -8.40401980457779e-06 -8.41124403165043e-06 -8.41505667879456e-06 -8.41451703711257e-06 -8.40903459522916e-06 1.51066998856523e-05 0.00268035395968752 0.0025741739876467 0.00257554281723802 0.00257747058093055 0.00257939380192304 0.00258089918016679 0.00258169547515111 0.00258158646111776 0.00258044903598945 -1.32728148392639 -0.741846034061399 -0.114609656474713 -0.114841707112959 -0.115169891099532 -0.115498845938077 -0.1157576615097 -0.115895656525368 -0.115878494926097 -0.115685046477238 diff --git a/tests/gentropy/data_samples/finngen_R9_AB1_EBV.SUSIE.snp.bgz b/tests/gentropy/data_samples/finngen_R9_AB1_EBV.SUSIE.snp.bgz new file mode 100644 index 0000000000000000000000000000000000000000..2f298d48bc31d5441209715a24abefbdc1779c86 GIT binary patch literal 35105 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 Z000301^_}s0stET0{{R300000002@G{aye7 literal 0 HcmV?d00001 diff --git a/tests/gentropy/data_samples/finngen_credset_summary_sample.tsv.bgz b/tests/gentropy/data_samples/finngen_credset_summary_sample.tsv.bgz new file mode 100644 index 0000000000000000000000000000000000000000..148f0f22fa564b24d7c9319c85a5fa24e6cd27f1 GIT binary patch literal 1338 zcmV-A1;zRwiwFb&00000{{{d;LjnLD1$|acZ`()=Jx~6N1(L&0-CQ?Kf=!dabr-v* zL7J#p1Fap{Zj0StznGDowyD#DA@W&6iEkd?Xt%jt?$Ty>Sgu#;Zkz75<38>-Rg<*G)X*5AtGm(6nbZw0r@|AzFiUf-8-Ea!;7m6riweXte^FZc58Wp%B(CBb;8+vn1Cnj z+zBi}$E*PqLYPV26Levi!6>qUn#YJx7)C&ZiKpdiw^^^s*W1nVcC|}?T+HXEmw0lf z_Gj(BazM(ooTc0;vW^T)po4G}t}R0*P*w#a%bZ)!U=ai%**JI) zIJ&uF29f6^+?-Emi}{NrAoU{31}YQrF=#BP0-AtD#sr-M1EPU@BmSp!?4G_$;Yi7< z1nR}GW&LcV0jV6IGAn0^Ito&3JV1vaNcCxuC3^@tH~?d9+QSJQ0~JV`UY;Y*Xt03A&qOuJuhRQ&o zD6^D1A#NYGu(bIZS)UB zOlJTNNZoJdA_Os$=Slb&Buu#jFb`3P+@=wYMI#4WP0igx2?_PU2j?d~j+AV35vnaY zSc8@W(wsp$(JVAfpp70vpp1Gj1*k^g0jTvqB48D*+ohI|AkXyh=KNAl{y;3#oAbrA z%ui?U=k*P!C&=N-5)%R)qb3K*pycZ8{GtmUU0pC$T)1Ti3!w4@H4mUp0A(+IA~CC~ z1Bu!;6Dt$vy3rx364mxZUGxa@+ySQZ*ZI}S>$m0V^yYkieKTF0|6NZ1dV4)T-M=)k z6GF}tA{(QGNje}W&PpDY(QwAlFjlClRK)-$2PN4PA@Cy;zZM;tAk8g1OaYZAsEq-2 zOaMMi5b78pGjeSl2r&y8M1YHFgGj^;g~C8VjzP=SZrD5wtL5E+k(a4J>{TIxCwaUk zOw<{oY8KD6z8eH6BLOwrfiS^F#XH^pkwxpl#&qFMGq)f{qnIGiK*~@%$E=aIkDr!zLm9t1p44!0^=@);_J)2#0`+7j zYCe(i+E^fwOyL6do3DUhmhOFzTGB6`e1DIWMLYhC1jddh&~eVA_^9u-i None: """Test finemapping results (SuSie) from source.""" + hl.init(sc=spark.sparkContext, log="/dev/null", idempotent=True) assert isinstance( FinnGenFinemapping.from_finngen_susie_finemapping( spark=spark, - finngen_finemapping_df="tests/gentropy/data_samples/finngen_R9_AB1_EBV.SUSIE.snp.gz", - finngen_finemapping_summaries="tests/gentropy/data_samples/finngen_credset_summary_sample.tsv", - finngen_release_prefix="FINNGEN_R10", + finngen_susie_finemapping_snp_files=finngen_susie_finemapping_snp_files, + finngen_susie_finemapping_cs_summary_files=finngen_susie_finemapping_cs_summary_files, + finngen_release_prefix="FINNGEN_R11", ), StudyLocus, ) diff --git a/tests/gentropy/datasource/finngen/test_finngen_study_index.py b/tests/gentropy/datasource/finngen/test_finngen_study_index.py index 6fc4665dc..5b2be30c4 100644 --- a/tests/gentropy/datasource/finngen/test_finngen_study_index.py +++ b/tests/gentropy/datasource/finngen/test_finngen_study_index.py @@ -3,6 +3,7 @@ from __future__ import annotations from pyspark.sql import SparkSession +from pyspark.sql import types as t from gentropy.dataset.study_index import StudyIndex from gentropy.datasource.finngen.study_index import FinnGenStudyIndex @@ -11,3 +12,75 @@ def test_finngen_study_index_from_source(spark: SparkSession) -> None: """Test study index from source.""" assert isinstance(FinnGenStudyIndex.from_source(spark), StudyIndex) + + +def test_finngen_study_index_add_efos(spark: SparkSession) -> None: + """Test finngen study index add efo ids.""" + study_index_table_data = [ + ( + "AB1_1", + "Actinomycosis", + "FINNGEN_R11", + "gwas", + ), + ( + "AB1_2", + "Some unknown trait", + "FINNGEN_R11", + "gwas", + ), + ( + "AB1_1", + "Some unknown trait", + "FINNGEN_R11", + "gwas", + ), + ( + "AB1_1", + "Bleeding", + "FINNGEN_R11", + "gwas", + ), + ] + study_index_df = spark.createDataFrame( + data=study_index_table_data, + schema=t.StructType( + [ + t.StructField("studyId", t.StringType(), nullable=False), + t.StructField("traitFromSource", t.StringType(), nullable=False), + t.StructField("projectId", t.StringType(), nullable=False), + t.StructField("studyType", t.StringType(), nullable=False), + ] + ), + ) + + curation_table_data = [ + ("FinnGen r11", "Actinomycosis", "http://www.ebi.ac.uk/efo/EFO_0007128"), + ("FinnGen r11", "bleeding", "http://purl.obolibrary.org/obo/MP_0001914"), + ("FinnGen r11", "Bruxism", "http://purl.obolibrary.org/obo/MONDO_0002443"), + ( + "PheWAS 2024", + "20161#Pack years of smoking", + "http://www.ebi.ac.uk/efo/EFO_0005671", + ), + ] + curation_df = spark.createDataFrame( + data=curation_table_data, + schema=t.StructType( + [ + t.StructField("STUDY", t.StringType(), nullable=False), + t.StructField("PROPERTY_VALUE", t.StringType(), nullable=False), + t.StructField("SEMANTIC_TAG", t.StringType(), nullable=False), + ] + ), + ) + + study_index = StudyIndex(_df=study_index_df, _schema=study_index_df.schema) + assert isinstance( + FinnGenStudyIndex.join_efo_mapping( + study_index, + finngen_release_prefix="FINNGEN_R11_", + efo_curation_mapping=curation_df, + ), + StudyIndex, + ) From 2612aa7275f485e46ff2d8d2458debe5e180f2b8 Mon Sep 17 00:00:00 2001 From: Daniel-Considine <113430683+Daniel-Considine@users.noreply.github.com> Date: Fri, 30 Aug 2024 14:30:46 +0100 Subject: [PATCH 018/188] fix: using h4 instead of log2(h4/h3) (#740) --- src/gentropy/method/l2g/feature_factory.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/gentropy/method/l2g/feature_factory.py b/src/gentropy/method/l2g/feature_factory.py index f037b57b4..1158c6067 100644 --- a/src/gentropy/method/l2g/feature_factory.py +++ b/src/gentropy/method/l2g/feature_factory.py @@ -1,4 +1,5 @@ """Collection of methods that extract features from the gentropy datasets to be fed in L2G.""" + from __future__ import annotations from functools import reduce @@ -59,7 +60,7 @@ def _get_max_coloc_per_credible_set( colocalisation_df = colocalisation.df.select( f.col("leftStudyLocusId").alias("studyLocusId"), "rightStudyLocusId", - f.coalesce("log2h4h3", "clpp").alias("score"), + f.coalesce("h4", "clpp").alias("score"), ColocalisationFactory._add_colocalisation_metric(), ) From 93a6e60b86bd43650e3c0d9a64f5c4798084d747 Mon Sep 17 00:00:00 2001 From: Yakov Date: Tue, 3 Sep 2024 11:44:38 +0100 Subject: [PATCH 019/188] fix: adding carma_tau parameter to susie_finemapper (#743) * fix: adding carma_tau parameter to susie_finemapper * fix: changing default * fix: defaults --- src/gentropy/config.py | 1 + src/gentropy/method/carma.py | 15 +++++++++++---- src/gentropy/susie_finemapper.py | 10 +++++++++- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/src/gentropy/config.py b/src/gentropy/config.py index 2d0cf5b8e..22bb3c55c 100644 --- a/src/gentropy/config.py +++ b/src/gentropy/config.py @@ -451,6 +451,7 @@ class FinemapperConfig(StepConfig): sum_pips: float = MISSING susie_est_tausq: bool = MISSING run_carma: bool = MISSING + carma_tau: float = MISSING run_sumstat_imputation: bool = MISSING carma_time_limit: int = MISSING imputed_r2_threshold: float = MISSING diff --git a/src/gentropy/method/carma.py b/src/gentropy/method/carma.py index af8816706..b46f23a56 100644 --- a/src/gentropy/method/carma.py +++ b/src/gentropy/method/carma.py @@ -1,4 +1,5 @@ """CARMA outlier detection method.""" + from __future__ import annotations import concurrent.futures @@ -18,7 +19,10 @@ class CARMA: @staticmethod def time_limited_CARMA_spike_slab_noEM( - z: np.ndarray, ld: np.ndarray, sec_threshold: float = 600 + z: np.ndarray, + ld: np.ndarray, + sec_threshold: float = 600, + tau: float = 0.04, ) -> dict[str, Any]: """The wrapper for the CARMA_spike_slab_noEM function that runs the function in a separate thread and terminates it if it takes too long. @@ -26,6 +30,7 @@ def time_limited_CARMA_spike_slab_noEM( z (np.ndarray): Numeric vector representing z-scores. ld (np.ndarray): Numeric matrix representing the linkage disequilibrium (LD) matrix. sec_threshold (float): The time threshold in seconds. + tau (float): Tuning parameter controlling the level of shrinkage of the LD matrix Returns: dict[str, Any]: A dictionary containing the following results: @@ -38,7 +43,9 @@ def time_limited_CARMA_spike_slab_noEM( try: # Execute CARMA.CARMA_spike_slab_noEM with a timeout with concurrent.futures.ThreadPoolExecutor(max_workers=1) as executor: - future = executor.submit(CARMA.CARMA_spike_slab_noEM, z=z, ld=ld) + future = executor.submit( + CARMA.CARMA_spike_slab_noEM, z=z, ld=ld, tau=tau + ) result = future.result(timeout=sec_threshold) except concurrent.futures.TimeoutError: # If execution exceeds the timeout, return None @@ -71,7 +78,7 @@ def CARMA_spike_slab_noEM( all_inner_iter (int): The number of inner iterations in each CARMA iteration. epsilon_threshold (float): Threshold for convergence in CARMA iterations. num_causal (int): Maximal number of causal variants to be selected in the final model. - tau (float): Tuning parameter controlling the degree of sparsity in the Spike-and-Slab prior. + tau (float): Tuning parameter controlling the level of shrinkage of the LD matrix. outlier_switch (bool): Whether to consider outlier detection in the analysis. outlier_BF_index (float): Bayes Factor threshold for identifying outliers. @@ -604,7 +611,7 @@ def _MCS_modified( # noqa: C901 num_causal (int): Maximal number of causal variants to be selected in the final model. outlier_switch (bool): Whether to consider outlier detection in the analysis. input_conditional_S_list (list[int] | None): The conditional set. Defaults to None. - tau (float): Tuning parameter controlling the degree of sparsity in the Spike-and-Slab prior. + tau (float): Tuning parameter controlling the level of shrinkage of the LD matrix. epsilon (float): Threshold for convergence in CARMA iterations. inner_all_iter (int): The number of inner iterations in each CARMA iteration. outlier_BF_index (float | None): Bayes Factor threshold for identifying outliers. Defaults to None. diff --git a/src/gentropy/susie_finemapper.py b/src/gentropy/susie_finemapper.py index 5ff36a764..f2997eb9f 100644 --- a/src/gentropy/susie_finemapper.py +++ b/src/gentropy/susie_finemapper.py @@ -58,6 +58,7 @@ def __init__( run_carma: bool = False, run_sumstat_imputation: bool = False, carma_time_limit: int = 600, + carma_tau: float = 0.15, imputed_r2_threshold: float = 0.9, ld_score_threshold: float = 5, ) -> None: @@ -79,6 +80,7 @@ def __init__( run_carma (bool): run CARMA, default is False run_sumstat_imputation (bool): run summary statistics imputation, default is False carma_time_limit (int): CARMA time limit, default is 600 seconds + carma_tau (float): CARMA tau, shrinkage parameter imputed_r2_threshold (float): imputed R2 threshold, default is 0.9 ld_score_threshold (float): LD score threshold ofr imputation, default is 5 """ @@ -113,6 +115,7 @@ def __init__( susie_est_tausq=susie_est_tausq, run_carma=run_carma, run_sumstat_imputation=run_sumstat_imputation, + carma_tau=carma_tau, carma_time_limit=carma_time_limit, imputed_r2_threshold=imputed_r2_threshold, ld_score_threshold=ld_score_threshold, @@ -654,6 +657,7 @@ def susie_finemapper_from_prepared_dataframes( run_carma: bool = False, run_sumstat_imputation: bool = False, carma_time_limit: int = 600, + carma_tau: float = 0.04, imputed_r2_threshold: float = 0.8, ld_score_threshold: float = 4, sum_pips: float = 0.99, @@ -677,6 +681,7 @@ def susie_finemapper_from_prepared_dataframes( run_carma (bool): run CARMA, default is False run_sumstat_imputation (bool): run summary statistics imputation, default is False carma_time_limit (int): CARMA time limit, default is 600 seconds + carma_tau (float): CARMA tau, shrinkage parameter imputed_r2_threshold (float): imputed R2 threshold, default is 0.8 ld_score_threshold (float): LD score threshold ofr imputation, default is 4 sum_pips (float): the expected sum of posterior probabilities in the locus, default is 0.99 (99% credible set) @@ -721,7 +726,7 @@ def susie_finemapper_from_prepared_dataframes( if run_carma: carma_output = CARMA.time_limited_CARMA_spike_slab_noEM( - z=z_to_fm, ld=ld_to_fm, sec_threshold=carma_time_limit + z=z_to_fm, ld=ld_to_fm, sec_threshold=carma_time_limit, tau=carma_tau ) if carma_output["Outliers"] != [] and carma_output["Outliers"] is not None: GWAS_df.drop(carma_output["Outliers"], inplace=True) @@ -1225,6 +1230,7 @@ def susie_finemapper_one_sl_row_v4_ss_gathered_boundaries( run_carma: bool = False, run_sumstat_imputation: bool = False, carma_time_limit: int = 600, + carma_tau: float = 0.04, imputed_r2_threshold: float = 0.9, ld_score_threshold: float = 5, sum_pips: float = 0.99, @@ -1245,6 +1251,7 @@ def susie_finemapper_one_sl_row_v4_ss_gathered_boundaries( run_carma (bool): run CARMA, default is False run_sumstat_imputation (bool): run summary statistics imputation, default is False carma_time_limit (int): CARMA time limit, default is 600 seconds + carma_tau (float): CARMA tau, shrinkage parameter imputed_r2_threshold (float): imputed R2 threshold, default is 0.8 ld_score_threshold (float): LD score threshold ofr imputation, default is 4 sum_pips (float): the expected sum of posterior probabilities in the locus, default is 0.99 (99% credible set) @@ -1443,6 +1450,7 @@ def susie_finemapper_one_sl_row_v4_ss_gathered_boundaries( run_carma=run_carma, run_sumstat_imputation=run_sumstat_imputation, carma_time_limit=carma_time_limit, + carma_tau=carma_tau, imputed_r2_threshold=imputed_r2_threshold, ld_score_threshold=ld_score_threshold, sum_pips=sum_pips, From bb8558c526b0532f2ec7d88990f570ed7496f10a Mon Sep 17 00:00:00 2001 From: Daniel Suveges Date: Tue, 3 Sep 2024 13:16:09 +0100 Subject: [PATCH 020/188] feat: logic and airflow pipeline for validation (#730) * refactor: generalised validation logic * refactor: generalised validation logic * fix(airflow): fine-tuning DAG for data validation * fix(validation): study locus uniqueness fixed * feat: add invalid/valid dataset generation in validation steps/dag (#734) * fix: does not belong in this PR * refactor: to be moved to orchestration repo * docs: respective docs pages for the steps * docs: ammend docstrings * revert: maintain dag for now but it should be removed eventually * feat: validate study_locus dataset to produce valid or invalid df * feat: adjust DAG to parametrise dataset validation * fix: duplicated row * feat: increase abstraction of Dataset validation of rows * docs: increase clarity of what the function does * fix: error message * revert: unintended change * test: testing dataset filtering by quality flag --------- Co-authored-by: DSuveges * chore: pre-commit auto fixes [...] --------- Co-authored-by: David Ochoa Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Szymon Szyszkowski <69353402+project-defiant@users.noreply.github.com> --- .../steps/study_locus_validation.md | 5 + docs/python_api/steps/study_validation.md | 5 + src/airflow/dags/data_validation.py | 96 +++++++++++++++++ src/gentropy/config.py | 42 ++++++++ src/gentropy/dataset/dataset.py | 79 ++++++++++++++ src/gentropy/dataset/study_index.py | 46 ++++---- src/gentropy/dataset/study_locus.py | 49 ++++++++- src/gentropy/study_locus_validation.py | 57 ++++++++++ src/gentropy/study_validation.py | 74 +++++++++++++ .../dataset/test_dataset_exclusion.py | 100 ++++++++++++++++++ 10 files changed, 530 insertions(+), 23 deletions(-) create mode 100644 docs/python_api/steps/study_locus_validation.md create mode 100644 docs/python_api/steps/study_validation.md create mode 100644 src/airflow/dags/data_validation.py create mode 100644 src/gentropy/study_locus_validation.py create mode 100644 src/gentropy/study_validation.py create mode 100644 tests/gentropy/dataset/test_dataset_exclusion.py diff --git a/docs/python_api/steps/study_locus_validation.md b/docs/python_api/steps/study_locus_validation.md new file mode 100644 index 000000000..350558806 --- /dev/null +++ b/docs/python_api/steps/study_locus_validation.md @@ -0,0 +1,5 @@ +--- +title: Study-Locus Validation +--- + +::: gentropy.study_locus_validation.StudyLocusValidationStep diff --git a/docs/python_api/steps/study_validation.md b/docs/python_api/steps/study_validation.md new file mode 100644 index 000000000..8e2b68099 --- /dev/null +++ b/docs/python_api/steps/study_validation.md @@ -0,0 +1,5 @@ +--- +title: Study Validation +--- + +::: gentropy.study_validation.StudyValidationStep diff --git a/src/airflow/dags/data_validation.py b/src/airflow/dags/data_validation.py new file mode 100644 index 000000000..875a169dc --- /dev/null +++ b/src/airflow/dags/data_validation.py @@ -0,0 +1,96 @@ +"""DAG to validate study locus and study index datasets.""" + +from __future__ import annotations + +from pathlib import Path + +import common_airflow as common + +from airflow.models.dag import DAG + +CLUSTER_NAME = "otg-validation" + +# Input datasets: +STUDY_INDICES = [ + "gs://gwas_catalog_data/study_index", + "gs://eqtl_catalogue_data/study_index", + "gs://finngen_data/r10/study_index", +] +STUDY_LOCI = [ + "gs://gwas_catalog_data/credible_set_datasets/gwas_catalog_PICSed_curated_associations", + "gs://gwas_catalog_data/credible_set_datasets/gwas_catalog_PICSed_summary_statistics", + "gs://eqtl_catalogue_data/credible_set_datasets/susie", + "gs://finngen_data/r10/credible_set_datasets/finngen_susie_processed", +] +TARGET_INDEX = "gs://genetics_etl_python_playground/releases/24.06/gene_index" +DISEASE_INDEX = "gs://open-targets-pre-data-releases/24.06/output/etl/parquet/diseases" + +# Output datasets: +VALIDATED_STUDY = "gs://ot-team/dsuveges/otg-data/validated_study_index" +INVALID_STUDY = f"{VALIDATED_STUDY}_invalid" +INVALID_STUDY_QC = [ + "UNRESOLVED_TARGET", + "UNRESOLVED_DISEASE", + "UNKNOWN_STUDY_TYPE", + "DUPLICATED_STUDY", + "NO_GENE_PROVIDED", +] + +VALIDATED_STUDY_LOCI = "gs://ot-team/dsuveges/otg-data/validated_credible_set" +INVALID_STUDY_LOCI = f"{VALIDATED_STUDY_LOCI}_invalid" +INVALID_STUDY_LOCUS_QC = [ + "DUPLICATED_STUDYLOCUS_ID", + "AMBIGUOUS_STUDY", + "FAILED_STUDY", + "MISSING_STUDY", + "NO_GENOMIC_LOCATION_FLAG", + "COMPOSITE_FLAG", + "INCONSISTENCY_FLAG", + "PALINDROMIC_ALLELE_FLAG", +] + +with DAG( + dag_id=Path(__file__).stem, + description="Open Targets Genetics — Study locus and study index validation", + default_args=common.shared_dag_args, + **common.shared_dag_kwargs, +) as dag: + # Definition of the study index validation step: + validate_studies = common.submit_step( + cluster_name=CLUSTER_NAME, + step_id="study_validation", + task_id="study_validation", + other_args=[ + f"step.study_index_path={STUDY_INDICES}", + f"step.target_index_path={TARGET_INDEX}", + f"step.disease_index_path={DISEASE_INDEX}", + f"step.valid_study_index_path={VALIDATED_STUDY}", + f"step.invalid_study_index_path={INVALID_STUDY_LOCI}", + f"step.invalid_qc_reasons={INVALID_STUDY_QC}", + ], + ) + + # Definition of the study locus validation step: + validate_study_loci = common.submit_step( + cluster_name=CLUSTER_NAME, + step_id="credible_set_validation", + task_id="credible_set_validation", + other_args=[ + f"step.study_index_path={VALIDATED_STUDY}", + f"step.study_locus_path={STUDY_LOCI}", + f"step.valid_study_locus_path={VALIDATED_STUDY_LOCI}", + f"step.invalid_study_locus_path={INVALID_STUDY_LOCI}", + f"step.invalid_qc_reasons={INVALID_STUDY_LOCUS_QC}", + ], + ) + + ( + common.create_cluster( + CLUSTER_NAME, + master_machine_type="n1-highmem-32", + ) + >> common.install_dependencies(CLUSTER_NAME) + >> validate_studies + >> validate_study_loci + # >> common.delete_cluster(CLUSTER_NAME) + ) diff --git a/src/gentropy/config.py b/src/gentropy/config.py index 22bb3c55c..ed5fe4c81 100644 --- a/src/gentropy/config.py +++ b/src/gentropy/config.py @@ -483,6 +483,38 @@ class CredibleSetQCConfig(StepConfig): _target_: str = "gentropy.credible_set_qc.CredibleSetQCStep" +@dataclass +class StudyValidationStepConfig(StepConfig): + """Configuration of the study index validation step. + + The study indices are read from multiple location, therefore we are expecting a list of paths. + """ + + study_index_path: list[str] = MISSING + target_index_path: str = MISSING + disease_index_path: str = MISSING + valid_study_index_path: str = MISSING + invalid_study_index_path: str = MISSING + invalid_qc_reasons: list[str] = MISSING + _target_: str = "gentropy.study_validation.StudyValidationStep" + + +@dataclass +class StudyLocusValidationStepConfig(StepConfig): + """Configuration of the study index validation step. + + The study locus datasets are read from multiple location, therefore we are expecting a list of paths. + """ + + study_index_path: str = MISSING + study_locus_path: list[str] = MISSING + valid_study_locus_path: str = MISSING + invalid_study_locus_path: str = MISSING + invalid_qc_reasons: list[str] = MISSING + gwas_significance: float = WindowBasedClumpingStepConfig.gwas_significance + _target_: str = "gentropy.study_locus_validation.StudyLocusValidationStep" + + @dataclass class Config: """Application configuration.""" @@ -544,3 +576,13 @@ def register_config() -> None: cs.store( group="step", name="locus_breaker_clumping", node=LocusBreakerClumpingConfig ) + cs.store( + group="step", + name="credible_set_validation", + node=StudyLocusValidationStepConfig, + ) + cs.store( + group="step", + name="study_validation", + node=StudyValidationStepConfig, + ) diff --git a/src/gentropy/dataset/dataset.py b/src/gentropy/dataset/dataset.py index b79930c23..b31537a2a 100644 --- a/src/gentropy/dataset/dataset.py +++ b/src/gentropy/dataset/dataset.py @@ -4,11 +4,13 @@ from abc import ABC, abstractmethod from dataclasses import dataclass +from enum import Enum from functools import reduce from typing import TYPE_CHECKING, Any import pyspark.sql.functions as f from pyspark.sql.types import DoubleType +from pyspark.sql.window import Window from typing_extensions import Self from gentropy.common.schemas import flatten_schema @@ -74,6 +76,24 @@ def get_schema(cls: type[Self]) -> StructType: """ pass + @classmethod + def get_QC_column_name(cls: type[Self]) -> str | None: + """Abstract method to get the QC column name. Assumes None unless overriden by child classes. + + Returns: + str | None: Column name + """ + return None + + @classmethod + def get_QC_categories(cls: type[Self]) -> list[str]: + """Method to get the QC categories for this dataset. Returns empty list unless overriden by child classes. + + Returns: + list[str]: Column name + """ + return [] + @classmethod def from_parquet( cls: type[Self], @@ -170,6 +190,46 @@ def validate_schema(self: Dataset) -> None: f"The following fields present differences in their datatypes: {fields_with_different_observed_datatype}." ) + def valid_rows(self: Self, invalid_flags: list[str], invalid: bool = False) -> Self: + """Filters `Dataset` according to a list of quality control flags. Only `Dataset` classes with a QC column can be validated. + + Args: + invalid_flags (list[str]): List of quality control flags to be excluded. + invalid (bool): If True returns the invalid rows, instead of the valids. Defaults to False. + + Returns: + Self: filtered dataset. + + Raises: + ValueError: If the Dataset does not contain a QC column. + """ + # If the invalid flags are not valid quality checks (enum) for this Dataset we raise an error: + for flag in invalid_flags: + if flag not in self.get_QC_categories(): + raise ValueError( + f"{flag} is not a valid QC flag for {type(self).__name__} ({self.get_QC_categories()})." + ) + + qc_column_name = self.get_QC_column_name() + # If Dataset (class) does not contain QC column we raise an error: + if not qc_column_name: + raise ValueError( + f"{type(self).__name__} objects do not contain a QC column to filter by." + ) + else: + column: str = qc_column_name + # If QC column (nullable) is not available in the dataframe we create an empty array: + qc = f.when(f.col(column).isNull(), f.array()).otherwise(f.col(column)) + + filterCondition = ~f.arrays_overlap( + f.array([f.lit(i) for i in invalid_flags]), qc + ) + # Returning the filtered dataset: + if invalid: + return self.filter(~filterCondition) + else: + return self.filter(filterCondition) + def drop_infinity_values(self: Self, *cols: str) -> Self: """Drop infinity values from Double typed column. @@ -260,3 +320,22 @@ def update_quality_flag( flag_condition, f.array_union(qc, f.array(f.lit(flag_text.value))), ).otherwise(qc) + + @staticmethod + def flag_duplicates(test_column: Column) -> Column: + """Return True for duplicated values in column. + + Args: + test_column (Column): Column to check for duplicates + + Returns: + Column: Column with a boolean flag for duplicates + """ + return ( + f.count(test_column).over( + Window.partitionBy(test_column).rowsBetween( + Window.unboundedPreceding, Window.unboundedFollowing + ) + ) + > 1 + ) diff --git a/src/gentropy/dataset/study_index.py b/src/gentropy/dataset/study_index.py index e8c787ed6..f60b2135c 100644 --- a/src/gentropy/dataset/study_index.py +++ b/src/gentropy/dataset/study_index.py @@ -10,7 +10,6 @@ from typing import TYPE_CHECKING from pyspark.sql import functions as f -from pyspark.sql.window import Window from gentropy.assets import data from gentropy.common.schemas import parse_spark_schema @@ -109,6 +108,24 @@ def get_schema(cls: type[StudyIndex]) -> StructType: """ return parse_spark_schema("study_index.json") + @classmethod + def get_QC_column_name(cls: type[StudyIndex]) -> str: + """Return the name of the quality control column. + + Returns: + str: The name of the quality control column. + """ + return "qualityControls" + + @classmethod + def get_QC_categories(cls: type[StudyIndex]) -> list[str]: + """Return the quality control categories. + + Returns: + list[str]: The quality control categories. + """ + return [member.value for member in StudyQualityCheck] + @classmethod def aggregate_and_map_ancestries( cls: type[StudyIndex], discovery_samples: Column @@ -197,7 +214,7 @@ def is_quality_flagged(self: StudyIndex) -> Column: if "qualityControls" not in self.df.columns: return f.lit(False) else: - return f.size(self.df.qualityControls) != 0 + return f.size(self.df["qualityControls"]) != 0 def has_summarystats(self: StudyIndex) -> Column: """Return a boolean column indicating if a study has harmonized summary statistics. @@ -213,30 +230,17 @@ def validate_unique_study_id(self: StudyIndex) -> StudyIndex: Returns: StudyIndex: with flagged duplicated studies. """ - validated_df = ( - self.df.withColumn( - "isDuplicated", - f.when( - f.count("studyType").over( - Window.partitionBy("studyId").rowsBetween( - Window.unboundedPreceding, Window.unboundedFollowing - ) - ) - > 1, - True, - ).otherwise(False), - ) - .withColumn( + return StudyIndex( + _df=self.df.withColumn( "qualityControls", - StudyIndex.update_quality_flag( + self.update_quality_flag( f.col("qualityControls"), - f.col("isDuplicated"), + self.flag_duplicates(f.col("studyId")), StudyQualityCheck.DUPLICATED_STUDY, ), - ) - .drop("isDuplicated") + ), + _schema=StudyIndex.get_schema(), ) - return StudyIndex(_df=validated_df, _schema=StudyIndex.get_schema()) def _normalise_disease( self: StudyIndex, diff --git a/src/gentropy/dataset/study_locus.py b/src/gentropy/dataset/study_locus.py index 05e6514cc..47a73c665 100644 --- a/src/gentropy/dataset/study_locus.py +++ b/src/gentropy/dataset/study_locus.py @@ -8,7 +8,7 @@ import numpy as np import pyspark.sql.functions as f -from pyspark.sql.types import FloatType +from pyspark.sql.types import FloatType, StringType from gentropy.common.schemas import parse_spark_schema from gentropy.common.spark_helpers import ( @@ -46,6 +46,7 @@ class StudyLocusQualityCheck(Enum): NOT_QUALIFYING_LD_BLOCK (str): LD block does not contain variants at the required R^2 threshold FAILED_STUDY (str): Flagging study loci if the study has failed QC MISSING_STUDY (str): Flagging study loci if the study is not found in the study index as a reference + DUPLICATED_STUDYLOCUS_ID (str): Study-locus identifier is not unique. """ SUBSIGNIFICANT_FLAG = "Subsignificant p-value" @@ -63,6 +64,7 @@ class StudyLocusQualityCheck(Enum): ) FAILED_STUDY = "Study has failed quality controls" MISSING_STUDY = "Study not found in the study index" + DUPLICATED_STUDYLOCUS_ID = "Non-unique study locus identifier" class CredibleInterval(Enum): @@ -99,9 +101,16 @@ def validate_study(self: StudyLocus, study_index: StudyIndex) -> StudyLocus: Returns: StudyLocus: Updated study locus with quality control flags. """ + # Quality controls is not a mandatory field in the study index schema, so we have to be ready to handle it: + qc_select_expression = ( + f.col("qualityControls") + if "qualityControls" in study_index.df.columns + else f.lit(None).cast(StringType()) + ) + study_flags = study_index.df.select( f.col("studyId").alias("study_studyId"), - f.col("qualityControls").alias("study_qualityControls"), + qc_select_expression.alias("study_qualityControls"), ) return StudyLocus( @@ -159,6 +168,24 @@ def validate_lead_pvalue(self: StudyLocus, pvalue_cutoff: float) -> StudyLocus: _schema=self.get_schema(), ) + def validate_unique_study_locus_id(self: StudyLocus) -> StudyLocus: + """Validating the uniqueness of study-locus identifiers and flagging duplicated studyloci. + + Returns: + StudyLocus: with flagged duplicated studies. + """ + return StudyLocus( + _df=self.df.withColumn( + "qualityControls", + self.update_quality_flag( + f.col("qualityControls"), + self.flag_duplicates(f.col("studyLocusId")), + StudyLocusQualityCheck.DUPLICATED_STUDYLOCUS_ID, + ), + ), + _schema=StudyLocus.get_schema(), + ) + @staticmethod def _qc_subsignificant_associations( quality_controls_column: Column, @@ -375,6 +402,24 @@ def get_schema(cls: type[StudyLocus]) -> StructType: """ return parse_spark_schema("study_locus.json") + @classmethod + def get_QC_column_name(cls: type[StudyLocus]) -> str: + """Quality control column. + + Returns: + str: Name of the quality control column. + """ + return "qualityControls" + + @classmethod + def get_QC_categories(cls: type[StudyLocus]) -> list[str]: + """Quality control categories. + + Returns: + list[str]: List of quality control categories. + """ + return [member.value for member in StudyLocusQualityCheck] + def filter_by_study_type( self: StudyLocus, study_type: str, study_index: StudyIndex ) -> StudyLocus: diff --git a/src/gentropy/study_locus_validation.py b/src/gentropy/study_locus_validation.py new file mode 100644 index 000000000..06995290c --- /dev/null +++ b/src/gentropy/study_locus_validation.py @@ -0,0 +1,57 @@ +"""Step to validate study locus dataset against study index.""" + +from __future__ import annotations + +from gentropy.common.session import Session +from gentropy.dataset.study_index import StudyIndex +from gentropy.dataset.study_locus import StudyLocus + + +class StudyLocusValidationStep: + """Study index validation step. + + This step reads and outputs a study index dataset with flagged studies + when target of disease validation fails. + """ + + def __init__( + self, + session: Session, + study_index_path: str, + study_locus_path: list[str], + gwas_significance: float, + valid_study_locus_path: str, + invalid_study_locus_path: str, + invalid_qc_reasons: list[str] = [], + ) -> None: + """Initialize step. + + Args: + session (Session): Session object. + study_index_path (str): Path to study index file. + study_locus_path (list[str]): Path to study locus dataset. + gwas_significance (float): GWAS significance threshold. + valid_study_locus_path (str): Path to write the valid records. + invalid_study_locus_path (str): Path to write the output file. + invalid_qc_reasons (list[str]): List of invalid quality check reason names from `StudyLocusQualityCheck` (e.g. ['SUBSIGNIFICANT_FLAG']). + """ + # Reading datasets: + study_index = StudyIndex.from_parquet(session, study_index_path) + + # Running validation then writing output: + study_locus_with_qc = ( + StudyLocus.from_parquet(session, list(study_locus_path)) + .validate_lead_pvalue( + pvalue_cutoff=gwas_significance + ) # Flagging study locus with subsignificant p-values + .validate_study(study_index) # Flagging studies not in study index + .validate_unique_study_locus_id() # Flagging duplicated study locus ids + ).persist() # we will need this for 2 types of outputs + + study_locus_with_qc.valid_rows(invalid_qc_reasons).df.write.parquet( + invalid_study_locus_path + ) + + study_locus_with_qc.valid_rows( + invalid_qc_reasons, invalid=True + ).df.write.parquet(valid_study_locus_path) diff --git a/src/gentropy/study_validation.py b/src/gentropy/study_validation.py new file mode 100644 index 000000000..5bfb83fe0 --- /dev/null +++ b/src/gentropy/study_validation.py @@ -0,0 +1,74 @@ +"""Step to validate study index against disease and target index.""" + +from __future__ import annotations + +from pyspark.sql import functions as f + +from gentropy.common.session import Session +from gentropy.dataset.gene_index import GeneIndex +from gentropy.dataset.study_index import StudyIndex + + +class StudyValidationStep: + """Study index validation step. + + This step reads and outputs a study index dataset with flagged studies + when target of disease validation fails. + """ + + def __init__( + self, + session: Session, + study_index_path: list[str], + target_index_path: str, + disease_index_path: str, + valid_study_index_path: str, + invalid_study_index_path: str, + invalid_qc_reasons: list[str] = [], + ) -> None: + """Initialize step. + + Args: + session (Session): Session object. + study_index_path (list[str]): Path to study index file. + target_index_path (str): Path to target index file. + disease_index_path (str): Path to disease index file. + valid_study_index_path (str): Path to write the valid records. + invalid_study_index_path (str): Path to write the output file. + invalid_qc_reasons (list[str]): List of invalid quality check reason names from `StudyQualityCheck` (e.g. ['DUPLICATED_STUDY']). + """ + # Reading datasets: + target_index = GeneIndex.from_parquet(session, target_index_path) + # Reading disease index and pre-process. + # This logic does not belong anywhere, but gentorpy has no disease dataset yet. + disease_index = ( + session.spark.read.parquet(disease_index_path) + .select( + f.col("id").alias("diseaseId"), + f.explode_outer( + f.when( + f.col("obsoleteTerms").isNotNull(), + f.array_union(f.array("id"), f.col("obsoleteTerms")), + ) + ).alias("efo"), + ) + .withColumn("efo", f.coalesce(f.col("efo"), f.col("diseaseId"))) + ) + study_index = StudyIndex.from_parquet(session, list(study_index_path)) + + # Running validation: + study_index_with_qc = ( + study_index.validate_disease(disease_index) + .validate_unique_study_id() # Flagging duplicated study ids + .validate_study_type() # Flagging non-supported study types. + .validate_target(target_index) # Flagging QTL studies with invalid targets + .validate_disease(disease_index) # Flagging invalid EFOs + ).persist() # we will need this for 2 types of outputs + + study_index_with_qc.valid_rows( + invalid_qc_reasons, invalid=True + ).df.write.parquet(invalid_study_index_path) + + study_index_with_qc.valid_rows(invalid_qc_reasons).df.write.parquet( + valid_study_index_path + ) diff --git a/tests/gentropy/dataset/test_dataset_exclusion.py b/tests/gentropy/dataset/test_dataset_exclusion.py new file mode 100644 index 000000000..361398f34 --- /dev/null +++ b/tests/gentropy/dataset/test_dataset_exclusion.py @@ -0,0 +1,100 @@ +"""Test dataset validation/exclusion.""" + +from __future__ import annotations + +import pyspark.sql.functions as f +import pytest +from pyspark.sql import SparkSession + +from gentropy.dataset.study_index import StudyIndex, StudyQualityCheck + + +class TestDataExclusion: + """Testing Dataset exclusion. + + Calling `dataset.valid_rows` methods on a mock datasets to test if + the right rows are excluded. + """ + + CORRECT_FILTER = ["The identifier of this study is not unique."] + INCORRECT_FILTER = ["Some mock flag."] + ALL_FILTERS = [member.value for member in StudyQualityCheck] + + DATASET = [ + # Good study no flag: + ("S1", None), + # Good study permissive flag: + ("S2", "This type of study is not supported."), + ("S2", "No valid disease identifier found."), + # Bad study: + ("S3", "The identifier of this study is not unique."), + ("S3", "This type of study is not supported."), + ] + + @pytest.fixture(autouse=True) + def _setup(self: TestDataExclusion, spark: SparkSession) -> None: + """Setup study the mock index for testing.""" + self.study_index = StudyIndex( + _df=( + spark.createDataFrame(self.DATASET, ["studyId", "flag"]) + .groupBy("studyId") + .agg(f.collect_list("flag").alias("qualityControls")) + .select( + "studyId", + "qualityControls", + f.lit("project1").alias("projectId"), + f.lit("gwas").alias("studyType"), + ) + ), + _schema=StudyIndex.get_schema(), + ) + + @pytest.mark.parametrize( + "filter_, expected", + [ + (CORRECT_FILTER, ["S1", "S2"]), + (ALL_FILTERS, ["S1"]), + ], + ) + def test_valid_rows( + self: TestDataExclusion, filter_: list[str], expected: list[str] + ) -> None: + """Test valid rows.""" + passing_studies = [ + study["studyId"] + for study in self.study_index.valid_rows( + filter_, invalid=False + ).df.collect() + ] + + assert passing_studies == expected + + @pytest.mark.parametrize( + "filter_, expected", + [ + (CORRECT_FILTER, ["S3"]), + (ALL_FILTERS, ["S2", "S3"]), + ], + ) + def test_invalid_rows( + self: TestDataExclusion, filter_: list[str], expected: list[str] + ) -> None: + """Test invalid rows.""" + failing_studies = [ + study["studyId"] + for study in self.study_index.valid_rows(filter_, invalid=True).df.collect() + ] + + assert failing_studies == expected + + def test_failing_quality_flag(self: TestDataExclusion) -> None: + """Test invalid quality flag.""" + with pytest.raises(ValueError): + self.study_index.valid_rows( + self.INCORRECT_FILTER, invalid=True + ).df.collect() + + with pytest.raises(ValueError): + self.study_index.valid_rows( + self.INCORRECT_FILTER, invalid=False + ).df.collect() From 1a7b0d7cccc29a1d628ce0af93d8a210d17d53bb Mon Sep 17 00:00:00 2001 From: Daniel Suveges Date: Tue, 3 Sep 2024 14:48:42 +0100 Subject: [PATCH 021/188] feat(variant index): improved data structure (#710) * feat(variant index): upating schema and logic * feat(variant index): vep transcript annotation improved with consequence score + transcript index * refactor: removed hardcoded schema definition from parser * fix(test): fixing mock variant index * fix: schema extraction fixed * fix: doctest issue resolved * fix: updating vep command in the DAG * fix: removing un-used sequence ontology terms * fix: adding example to sorter method + changing variable names --------- Co-authored-by: Szymon Szyszkowski <69353402+project-defiant@users.noreply.github.com> --- src/airflow/dags/variant_index.py | 8 + src/gentropy/assets/data/so_mappings.json | 43 ----- .../data/variant_consequence_to_score.tsv | 46 +++++ .../assets/schemas/variant_index.json | 38 +++- .../assets/schemas/vep_json_output.json | 42 +++++ src/gentropy/common/spark_helpers.py | 90 +++++++++- src/gentropy/datasource/ensembl/vep_parser.py | 169 ++++++++++-------- tests/gentropy/conftest.py | 7 +- tests/gentropy/data_samples/vep_sample.jsonl | 4 +- .../datasource/ensembl/test_vep_variants.py | 2 +- 10 files changed, 322 insertions(+), 127 deletions(-) delete mode 100644 src/gentropy/assets/data/so_mappings.json create mode 100644 src/gentropy/assets/data/variant_consequence_to_score.tsv diff --git a/src/airflow/dags/variant_index.py b/src/airflow/dags/variant_index.py index 9d0736632..98ba48198 100644 --- a/src/airflow/dags/variant_index.py +++ b/src/airflow/dags/variant_index.py @@ -242,10 +242,18 @@ def vep_annotation(pm: PathManager, **kwargs: Any) -> None: --dir_plugins {pm.cache_dir}/VEP_plugins \ --sift b \ --polyphen b \ + --fasta {pm.cache_dir}/Homo_sapiens.GRCh38.dna.primary_assembly.fa.gz \ + --mane_select \ + --appris \ + --hgvsg \ + --pick_order mane_select,canonical \ + --per_gene \ --uniprot \ --check_existing \ --exclude_null_alleles \ --canonical \ + --plugin TSSDistance \ + --distance 500000 \ --plugin LoF,loftee_path:{pm.cache_dir}/VEP_plugins,gerp_bigwig:{pm.cache_dir}/gerp_conservation_scores.homo_sapiens.GRCh38.bw,human_ancestor_fa:{pm.cache_dir}/human_ancestor.fa.gz,conservation_file:/opt/vep/loftee.sql \ --plugin AlphaMissense,file={pm.cache_dir}/AlphaMissense_hg38.tsv.gz,transcript_match=1 \ --plugin CADD,snv={pm.cache_dir}/CADD_GRCh38_whole_genome_SNVs.tsv.gz", diff --git a/src/gentropy/assets/data/so_mappings.json b/src/gentropy/assets/data/so_mappings.json deleted file mode 100644 index 8a087b6f7..000000000 --- a/src/gentropy/assets/data/so_mappings.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "transcript_ablation": "SO_0001893", - "splice_acceptor_variant": "SO_0001574", - "splice_donor_variant": "SO_0001575", - "stop_gained": "SO_0001587", - "frameshift_variant": "SO_0001589", - "stop_lost": "SO_0001578", - "start_lost": "SO_0002012", - "transcript_amplification": "SO_0001889", - "feature_elongation": "SO_0001907", - "feature_truncation": "SO_0001906", - "inframe_insertion": "SO_0001821", - "inframe_deletion": "SO_0001822", - "missense_variant": "SO_0001583", - "protein_altering_variant": "SO_0001818", - "splice_donor_5th_base_variant": "SO_0001787", - "splice_region_variant": "SO_0001630", - "splice_donor_region_variant": "SO_0002170", - "splice_polypyrimidine_tract_variant": "SO_0002169", - "incomplete_terminal_codon_variant": "SO_0001626", - "start_retained_variant": "SO_0002019", - "stop_retained_variant": "SO_0001567", - "synonymous_variant": "SO_0001819", - "coding_sequence_variant": "SO_0001580", - "mature_miRNA_variant": "SO_0001620", - "5_prime_UTR_variant": "SO_0001623", - "3_prime_UTR_variant": "SO_0001624", - "non_coding_transcript_exon_variant": "SO_0001792", - "intron_variant": "SO_0001627", - "NMD_transcript_variant": "SO_0001621", - "non_coding_transcript_variant": "SO_0001619", - "coding_transcript_variant": "SO_0001968", - "upstream_gene_variant": "SO_0001631", - "downstream_gene_variant": "SO_0001632", - "TFBS_ablation": "SO_0001895", - "TFBS_amplification": "SO_0001892", - "TF_binding_site_variant": "SO_0001782", - "regulatory_region_ablation": "SO_0001894", - "regulatory_region_amplification": "SO_0001891", - "regulatory_region_variant": "SO_0001566", - "intergenic_variant": "SO_0001628", - "sequence_variant": "SO_0001060" -} diff --git a/src/gentropy/assets/data/variant_consequence_to_score.tsv b/src/gentropy/assets/data/variant_consequence_to_score.tsv new file mode 100644 index 000000000..589a855e6 --- /dev/null +++ b/src/gentropy/assets/data/variant_consequence_to_score.tsv @@ -0,0 +1,46 @@ +variantFunctionalConsequenceId label score +SO_0001893 transcript_ablation 1.0 +ECO_0000205 curator_inference +SO_0002165 trinucleotide_repeat_expansion +SO_0001574 splice_acceptor_variant 1.0 +SO_0001575 splice_donor_variant 1.0 +SO_0001587 stop_gained 1.0 +SO_0001589 frameshift_variant 1.0 +SO_0002012 start_lost 1.0 +SO_0001578 stop_lost 1.0 +SO_0001889 transcript_amplification 1.0 +SO_0001894 regulatory_region_ablation 0.66 +SO_0001583 missense_variant 0.66 +SO_0001818 protein_altering_variant 0.66 +SO_0001821 inframe_insertion 0.66 +SO_0001822 inframe_deletion 0.66 +SO_0001582 initiator_codon_variant +SO_0001630 splice_region_variant 0.33 +SO_0001626 incomplete_terminal_codon_variant 0.33 +SO_0001567 stop_retained_variant 0.33 +SO_0001819 synonymous_variant 0.33 +SO_0002019 start_retained_variant 0.33 +SO_0001619 non_coding_transcript_variant 0.0 +SO_0001620 mature_miRNA_variant 0.0 +SO_0001621 NMD_transcript_variant 0.1 +SO_0001623 5_prime_UTR_variant 0.1 +SO_0001624 3_prime_UTR_variant 0.1 +SO_0001627 intron_variant 0.1 +SO_0001792 non_coding_transcript_exon_variant 0.0 +SO_0001580 coding_sequence_variant 0.0 +SO_0001566 regulatory_region_variant 0.0 +SO_0001631 upstream_gene_variant 0.0 +SO_0001632 downstream_gene_variant 0.0 +SO_0001782 TF_binding_site_variant 0.0 +SO_0001891 regulatory_region_amplification 0.0 +SO_0001892 TFBS_amplification 0.0 +SO_0001895 TFBS_ablation 0.0 +SO_0001906 feature_truncation 0.0 +SO_0001907 feature_elongation 0.0 +SO_0001628 intergenic_variant 0.0 +SO_0001060 sequence_variant +SO_0001825 conservative_inframe_deletion +SO_0001787 splice_donor_5th_base_variant 0.66 +SO_0002170 splice_donor_region_variant 0.33 +SO_0002169 splice_polypyrimidine_tract_variant 0.33 +SO_0001968 coding_transcript_variant 0.1 diff --git a/src/gentropy/assets/schemas/variant_index.json b/src/gentropy/assets/schemas/variant_index.json index 16b1c1b11..6d5e211ac 100644 --- a/src/gentropy/assets/schemas/variant_index.json +++ b/src/gentropy/assets/schemas/variant_index.json @@ -128,10 +128,28 @@ }, { "metadata": {}, - "name": "distance", + "name": "distanceFromFootprint", "nullable": true, "type": "long" }, + { + "metadata": {}, + "name": "distanceFromTss", + "nullable": true, + "type": "long" + }, + { + "metadata": {}, + "name": "appris", + "nullable": true, + "type": "string" + }, + { + "metadata": {}, + "name": "maneSelect", + "nullable": true, + "type": "string" + }, { "metadata": {}, "name": "targetId", @@ -162,6 +180,18 @@ "nullable": true, "type": "float" }, + { + "metadata": {}, + "name": "consequenceScore", + "nullable": true, + "type": "float" + }, + { + "metadata": {}, + "name": "transcriptIndex", + "nullable": true, + "type": "integer" + }, { "metadata": {}, "name": "transcriptId", @@ -184,6 +214,12 @@ "type": "array" } }, + { + "metadata": {}, + "name": "hgvsId", + "nullable": true, + "type": "string" + }, { "name": "alleleFrequencies", "type": { diff --git a/src/gentropy/assets/schemas/vep_json_output.json b/src/gentropy/assets/schemas/vep_json_output.json index ecad3ea1e..43c3f4ad7 100644 --- a/src/gentropy/assets/schemas/vep_json_output.json +++ b/src/gentropy/assets/schemas/vep_json_output.json @@ -20,6 +20,12 @@ "containsNull": true, "elementType": { "fields": [ + { + "metadata": {}, + "name": "hgvsg", + "nullable": true, + "type": "string" + }, { "metadata": {}, "name": "cadd_phred", @@ -316,6 +322,42 @@ "nullable": true, "type": "string" }, + { + "metadata": {}, + "name": "hgvsg", + "nullable": true, + "type": "string" + }, + { + "metadata": {}, + "name": "hgvsc", + "nullable": true, + "type": "string" + }, + { + "metadata": {}, + "name": "hgvsp", + "nullable": true, + "type": "string" + }, + { + "metadata": {}, + "name": "appris", + "nullable": true, + "type": "string" + }, + { + "metadata": {}, + "name": "mane_select", + "nullable": true, + "type": "string" + }, + { + "metadata": {}, + "name": "tssdistance", + "nullable": true, + "type": "long" + }, { "metadata": {}, "name": "cadd_phred", diff --git a/src/gentropy/common/spark_helpers.py b/src/gentropy/common/spark_helpers.py index 4b22e00c2..65d3ae17b 100644 --- a/src/gentropy/common/spark_helpers.py +++ b/src/gentropy/common/spark_helpers.py @@ -5,7 +5,8 @@ import re import sys from functools import reduce, wraps -from typing import TYPE_CHECKING, Any, Callable, Iterable, Optional, TypeVar +from itertools import chain +from typing import TYPE_CHECKING, Any, Callable, Dict, Iterable, Optional, TypeVar import pyspark.sql.functions as f import pyspark.sql.types as t @@ -375,6 +376,93 @@ def order_array_of_structs_by_field(column_name: str, field_name: str) -> Column ) +def order_array_of_structs_by_two_fields( + array_name: str, descending_column: str, ascending_column: str +) -> Column: + """Sort array of structs by a field in descending order and by an other field in an ascending order. + + This function doesn't deal with null values, assumes the sort columns are not nullable. + + Args: + array_name (str): Column name with array of structs + descending_column (str): Name of the first keys sorted in descending order + ascending_column (str): Name of the second keys sorted in ascending order + + Returns: + Column: Sorted column + + Examples: + >>> data = [(1.0, 45, 'First'), (0.5, 232, 'Third'), (0.5, 233, 'Fourth'), (1.0, 125, 'Second'),] + >>> ( + ... spark.createDataFrame(data, ['col1', 'col2', 'ranking']) + ... .groupBy(f.lit('c')) + ... .agg(f.collect_list(f.struct('col1','col2', 'ranking')).alias('list')) + ... .select(order_array_of_structs_by_two_fields('list', 'col1', 'col2').alias('sorted_list')) + ... .show(truncate=False) + ... ) + +-----------------------------------------------------------------------------+ + |sorted_list | + +-----------------------------------------------------------------------------+ + |[{1.0, 45, First}, {1.0, 125, Second}, {0.5, 232, Third}, {0.5, 233, Fourth}]| + +-----------------------------------------------------------------------------+ + + """ + return f.expr( + f""" + array_sort( + {array_name}, + (left, right) -> case + when left.{descending_column} is null and right.{descending_column} is null then 0 + when left.{ascending_column} is null and right.{ascending_column} is null then 0 + + when left.{descending_column} is null then 1 + when right.{descending_column} is null then -1 + + when left.{ascending_column} is null then 1 + when right.{ascending_column} is null then -1 + + when left.{descending_column} < right.{descending_column} then 1 + when left.{descending_column} > right.{descending_column} then -1 + when left.{descending_column} == right.{descending_column} and left.{ascending_column} > right.{ascending_column} then 1 + when left.{descending_column} == right.{descending_column} and left.{ascending_column} < right.{ascending_column} then -1 + end) + """ + ) + +def map_column_by_dictionary(col: Column, mapping_dict: Dict[str, str]) -> Column: + """Map column values to dictionary values by key. + + Missing consequence label will be converted to None, unmapped consequences will be mapped as None. + + Args: + col (Column): Column containing labels to map. + mapping_dict (Dict[str, str]): Dictionary with mapping key/value pairs. + + Returns: + Column: Column with mapped values. + + Examples: + >>> data = [('consequence_1',),('unmapped_consequence',),(None,)] + >>> m = {'consequence_1': 'SO:000000'} + >>> ( + ... spark.createDataFrame(data, ['label']) + ... .select('label',map_column_by_dictionary(f.col('label'),m).alias('id')) + ... .show() + ... ) + +--------------------+---------+ + | label| id| + +--------------------+---------+ + | consequence_1|SO:000000| + |unmapped_consequence| null| + | null| null| + +--------------------+---------+ + + """ + map_expr = f.create_map(*[f.lit(x) for x in chain(*mapping_dict.items())]) + + return map_expr[col] + + def pivot_df( df: DataFrame, pivot_col: str, diff --git a/src/gentropy/datasource/ensembl/vep_parser.py b/src/gentropy/datasource/ensembl/vep_parser.py index 2259ef34e..c7ee05d13 100644 --- a/src/gentropy/datasource/ensembl/vep_parser.py +++ b/src/gentropy/datasource/ensembl/vep_parser.py @@ -3,10 +3,9 @@ from __future__ import annotations import importlib.resources as pkg_resources -import json -from itertools import chain -from typing import TYPE_CHECKING, Dict, List +from typing import TYPE_CHECKING, List +import pandas as pd from pyspark.sql import SparkSession from pyspark.sql import functions as f from pyspark.sql import types as t @@ -15,7 +14,9 @@ from gentropy.common.schemas import parse_spark_schema from gentropy.common.spark_helpers import ( enforce_schema, + map_column_by_dictionary, order_array_of_structs_by_field, + order_array_of_structs_by_two_fields, ) from gentropy.dataset.variant_index import VariantIndex @@ -27,36 +28,15 @@ class VariantEffectPredictorParser: """Collection of methods to parse VEP output in json format.""" # Schema description of the dbXref object: - DBXREF_SCHEMA = t.ArrayType( - t.StructType( - [ - t.StructField("id", t.StringType(), True), - t.StructField("source", t.StringType(), True), - ] - ) - ) + DBXREF_SCHEMA = VariantIndex.get_schema()["dbXrefs"].dataType # Schema description of the in silico predictor object: - IN_SILICO_PREDICTOR_SCHEMA = t.StructType( - [ - t.StructField("method", t.StringType(), True), - t.StructField("assessment", t.StringType(), True), - t.StructField("score", t.FloatType(), True), - t.StructField("assessmentFlag", t.StringType(), True), - t.StructField("targetId", t.StringType(), True), - ] - ) + IN_SILICO_PREDICTOR_SCHEMA = VariantIndex.get_schema()[ + "inSilicoPredictors" + ].dataType # Schema for the allele frequency column: - ALLELE_FREQUENCY_SCHEMA = t.ArrayType( - t.StructType( - [ - t.StructField("populationName", t.StringType(), True), - t.StructField("alleleFrequency", t.DoubleType(), True), - ] - ), - False, - ) + ALLELE_FREQUENCY_SCHEMA = VariantIndex.get_schema()["alleleFrequencies"].dataType @staticmethod def get_schema() -> t.StructType: @@ -371,12 +351,12 @@ def _get_max_alpha_missense(transcripts: Column) -> Column: ... .select(VariantEffectPredictorParser._get_max_alpha_missense(f.col('transcripts')).alias('am')) ... .show(truncate=False) ... ) - +----------------------------------------------------+ - |am | - +----------------------------------------------------+ - |{max alpha missense, assessment 1, 0.4, null, gene1}| - |{max alpha missense, null, null, null, gene1} | - +----------------------------------------------------+ + +------------------------------------------------------+ + |am | + +------------------------------------------------------+ + |[{max alpha missense, assessment 1, 0.4, null, gene1}]| + |[{max alpha missense, null, null, null, gene1}] | + +------------------------------------------------------+ """ return f.transform( @@ -546,42 +526,6 @@ def _collect_uniprot_accessions(trembl: Column, swissprot: Column) -> Column: lambda x: x.isNotNull(), ) - @staticmethod - def _consequence_to_sequence_ontology( - col: Column, so_dict: Dict[str, str] - ) -> Column: - """Convert VEP consequence terms to sequence ontology identifiers. - - Missing consequence label will be converted to None, unmapped consequences will be mapped as None. - - Args: - col (Column): Column containing VEP consequence terms. - so_dict (Dict[str, str]): Dictionary mapping VEP consequence terms to sequence ontology identifiers. - - Returns: - Column: Column containing sequence ontology identifiers. - - Examples: - >>> data = [('consequence_1',),('unmapped_consequence',),(None,)] - >>> m = {'consequence_1': 'SO:000000'} - >>> ( - ... spark.createDataFrame(data, ['label']) - ... .select('label',VariantEffectPredictorParser._consequence_to_sequence_ontology(f.col('label'),m).alias('id')) - ... .show() - ... ) - +--------------------+---------+ - | label| id| - +--------------------+---------+ - | consequence_1|SO:000000| - |unmapped_consequence| null| - | null| null| - +--------------------+---------+ - - """ - map_expr = f.create_map(*[f.lit(x) for x in chain(*so_dict.items())]) - - return map_expr[col].alias("ancestry") - @staticmethod def _parse_variant_location_id(vep_input_field: Column) -> List[Column]: r"""Parse variant identifier, chromosome, position, reference allele and alternate allele from VEP input field. @@ -622,10 +566,22 @@ def process_vep_output( Returns: DataFrame: processed data in the right shape. """ - # Reading consequence to sequence ontology map: - sequence_ontology_map = json.loads( - pkg_resources.read_text(data, "so_mappings.json", encoding="utf-8") + so_df = pd.read_csv( + pkg_resources.open_text( + data, "variant_consequence_to_score.tsv", encoding="utf-8" + ), + sep="\t", ) + + # Reading consequence to sequence ontology map: + sequence_ontology_map = { + row["label"]: row["variantFunctionalConsequenceId"] + for _, row in so_df.iterrows() + } + + # Reading score dictionary: + score_dictionary = {row["label"]: row["score"] for _, row in so_df.iterrows()} + # Processing VEP output: return ( vep_output @@ -704,9 +660,20 @@ def process_vep_output( ) .alias("inSilicoPredictors"), # Convert consequence to SO: - cls._consequence_to_sequence_ontology( + map_column_by_dictionary( f.col("most_severe_consequence"), sequence_ontology_map ).alias("mostSevereConsequenceId"), + # Extract HGVS identifier: + f.when( + f.size("transcript_consequences") > 0, + f.col("transcript_consequences").getItem(0).getItem("hgvsg"), + ) + .when( + f.size("intergenic_consequences") > 0, + f.col("intergenic_consequences").getItem(0).getItem("hgvsg"), + ) + .otherwise(f.lit(None)) + .alias("hgvsId"), # Collect transcript consequence: f.when( f.col("transcript_consequences").isNotNull(), @@ -716,10 +683,21 @@ def process_vep_output( # Convert consequence terms to SO identifier: f.transform( transcript.consequence_terms, - lambda y: cls._consequence_to_sequence_ontology( + lambda y: map_column_by_dictionary( y, sequence_ontology_map ), ).alias("variantFunctionalConsequenceIds"), + # Convert consequence terms to consequence score: + f.array_max( + f.transform( + transcript.consequence_terms, + lambda term: map_column_by_dictionary( + term, score_dictionary + ), + ) + ) + .cast(t.FloatType()) + .alias("consequenceScore"), # Format amino acid change: cls._parser_amino_acid_change( transcript.amino_acids, transcript.protein_end @@ -733,9 +711,20 @@ def process_vep_output( f.when(transcript.canonical == 1, f.lit(True)) .otherwise(f.lit(False)) .alias("isEnsemblCanonical"), - # Extract other fields as is: + # Extract footprint distance: transcript.codons.alias("codons"), - transcript.distance.alias("distance"), + f.when(transcript.distance.isNotNull(), transcript.distance) + .otherwise(f.lit(0)) + .cast(t.LongType()) + .alias("distanceFromFootprint"), + # Extract distance from the transcription start site: + transcript.tssdistance.cast(t.LongType()).alias( + "distanceFromTss" + ), + # Extracting APPRIS isoform annotation for this transcript: + transcript.appris.alias("appris"), + # Extracting MANE select transcript: + transcript.mane_select.alias("maneSelect"), transcript.gene_id.alias("targetId"), transcript.impact.alias("impact"), transcript.lof.cast(t.StringType()).alias( @@ -756,6 +745,30 @@ def process_vep_output( # Adding empty array for allele frequencies - now this piece of data is not coming form the VEP data: f.array().cast(cls.ALLELE_FREQUENCY_SCHEMA).alias("alleleFrequencies"), ) + # Dropping transcripts where the consequence score or the distance is null: + .withColumn( + "transcriptConsequences", + f.filter( + f.col("transcriptConsequences"), + lambda x: x.getItem("consequenceScore").isNotNull() + & x.getItem("distanceFromFootprint").isNotNull(), + ), + ) + # Sort transcript consequences by consequence score and distance from footprint and add index: + .withColumn( + "transcriptConsequences", + f.when( + f.col("transcriptConsequences").isNotNull(), + f.transform( + order_array_of_structs_by_two_fields( + "transcriptConsequences", + "consequenceScore", + "distanceFromFootprint", + ), + lambda x, i: x.withField("transcriptIndex", i + f.lit(1)), + ), + ), + ) # Adding protvar xref for missense variants: # TODO: making and extendable list of consequences .withColumn( "protvar_xrefs", diff --git a/tests/gentropy/conftest.py b/tests/gentropy/conftest.py index 9ae7ace58..629f3a505 100644 --- a/tests/gentropy/conftest.py +++ b/tests/gentropy/conftest.py @@ -323,12 +323,17 @@ def mock_variant_index(spark: SparkSession) -> VariantIndex: "uniprotAccessions", array(cast(rand() as string)), "isEnsemblCanonical", cast(rand() as boolean), "codons", cast(rand() as string), - "distance", cast(rand() as long), + "distanceFromTss", cast(rand() as long), + "distanceFromFootprint", cast(rand() as long), + "appris", cast(rand() as string), + "maneSelect", cast(rand() as string), "targetId", cast(rand() as string), "impact", cast(rand() as string), "lofteePrediction", cast(rand() as string), "siftPrediction", rand(), "polyphenPrediction", rand(), + "consequenceScore", cast(rand() as float), + "transcriptIndex", cast(rand() as integer), "transcriptId", cast(rand() as string) ) ) diff --git a/tests/gentropy/data_samples/vep_sample.jsonl b/tests/gentropy/data_samples/vep_sample.jsonl index 78a76f150..2a3cb05dc 100644 --- a/tests/gentropy/data_samples/vep_sample.jsonl +++ b/tests/gentropy/data_samples/vep_sample.jsonl @@ -1,2 +1,2 @@ -{"transcript_consequences":[{"gene_id":"ENSG00000168702","swissprot":["Q9NZR2.181"],"uniparc":["UPI00001B045B"],"transcript_id":"ENST00000389484","impact":"MODIFIER","canonical":1,"consequence_terms":["intron_variant"],"strand":-1,"variant_allele":"T"}],"assembly_name":"GRCh38","most_severe_consequence":"intron_variant","strand":1,"seq_region_name":"2","start":140699626,"end":140699625,"input":"2\t140699625\t2_140699625_G_GT\tG\tGT","allele_string":"-/T","id":"2_140699625_G_GT"} -{"transcript_consequences":[{"impact":"MODIFIER","consequence_terms":["upstream_gene_variant"],"distance":682,"trembl":["A0A2U3TZJ1.14"],"cadd_raw":4.846757,"cadd_phred":27.1,"transcript_id":"ENST00000336451","strand":-1,"variant_allele":"T","gene_id":"ENSG00000155906","uniparc":["UPI000D18E792"]},{"lof_info":"INTRON_SIZE:8753","consequence_terms":["splice_donor_variant"],"impact":"HIGH","transcript_id":"ENST00000444024","cadd_phred":27.1,"cadd_raw":4.846757,"strand":-1,"variant_allele":"T","lof":"HC","canonical":1,"uniprot_isoform":["Q9NWS8-1"],"uniparc":["UPI00001AEAE1"],"swissprot":["Q9NWS8.145"],"gene_id":"ENSG00000155906"},{"gene_id":"ENSG00000155906","uniparc":["UPI000006DC2F"],"swissprot":["Q9NWS8.145"],"uniprot_isoform":["Q9NWS8-3"],"lof":"HC","variant_allele":"T","strand":-1,"cadd_phred":27.1,"transcript_id":"ENST00000491268","cadd_raw":4.846757,"consequence_terms":["splice_donor_variant"],"impact":"HIGH","lof_info":"INTRON_SIZE:8753"},{"variant_allele":"T","strand":-1,"uniparc":["UPI0002A12044"],"gene_id":"ENSG00000155906","consequence_terms":["intron_variant"],"impact":"MODIFIER","transcript_id":"ENST00000622845","cadd_phred":27.1,"cadd_raw":4.846757,"trembl":["A0A087WXU0.51"]},{"transcript_id":"ENST00000643564","cadd_phred":27.1,"cadd_raw":4.846757,"consequence_terms":["non_coding_transcript_exon_variant"],"impact":"MODIFIER","gene_id":"ENSG00000155906","cdna_start":578,"cdna_end":578,"strand":-1,"variant_allele":"T"},{"transcript_id":"ENST00000644054","cadd_phred":27.1,"trembl":["A0A2R8YFC3.14"],"cadd_raw":4.846757,"consequence_terms":["splice_donor_variant","NMD_transcript_variant"],"impact":"HIGH","uniparc":["UPI001B8998C5"],"gene_id":"ENSG00000155906","strand":-1,"variant_allele":"T"},{"transcript_id":"ENST00000644711","cadd_phred":27.1,"cadd_raw":4.846757,"trembl":["A0A2R8Y4J4.16"],"consequence_terms":["splice_donor_variant","NMD_transcript_variant"],"impact":"HIGH","uniparc":["UPI000D1907AF"],"gene_id":"ENSG00000155906","variant_allele":"T","strand":-1},{"gene_id":"ENSG00000155906","transcript_id":"ENST00000645367","cadd_phred":27.1,"cadd_raw":4.846757,"consequence_terms":["splice_donor_variant","non_coding_transcript_variant"],"impact":"HIGH","strand":-1,"variant_allele":"T"},{"cadd_phred":27.1,"transcript_id":"ENST00000645895","cadd_raw":4.846757,"gene_id":"ENSG00000155906","variant_allele":"T","strand":-1,"consequence_terms":["splice_donor_variant","non_coding_transcript_variant"],"impact":"HIGH"},{"gene_id":"ENSG00000155906","cdna_end":724,"cdna_start":724,"variant_allele":"T","strand":-1,"cadd_phred":27.1,"transcript_id":"ENST00000645917","cadd_raw":4.846757,"consequence_terms":["non_coding_transcript_exon_variant"],"impact":"MODIFIER"},{"impact":"HIGH","consequence_terms":["splice_donor_variant","NMD_transcript_variant"],"cadd_raw":4.846757,"trembl":["A0A2R8Y4P5.16"],"cadd_phred":27.1,"transcript_id":"ENST00000646926","variant_allele":"T","strand":-1,"uniparc":["UPI001B89CA49"],"gene_id":"ENSG00000155906"},{"transcript_id":"ENST00000682004","cadd_phred":27.1,"cadd_raw":4.846757,"gene_id":"ENSG00000155906","variant_allele":"T","strand":-1,"consequence_terms":["splice_donor_variant","non_coding_transcript_variant"],"impact":"HIGH"},{"gene_id":"ENSG00000155906","uniparc":["UPI001B88E93C"],"lof":"HC","strand":-1,"variant_allele":"T","trembl":["A0A804HHY2.7"],"cadd_raw":4.846757,"transcript_id":"ENST00000682299","cadd_phred":27.1,"impact":"HIGH","consequence_terms":["splice_donor_variant"],"lof_info":"INTRON_SIZE:8753"},{"uniparc":["UPI001B8920B1"],"gene_id":"ENSG00000155906","strand":-1,"variant_allele":"T","trembl":["A0A804HLE1.7"],"cadd_raw":4.846757,"cadd_phred":27.1,"transcript_id":"ENST00000682392","impact":"HIGH","consequence_terms":["splice_donor_variant","NMD_transcript_variant"]},{"cadd_raw":4.846757,"trembl":["A0A804HHW6.7"],"cadd_phred":27.1,"transcript_id":"ENST00000682641","impact":"HIGH","consequence_terms":["splice_donor_variant"],"lof_info":"INTRON_SIZE:8753","gene_id":"ENSG00000155906","uniparc":["UPI001B893F2B"],"lof":"HC","variant_allele":"T","strand":-1},{"gene_id":"ENSG00000155906","transcript_id":"ENST00000682760","cadd_phred":27.1,"cadd_raw":4.846757,"consequence_terms":["splice_donor_variant","non_coding_transcript_variant"],"impact":"HIGH","strand":-1,"variant_allele":"T"},{"variant_allele":"T","strand":-1,"impact":"HIGH","consequence_terms":["splice_donor_variant","non_coding_transcript_variant"],"cadd_raw":4.846757,"cadd_phred":27.1,"transcript_id":"ENST00000683439","gene_id":"ENSG00000155906"},{"gene_id":"ENSG00000155906","swissprot":["Q9NWS8.145"],"uniparc":["UPI00001AEAE1"],"lof":"HC","uniprot_isoform":["Q9NWS8-1"],"strand":-1,"variant_allele":"T","cadd_raw":4.846757,"transcript_id":"ENST00000683724","cadd_phred":27.1,"impact":"HIGH","consequence_terms":["splice_donor_variant"],"lof_info":"INTRON_SIZE:8753"},{"gene_id":"ENSG00000155906","transcript_id":"ENST00000683740","cadd_phred":27.1,"cadd_raw":4.846757,"consequence_terms":["splice_donor_variant","non_coding_transcript_variant"],"impact":"HIGH","variant_allele":"T","strand":-1},{"cadd_phred":27.1,"transcript_id":"ENST00000684301","cadd_raw":4.846757,"consequence_terms":["splice_donor_variant","NMD_transcript_variant"],"impact":"HIGH","gene_id":"ENSG00000155906","uniparc":["UPI000006DC2F"],"swissprot":["Q9NWS8.145"],"uniprot_isoform":["Q9NWS8-3"],"variant_allele":"T","strand":-1},{"gene_id":"ENSG00000155906","cadd_raw":4.846757,"cadd_phred":27.1,"transcript_id":"ENST00000684658","impact":"HIGH","consequence_terms":["splice_donor_variant","non_coding_transcript_variant"],"strand":-1,"variant_allele":"T"},{"consequence_terms":["splice_donor_variant","non_coding_transcript_variant"],"impact":"HIGH","variant_allele":"T","strand":-1,"gene_id":"ENSG00000155906","cadd_phred":27.1,"transcript_id":"ENST00000684715","cadd_raw":4.846757},{"impact":"HIGH","consequence_terms":["splice_donor_variant","NMD_transcript_variant"],"trembl":["A0A804HKF8.7"],"cadd_raw":4.846757,"cadd_phred":27.1,"transcript_id":"ENST00000684765","strand":-1,"variant_allele":"T","uniparc":["UPI001B89CAE3"],"gene_id":"ENSG00000155906"}],"seq_region_name":"6","assembly_name":"GRCh38","end":151445307,"strand":1,"most_severe_consequence":"splice_donor_variant","start":151445307,"id":"6_151445307_C_T","colocated_variants":[{"clin_sig_allele":"T:pathogenic;T:likely_pathogenic","end":151445307,"var_synonyms":{"ClinVar":["RCV000032983","VCV000039764","RCV001814019"],"OMIM":[614917.0001]},"strand":1,"start":151445307,"allele_string":"C/T","clin_sig":["likely_pathogenic","pathogenic"],"seq_region_name":"6","pubmed":[23022099,18835491],"phenotype_or_disease":1,"id":"rs1562800908"}],"input":"6\t151445307\t6_151445307_C_T\tC\tT","allele_string":"C/T"} +{"most_severe_consequence":"missense_variant","input":"17\t29510931\trs2153029597\tT\tC","assembly_name":"GRCh38","transcript_consequences":[{"consequence_terms":["downstream_gene_variant"],"gene_id":"ENSG00000238007","hgvsg":"17:g.29510931T>C","cadd_phred":28.9,"strand":1,"canonical":1,"impact":"MODIFIER","tssdistance":498066,"variant_allele":"C","cadd_raw":5.156509,"transcript_id":"ENST00000436028","distance":494419},{"hgvsg":"17:g.29510931T>C","consequence_terms":["downstream_gene_variant"],"gene_id":"ENSG00000222363","strand":1,"impact":"MODIFIER","canonical":1,"cadd_phred":28.9,"variant_allele":"C","tssdistance":122371,"transcript_id":"ENST00000410431","distance":122248,"cadd_raw":5.156509},{"cadd_raw":5.156509,"transcript_id":"ENST00000581240","distance":128696,"tssdistance":128696,"variant_allele":"C","cadd_phred":28.9,"strand":1,"impact":"MODIFIER","canonical":1,"consequence_terms":["upstream_gene_variant"],"gene_id":"ENSG00000263370","hgvsg":"17:g.29510931T>C"},{"consequence_terms":["downstream_gene_variant"],"gene_id":"ENSG00000264007","hgvsg":"17:g.29510931T>C","cadd_phred":28.9,"strand":-1,"impact":"MODIFIER","canonical":1,"tssdistance":111323,"variant_allele":"C","cadd_raw":5.156509,"transcript_id":"ENST00000582367","distance":110686},{"cadd_raw":5.156509,"distance":49616,"transcript_id":"ENST00000307201","appris":"P1","tssdistance":56106,"uniparc":["UPI00001C1FC9"],"swissprot":["Q6UXT9.120"],"variant_allele":"C","cadd_phred":28.9,"mane_select":"NM_198147.3","impact":"MODIFIER","canonical":1,"strand":-1,"gene_id":"ENSG00000168792","consequence_terms":["downstream_gene_variant"],"hgvsg":"17:g.29510931T>C"},{"strand":1,"impact":"MODIFIER","canonical":1,"cadd_phred":28.9,"hgvsg":"17:g.29510931T>C","consequence_terms":["upstream_gene_variant"],"gene_id":"ENSG00000264290","transcript_id":"ENST00000579050","distance":58649,"cadd_raw":5.156509,"variant_allele":"C","tssdistance":58649},{"strand":1,"canonical":1,"impact":"MODIFIER","cadd_phred":28.9,"hgvsg":"17:g.29510931T>C","consequence_terms":["upstream_gene_variant"],"gene_id":"ENSG00000263657","transcript_id":"ENST00000577846","distance":250172,"cadd_raw":5.156509,"variant_allele":"C","tssdistance":250172},{"variant_allele":"C","swissprot":["Q6QEF8.143"],"uniparc":["UPI0000DA4C55"],"tssdistance":111981,"transcript_id":"ENST00000388767","distance":103831,"cadd_raw":5.156509,"uniprot_isoform":["Q6QEF8-5"],"hgvsg":"17:g.29510931T>C","consequence_terms":["downstream_gene_variant"],"gene_id":"ENSG00000167549","strand":-1,"canonical":1,"impact":"MODIFIER","mane_select":"NM_032854.4","cadd_phred":28.9},{"hgvsg":"17:g.29510931T>C","consequence_terms":["upstream_gene_variant"],"gene_id":"ENSG00000263781","strand":-1,"impact":"MODIFIER","canonical":1,"cadd_phred":28.9,"variant_allele":"C","tssdistance":489291,"transcript_id":"ENST00000580924","distance":489291,"cadd_raw":5.156509},{"strand":1,"impact":"MODIFIER","canonical":1,"mane_select":"NM_198529.4","cadd_phred":28.9,"uniprot_isoform":["A4FU69-1"],"hgvsg":"17:g.29510931T>C","consequence_terms":["upstream_gene_variant"],"gene_id":"ENSG00000176927","appris":"P1","transcript_id":"ENST00000394835","distance":430703,"cadd_raw":5.156509,"variant_allele":"C","swissprot":["A4FU69.119"],"uniparc":["UPI0000E59EF5"],"tssdistance":430703},{"cdna_start":2399,"tssdistance":120568,"amino_acids":"L/P","swissprot":["Q7L7X3.173"],"transcript_id":"ENST00000261716","appris":"P1","consequence_terms":["missense_variant"],"trembl":["A0A024QZ70.65"],"cds_start":1643,"mane_select":"NM_020791.4","cadd_phred":28.9,"strand":1,"cds_end":1643,"impact":"MODERATE","canonical":1,"uniparc":["UPI000004A033"],"variant_allele":"C","cadd_raw":5.156509,"sift_score":0,"protein_start":548,"cdna_end":2399,"gene_id":"ENSG00000160551","uniprot_isoform":["Q7L7X3-1"],"codons":"cTg/cCg","sift_prediction":"deleterious_low_confidence","hgvsg":"17:g.29510931T>C","alphamissense":{"am_class":"likely_pathogenic","am_pathogenicity":0.9994},"protein_end":548,"polyphen_score":0.999,"polyphen_prediction":"probably_damaging"},{"uniparc":["UPI0000246D82"],"tssdistance":82201,"variant_allele":"C","swissprot":["Q86YJ7.146"],"cadd_raw":5.156509,"transcript_id":"ENST00000394859","appris":"P1","distance":82201,"consequence_terms":["upstream_gene_variant"],"gene_id":"ENSG00000198720","uniprot_isoform":["Q86YJ7-1"],"hgvsg":"17:g.29510931T>C","trembl":["A0A024QZ29.60"],"mane_select":"NM_152345.5","cadd_phred":28.9,"strand":1,"impact":"MODIFIER","canonical":1},{"transcript_id":"ENST00000459235","distance":372075,"cadd_raw":5.156509,"variant_allele":"C","tssdistance":372075,"strand":1,"impact":"MODIFIER","canonical":1,"cadd_phred":28.9,"hgvsg":"17:g.29510931T>C","consequence_terms":["upstream_gene_variant"],"gene_id":"ENSG00000239129"},{"tssdistance":205754,"variant_allele":"C","cadd_raw":5.156509,"distance":205348,"transcript_id":"ENST00000493028","gene_id":"ENSG00000240531","consequence_terms":["downstream_gene_variant"],"hgvsg":"17:g.29510931T>C","cadd_phred":28.9,"impact":"MODIFIER","canonical":1,"strand":-1},{"consequence_terms":["downstream_gene_variant"],"gene_id":"ENSG00000284162","hgvsg":"17:g.29510931T>C","cadd_phred":28.9,"strand":1,"canonical":1,"impact":"MODIFIER","tssdistance":120269,"variant_allele":"C","cadd_raw":5.156509,"transcript_id":"ENST00000580425","distance":120201},{"tssdistance":49616,"variant_allele":"C","cadd_raw":5.156509,"transcript_id":"ENST00000581474","distance":49616,"consequence_terms":["upstream_gene_variant"],"gene_id":"ENSG00000264031","hgvsg":"17:g.29510931T>C","cadd_phred":28.9,"strand":1,"canonical":1,"impact":"MODIFIER"},{"hgvsg":"17:g.29510931T>C","gene_id":"ENSG00000222858","consequence_terms":["downstream_gene_variant"],"impact":"MODIFIER","canonical":1,"strand":-1,"cadd_phred":28.9,"variant_allele":"C","tssdistance":130771,"distance":130680,"transcript_id":"ENST00000410926","cadd_raw":5.156509},{"tssdistance":461583,"variant_allele":"C","cadd_raw":5.156509,"transcript_id":"ENST00000581995","distance":461583,"consequence_terms":["upstream_gene_variant"],"gene_id":"ENSG00000264435","hgvsg":"17:g.29510931T>C","cadd_phred":28.9,"strand":1,"canonical":1,"impact":"MODIFIER"},{"gene_id":"ENSG00000179761","consequence_terms":["downstream_gene_variant"],"hgvsg":"17:g.29510931T>C","mane_select":"NM_016518.3","cadd_phred":28.9,"canonical":1,"impact":"MODIFIER","strand":1,"tssdistance":467790,"uniparc":["UPI00001410B0"],"swissprot":["Q9P0Z9.165"],"variant_allele":"C","cadd_raw":5.156509,"distance":453715,"appris":"P1","transcript_id":"ENST00000323372"},{"strand":-1,"canonical":1,"impact":"MODIFIER","cadd_phred":28.9,"hgvsg":"17:g.29510931T>C","consequence_terms":["upstream_gene_variant"],"gene_id":"ENSG00000253064","transcript_id":"ENST00000517255","distance":86064,"cadd_raw":5.156509,"variant_allele":"C","tssdistance":86064},{"tssdistance":313146,"variant_allele":"C","cadd_raw":5.156509,"distance":313146,"transcript_id":"ENST00000580309","gene_id":"ENSG00000264050","consequence_terms":["upstream_gene_variant"],"hgvsg":"17:g.29510931T>C","cadd_phred":28.9,"canonical":1,"impact":"MODIFIER","strand":-1},{"variant_allele":"C","tssdistance":134916,"transcript_id":"ENST00000582881","distance":133865,"cadd_raw":5.156509,"hgvsg":"17:g.29510931T>C","consequence_terms":["downstream_gene_variant"],"gene_id":"ENSG00000265625","strand":-1,"impact":"MODIFIER","canonical":1,"cadd_phred":28.9},{"hgvsg":"17:g.29510931T>C","gene_id":"ENSG00000240074","consequence_terms":["upstream_gene_variant"],"impact":"MODIFIER","canonical":1,"strand":1,"cadd_phred":28.9,"variant_allele":"C","tssdistance":344828,"distance":344828,"transcript_id":"ENST00000478775","cadd_raw":5.156509},{"cadd_phred":28.9,"canonical":1,"impact":"MODIFIER","strand":-1,"gene_id":"ENSG00000264647","consequence_terms":["downstream_gene_variant"],"hgvsg":"17:g.29510931T>C","cadd_raw":5.156509,"distance":80772,"transcript_id":"ENST00000584986","tssdistance":81310,"variant_allele":"C"},{"variant_allele":"C","tssdistance":65531,"transcript_id":"ENST00000365335","distance":65531,"cadd_raw":5.156509,"hgvsg":"17:g.29510931T>C","consequence_terms":["upstream_gene_variant"],"gene_id":"ENSG00000202205","strand":-1,"canonical":1,"impact":"MODIFIER","cadd_phred":28.9},{"gene_id":"ENSG00000266111","consequence_terms":["downstream_gene_variant"],"hgvsg":"17:g.29510931T>C","cadd_phred":28.9,"impact":"MODIFIER","canonical":1,"strand":1,"tssdistance":158862,"variant_allele":"C","cadd_raw":5.156509,"distance":106826,"transcript_id":"ENST00000584958"},{"variant_allele":"C","tssdistance":265770,"distance":264816,"transcript_id":"ENST00000580031","cadd_raw":5.156509,"hgvsg":"17:g.29510931T>C","gene_id":"ENSG00000265713","consequence_terms":["downstream_gene_variant"],"canonical":1,"impact":"MODIFIER","strand":-1,"cadd_phred":28.9},{"consequence_terms":["downstream_gene_variant"],"gene_id":"ENSG00000108255","uniprot_isoform":["P05813-1"],"hgvsg":"17:g.29510931T>C","mane_select":"NM_005208.5","cadd_phred":28.9,"strand":1,"impact":"MODIFIER","canonical":1,"uniparc":["UPI00001283CF"],"tssdistance":264072,"variant_allele":"C","swissprot":["P05813.205"],"cadd_raw":5.156509,"transcript_id":"ENST00000225387","appris":"P1","distance":256437},{"consequence_terms":["upstream_gene_variant"],"gene_id":"ENSG00000264808","hgvsg":"17:g.29510931T>C","cadd_phred":28.9,"strand":-1,"canonical":1,"impact":"MODIFIER","tssdistance":120702,"variant_allele":"C","cadd_raw":5.156509,"transcript_id":"ENST00000685798","distance":120702},{"cadd_phred":28.9,"strand":-1,"canonical":1,"impact":"MODIFIER","consequence_terms":["downstream_gene_variant"],"gene_id":"ENSG00000290082","hgvsg":"17:g.29510931T>C","cadd_raw":5.156509,"transcript_id":"ENST00000702873","distance":56892,"tssdistance":57602,"variant_allele":"C"},{"mane_select":"NM_078471.4","cadd_phred":28.9,"strand":-1,"canonical":1,"impact":"MODIFIER","consequence_terms":["upstream_gene_variant"],"gene_id":"ENSG00000196535","uniprot_isoform":["Q92614-1"],"hgvsg":"17:g.29510931T>C","cadd_raw":5.156509,"appris":"P4","transcript_id":"ENST00000527372","distance":330533,"uniparc":["UPI0000167F32"],"tssdistance":330533,"variant_allele":"C","swissprot":["Q92614.216"]},{"cadd_raw":5.156509,"transcript_id":"ENST00000492004","distance":170109,"tssdistance":170109,"variant_allele":"C","cadd_phred":28.9,"strand":-1,"impact":"MODIFIER","canonical":1,"consequence_terms":["upstream_gene_variant"],"gene_id":"ENSG00000239256","hgvsg":"17:g.29510931T>C"},{"gene_id":"ENSG00000263709","consequence_terms":["downstream_gene_variant"],"hgvsg":"17:g.29510931T>C","cadd_phred":28.9,"canonical":1,"impact":"MODIFIER","strand":1,"tssdistance":370448,"variant_allele":"C","cadd_raw":5.156509,"distance":355442,"transcript_id":"ENST00000582196"},{"consequence_terms":["upstream_gene_variant"],"gene_id":"ENSG00000252657","hgvsg":"17:g.29510931T>C","cadd_phred":28.9,"strand":1,"impact":"MODIFIER","canonical":1,"tssdistance":266688,"variant_allele":"C","cadd_raw":5.156509,"transcript_id":"ENST00000516848","distance":266688},{"trembl":["F5H527.88"],"mane_select":"NM_001282129.2","cadd_phred":28.9,"strand":-1,"impact":"MODIFIER","canonical":1,"consequence_terms":["downstream_gene_variant"],"gene_id":"ENSG00000141298","hgvsg":"17:g.29510931T>C","cadd_raw":5.156509,"transcript_id":"ENST00000540801","appris":"A1","distance":115007,"uniparc":["UPI0002065A97"],"tssdistance":419297,"variant_allele":"C"},{"tssdistance":216783,"uniparc":["UPI00001B078D"],"swissprot":["Q7Z417.159"],"variant_allele":"C","cadd_raw":5.156509,"distance":216783,"transcript_id":"ENST00000225388","appris":"P1","gene_id":"ENSG00000108256","consequence_terms":["upstream_gene_variant"],"hgvsg":"17:g.29510931T>C","uniprot_isoform":["Q7Z417-1"],"mane_select":"NM_020772.3","cadd_phred":28.9,"impact":"MODIFIER","canonical":1,"strand":-1},{"consequence_terms":["downstream_gene_variant"],"gene_id":"ENSG00000108262","uniprot_isoform":["Q9Y2X7-1"],"hgvsg":"17:g.29510931T>C","mane_select":"NM_014030.4","cadd_phred":28.9,"strand":-1,"impact":"MODIFIER","canonical":1,"uniparc":["UPI000013C867"],"tssdistance":78717,"variant_allele":"C","swissprot":["Q9Y2X7.219"],"cadd_raw":5.156509,"transcript_id":"ENST00000225394","appris":"A1","distance":62544},{"variant_allele":"C","tssdistance":499922,"transcript_id":"ENST00000581964","distance":499922,"cadd_raw":5.156509,"hgvsg":"17:g.29510931T>C","consequence_terms":["upstream_gene_variant"],"gene_id":"ENSG00000263613","strand":-1,"impact":"MODIFIER","canonical":1,"cadd_phred":28.9},{"variant_allele":"C","tssdistance":306457,"transcript_id":"ENST00000580812","distance":306457,"cadd_raw":5.156509,"hgvsg":"17:g.29510931T>C","consequence_terms":["upstream_gene_variant"],"gene_id":"ENSG00000178082","strand":-1,"impact":"MODIFIER","canonical":1,"cadd_phred":28.9},{"variant_allele":"C","tssdistance":352471,"distance":352471,"transcript_id":"ENST00000584258","cadd_raw":5.156509,"hgvsg":"17:g.29510931T>C","gene_id":"ENSG00000263477","consequence_terms":["upstream_gene_variant"],"canonical":1,"impact":"MODIFIER","strand":1,"cadd_phred":28.9},{"cadd_raw":5.156509,"transcript_id":"ENST00000301057","appris":"P1","distance":57770,"uniparc":["UPI000003B08D"],"tssdistance":57770,"variant_allele":"C","swissprot":["Q8NBR0.130"],"mane_select":"NM_138349.4","cadd_phred":28.9,"strand":1,"impact":"MODIFIER","canonical":1,"consequence_terms":["upstream_gene_variant"],"gene_id":"ENSG00000167543","hgvsg":"17:g.29510931T>C"}],"allele_string":"T/C","seq_region_name":"17","strand":1,"end":29510931,"start":29510931,"colocated_variants":[{"clin_sig":["pathogenic"],"clin_sig_allele":"C:pathogenic","phenotype_or_disease":1,"strand":1,"allele_string":"T/C","start":29510931,"id":"rs2153029597","seq_region_name":"17","pubmed":[33565190],"end":29510931,"var_synonyms":{"ClinVar":["RCV001731168","VCV001300172"],"OMIM":[610266.0003]}}],"id":"rs2153029597"} +{"strand":1,"seq_region_name":"9","allele_string":"C/T","transcript_consequences":[{"hgvsg":"9:g.82445881C>T","consequence_terms":["upstream_gene_variant"],"gene_id":"ENSG00000228046","strand":-1,"impact":"MODIFIER","canonical":1,"cadd_phred":7.002,"variant_allele":"T","tssdistance":17856,"transcript_id":"ENST00000392516","distance":17856,"cadd_raw":0.6583},{"cadd_phred":7.002,"impact":"MODIFIER","canonical":1,"strand":1,"gene_id":"ENSG00000225085","consequence_terms":["downstream_gene_variant"],"hgvsg":"9:g.82445881C>T","cadd_raw":0.6583,"distance":39642,"transcript_id":"ENST00000436084","tssdistance":40693,"variant_allele":"T"},{"cadd_raw":0.6583,"transcript_id":"ENST00000637606","tssdistance":468267,"variant_allele":"T","cadd_phred":7.002,"canonical":1,"impact":"MODIFIER","strand":1,"gene_id":"ENSG00000290551","consequence_terms":["intron_variant","non_coding_transcript_variant"],"hgvsg":"9:g.82445881C>T"},{"gene_id":"ENSG00000278988","consequence_terms":["upstream_gene_variant"],"hgvsg":"9:g.82445881C>T","cadd_phred":7.002,"canonical":1,"impact":"MODIFIER","strand":1,"tssdistance":97837,"variant_allele":"T","cadd_raw":0.6583,"distance":97837,"transcript_id":"ENST00000623079"},{"swissprot":["Q6ZQQ2.115"],"variant_allele":"T","tssdistance":457109,"uniparc":["UPI00001C10A6"],"distance":450628,"appris":"P1","transcript_id":"ENST00000344803","cadd_raw":0.6583,"hgvsg":"9:g.82445881C>T","gene_id":"ENSG00000214929","consequence_terms":["downstream_gene_variant"],"impact":"MODIFIER","canonical":1,"strand":1,"cadd_phred":7.002,"mane_select":"NM_001001670.3"},{"cadd_phred":7.002,"impact":"MODIFIER","canonical":1,"strand":-1,"gene_id":"ENSG00000230360","consequence_terms":["upstream_gene_variant"],"hgvsg":"9:g.82445881C>T","cadd_raw":0.6583,"distance":357113,"transcript_id":"ENST00000417796","tssdistance":357113,"variant_allele":"T"},{"cadd_raw":0.6583,"transcript_id":"ENST00000422010","distance":5775,"tssdistance":5775,"variant_allele":"T","cadd_phred":7.002,"strand":1,"canonical":1,"impact":"MODIFIER","consequence_terms":["upstream_gene_variant"],"gene_id":"ENSG00000232749","hgvsg":"9:g.82445881C>T"},{"tssdistance":12976,"variant_allele":"T","cadd_raw":0.6583,"transcript_id":"ENST00000438986","distance":12976,"consequence_terms":["upstream_gene_variant"],"gene_id":"ENSG00000228123","hgvsg":"9:g.82445881C>T","cadd_phred":7.002,"strand":-1,"canonical":1,"impact":"MODIFIER"},{"tssdistance":382199,"variant_allele":"T","cadd_raw":0.6583,"transcript_id":"ENST00000434692","distance":382199,"consequence_terms":["upstream_gene_variant"],"gene_id":"ENSG00000231649","hgvsg":"9:g.82445881C>T","cadd_phred":7.002,"strand":-1,"canonical":1,"impact":"MODIFIER"},{"tssdistance":298911,"variant_allele":"T","cadd_raw":0.6583,"transcript_id":"ENST00000432491","distance":298186,"consequence_terms":["downstream_gene_variant"],"gene_id":"ENSG00000233309","hgvsg":"9:g.82445881C>T","cadd_phred":7.002,"strand":-1,"canonical":1,"impact":"MODIFIER"},{"canonical":1,"impact":"MODIFIER","strand":1,"cadd_phred":7.002,"hgvsg":"9:g.82445881C>T","gene_id":"ENSG00000235377","consequence_terms":["downstream_gene_variant"],"distance":314249,"transcript_id":"ENST00000445918","cadd_raw":0.6583,"variant_allele":"T","tssdistance":315129},{"variant_allele":"T","tssdistance":17682,"distance":17588,"transcript_id":"ENST00000636401","cadd_raw":0.6583,"hgvsg":"9:g.82445881C>T","gene_id":"ENSG00000228430","consequence_terms":["downstream_gene_variant"],"impact":"MODIFIER","canonical":1,"strand":1,"cadd_phred":7.002},{"cadd_raw":0.6583,"transcript_id":"ENST00000585776","distance":468792,"tssdistance":468792,"variant_allele":"T","cadd_phred":7.002,"strand":-1,"impact":"MODIFIER","canonical":1,"consequence_terms":["upstream_gene_variant"],"gene_id":"ENSG00000267559","hgvsg":"9:g.82445881C>T"},{"impact":"MODIFIER","canonical":1,"strand":1,"cadd_phred":7.002,"hgvsg":"9:g.82445881C>T","gene_id":"ENSG00000237770","consequence_terms":["downstream_gene_variant"],"distance":473751,"transcript_id":"ENST00000429999","cadd_raw":0.6583,"variant_allele":"T","tssdistance":479317},{"distance":166671,"transcript_id":"ENST00000661177","cadd_raw":0.6583,"variant_allele":"T","tssdistance":200703,"impact":"MODIFIER","canonical":1,"strand":-1,"cadd_phred":7.002,"hgvsg":"9:g.82445881C>T","gene_id":"ENSG00000286612","consequence_terms":["downstream_gene_variant"]},{"mane_select":"NM_207416.3","cadd_phred":7.002,"impact":"MODIFIER","canonical":1,"strand":1,"gene_id":"ENSG00000186788","consequence_terms":["downstream_gene_variant"],"hgvsg":"9:g.82445881C>T","cadd_raw":0.6583,"distance":495788,"appris":"P1","transcript_id":"ENST00000445385","tssdistance":502381,"uniparc":["UPI000048D678"],"swissprot":["P0C874.81"],"variant_allele":"T"}],"assembly_name":"GRCh38","input":"9\t82445881\t9_82445881_C_T\tC\tT","most_severe_consequence":"intron_variant","id":"9_82445881_C_T","colocated_variants":[{"phenotype_or_disease":1,"strand":1,"allele_string":"C/G/T","frequencies":{"T":{"gnomadg":0.01197,"gnomadg_amr":0.0191,"gnomadg_afr":0.003331,"gnomadg_asj":0.02364,"eas":0,"amr":0.0216,"gnomadg_eas":0,"sas":0,"gnomadg_nfe":0.01704,"gnomadg_fin":0.009992,"gnomadg_mid":0.006329,"afr":0,"gnomadg_oth":0.01772,"gnomadg_ami":0.003289,"af":0.0068,"eur":0.0189,"gnomadg_sas":0.0004142}},"start":82445881,"id":"rs117517710","seq_region_name":"9","pubmed":[31073882],"end":82445881}],"end":82445881,"start":82445881} diff --git a/tests/gentropy/datasource/ensembl/test_vep_variants.py b/tests/gentropy/datasource/ensembl/test_vep_variants.py index e3313a1e5..97f255cf0 100644 --- a/tests/gentropy/datasource/ensembl/test_vep_variants.py +++ b/tests/gentropy/datasource/ensembl/test_vep_variants.py @@ -104,7 +104,7 @@ def _setup(self: TestVEPParser, spark: SparkSession) -> None: schema=VariantEffectPredictorParser.get_schema(), ) self.processed_vep_output = VariantEffectPredictorParser.process_vep_output( - self.raw_vep_output + self.raw_vep_output, 200 ) def test_extract_variant_index_from_vep( From 3ea47a954b98d6dd0558670b3f4e82645016ad09 Mon Sep 17 00:00:00 2001 From: Szymon Szyszkowski <69353402+project-defiant@users.noreply.github.com> Date: Tue, 3 Sep 2024 20:54:01 +0200 Subject: [PATCH 022/188] fix: remove finngen prefix from credible set (#746) --- src/gentropy/config.py | 1 - src/gentropy/datasource/finngen/finemapping.py | 10 ++-------- src/gentropy/datasource/finngen/study_index.py | 2 +- src/gentropy/finngen_finemapping_ingestion.py | 3 --- .../datasource/finngen/test_finngen_finemapping.py | 1 - 5 files changed, 3 insertions(+), 14 deletions(-) diff --git a/src/gentropy/config.py b/src/gentropy/config.py index ed5fe4c81..9089dbecf 100644 --- a/src/gentropy/config.py +++ b/src/gentropy/config.py @@ -154,7 +154,6 @@ class FinngenFinemappingConfig(StepConfig): finngen_susie_finemapping_cs_summary_files: str = ( "gs://finngen-public-data-r11/finemap/summary/*.cred.summary.tsv" ) - finngen_release_prefix: str = "FINNGEN_R11_" finngen_finemapping_out: str = MISSING _target_: str = ( "gentropy.finngen_finemapping_ingestion.FinnGenFinemappingIngestionStep" diff --git a/src/gentropy/datasource/finngen/finemapping.py b/src/gentropy/datasource/finngen/finemapping.py index 340b1d3c9..cbdd01fdc 100644 --- a/src/gentropy/datasource/finngen/finemapping.py +++ b/src/gentropy/datasource/finngen/finemapping.py @@ -206,7 +206,6 @@ def from_finngen_susie_finemapping( spark: SparkSession, finngen_susie_finemapping_snp_files: (str | list[str]), finngen_susie_finemapping_cs_summary_files: (str | list[str]), - finngen_release_prefix: str, credset_lbf_threshold: float = 0.8685889638065036, ) -> StudyLocus: """Process the SuSIE finemapping output for FinnGen studies. @@ -262,7 +261,6 @@ def from_finngen_susie_finemapping( spark (SparkSession): SparkSession object. finngen_susie_finemapping_snp_files (str | list[str]): SuSIE finemapping output filename(s). finngen_susie_finemapping_cs_summary_files (str | list[str]): filename of SuSIE finemapping credible set summaries. - finngen_release_prefix (str): FinnGen study prefix. credset_lbf_threshold (float, optional): Filter out credible sets below, Default 0.8685889638065036 == np.log10(np.exp(2)), this is threshold from publication. Returns: @@ -297,9 +295,7 @@ def from_finngen_susie_finemapping( .filter(f.col("cs").cast(t.IntegerType()) > 0) .select( # Add study idenfitier. - f.concat(f.lit(finngen_release_prefix), f.col("trait")) - .cast(t.StringType()) - .alias("studyId"), + f.col("trait").cast(t.StringType()).alias("studyId"), f.col("region"), # Add variant information. f.regexp_replace(f.col("v"), ":", "_").alias("variantId"), @@ -412,9 +408,7 @@ def from_finngen_susie_finemapping( (f.col("credibleSetlog10BF") > credset_lbf_threshold) | (f.col("credibleSetIndex") == 1) ) - .withColumn( - "studyId", f.concat(f.lit(finngen_release_prefix), f.col("trait")) - ) + .withColumn("studyId", f.col("trait")) ) processed_finngen_finemapping_df = processed_finngen_finemapping_df.join( diff --git a/src/gentropy/datasource/finngen/study_index.py b/src/gentropy/datasource/finngen/study_index.py index 71dce10d4..210c4330c 100644 --- a/src/gentropy/datasource/finngen/study_index.py +++ b/src/gentropy/datasource/finngen/study_index.py @@ -55,7 +55,7 @@ def join_efo_mapping( ) if not finngen_release_prefix_match: raise ValueError( - f"Invalid FinnGen release prefix: {finngen_release_prefix}, use the format FINNGEN_R*_" + f"Invalid FinnGen release prefix: {finngen_release_prefix}, use the format FINNGEN_R*" ) finngen_release = finngen_release_prefix_match.group("release").upper() diff --git a/src/gentropy/finngen_finemapping_ingestion.py b/src/gentropy/finngen_finemapping_ingestion.py index e85508023..80089cf68 100644 --- a/src/gentropy/finngen_finemapping_ingestion.py +++ b/src/gentropy/finngen_finemapping_ingestion.py @@ -20,7 +20,6 @@ def __init__( finngen_finemapping_out: str, finngen_susie_finemapping_snp_files: str = FinngenFinemappingConfig().finngen_susie_finemapping_snp_files, finngen_susie_finemapping_cs_summary_files: str = FinngenFinemappingConfig().finngen_susie_finemapping_cs_summary_files, - finngen_release_prefix: str = FinngenFinemappingConfig().finngen_release_prefix, ) -> None: """Run FinnGen finemapping ingestion step. @@ -29,7 +28,6 @@ def __init__( finngen_finemapping_out (str): Output path for the finemapping results in StudyLocus format. finngen_susie_finemapping_snp_files(str): Path to the FinnGen SuSIE finemapping results. finngen_susie_finemapping_cs_summary_files (str): FinnGen SuSIE summaries for CS filters(LBF>2). - finngen_release_prefix (str): Release prefix for FinnGen. """ # Read finemapping outputs from the input paths. @@ -37,7 +35,6 @@ def __init__( spark=session.spark, finngen_susie_finemapping_snp_files=finngen_susie_finemapping_snp_files, finngen_susie_finemapping_cs_summary_files=finngen_susie_finemapping_cs_summary_files, - finngen_release_prefix=finngen_release_prefix, ) # Write the output. diff --git a/tests/gentropy/datasource/finngen/test_finngen_finemapping.py b/tests/gentropy/datasource/finngen/test_finngen_finemapping.py index a7ffa4bc2..ed0b68643 100644 --- a/tests/gentropy/datasource/finngen/test_finngen_finemapping.py +++ b/tests/gentropy/datasource/finngen/test_finngen_finemapping.py @@ -40,7 +40,6 @@ def test_finngen_finemapping_from_finngen_susie_finemapping( spark=spark, finngen_susie_finemapping_snp_files=finngen_susie_finemapping_snp_files, finngen_susie_finemapping_cs_summary_files=finngen_susie_finemapping_cs_summary_files, - finngen_release_prefix="FINNGEN_R11", ), StudyLocus, ) From 12ff35ba10547a3deefea8b6f4db5b81669cc57e Mon Sep 17 00:00:00 2001 From: Szymon Szyszkowski <69353402+project-defiant@users.noreply.github.com> Date: Wed, 4 Sep 2024 11:53:58 +0200 Subject: [PATCH 023/188] fix(finngen_r11): preserve all studyIds (#747) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(finngen_r11): preserve all studyIds Preserve all studyIds, even if EFO mapping is missing, so mapping between studyIndex and StudyLocus is by studyId column is accurate. * fix: typo in docstring Co-authored-by: Irene López Santiago <45119610+ireneisdoomed@users.noreply.github.com> --------- Co-authored-by: Szymon Szyszkowski Co-authored-by: Irene López Santiago <45119610+ireneisdoomed@users.noreply.github.com> --- src/gentropy/datasource/finngen/study_index.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/gentropy/datasource/finngen/study_index.py b/src/gentropy/datasource/finngen/study_index.py index 210c4330c..1e2e71f72 100644 --- a/src/gentropy/datasource/finngen/study_index.py +++ b/src/gentropy/datasource/finngen/study_index.py @@ -38,6 +38,10 @@ def join_efo_mapping( All studies without EFO traits are dropped. The EFO mappings are then aggregated into lists per studyId. + NOTE: preserve all studyId entries even if they don't have EFO mappings. + This is to avoid discrepancies between `study_index` and `credible_set` `studyId` column. + The rows with missing EFO mappings will be dropped in the study_index validation step. + Args: study_index (StudyIndex): Study index table. efo_curation_mapping (DataFrame): Dataframe with EFO mappings. @@ -70,8 +74,10 @@ def join_efo_mapping( f.col("PROPERTY_VALUE").alias("traitFromSource"), ) ) - # NOTE: inner join to keep only the studies with EFO mappings - si_df = study_index.df.join(efo_mappings, on="traitFromSource", how="inner") + + si_df = study_index.df.join( + efo_mappings, on="traitFromSource", how="left_outer" + ) common_cols = [c for c in si_df.columns if c != "traitFromSourceMappedId"] si_df = si_df.groupby(common_cols).agg( f.collect_list("traitFromSourceMappedId").alias("traitFromSourceMappedIds") From 15a058ee470942574c2c274821cfb28515340242 Mon Sep 17 00:00:00 2001 From: Daniel-Considine <113430683+Daniel-Considine@users.noreply.github.com> Date: Mon, 9 Sep 2024 14:43:16 +0100 Subject: [PATCH 024/188] feat: adding finemapping method to studylocusid hash (#744) * feat: adding finemapping method to studylocusid hash * chore: updating function in needed files * test: update doc test * fix: mistakes * fix: tidying logic * chore: adding studyLocusId recalculation to pics finemapping method --------- Co-authored-by: Szymon Szyszkowski <69353402+project-defiant@users.noreply.github.com> --- src/gentropy/dataset/study_locus.py | 29 ++++++++++++------- .../datasource/eqtl_catalogue/finemapping.py | 2 +- .../datasource/finngen/finemapping.py | 4 ++- .../open_targets/l2g_gold_standard.py | 1 + src/gentropy/l2g.py | 1 + src/gentropy/method/pics.py | 6 ++++ src/gentropy/susie_finemapper.py | 7 +++-- 7 files changed, 36 insertions(+), 14 deletions(-) diff --git a/src/gentropy/dataset/study_locus.py b/src/gentropy/dataset/study_locus.py index 47a73c665..ee488b019 100644 --- a/src/gentropy/dataset/study_locus.py +++ b/src/gentropy/dataset/study_locus.py @@ -347,29 +347,38 @@ def _align_overlapping_tags( ) @staticmethod - def assign_study_locus_id(study_id_col: Column, variant_id_col: Column) -> Column: + def assign_study_locus_id( + study_id_col: Column, + variant_id_col: Column, + finemapping_col: Column = None, + ) -> Column: """Hashes a column with a variant ID and a study ID to extract a consistent studyLocusId. Args: study_id_col (Column): column name with a study ID variant_id_col (Column): column name with a variant ID + finemapping_col (Column, optional): column with fine mapping methodology Returns: Column: column with a study locus ID Examples: - >>> df = spark.createDataFrame([("GCST000001", "1_1000_A_C"), ("GCST000002", "1_1000_A_C")]).toDF("studyId", "variantId") - >>> df.withColumn("study_locus_id", StudyLocus.assign_study_locus_id(f.col("studyId"), f.col("variantId"))).show() - +----------+----------+-------------------+ - | studyId| variantId| study_locus_id| - +----------+----------+-------------------+ - |GCST000001|1_1000_A_C|1553357789130151995| - |GCST000002|1_1000_A_C|-415050894682709184| - +----------+----------+-------------------+ + >>> df = spark.createDataFrame([("GCST000001", "1_1000_A_C", "SuSiE-inf"), ("GCST000002", "1_1000_A_C", "pics")]).toDF("studyId", "variantId", "finemappingMethod") + >>> df.withColumn("study_locus_id", StudyLocus.assign_study_locus_id(f.col("studyId"), f.col("variantId"), f.col("finemappingMethod"))).show() + +----------+----------+-----------------+-------------------+ + | studyId| variantId|finemappingMethod| study_locus_id| + +----------+----------+-----------------+-------------------+ + |GCST000001|1_1000_A_C| SuSiE-inf|3801266831619496075| + |GCST000002|1_1000_A_C| pics|1581844826999194430| + +----------+----------+-----------------+-------------------+ """ + if finemapping_col is None: + finemapping_col = f.lit(None).cast(StringType()) variant_id_col = f.coalesce(variant_id_col, f.rand().cast("string")) - return f.xxhash64(study_id_col, variant_id_col).alias("studyLocusId") + return f.xxhash64(study_id_col, variant_id_col, finemapping_col).alias( + "studyLocusId" + ) @classmethod def calculate_credible_set_log10bf(cls: type[StudyLocus], logbfs: Column) -> Column: diff --git a/src/gentropy/datasource/eqtl_catalogue/finemapping.py b/src/gentropy/datasource/eqtl_catalogue/finemapping.py index 21bf8ec38..a5c02dd3e 100644 --- a/src/gentropy/datasource/eqtl_catalogue/finemapping.py +++ b/src/gentropy/datasource/eqtl_catalogue/finemapping.py @@ -259,7 +259,7 @@ def from_susie_results( .select( *study_locus_cols, StudyLocus.assign_study_locus_id( - f.col("studyId"), f.col("variantId") + f.col("studyId"), f.col("variantId"), f.col("finemappingMethod") ), StudyLocus.calculate_credible_set_log10bf( f.col("locus.logBF") diff --git a/src/gentropy/datasource/finngen/finemapping.py b/src/gentropy/datasource/finngen/finemapping.py index cbdd01fdc..092a79372 100644 --- a/src/gentropy/datasource/finngen/finemapping.py +++ b/src/gentropy/datasource/finngen/finemapping.py @@ -470,7 +470,9 @@ def from_finngen_susie_finemapping( ) ).withColumn( "studyLocusId", - StudyLocus.assign_study_locus_id(f.col("studyId"), f.col("variantId")), + StudyLocus.assign_study_locus_id( + f.col("studyId"), f.col("variantId"), f.col("finemappingMethod") + ), ) return StudyLocus( diff --git a/src/gentropy/datasource/open_targets/l2g_gold_standard.py b/src/gentropy/datasource/open_targets/l2g_gold_standard.py index 97b04320c..2cfcd62f8 100644 --- a/src/gentropy/datasource/open_targets/l2g_gold_standard.py +++ b/src/gentropy/datasource/open_targets/l2g_gold_standard.py @@ -1,4 +1,5 @@ """Parser for OTPlatform locus to gene gold standards curation.""" + from __future__ import annotations from typing import Type diff --git a/src/gentropy/l2g.py b/src/gentropy/l2g.py index 432e46f88..cb13d3640 100644 --- a/src/gentropy/l2g.py +++ b/src/gentropy/l2g.py @@ -201,6 +201,7 @@ def _generate_feature_matrix(self) -> L2GFeatureMatrix: f.col("sentinel_variant.alleles.reference"), f.col("sentinel_variant.alleles.alternative"), ), + f.col("finemappingMethod"), ).alias("studyLocusId"), ) ), diff --git a/src/gentropy/method/pics.py b/src/gentropy/method/pics.py index e5ed5f2c6..2de06f512 100644 --- a/src/gentropy/method/pics.py +++ b/src/gentropy/method/pics.py @@ -254,6 +254,12 @@ def finemap( "finemappingMethod", f.coalesce(f.col("finemappingMethod"), f.lit("pics")), ) + .withColumn( + "studyLocusId", + StudyLocus.assign_study_locus_id( + "studyId", "variantId", "finemappingMethod" + ), + ) .drop("neglog_pvalue") ), _schema=StudyLocus.get_schema(), diff --git a/src/gentropy/susie_finemapper.py b/src/gentropy/susie_finemapper.py index f2997eb9f..f4b9141d0 100644 --- a/src/gentropy/susie_finemapper.py +++ b/src/gentropy/susie_finemapper.py @@ -94,7 +94,10 @@ def __init__( study_locus = ( StudyLocus.from_parquet(session, study_locus_input) .df.withColumn( - "studyLocusId", StudyLocus.assign_study_locus_id("studyId", "variantId") + "studyLocusId", + StudyLocus.assign_study_locus_id( + "studyId", "variantId", "finemappingMethod" + ), ) .collect()[0] ) @@ -380,7 +383,7 @@ def susie_inf_to_studylocus( .withColumn( "studyLocusId", StudyLocus.assign_study_locus_id( - f.col("studyId"), f.col("variantId") + f.col("studyId"), f.col("variantId"), f.col("finemappingMethod") ), ) .select( From 3c1e81a78cc7a49b43902c6de24586f9d1ca3a41 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Sep 2024 16:59:42 +0100 Subject: [PATCH 025/188] build(deps-dev): bump ipython from 8.26.0 to 8.27.0 (#741) Bumps [ipython](https://github.com/ipython/ipython) from 8.26.0 to 8.27.0. - [Release notes](https://github.com/ipython/ipython/releases) - [Commits](https://github.com/ipython/ipython/compare/8.26.0...8.27.0) --- updated-dependencies: - dependency-name: ipython dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Szymon Szyszkowski <69353402+project-defiant@users.noreply.github.com> --- poetry.lock | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/poetry.lock b/poetry.lock index 46d0cf279..21c53d38d 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. [[package]] name = "aiodns" @@ -4051,13 +4051,13 @@ test = ["flaky", "ipyparallel", "pre-commit", "pytest (>=7.0)", "pytest-asyncio [[package]] name = "ipython" -version = "8.26.0" +version = "8.27.0" description = "IPython: Productive Interactive Computing" optional = false python-versions = ">=3.10" files = [ - {file = "ipython-8.26.0-py3-none-any.whl", hash = "sha256:e6b347c27bdf9c32ee9d31ae85defc525755a1869f14057e900675b9e8d6e6ff"}, - {file = "ipython-8.26.0.tar.gz", hash = "sha256:1cec0fbba8404af13facebe83d04436a7434c7400e59f47acf467c64abd0956c"}, + {file = "ipython-8.27.0-py3-none-any.whl", hash = "sha256:f68b3cb8bde357a5d7adc9598d57e22a45dfbea19eb6b98286fa3b288c9cd55c"}, + {file = "ipython-8.27.0.tar.gz", hash = "sha256:0b99a2dc9f15fd68692e898e5568725c6d49c527d36a9fb5960ffbdeaa82ff7e"}, ] [package.dependencies] @@ -4835,6 +4835,7 @@ description = "Expand standard functools to methods" optional = false python-versions = "*" files = [ + {file = "methodtools-0.4.7-py2.py3-none-any.whl", hash = "sha256:5e188c780b236adc12e75b5f078c5afb419ef99eb648569fc6d7071f053a1f11"}, {file = "methodtools-0.4.7.tar.gz", hash = "sha256:e213439dd64cfe60213f7015da6efe5dd4003fd89376db3baa09fe13ec2bb0ba"}, ] @@ -6879,6 +6880,7 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, @@ -8431,6 +8433,7 @@ description = "'Turn functions and methods into fully controllable objects'" optional = false python-versions = "*" files = [ + {file = "wirerope-0.4.7-py2.py3-none-any.whl", hash = "sha256:332973a3be6898f02fd0e73b2e20414c5102cc6c811d75856a938206677495c8"}, {file = "wirerope-0.4.7.tar.gz", hash = "sha256:f3961039218276283c5037da0fa164619def0327595f10892d562a61a8603990"}, ] From 151b4ec8f177b461f21ded39207206eae9bfdfd2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 10 Sep 2024 09:42:27 +0100 Subject: [PATCH 026/188] build(deps-dev): bump deptry from 0.19.1 to 0.20.0 (#742) Bumps [deptry](https://github.com/fpgmaas/deptry) from 0.19.1 to 0.20.0. - [Release notes](https://github.com/fpgmaas/deptry/releases) - [Changelog](https://github.com/fpgmaas/deptry/blob/main/CHANGELOG.md) - [Commits](https://github.com/fpgmaas/deptry/compare/0.19.1...0.20.0) --- updated-dependencies: - dependency-name: deptry dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Szymon Szyszkowski <69353402+project-defiant@users.noreply.github.com> --- poetry.lock | 28 ++++++++++++++-------------- pyproject.toml | 2 +- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/poetry.lock b/poetry.lock index 21c53d38d..2ba1390ce 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1667,23 +1667,23 @@ dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "sphinx (<2)", "tox"] [[package]] name = "deptry" -version = "0.19.1" +version = "0.20.0" description = "A command line utility to check for unused, missing and transitive dependencies in a Python project." optional = false python-versions = ">=3.8" files = [ - {file = "deptry-0.19.1-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:3a20ef0dd1c737fb05553d1b9c2fa9f185d0c9d3d881d255334cef401ffdc599"}, - {file = "deptry-0.19.1-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:2c6b2df353e5113fd2f787c2f7e694657548d388929e988e8644bd178e19fc5c"}, - {file = "deptry-0.19.1-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a407bab3486e3844f93d702f1a381942873b2a46056c693b5634bbde219bb056"}, - {file = "deptry-0.19.1-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:43f33789b97b47313609e92b62fabf8a71bba0d35a7476806da5d3d152e32345"}, - {file = "deptry-0.19.1-cp38-abi3-win_amd64.whl", hash = "sha256:0bad85a77b31360d0f52383b14783fdae4a201b597c0158fe10e91a779c67079"}, - {file = "deptry-0.19.1-cp38-abi3-win_arm64.whl", hash = "sha256:c59142d9dca8873325692fbb7aa1d2902fde87020dcc8102f75120ba95515172"}, - {file = "deptry-0.19.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a1abc119f9c8536b8ab1ee2122d4130665f33225d00d8615256ce354eb2c11ba"}, - {file = "deptry-0.19.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:7344c6cea032b549d86e156aa1e679fb94cd44deb7e93f25cb6d9c0ded5ea06f"}, - {file = "deptry-0.19.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ff7d8954265c48ea334fdd508339c51d3fba05e2d4a8be47712c69d1c8d35c94"}, - {file = "deptry-0.19.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:023073247e5dac21254bf7b600ca2e2b71560652d2dfbe11535445ee912ca059"}, - {file = "deptry-0.19.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:af8a0a9c42f8f92dfbc048e724fa89b9131f032f7e245812260560c214395abf"}, - {file = "deptry-0.19.1.tar.gz", hash = "sha256:1c12fea1d2301f42c7035c5636e4b9421457fde256fe7a241245662d20b4c841"}, + {file = "deptry-0.20.0-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:41434d95124851b83cb05524d1a09ad6fea62006beafed2ef90a6b501c1b237f"}, + {file = "deptry-0.20.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:b3b4b22d1406147de5d606a24042126cd74d52fdfdb0232b9c5fd0270d601610"}, + {file = "deptry-0.20.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:012fb106dbea6ca95196cdcd75ac90c516c8f01292f7934f2e802a7cf025a660"}, + {file = "deptry-0.20.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8ce3920e2bd6d2b4427ab31ab8efb94bbef897001c2d395782bc30002966d12d"}, + {file = "deptry-0.20.0-cp38-abi3-win_amd64.whl", hash = "sha256:0c90ce64e637d0e902bc97c5a020adecfee9e9f09ee0bf4c61554994139bebdb"}, + {file = "deptry-0.20.0-cp38-abi3-win_arm64.whl", hash = "sha256:6886ff44aaf26fd83093f14f844ebc84589d90df9bbad9a1625e8a080e6f1be2"}, + {file = "deptry-0.20.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:ace3b39b1d0763f357c79bab003d1b135bea2eb61102be539992621a42d1ac7b"}, + {file = "deptry-0.20.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d1a00f8c9e6c0829a4a523edd5e526e3df06d2b50e0a99446f09f9723df2efad"}, + {file = "deptry-0.20.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e233859f150df70ffff76e95f9b7326fc25494b9beb26e776edae20f0f515e7d"}, + {file = "deptry-0.20.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f92e7e97ef42477717747b190bc6796ab94b35655af126d8c577f7eae0eb3a9"}, + {file = "deptry-0.20.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:f6cee6005997791bb77155667be055333fb63ae9a24f0f103f25faf1e7affe34"}, + {file = "deptry-0.20.0.tar.gz", hash = "sha256:62e9aaf3aea9e2ca66c85da98a0ba0290b4d3daea4e1d0ad937d447bd3c36402"}, ] [package.dependencies] @@ -8690,4 +8690,4 @@ test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", [metadata] lock-version = "2.0" python-versions = "^3.10, <3.11" -content-hash = "04bc80689794ab41c58a2daf8f7841a36b6f34bed3b74069b6e0e8c30f32d24b" +content-hash = "489d535e828faa827aa6cedc3bb739eff1c3b841770d3b9e94bdde44e572e621" diff --git a/pyproject.toml b/pyproject.toml index 3dbf9f8ff..d91629ab3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -75,7 +75,7 @@ apache-airflow = "^2.8.0" apache-airflow-providers-google = "^10.13.1" pydoclint = ">=0.3.8,<0.6.0" prettier = "^0.0.7" -deptry = ">=0.12,<0.20" +deptry = ">=0.12,<0.21" yamllint = "^1.33.0" [tool.semantic_release] From 0b216f60bd8ffd2235dae80a91ade53cc4e67812 Mon Sep 17 00:00:00 2001 From: Szymon Szyszkowski <69353402+project-defiant@users.noreply.github.com> Date: Tue, 10 Sep 2024 14:37:12 +0200 Subject: [PATCH 027/188] fix: validation name mapping (#753) * fix: use mapping instead of enum values in valid_rows * fix: typos * fix: swap valid and invalid paths --------- Co-authored-by: Szymon Szyszkowski --- src/gentropy/dataset/dataset.py | 27 +++++++++++++------ src/gentropy/dataset/study_index.py | 8 +++--- src/gentropy/dataset/study_locus.py | 8 +++--- src/gentropy/study_locus_validation.py | 10 +++---- .../dataset/test_dataset_exclusion.py | 22 +++++++-------- 5 files changed, 41 insertions(+), 34 deletions(-) diff --git a/src/gentropy/dataset/dataset.py b/src/gentropy/dataset/dataset.py index b31537a2a..e019ea379 100644 --- a/src/gentropy/dataset/dataset.py +++ b/src/gentropy/dataset/dataset.py @@ -86,13 +86,15 @@ def get_QC_column_name(cls: type[Self]) -> str | None: return None @classmethod - def get_QC_categories(cls: type[Self]) -> list[str]: - """Method to get the QC categories for this dataset. Returns empty list unless overriden by child classes. + def get_QC_mappings(cls: type[Self]) -> dict[str, str]: + """Method to get the mapping between QC flag and corresponding QC category value. + + Returns empty dict unless overriden by child classes. Returns: - list[str]: Column name + dict[str, str]: Mapping between flag name and QC column category value. """ - return [] + return {} @classmethod def from_parquet( @@ -193,22 +195,31 @@ def validate_schema(self: Dataset) -> None: def valid_rows(self: Self, invalid_flags: list[str], invalid: bool = False) -> Self: """Filters `Dataset` according to a list of quality control flags. Only `Dataset` classes with a QC column can be validated. + This method checks do following steps: + - Check if the Dataset contains a QC column. + - Check if the invalid_flags exist in the QC mappings flags. + - Filter the Dataset according to the invalid_flags and invalid parameters. + Args: invalid_flags (list[str]): List of quality control flags to be excluded. - invalid (bool): If True returns the invalid rows, instead of the valids. Defaults to False. + invalid (bool): If True returns the invalid rows, instead of the valid. Defaults to False. Returns: Self: filtered dataset. Raises: ValueError: If the Dataset does not contain a QC column. + ValueError: If the invalid_flags elements do not exist in QC mappings flags. """ # If the invalid flags are not valid quality checks (enum) for this Dataset we raise an error: + invalid_reasons = [] for flag in invalid_flags: - if flag not in self.get_QC_categories(): + if flag not in self.get_QC_mappings(): raise ValueError( - f"{flag} is not a valid QC flag for {type(self).__name__} ({self.get_QC_categories()})." + f"{flag} is not a valid QC flag for {type(self).__name__} ({self.get_QC_mappings()})." ) + reason = self.get_QC_mappings()[flag] + invalid_reasons.append(reason) qc_column_name = self.get_QC_column_name() # If Dataset (class) does not contain QC column we raise an error: @@ -222,7 +233,7 @@ def valid_rows(self: Self, invalid_flags: list[str], invalid: bool = False) -> S qc = f.when(f.col(column).isNull(), f.array()).otherwise(f.col(column)) filterCondition = ~f.arrays_overlap( - f.array([f.lit(i) for i in invalid_flags]), qc + f.array([f.lit(i) for i in invalid_reasons]), qc ) # Returning the filtered dataset: if invalid: diff --git a/src/gentropy/dataset/study_index.py b/src/gentropy/dataset/study_index.py index f60b2135c..ac637f137 100644 --- a/src/gentropy/dataset/study_index.py +++ b/src/gentropy/dataset/study_index.py @@ -118,13 +118,13 @@ def get_QC_column_name(cls: type[StudyIndex]) -> str: return "qualityControls" @classmethod - def get_QC_categories(cls: type[StudyIndex]) -> list[str]: - """Return the quality control categories. + def get_QC_mappings(cls: type[StudyIndex]) -> dict[str, str]: + """Quality control flag to QC column category mappings. Returns: - list[str]: The quality control categories. + dict[str, str]: Mapping between flag name and QC column category value. """ - return [member.value for member in StudyQualityCheck] + return {member.name: member.value for member in StudyQualityCheck} @classmethod def aggregate_and_map_ancestries( diff --git a/src/gentropy/dataset/study_locus.py b/src/gentropy/dataset/study_locus.py index ee488b019..edf9dc8be 100644 --- a/src/gentropy/dataset/study_locus.py +++ b/src/gentropy/dataset/study_locus.py @@ -421,13 +421,13 @@ def get_QC_column_name(cls: type[StudyLocus]) -> str: return "qualityControls" @classmethod - def get_QC_categories(cls: type[StudyLocus]) -> list[str]: - """Quality control categories. + def get_QC_mappings(cls: type[StudyLocus]) -> dict[str, str]: + """Quality control flag to QC column category mappings. Returns: - list[str]: List of quality control categories. + dict[str, str]: Mapping between flag name and QC column category value. """ - return [member.value for member in StudyLocusQualityCheck] + return {member.name: member.value for member in StudyLocusQualityCheck} def filter_by_study_type( self: StudyLocus, study_type: str, study_index: StudyIndex diff --git a/src/gentropy/study_locus_validation.py b/src/gentropy/study_locus_validation.py index 06995290c..41a572e79 100644 --- a/src/gentropy/study_locus_validation.py +++ b/src/gentropy/study_locus_validation.py @@ -48,10 +48,10 @@ def __init__( .validate_unique_study_locus_id() # Flagging duplicated study locus ids ).persist() # we will need this for 2 types of outputs - study_locus_with_qc.valid_rows(invalid_qc_reasons).df.write.parquet( - invalid_study_locus_path - ) - study_locus_with_qc.valid_rows( invalid_qc_reasons, invalid=True - ).df.write.parquet(valid_study_locus_path) + ).df.write.parquet(invalid_study_locus_path) + + study_locus_with_qc.valid_rows(invalid_qc_reasons).df.write.parquet( + valid_study_locus_path + ) diff --git a/tests/gentropy/dataset/test_dataset_exclusion.py b/tests/gentropy/dataset/test_dataset_exclusion.py index 361398f34..329a0a1d5 100644 --- a/tests/gentropy/dataset/test_dataset_exclusion.py +++ b/tests/gentropy/dataset/test_dataset_exclusion.py @@ -16,9 +16,9 @@ class TestDataExclusion: the right rows are excluded. """ - CORRECT_FILTER = ["The identifier of this study is not unique."] - INCORRECT_FILTER = ["Some mock flag."] - ALL_FILTERS = [member.value for member in StudyQualityCheck] + CORRECT_FLAG = ["DUPLICATED_STUDY"] + INCORRECT_FLAG = ["UNKNOWN_CATEGORY"] + ALL_FLAGS = [member.name for member in StudyQualityCheck] DATASET = [ # Good study no flag: @@ -52,8 +52,8 @@ def _setup(self: TestDataExclusion, spark: SparkSession) -> None: @pytest.mark.parametrize( "filter_, expected", [ - (CORRECT_FILTER, ["S1", "S2"]), - (ALL_FILTERS, ["S1"]), + (CORRECT_FLAG, ["S1", "S2"]), + (ALL_FLAGS, ["S1"]), ], ) def test_valid_rows( @@ -72,8 +72,8 @@ def test_valid_rows( @pytest.mark.parametrize( "filter_, expected", [ - (CORRECT_FILTER, ["S3"]), - (ALL_FILTERS, ["S2", "S3"]), + (CORRECT_FLAG, ["S3"]), + (ALL_FLAGS, ["S2", "S3"]), ], ) def test_invalid_rows( @@ -90,11 +90,7 @@ def test_invalid_rows( def test_failing_quality_flag(self: TestDataExclusion) -> None: """Test invalid quality flag.""" with pytest.raises(ValueError): - self.study_index.valid_rows( - self.INCORRECT_FILTER, invalid=True - ).df.collect() + self.study_index.valid_rows(self.INCORRECT_FLAG, invalid=True).df.collect() with pytest.raises(ValueError): - self.study_index.valid_rows( - self.INCORRECT_FILTER, invalid=False - ).df.collect() + self.study_index.valid_rows(self.INCORRECT_FLAG, invalid=False).df.collect() From 010c881ce10c5851734b088ec6106f9d1be2d78a Mon Sep 17 00:00:00 2001 From: Yakov Date: Wed, 11 Sep 2024 09:25:59 +0100 Subject: [PATCH 028/188] fix: removing old functions (#752) Co-authored-by: Szymon Szyszkowski <69353402+project-defiant@users.noreply.github.com> --- src/gentropy/susie_finemapper.py | 653 ------------------------------- 1 file changed, 653 deletions(-) diff --git a/src/gentropy/susie_finemapper.py b/src/gentropy/susie_finemapper.py index f4b9141d0..587ea7963 100644 --- a/src/gentropy/susie_finemapper.py +++ b/src/gentropy/susie_finemapper.py @@ -27,7 +27,6 @@ ) from gentropy.dataset.study_index import StudyIndex from gentropy.dataset.study_locus import StudyLocus -from gentropy.dataset.summary_statistics import SummaryStatistics from gentropy.datasource.gnomad.ld import GnomADLDMatrix from gentropy.method.carma import CARMA from gentropy.method.sumstat_imputation import SummaryStatisticsImputation @@ -136,141 +135,6 @@ def __init__( index=False, ) - @staticmethod - def susie_finemapper_one_studylocus_row( - GWAS: SummaryStatistics, - session: Session, - study_locus_row: Row, - study_index: StudyIndex, - radius: int = 1_000_000, - max_causal_snps: int = 10, - primary_signal_pval_threshold: float = 5e-8, - secondary_signal_pval_threshold: float = 1e-7, - purity_mean_r2_threshold: float = 0, - purity_min_r2_threshold: float = 0.25, - sum_pips: float = 0.99, - cs_lbf_thr: float = 2, - ) -> StudyLocus: - """Susie fine-mapper for StudyLocus row with SummaryStatistics object. - - Args: - GWAS (SummaryStatistics): GWAS summary statistics - session (Session): Spark session - study_locus_row (Row): StudyLocus row - study_index (StudyIndex): StudyIndex object - radius (int): window size for fine-mapping - max_causal_snps (int): number of causal variants - primary_signal_pval_threshold (float): p-value threshold for the lead variant from the primary signal (credibleSetIndex==1) - secondary_signal_pval_threshold (float): p-value threshold for the lead variant from the secondary signals - purity_mean_r2_threshold (float): thrshold for purity mean r2 qc metrics for filtering credible sets - purity_min_r2_threshold (float): thrshold for purity min r2 qc metrics for filtering credible sets - sum_pips (float): the expected sum of posterior probabilities in the locus, default is 0.99 (99% credible set) - cs_lbf_thr (float): credible set logBF threshold for filtering credible sets, default is 2 - - Returns: - StudyLocus: StudyLocus object with fine-mapped credible sets - """ - # PLEASE DO NOT REMOVE THIS LINE - pd.DataFrame.iteritems = pd.DataFrame.items - - chromosome = study_locus_row["chromosome"] - position = study_locus_row["position"] - studyId = study_locus_row["studyId"] - - study_index_df = study_index._df - study_index_df = study_index_df.filter(f.col("studyId") == studyId) - major_population = study_index_df.select( - "studyId", - f.array_max(f.col("ldPopulationStructure")) - .getItem("ldPopulation") - .alias("majorPopulation"), - ).collect()[0]["majorPopulation"] - - region = ( - chromosome - + ":" - + str(int(position - radius)) - + "-" - + str(int(position + radius)) - ) - - gwas_df = ( - GWAS.df.withColumn("z", f.col("beta") / f.col("standardError")) - .withColumn("chromosome", f.split(f.col("variantId"), "_")[0]) - .withColumn("position", f.split(f.col("variantId"), "_")[1]) - .filter(f.col("studyId") == studyId) - .filter(f.col("z").isNotNull()) - ) - # Remove ALL duplicated variants from GWAS DataFrame - we don't know which is correct - variant_counts = gwas_df.groupBy("variantId").count() - unique_variants = variant_counts.filter(f.col("count") == 1) - gwas_df = gwas_df.join(unique_variants, on="variantId", how="left_semi") - - ld_index = ( - GnomADLDMatrix() - .get_locus_index( - study_locus_row=study_locus_row, - radius=radius, - major_population=major_population, - ) - .withColumn( - "variantId", - f.concat( - f.lit(chromosome), - f.lit("_"), - f.col("`locus.position`"), - f.lit("_"), - f.col("alleles").getItem(0), - f.lit("_"), - f.col("alleles").getItem(1), - ).cast("string"), - ) - ) - - # Filtering out the variants that are not in the LD matrix, we don't need them - gwas_index = gwas_df.join( - ld_index.select("variantId", "alleles", "idx"), on="variantId" - ).sort("idx") - - gnomad_ld = GnomADLDMatrix.get_numpy_matrix( - gwas_index, gnomad_ancestry=major_population - ) - - pd_df = gwas_index.toPandas() - z_to_fm = np.array(pd_df["z"]) - ld_to_fm = gnomad_ld - - susie_output = SUSIE_inf.susie_inf(z=z_to_fm, LD=ld_to_fm, L=max_causal_snps) - - schema = StructType( - [ - StructField("variantId", StringType(), True), - StructField("chromosome", StringType(), True), - StructField("position", IntegerType(), True), - StructField("z", DoubleType(), True), - ] - ) - pd_df["position"] = pd_df["position"].astype(int) - variant_index = session.spark.createDataFrame( - pd_df[["variantId", "chromosome", "position", "z"]], - schema=schema, - ) - - return SusieFineMapperStep.susie_inf_to_studylocus( - susie_output=susie_output, - session=session, - studyId=studyId, - region=region, - variant_index=variant_index, - ld_matrix=ld_to_fm, - primary_signal_pval_threshold=primary_signal_pval_threshold, - secondary_signal_pval_threshold=secondary_signal_pval_threshold, - purity_mean_r2_threshold=purity_mean_r2_threshold, - purity_min_r2_threshold=purity_min_r2_threshold, - sum_pips=sum_pips, - cs_lbf_thr=cs_lbf_thr, - ) - @staticmethod def susie_inf_to_studylocus( susie_output: dict[str, Any], @@ -506,147 +370,6 @@ def susie_inf_to_studylocus( _schema=StudyLocus.get_schema(), ) - @staticmethod - def susie_finemapper_ss_gathered( - session: Session, - study_locus_row: Row, - study_index: StudyIndex, - radius: int = 1_000_000, - max_causal_snps: int = 10, - primary_signal_pval_threshold: float = 5e-8, - secondary_signal_pval_threshold: float = 1e-7, - purity_mean_r2_threshold: float = 0, - purity_min_r2_threshold: float = 0.25, - cs_lbf_thr: float = 2, - sum_pips: float = 0.99, - ) -> StudyLocus | None: - """Susie fine-mapper for StudyLocus row with locus annotated summary statistics. - - Args: - session (Session): Spark session - study_locus_row (Row): StudyLocus row - study_index (StudyIndex): StudyIndex object - radius (int): window size for fine-mapping - max_causal_snps (int): number of causal variants - primary_signal_pval_threshold (float): p-value threshold for the lead variant from the primary signal (credibleSetIndex==1) - secondary_signal_pval_threshold (float): p-value threshold for the lead variant from the secondary signals - purity_mean_r2_threshold (float): thrshold for purity mean r2 qc metrics for filtering credible sets - purity_min_r2_threshold (float): thrshold for purity min r2 qc metrics for filtering credible sets - cs_lbf_thr (float): credible set logBF threshold for filtering credible sets - sum_pips (float): the expected sum of posterior probabilities in the locus, default is 0.99 (99% credible set) - - Returns: - StudyLocus | None: StudyLocus object with fine-mapped credible sets, or None - """ - # PLEASE DO NOT REMOVE THIS LINE - pd.DataFrame.iteritems = pd.DataFrame.items - - chromosome = study_locus_row["chromosome"] - position = study_locus_row["position"] - studyId = study_locus_row["studyId"] - - study_index_df = study_index._df - study_index_df = study_index_df.filter(f.col("studyId") == studyId) - major_population = study_index_df.select( - "studyId", - f.array_max(f.col("ldPopulationStructure")) - .getItem("ldPopulation") - .alias("majorPopulation"), - ).collect()[0]["majorPopulation"] - - region = ( - chromosome - + ":" - + str(int(position - radius)) - + "-" - + str(int(position + radius)) - ) - - schema = StudyLocus.get_schema() - gwas_df = session.spark.createDataFrame([study_locus_row], schema=schema) - exploded_df = gwas_df.select(f.explode("locus").alias("locus")) - - result_df = exploded_df.select( - "locus.variantId", "locus.beta", "locus.standardError" - ) - gwas_df = ( - result_df.withColumn("z", f.col("beta") / f.col("standardError")) - .withColumn("chromosome", f.split(f.col("variantId"), "_")[0]) - .withColumn("position", f.split(f.col("variantId"), "_")[1]) - .filter(f.col("z").isNotNull()) - ) - # Remove ALL duplicated variants from GWAS DataFrame - we don't know which is correct - variant_counts = gwas_df.groupBy("variantId").count() - unique_variants = variant_counts.filter(f.col("count") == 1) - gwas_df = gwas_df.join(unique_variants, on="variantId", how="left_semi") - - ld_index = ( - GnomADLDMatrix() - .get_locus_index( - study_locus_row=study_locus_row, - radius=radius, - major_population=major_population, - ) - .withColumn( - "variantId", - f.concat( - f.lit(chromosome), - f.lit("_"), - f.col("`locus.position`"), - f.lit("_"), - f.col("alleles").getItem(0), - f.lit("_"), - f.col("alleles").getItem(1), - ).cast("string"), - ) - ) - - # Filtering out the variants that are not in the LD matrix, we don't need them - gwas_index = gwas_df.join( - ld_index.select("variantId", "alleles", "idx"), on="variantId" - ).sort("idx") - if gwas_index.rdd.isEmpty(): - logging.warning("No overlapping variants in the LD Index") - return None - gnomad_ld = GnomADLDMatrix.get_numpy_matrix( - gwas_index, gnomad_ancestry=major_population - ) - - pd_df = gwas_index.toPandas() - z_to_fm = np.array(pd_df["z"]) - ld_to_fm = gnomad_ld - - susie_output = SUSIE_inf.susie_inf(z=z_to_fm, LD=ld_to_fm, L=max_causal_snps) - - schema = StructType( - [ - StructField("variantId", StringType(), True), - StructField("chromosome", StringType(), True), - StructField("position", IntegerType(), True), - StructField("z", DoubleType(), True), - ] - ) - pd_df["position"] = pd_df["position"].astype(int) - variant_index = session.spark.createDataFrame( - pd_df[["variantId", "chromosome", "position", "z"]], - schema=schema, - ) - - return SusieFineMapperStep.susie_inf_to_studylocus( - susie_output=susie_output, - session=session, - studyId=studyId, - region=region, - variant_index=variant_index, - ld_matrix=ld_to_fm, - primary_signal_pval_threshold=primary_signal_pval_threshold, - secondary_signal_pval_threshold=secondary_signal_pval_threshold, - purity_mean_r2_threshold=purity_mean_r2_threshold, - purity_min_r2_threshold=purity_min_r2_threshold, - cs_lbf_thr=cs_lbf_thr, - sum_pips=sum_pips, - ) - @staticmethod def susie_finemapper_from_prepared_dataframes( GWAS_df: DataFrame, @@ -847,382 +570,6 @@ def susie_finemapper_from_prepared_dataframes( "log": log_df, } - @staticmethod - def susie_finemapper_one_studylocus_row_v2_dev( - GWAS: SummaryStatistics, - session: Session, - study_locus_row: Row, - study_index: StudyIndex, - radius: int = 1_000_000, - max_causal_snps: int = 10, - susie_est_tausq: bool = False, - run_carma: bool = False, - run_sumstat_imputation: bool = False, - carma_time_limit: int = 600, - imputed_r2_threshold: float = 0.9, - ld_score_threshold: float = 5, - sum_pips: float = 0.99, - primary_signal_pval_threshold: float = 5e-8, - secondary_signal_pval_threshold: float = 1e-7, - purity_mean_r2_threshold: float = 0, - purity_min_r2_threshold: float = 0.25, - cs_lbf_thr: float = 2, - ) -> dict[str, Any]: - """Susie fine-mapper function that uses Summary Statstics, chromosome and position as inputs. - - Args: - GWAS (SummaryStatistics): GWAS summary statistics - session (Session): Spark session - study_locus_row (Row): StudyLocus row - study_index (StudyIndex): StudyIndex object - radius (int): Radius in base-pairs of window for fine-mapping - max_causal_snps (int): maximum number of causal variants - susie_est_tausq (bool): estimate tau squared, default is False - run_carma (bool): run CARMA, default is False - run_sumstat_imputation (bool): run summary statistics imputation, default is False - carma_time_limit (int): CARMA time limit, default is 600 seconds - imputed_r2_threshold (float): imputed R2 threshold, default is 0.8 - ld_score_threshold (float): LD score threshold ofr imputation, default is 4 - sum_pips (float): the expected sum of posterior probabilities in the locus, default is 0.99 (99% credible set) - primary_signal_pval_threshold (float): p-value threshold for the lead variant from the primary signal (credibleSetIndex==1) - secondary_signal_pval_threshold (float): p-value threshold for the lead variant from the secondary signals - purity_mean_r2_threshold (float): thrshold for purity mean r2 qc metrics for filtering credible sets - purity_min_r2_threshold (float): thrshold for purity min r2 qc metrics for filtering credible sets - cs_lbf_thr (float): credible set logBF threshold for filtering credible sets, default is 2 - - Returns: - dict[str, Any]: dictionary with study locus, number of GWAS variants, number of LD variants, number of variants after merge, number of outliers, number of imputed variants, number of variants to fine-map - """ - # PLEASE DO NOT REMOVE THIS LINE - pd.DataFrame.iteritems = pd.DataFrame.items - - chromosome = study_locus_row["chromosome"] - position = study_locus_row["position"] - studyId = study_locus_row["studyId"] - - study_index_df = study_index._df - study_index_df = study_index_df.filter(f.col("studyId") == studyId) - major_population = study_index_df.select( - "studyId", - f.array_max(f.col("ldPopulationStructure")) - .getItem("ldPopulation") - .alias("majorPopulation"), - ).collect()[0]["majorPopulation"] - - region = ( - chromosome - + ":" - + str(int(position - radius)) - + "-" - + str(int(position + radius)) - ) - gwas_df = ( - GWAS.df.withColumn("z", f.col("beta") / f.col("standardError")) - .withColumn( - "chromosome", f.split(f.col("variantId"), "_")[0].cast("string") - ) - .withColumn("position", f.split(f.col("variantId"), "_")[1].cast("int")) - .filter(f.col("studyId") == studyId) - .filter(f.col("z").isNotNull()) - .filter(f.col("chromosome") == chromosome) - .filter(f.col("position") >= position - radius) - .filter(f.col("position") <= position + radius) - ) - - ld_index = ( - GnomADLDMatrix() - .get_locus_index( - study_locus_row=study_locus_row, - radius=radius, - major_population=major_population, - ) - .withColumn( - "variantId", - f.concat( - f.lit(chromosome), - f.lit("_"), - f.col("`locus.position`"), - f.lit("_"), - f.col("alleles").getItem(0), - f.lit("_"), - f.col("alleles").getItem(1), - ).cast("string"), - ) - ) - - gnomad_ld = GnomADLDMatrix.get_numpy_matrix( - ld_index, gnomad_ancestry=major_population - ) - - out = SusieFineMapperStep.susie_finemapper_from_prepared_dataframes( - GWAS_df=gwas_df, - ld_index=ld_index, - gnomad_ld=gnomad_ld, - L=max_causal_snps, - session=session, - studyId=studyId, - region=region, - susie_est_tausq=susie_est_tausq, - run_carma=run_carma, - run_sumstat_imputation=run_sumstat_imputation, - carma_time_limit=carma_time_limit, - imputed_r2_threshold=imputed_r2_threshold, - ld_score_threshold=ld_score_threshold, - sum_pips=sum_pips, - primary_signal_pval_threshold=primary_signal_pval_threshold, - secondary_signal_pval_threshold=secondary_signal_pval_threshold, - purity_mean_r2_threshold=purity_mean_r2_threshold, - purity_min_r2_threshold=purity_min_r2_threshold, - cs_lbf_thr=cs_lbf_thr, - ) - - return out - - @staticmethod - def susie_finemapper_one_studylocus_row_v3_dev_ss_gathered( - session: Session, - study_locus_row: Row, - study_index: StudyIndex, - radius: int = 1_000_000, - max_causal_snps: int = 10, - susie_est_tausq: bool = False, - run_carma: bool = False, - run_sumstat_imputation: bool = False, - carma_time_limit: int = 600, - imputed_r2_threshold: float = 0.9, - ld_score_threshold: float = 5, - sum_pips: float = 0.99, - primary_signal_pval_threshold: float = 5e-8, - secondary_signal_pval_threshold: float = 1e-7, - purity_mean_r2_threshold: float = 0, - purity_min_r2_threshold: float = 0.25, - cs_lbf_thr: float = 2, - ) -> dict[str, Any] | None: - """Susie fine-mapper function that uses study-locus row with collected locus, chromosome and position as inputs. - - Args: - session (Session): Spark session - study_locus_row (Row): StudyLocus row with collected locus - study_index (StudyIndex): StudyIndex object - radius (int): Radius in base-pairs of window for fine-mapping - max_causal_snps (int): maximum number of causal variants - susie_est_tausq (bool): estimate tau squared, default is False - run_carma (bool): run CARMA, default is False - run_sumstat_imputation (bool): run summary statistics imputation, default is False - carma_time_limit (int): CARMA time limit, default is 600 seconds - imputed_r2_threshold (float): imputed R2 threshold, default is 0.8 - ld_score_threshold (float): LD score threshold ofr imputation, default is 4 - sum_pips (float): the expected sum of posterior probabilities in the locus, default is 0.99 (99% credible set) - primary_signal_pval_threshold (float): p-value threshold for the lead variant from the primary signal (credibleSetIndex==1) - secondary_signal_pval_threshold (float): p-value threshold for the lead variant from the secondary signals - purity_mean_r2_threshold (float): thrshold for purity mean r2 qc metrics for filtering credible sets - purity_min_r2_threshold (float): thrshold for purity min r2 qc metrics for filtering credible sets - cs_lbf_thr (float): credible set logBF threshold for filtering credible sets, default is 2 - - Returns: - dict[str, Any] | None: dictionary with study locus, number of GWAS variants, number of LD variants, number of variants after merge, number of outliers, number of imputed variants, number of variants to fine-map, or None - """ - # PLEASE DO NOT REMOVE THIS LINE - pd.DataFrame.iteritems = pd.DataFrame.items - - chromosome = study_locus_row["chromosome"] - position = study_locus_row["position"] - studyId = study_locus_row["studyId"] - - study_index_df = study_index._df - study_index_df = study_index_df.filter(f.col("studyId") == studyId) - major_population = study_index_df.select( - "studyId", - f.array_max(f.col("ldPopulationStructure")) - .getItem("ldPopulation") - .alias("majorPopulation"), - ).collect()[0]["majorPopulation"] - - region = ( - chromosome - + ":" - + str(int(position - radius)) - + "-" - + str(int(position + radius)) - ) - - schema = StudyLocus.get_schema() - gwas_df = session.spark.createDataFrame([study_locus_row], schema=schema) - exploded_df = gwas_df.select(f.explode("locus").alias("locus")) - - result_df = exploded_df.select( - "locus.variantId", "locus.beta", "locus.standardError" - ) - gwas_df = ( - result_df.withColumn("z", f.col("beta") / f.col("standardError")) - .withColumn( - "chromosome", f.split(f.col("variantId"), "_")[0].cast("string") - ) - .withColumn("position", f.split(f.col("variantId"), "_")[1].cast("int")) - .filter(f.col("chromosome") == chromosome) - .filter(f.col("position") >= position - radius) - .filter(f.col("position") <= position + radius) - .filter(f.col("z").isNotNull()) - ) - - # Remove ALL duplicated variants from GWAS DataFrame - we don't know which is correct - variant_counts = gwas_df.groupBy("variantId").count() - unique_variants = variant_counts.filter(f.col("count") == 1) - gwas_df = gwas_df.join(unique_variants, on="variantId", how="left_semi") - - ld_index = ( - GnomADLDMatrix() - .get_locus_index( - study_locus_row=study_locus_row, - radius=radius, - major_population=major_population, - ) - .withColumn( - "variantId", - f.concat( - f.lit(chromosome), - f.lit("_"), - f.col("`locus.position`"), - f.lit("_"), - f.col("alleles").getItem(0), - f.lit("_"), - f.col("alleles").getItem(1), - ).cast("string"), - ) - ) - # Remove ALL duplicated variants from ld_index DataFrame - we don't know which is correct - variant_counts = ld_index.groupBy("variantId").count() - unique_variants = variant_counts.filter(f.col("count") == 1) - ld_index = ld_index.join(unique_variants, on="variantId", how="left_semi").sort( - "idx" - ) - - if not run_sumstat_imputation: - # Filtering out the variants that are not in the LD matrix, we don't need them - gwas_index = gwas_df.join( - ld_index.select("variantId", "alleles", "idx"), on="variantId" - ).sort("idx") - gwas_df = gwas_index.select( - "variantId", - "z", - "chromosome", - "position", - "beta", - "StandardError", - ) - gwas_index = gwas_index.drop( - "z", "chromosome", "position", "beta", "StandardError" - ) - if gwas_index.rdd.isEmpty(): - logging.warning("No overlapping variants in the LD Index") - return None - gnomad_ld = GnomADLDMatrix.get_numpy_matrix( - gwas_index, gnomad_ancestry=major_population - ) - # Module to remove NANs from the LD matrix - if sum(sum(np.isnan(gnomad_ld))) > 0: - gwas_index = gwas_index.toPandas() - - # First round of filtering out the variants with NANs - nan_count = 1 - (sum(np.isnan(gnomad_ld)) / len(gnomad_ld)) - indices = np.where(nan_count >= 0.98) - indices = indices[0] - gnomad_ld = gnomad_ld[indices][:, indices] - - gwas_index = gwas_index.iloc[indices, :] - - if len(gwas_index) == 0: - logging.warning("No overlapping variants in the LD Index") - return None - - # Second round of filtering out the variants with NANs - nan_count = sum(np.isnan(gnomad_ld)) - indices = np.where(nan_count == 0) - indices = indices[0] - - gnomad_ld = gnomad_ld[indices][:, indices] - gwas_index = gwas_index.iloc[indices, :] - - if len(gwas_index) == 0: - logging.warning("No overlapping variants in the LD Index") - return None - - gwas_index = session.spark.createDataFrame(gwas_index) - else: - gwas_index = gwas_df.join( - ld_index.select("variantId", "alleles", "idx"), on="variantId" - ).sort("idx") - if gwas_index.rdd.isEmpty(): - logging.warning("No overlapping variants in the LD Index") - return None - gwas_index = ld_index - gnomad_ld = GnomADLDMatrix.get_numpy_matrix( - gwas_index, gnomad_ancestry=major_population - ) - # Module to remove NANs from the LD matrix - if sum(sum(np.isnan(gnomad_ld))) > 0: - gwas_index = gwas_index.toPandas() - - # First round of filtering out the variants with NANs - nan_count = 1 - (sum(np.isnan(gnomad_ld)) / len(gnomad_ld)) - indices = np.where(nan_count >= 0.98) - indices = indices[0] - gnomad_ld = gnomad_ld[indices][:, indices] - - gwas_index = gwas_index.iloc[indices, :] - - if len(gwas_index) == 0: - logging.warning("No overlapping variants in the LD Index") - return None - - # Second round of filtering out the variants with NANs - nan_count = sum(np.isnan(gnomad_ld)) - indices = np.where(nan_count == 0) - indices = indices[0] - - gnomad_ld = gnomad_ld[indices][:, indices] - gwas_index = gwas_index.iloc[indices, :] - - if len(gwas_index) == 0: - logging.warning("No overlapping variants in the LD Index") - return None - - gwas_index = session.spark.createDataFrame(gwas_index) - - # sanity filters on LD matrix - np.fill_diagonal(gnomad_ld, 1) - gnomad_ld[gnomad_ld > 1] = 1 - gnomad_ld[gnomad_ld < -1] = -1 - upper_triangle = np.triu(gnomad_ld) - gnomad_ld = ( - upper_triangle + upper_triangle.T - np.diag(upper_triangle.diagonal()) - ) - np.fill_diagonal(gnomad_ld, 1) - - out = SusieFineMapperStep.susie_finemapper_from_prepared_dataframes( - GWAS_df=gwas_df, - ld_index=gwas_index, - gnomad_ld=gnomad_ld, - L=max_causal_snps, - session=session, - studyId=studyId, - region=region, - susie_est_tausq=susie_est_tausq, - run_carma=run_carma, - run_sumstat_imputation=run_sumstat_imputation, - carma_time_limit=carma_time_limit, - imputed_r2_threshold=imputed_r2_threshold, - ld_score_threshold=ld_score_threshold, - sum_pips=sum_pips, - primary_signal_pval_threshold=primary_signal_pval_threshold, - secondary_signal_pval_threshold=secondary_signal_pval_threshold, - purity_mean_r2_threshold=purity_mean_r2_threshold, - purity_min_r2_threshold=purity_min_r2_threshold, - cs_lbf_thr=cs_lbf_thr, - ) - - return out - @staticmethod def susie_finemapper_one_sl_row_v4_ss_gathered_boundaries( session: Session, From feb9cadeb282d4f5dcfda4e261710f55e723f2c5 Mon Sep 17 00:00:00 2001 From: Kirill Tsukanov Date: Wed, 11 Sep 2024 13:24:28 +0100 Subject: [PATCH 029/188] refactor: generalise per-chromosome processing (#754) * refactor: move VA preparation logic into a separate module * refactor: generalise per-chromosome summary stats ingestion * Update src/gentropy/common/per_chromosome.py Co-authored-by: Szymon Szyszkowski <69353402+project-defiant@users.noreply.github.com> --------- Co-authored-by: Szymon Szyszkowski <69353402+project-defiant@users.noreply.github.com> --- src/gentropy/common/per_chromosome.py | 98 +++++++++++++++++++ .../ukb_ppp_eur_sumstat_preprocess.py | 76 ++------------ 2 files changed, 104 insertions(+), 70 deletions(-) create mode 100644 src/gentropy/common/per_chromosome.py diff --git a/src/gentropy/common/per_chromosome.py b/src/gentropy/common/per_chromosome.py new file mode 100644 index 000000000..528e6ffbe --- /dev/null +++ b/src/gentropy/common/per_chromosome.py @@ -0,0 +1,98 @@ +"""Spark operations to make efficient per-chromosome processing possible.""" + +from __future__ import annotations + +import pyspark.sql.functions as f +from pyspark.sql import SparkSession + +from gentropy.datasource.ukb_ppp_eur.summary_stats import UkbPppEurSummaryStats + + +def prepare_va(session: SparkSession, variant_annotation_path: str, tmp_variant_annotation_path: str) -> None: + """Prepare the Variant Annotation dataset for efficient per-chromosome joins. + + Args: + session (SparkSession): The Spark session to be used for reading and writing data. + variant_annotation_path (str): The path to the input variant annotation dataset. + tmp_variant_annotation_path (str): The path to store the temporary output for the repartitioned annotation dataset. + """ + va_df = ( + session + .spark + .read + .parquet(variant_annotation_path) + ) + va_df_direct = ( + va_df. + select( + f.col("chromosome").alias("vaChromosome"), + f.col("variantId"), + f.concat_ws( + "_", + f.col("chromosome"), + f.col("position"), + f.col("referenceAllele"), + f.col("alternateAllele") + ).alias("ukb_ppp_id"), + f.lit("direct").alias("direction") + ) + ) + va_df_flip = ( + va_df. + select( + f.col("chromosome").alias("vaChromosome"), + f.col("variantId"), + f.concat_ws( + "_", + f.col("chromosome"), + f.col("position"), + f.col("alternateAllele"), + f.col("referenceAllele") + ).alias("ukb_ppp_id"), + f.lit("flip").alias("direction") + ) + ) + ( + va_df_direct.union(va_df_flip) + .coalesce(1) + .repartition("vaChromosome") + .write + .partitionBy("vaChromosome") + .mode("overwrite") + .parquet(tmp_variant_annotation_path) + ) + + +def process_summary_stats_per_chromosome(session: SparkSession, ingestion_class: type[UkbPppEurSummaryStats], raw_summary_stats_path: str, tmp_variant_annotation_path: str, summary_stats_output_path: str) -> None: + """Processes summary statistics for each chromosome, partitioning and writing results. + + Args: + session (SparkSession): The Spark session to use for distributed data processing. + ingestion_class (type[UkbPppEurSummaryStats]): The class used to handle ingestion of source data. Must have a `from_source` method returning a DataFrame. + raw_summary_stats_path (str): The path to the raw summary statistics files. + tmp_variant_annotation_path (str): The path to temporary variant annotation data, used for chromosome joins. + summary_stats_output_path (str): The output path to write processed summary statistics as parquet files. + """ + # Set mode to overwrite for processing the first chromosome. + write_mode = "overwrite" + # Chromosome 23 is X, this is handled downstream. + for chromosome in list(range(1, 24)): + logging_message = f" Processing chromosome {chromosome}" + session.logger.info(logging_message) + ( + ingestion_class.from_source( + spark=session.spark, + raw_summary_stats_path=raw_summary_stats_path, + tmp_variant_annotation_path=tmp_variant_annotation_path, + chromosome=str(chromosome), + ) + .df + .coalesce(1) + .repartition("studyId", "chromosome") + .write + .partitionBy("studyId", "chromosome") + .mode(write_mode) + .parquet(summary_stats_output_path) + ) + # Now that we have written the first chromosome, change mode to append for subsequent operations. + write_mode = "append" diff --git a/src/gentropy/ukb_ppp_eur_sumstat_preprocess.py b/src/gentropy/ukb_ppp_eur_sumstat_preprocess.py index fc7fed548..b192d963f 100644 --- a/src/gentropy/ukb_ppp_eur_sumstat_preprocess.py +++ b/src/gentropy/ukb_ppp_eur_sumstat_preprocess.py @@ -2,8 +2,10 @@ from __future__ import annotations -import pyspark.sql.functions as f - +from gentropy.common.per_chromosome import ( + prepare_va, + process_summary_stats_per_chromosome, +) from gentropy.common.session import Session from gentropy.datasource.ukb_ppp_eur.study_index import UkbPppEurStudyIndex from gentropy.datasource.ukb_ppp_eur.summary_stats import UkbPppEurSummaryStats @@ -27,51 +29,7 @@ def __init__( summary_stats_output_path (str): Summary stats output path. """ session.logger.info("Pre-compute the direct and flipped variant annotation dataset.") - va_df = ( - session - .spark - .read - .parquet(variant_annotation_path) - ) - va_df_direct = ( - va_df. - select( - f.col("chromosome").alias("vaChromosome"), - f.col("variantId"), - f.concat_ws( - "_", - f.col("chromosome"), - f.col("position"), - f.col("referenceAllele"), - f.col("alternateAllele") - ).alias("ukb_ppp_id"), - f.lit("direct").alias("direction") - ) - ) - va_df_flip = ( - va_df. - select( - f.col("chromosome").alias("vaChromosome"), - f.col("variantId"), - f.concat_ws( - "_", - f.col("chromosome"), - f.col("position"), - f.col("alternateAllele"), - f.col("referenceAllele") - ).alias("ukb_ppp_id"), - f.lit("flip").alias("direction") - ) - ) - ( - va_df_direct.union(va_df_flip) - .coalesce(1) - .repartition("vaChromosome") - .write - .partitionBy("vaChromosome") - .mode("overwrite") - .parquet(tmp_variant_annotation_path) - ) + prepare_va(session, variant_annotation_path, tmp_variant_annotation_path) session.logger.info("Process study index.") ( @@ -87,26 +45,4 @@ def __init__( ) session.logger.info("Process and harmonise summary stats.") - # Set mode to overwrite for processing the first chromosome. - write_mode = "overwrite" - # Chromosome 23 is X, this is handled downstream. - for chromosome in list(range(1, 24)): - logging_message = f" Processing chromosome {chromosome}" - session.logger.info(logging_message) - ( - UkbPppEurSummaryStats.from_source( - spark=session.spark, - raw_summary_stats_path=raw_summary_stats_path, - tmp_variant_annotation_path=tmp_variant_annotation_path, - chromosome=str(chromosome), - ) - .df - .coalesce(1) - .repartition("studyId", "chromosome") - .write - .partitionBy("studyId", "chromosome") - .mode(write_mode) - .parquet(summary_stats_output_path) - ) - # Now that we have written the first chromosome, change mode to append for subsequent operations. - write_mode = "append" + process_summary_stats_per_chromosome(session, UkbPppEurSummaryStats, raw_summary_stats_path, tmp_variant_annotation_path, summary_stats_output_path) From d10cc207c0bc6c538e887e3fea6f4b1e6eb081ca Mon Sep 17 00:00:00 2001 From: Kirill Tsukanov Date: Wed, 11 Sep 2024 13:30:21 +0100 Subject: [PATCH 030/188] refactor: generalise the harmonisation pipeline (#755) * refactor: move harmonisation into a separate module * refactor: make column names configurable * feat: make INFO and A1FREQ columns optional * docs: expand comments on tmp_variant_annotation_path and variant types --- src/gentropy/common/harmonise.py | 184 ++++++++++++++++++ .../datasource/ukb_ppp_eur/summary_stats.py | 142 ++------------ 2 files changed, 199 insertions(+), 127 deletions(-) create mode 100644 src/gentropy/common/harmonise.py diff --git a/src/gentropy/common/harmonise.py b/src/gentropy/common/harmonise.py new file mode 100644 index 000000000..aac763e43 --- /dev/null +++ b/src/gentropy/common/harmonise.py @@ -0,0 +1,184 @@ +"""Variant harmonisation utilities.""" + +import pyspark.sql.functions as f +import pyspark.sql.types as t +from pyspark.sql import DataFrame, SparkSession + +from gentropy.common.spark_helpers import neglog_pvalue_to_mantissa_and_exponent + + +def harmonise_summary_stats( + spark: SparkSession, + raw_summary_stats_path: str, + tmp_variant_annotation_path: str, + chromosome: str, + colname_position: str, + colname_allele0: str, + colname_allele1: str, + colname_a1freq: str, + colname_info: str, + colname_beta: str, + colname_se: str, + colname_mlog10p: str, + colname_n: str, +) -> DataFrame: + """Ingest and harmonise the summary stats. + + 1. Rename chromosome 23 to X. + 2. Filter out low INFO rows. + 3. Filter out low frequency rows. + 4. Assign variant types. + 5. Create variant ID for joining the variant annotation dataset. + 6. Join with the Variant Annotation dataset. + 7. Drop bad quality variants. + + Args: + spark (SparkSession): Spark session object. + raw_summary_stats_path (str): Input raw summary stats path. + tmp_variant_annotation_path (str): Path to the Variant Annotation dataset which has been further prepared and processed by the per_chromosome module (previous PR in the chain) to speed up the joins in the harmonisation phase. It includes all variants in both the direct (A0/A1) and reverse (A1/A0) orientations, so that the direction of the variant can be easily determined on joining. + chromosome (str): Which chromosome to process. + colname_position (str): Column name for position. + colname_allele0 (str): Column name for allele0. + colname_allele1 (str): Column name for allele1. + colname_a1freq (str): Column name for allele1 frequency (optional). + colname_info (str): Column name for INFO, reflecting variant quality (optional). + colname_beta (str): Column name for beta. + colname_se (str): Column name for beta standard error. + colname_mlog10p (str): Column name for -log10(p). + colname_n (str): Column name for the number of samples. + + Returns: + DataFrame: A harmonised summary stats dataframe. + """ + # Read the precomputed variant annotation dataset. + va_df = ( + spark + .read + .parquet(tmp_variant_annotation_path) + .filter(f.col("vaChromosome") == ("X" if chromosome == "23" else chromosome)) + .persist() + ) + + # Read and process the summary stats dataset. + df = ( + spark + .read + .parquet(raw_summary_stats_path) + .filter(f.col("chromosome") == chromosome) + # Harmonise, 1: Rename chromosome 23 to X. + .withColumn( + "chromosome", + f.when( + f.col("chromosome") == "23", "X" + ).otherwise(f.col("chromosome")) + ) + ) + if colname_info: + # Harmonise, 2: Filter out low INFO rows. + df = df.filter(f.col(colname_info) >= 0.8) + if colname_a1freq: + # Harmonise, 3: Filter out low frequency rows. + df = ( + df + .withColumn( + "MAF", + f.when(f.col(colname_a1freq) < 0.5, f.col(colname_a1freq)) + .otherwise(1 - f.col(colname_a1freq)) + ) + .filter(f.col("MAF") >= 0.0001) + .drop("MAF") + ) + df = ( + df + # Harmonise, 4: Assign variant types. + # There are three possible variant types: + # 1. `snp_c` means an SNP converting a base into its complementary base: A<>T or G> SummaryStatistics: """Ingest and harmonise all summary stats for UKB PPP (EUR) data. - 1. Rename chromosome 23 to X. - 2. Filter out low INFO rows. - 3. Filter out low frequency rows. - 4. Assign variant types. - 5. Create variant ID for joining the variant annotation dataset. - 6. Join with the Variant Annotation dataset. - 7. Drop bad quality variants. - Args: spark (SparkSession): Spark session object. raw_summary_stats_path (str): Input raw summary stats path. @@ -43,122 +33,20 @@ def from_source( Returns: SummaryStatistics: Processed summary statistics dataset for a given chromosome. """ - # Read the precomputed variant annotation dataset. - va_df = ( - spark - .read - .parquet(tmp_variant_annotation_path) - .filter(f.col("vaChromosome") == ("X" if chromosome == "23" else chromosome)) - .persist() - ) - - # Read and process the summary stats dataset. - df = ( - spark - .read - .parquet(raw_summary_stats_path) - .filter(f.col("chromosome") == chromosome) - # Harmonise, 1: Rename chromosome 23 to X. - .withColumn( - "chromosome", - f.when( - f.col("chromosome") == "23", "X" - ).otherwise(f.col("chromosome")) - ) - # Harmonise, 2: Filter out low INFO rows. - .filter(f.col("INFO") >= 0.8) - # Harmonise, 3: Filter out low frequency rows. - .withColumn( - "MAF", - f.when(f.col("A1FREQ") < 0.5, f.col("A1FREQ")) - .otherwise(1 - f.col("A1FREQ")) - ) - .filter(f.col("MAF") >= 0.0001) - .drop("MAF") - # Harmonise, 4: Assign variant types. - .withColumn( - "variant_type", - f.when( - (f.length("ALLELE0") == 1) & (f.length("ALLELE1") == 1), - f.when( - ((f.col("ALLELE0") == "A") & (f.col("ALLELE1") == "T")) | - ((f.col("ALLELE0") == "T") & (f.col("ALLELE1") == "A")) | - ((f.col("ALLELE0") == "G") & (f.col("ALLELE1") == "C")) | - ((f.col("ALLELE0") == "C") & (f.col("ALLELE1") == "G")), - "snp_c" - ) - .otherwise( - "snp_n" - ) - ) - .otherwise( - "indel" - ) - ) - # Harmonise, 5: Create variant ID for joining the variant annotation dataset. - .withColumn( - "GENPOS", - f.col("GENPOS").cast("integer") - ) - .withColumn( - "ukb_ppp_id", - f.concat_ws( - "_", - f.col("chromosome"), - f.col("GENPOS"), - f.col("ALLELE0"), - f.col("ALLELE1") - ) - ) - ) - # Harmonise, 6: Join with the Variant Annotation dataset. - df = ( - df - .join(va_df, (df["chromosome"] == va_df["vaChromosome"]) & (df["ukb_ppp_id"] == va_df["ukb_ppp_id"]), "inner") - .drop("vaChromosome", "ukb_ppp_id") - .withColumn( - "effectAlleleFrequencyFromSource", - f.when( - f.col("direction") == "direct", - f.col("A1FREQ").cast("float") - ).otherwise(1 - f.col("A1FREQ").cast("float")) - ) - .withColumn( - "beta", - f.when( - f.col("direction") == "direct", - f.col("BETA").cast("double") - ).otherwise(-f.col("BETA").cast("double")) - ) - ) - df = ( - # Harmonise, 7: Drop bad quality variants. - df - .filter( - ~ ((f.col("variant_type") == "snp_c") & (f.col("direction") == "flip")) - ) - ) - - # Prepare the fields according to schema. - df = ( - df - .select( - f.col("studyId"), - f.col("chromosome"), - f.col("variantId"), - f.col("beta"), - f.col("GENPOS").cast(t.IntegerType()).alias("position"), - # Parse p-value into mantissa and exponent. - *neglog_pvalue_to_mantissa_and_exponent(f.col("LOG10P").cast(t.DoubleType())), - # Add standard error and sample size information. - f.col("SE").cast("double").alias("standardError"), - f.col("N").cast("integer").alias("sampleSize"), - ) - # Drop rows which don't have proper position or beta value. - .filter( - f.col("position").cast(t.IntegerType()).isNotNull() - & (f.col("beta") != 0) - ) + df = harmonise_summary_stats( + spark, + raw_summary_stats_path, + tmp_variant_annotation_path, + chromosome, + colname_position="GENPOS", + colname_allele0="ALLELE0", + colname_allele1="ALLELE1", + colname_a1freq="A1FREQ", + colname_info="INFO", + colname_beta="BETA", + colname_se="SE", + colname_mlog10p="LOG10P", + colname_n="N", ) # Create the summary statistics object. From a49ae9ace6e0129984000bc15c8092ca142d2c42 Mon Sep 17 00:00:00 2001 From: Kirill Tsukanov Date: Wed, 11 Sep 2024 13:46:40 +0100 Subject: [PATCH 031/188] feat: ingest FinnGen UKB meta-analysis data (#756) * feat: implement FinnGen UKB meta-analysis ingestion and harmonisation * chore: remove ot_finngen_ukb_meta.yaml * chore: remove raw_study_index_path to raw_study_index_path_from_tsv * fix: use session.write_mode * style: rename class to FinngenUkbMetaIngestionStep --- .../ot_ukb_ppp_eur_sumstat_preprocess.yaml | 2 +- src/airflow/dags/ukb_ppp_eur.py | 2 +- src/gentropy/common/harmonise.py | 38 +++++------ src/gentropy/common/per_chromosome.py | 16 ++++- src/gentropy/config.py | 15 ++++- .../datasource/finngen_ukb_meta/__init__.py | 3 + .../finngen_ukb_meta/study_index.py | 62 ++++++++++++++++++ .../finngen_ukb_meta/summary_stats.py | 63 +++++++++++++++++++ .../datasource/ukb_ppp_eur/study_index.py | 6 +- .../datasource/ukb_ppp_eur/summary_stats.py | 2 + src/gentropy/finngen_ukb_meta.py | 49 +++++++++++++++ .../ukb_ppp_eur_sumstat_preprocess.py | 8 +-- 12 files changed, 236 insertions(+), 30 deletions(-) create mode 100644 src/gentropy/datasource/finngen_ukb_meta/__init__.py create mode 100644 src/gentropy/datasource/finngen_ukb_meta/study_index.py create mode 100644 src/gentropy/datasource/finngen_ukb_meta/summary_stats.py create mode 100644 src/gentropy/finngen_ukb_meta.py diff --git a/config/step/ot_ukb_ppp_eur_sumstat_preprocess.yaml b/config/step/ot_ukb_ppp_eur_sumstat_preprocess.yaml index 1f8c108bc..24da7bad0 100644 --- a/config/step/ot_ukb_ppp_eur_sumstat_preprocess.yaml +++ b/config/step/ot_ukb_ppp_eur_sumstat_preprocess.yaml @@ -1,7 +1,7 @@ defaults: - ukb_ppp_eur_sumstat_preprocess -raw_study_index_path: ??? +raw_study_index_path_from_tsv: ??? raw_summary_stats_path: ??? variant_annotation_path: ??? tmp_variant_annotation_path: ??? diff --git a/src/airflow/dags/ukb_ppp_eur.py b/src/airflow/dags/ukb_ppp_eur.py index f0d0e1fe8..c8df8cf5b 100644 --- a/src/airflow/dags/ukb_ppp_eur.py +++ b/src/airflow/dags/ukb_ppp_eur.py @@ -33,7 +33,7 @@ cluster_name=CLUSTER_NAME, step_id="ot_ukb_ppp_eur_sumstat_preprocess", other_args=[ - f"step.raw_study_index_path={UKB_PPP_EUR_STUDY_INDEX}", + f"step.raw_study_index_path_from_tsv={UKB_PPP_EUR_STUDY_INDEX}", f"step.raw_summary_stats_path={UKB_PPP_EUR_SUMMARY_STATS}", f"step.variant_annotation_path={VARIANT_ANNOTATION}", f"step.tmp_variant_annotation_path={TMP_VARIANT_ANNOTATION}", diff --git a/src/gentropy/common/harmonise.py b/src/gentropy/common/harmonise.py index aac763e43..9b570eec6 100644 --- a/src/gentropy/common/harmonise.py +++ b/src/gentropy/common/harmonise.py @@ -15,12 +15,12 @@ def harmonise_summary_stats( colname_position: str, colname_allele0: str, colname_allele1: str, - colname_a1freq: str, - colname_info: str, + colname_a1freq: str | None, + colname_info: str | None, colname_beta: str, colname_se: str, colname_mlog10p: str, - colname_n: str, + colname_n: str | None, ) -> DataFrame: """Ingest and harmonise the summary stats. @@ -40,12 +40,12 @@ def harmonise_summary_stats( colname_position (str): Column name for position. colname_allele0 (str): Column name for allele0. colname_allele1 (str): Column name for allele1. - colname_a1freq (str): Column name for allele1 frequency (optional). - colname_info (str): Column name for INFO, reflecting variant quality (optional). + colname_a1freq (str | None): Column name for allele1 frequency (optional). + colname_info (str | None): Column name for INFO, reflecting variant quality (optional). colname_beta (str): Column name for beta. colname_se (str): Column name for beta standard error. colname_mlog10p (str): Column name for -log10(p). - colname_n (str): Column name for the number of samples. + colname_n (str | None): Column name for the number of samples (optional). Returns: DataFrame: A harmonised summary stats dataframe. @@ -159,20 +159,22 @@ def harmonise_summary_stats( ) # Prepare the fields according to schema. + select_expr = [ + f.col("studyId"), + f.col("chromosome"), + f.col("variantId"), + f.col("beta"), + f.col(colname_position).cast(t.IntegerType()).alias("position"), + # Parse p-value into mantissa and exponent. + *neglog_pvalue_to_mantissa_and_exponent(f.col(colname_mlog10p).cast(t.DoubleType())), + # Add standard error and sample size information. + f.col(colname_se).cast("double").alias("standardError"), + ] + if colname_n: + select_expr.append(f.col(colname_n).cast("integer").alias("sampleSize")) df = ( df - .select( - f.col("studyId"), - f.col("chromosome"), - f.col("variantId"), - f.col("beta"), - f.col(colname_position).cast(t.IntegerType()).alias("position"), - # Parse p-value into mantissa and exponent. - *neglog_pvalue_to_mantissa_and_exponent(f.col(colname_mlog10p).cast(t.DoubleType())), - # Add standard error and sample size information. - f.col(colname_se).cast("double").alias("standardError"), - f.col(colname_n).cast("integer").alias("sampleSize"), - ) + .select(*select_expr) # Drop rows which don't have proper position or beta value. .filter( f.col("position").cast(t.IntegerType()).isNotNull() diff --git a/src/gentropy/common/per_chromosome.py b/src/gentropy/common/per_chromosome.py index 528e6ffbe..f2cedd98e 100644 --- a/src/gentropy/common/per_chromosome.py +++ b/src/gentropy/common/per_chromosome.py @@ -5,6 +5,9 @@ import pyspark.sql.functions as f from pyspark.sql import SparkSession +from gentropy.datasource.finngen_ukb_meta.summary_stats import ( + FinngenUkbMetaSummaryStats, +) from gentropy.datasource.ukb_ppp_eur.summary_stats import UkbPppEurSummaryStats @@ -63,15 +66,23 @@ def prepare_va(session: SparkSession, variant_annotation_path: str, tmp_variant_ ) -def process_summary_stats_per_chromosome(session: SparkSession, ingestion_class: type[UkbPppEurSummaryStats], raw_summary_stats_path: str, tmp_variant_annotation_path: str, summary_stats_output_path: str) -> None: +def process_summary_stats_per_chromosome( + session: SparkSession, + ingestion_class: type[UkbPppEurSummaryStats] | type[FinngenUkbMetaSummaryStats], + raw_summary_stats_path: str, + tmp_variant_annotation_path: str, + summary_stats_output_path: str, + study_index_path: str, + ) -> None: """Processes summary statistics for each chromosome, partitioning and writing results. Args: session (SparkSession): The Spark session to use for distributed data processing. - ingestion_class (type[UkbPppEurSummaryStats]): The class used to handle ingestion of source data. Must have a `from_source` method returning a DataFrame. + ingestion_class (type[UkbPppEurSummaryStats] | type[FinngenUkbMetaSummaryStats]): The class used to handle ingestion of source data. Must have a `from_source` method returning a DataFrame. raw_summary_stats_path (str): The path to the raw summary statistics files. tmp_variant_annotation_path (str): The path to temporary variant annotation data, used for chromosome joins. summary_stats_output_path (str): The output path to write processed summary statistics as parquet files. + study_index_path (str): The path to study index, which is necessary in some cases to populate the sample size column. """ # Set mode to overwrite for processing the first chromosome. write_mode = "overwrite" @@ -85,6 +96,7 @@ def process_summary_stats_per_chromosome(session: SparkSession, ingestion_class: raw_summary_stats_path=raw_summary_stats_path, tmp_variant_annotation_path=tmp_variant_annotation_path, chromosome=str(chromosome), + study_index_path=study_index_path, ) .df .coalesce(1) diff --git a/src/gentropy/config.py b/src/gentropy/config.py index 9089dbecf..181e9042d 100644 --- a/src/gentropy/config.py +++ b/src/gentropy/config.py @@ -299,7 +299,7 @@ class PICSConfig(StepConfig): class UkbPppEurConfig(StepConfig): """UKB PPP (EUR) ingestion step configuration.""" - raw_study_index_path: str = MISSING + raw_study_index_path_from_tsv: str = MISSING raw_summary_stats_path: str = MISSING tmp_variant_annotation_path: str = MISSING variant_annotation_path: str = MISSING @@ -308,6 +308,19 @@ class UkbPppEurConfig(StepConfig): _target_: str = "gentropy.ukb_ppp_eur_sumstat_preprocess.UkbPppEurStep" +@dataclass +class FinngenUkbMetaConfig(StepConfig): + """FinnGen UKB meta-analysis ingestion step configuration.""" + + raw_study_index_path_from_tsv: str = MISSING + raw_summary_stats_path: str = MISSING + tmp_variant_annotation_path: str = MISSING + variant_annotation_path: str = MISSING + study_index_output_path: str = MISSING + summary_stats_output_path: str = MISSING + _target_: str = "gentropy.finngen_ukb_meta.FinngenUkbMetaIngestionStep" + + @dataclass class GnomadVariantConfig(StepConfig): """Gnomad variant ingestion step configuration.""" diff --git a/src/gentropy/datasource/finngen_ukb_meta/__init__.py b/src/gentropy/datasource/finngen_ukb_meta/__init__.py new file mode 100644 index 000000000..8d6cfd752 --- /dev/null +++ b/src/gentropy/datasource/finngen_ukb_meta/__init__.py @@ -0,0 +1,3 @@ +"""FinnGen UKB meta-analysis data source.""" + +from __future__ import annotations diff --git a/src/gentropy/datasource/finngen_ukb_meta/study_index.py b/src/gentropy/datasource/finngen_ukb_meta/study_index.py new file mode 100644 index 000000000..76e82f0eb --- /dev/null +++ b/src/gentropy/datasource/finngen_ukb_meta/study_index.py @@ -0,0 +1,62 @@ +"""Study Index for Finngen data source.""" +from __future__ import annotations + +import pyspark.sql.functions as f +from pyspark.sql import SparkSession + +from gentropy.dataset.study_index import StudyIndex + + +class FinngenUkbMetaStudyIndex(StudyIndex): + """Study index dataset from FinnGen UKB meta-analysis.""" + + @classmethod + def from_source( + cls: type[FinngenUkbMetaStudyIndex], + spark: SparkSession, + raw_study_index_path_from_tsv: str, + ) -> StudyIndex: + """This function ingests study level metadata from FinnGen UKB meta-analysis. + + Args: + spark (SparkSession): Spark session object. + raw_study_index_path_from_tsv (str): Raw study index path. + + Returns: + StudyIndex: Parsed and annotated FinnGen UKB meta-analysis study table. + """ + # Read the raw study index and process. + study_index_df = ( + spark.read.csv(raw_study_index_path_from_tsv, sep="\t", header=True) + .select( + f.lit("gwas").alias("studyType"), + f.lit("FINNGEN_R11_UKB_META").alias("projectId"), + f.col("_gentropy_study_id").alias("studyId"), + f.col("name").alias("traitFromSource"), + f.lit(True).alias("hasSumstats"), + f.col("_gentropy_summary_stats_link").alias("summarystatsLocation"), + (f.col("fg_n_cases") + f.col("ukbb_n_cases") + f.col("fg_n_controls") + f.col("ukbb_n_controls")).alias("nSamples") + ) + ) + # Add population structure. + study_index_df = ( + study_index_df + .withColumn( + "discoverySamples", + f.array( + f.struct( + f.col("nSamples").cast("integer").alias("sampleSize"), + f.lit("European").alias("ancestry"), + ) + ) + ) + .withColumn( + "ldPopulationStructure", + cls.aggregate_and_map_ancestries(f.col("discoverySamples")), + ) + ) + + return StudyIndex( + _df=study_index_df, + _schema=StudyIndex.get_schema(), + ) diff --git a/src/gentropy/datasource/finngen_ukb_meta/summary_stats.py b/src/gentropy/datasource/finngen_ukb_meta/summary_stats.py new file mode 100644 index 000000000..6e45736c3 --- /dev/null +++ b/src/gentropy/datasource/finngen_ukb_meta/summary_stats.py @@ -0,0 +1,63 @@ +"""Summary statistics ingestion for FinnGen UKB meta-analysis.""" + +from __future__ import annotations + +from dataclasses import dataclass + +from pyspark.sql import SparkSession + +from gentropy.common.harmonise import harmonise_summary_stats +from gentropy.dataset.summary_statistics import SummaryStatistics + + +@dataclass +class FinngenUkbMetaSummaryStats: + """Summary statistics dataset for FinnGen UKB meta-analysis.""" + + @classmethod + def from_source( + cls: type[FinngenUkbMetaSummaryStats], + spark: SparkSession, + raw_summary_stats_path: str, + tmp_variant_annotation_path: str, + chromosome: str, + study_index_path: str, + ) -> SummaryStatistics: + """Ingest and harmonise all summary stats for FinnGen UKB meta-analysis data. + + Args: + spark (SparkSession): Spark session object. + raw_summary_stats_path (str): Input raw summary stats path. + tmp_variant_annotation_path (str): Input variant annotation dataset path. + chromosome (str): Which chromosome to process. + study_index_path (str): The path to study index, which is necessary in some cases to populate the sample size column. + + Returns: + SummaryStatistics: Processed summary statistics dataset for a given chromosome. + """ + # Run the harmonisation steps. + df = harmonise_summary_stats( + spark, + raw_summary_stats_path, + tmp_variant_annotation_path, + chromosome, + colname_position="POS", + colname_allele0="REF", + colname_allele1="ALT", + colname_a1freq=None, + colname_info=None, + colname_beta="all_inv_var_meta_beta", + colname_se="all_inv_var_meta_sebeta", + colname_mlog10p="all_inv_var_meta_mlogp", + colname_n=None, + ) + + # Populate the sample size column from the study index. + study_index = spark.read.parquet(study_index_path).select("studyId", "nSamples") + df = df.join(study_index, on=["studyId"], how="inner") + + # Create the summary statistics object. + return SummaryStatistics( + _df=df, + _schema=SummaryStatistics.get_schema(), + ) diff --git a/src/gentropy/datasource/ukb_ppp_eur/study_index.py b/src/gentropy/datasource/ukb_ppp_eur/study_index.py index 3e0a7d782..f694b9a47 100644 --- a/src/gentropy/datasource/ukb_ppp_eur/study_index.py +++ b/src/gentropy/datasource/ukb_ppp_eur/study_index.py @@ -14,14 +14,14 @@ class UkbPppEurStudyIndex(StudyIndex): def from_source( cls: type[UkbPppEurStudyIndex], spark: SparkSession, - raw_study_index_path: str, + raw_study_index_path_from_tsv: str, raw_summary_stats_path: str, ) -> StudyIndex: """This function ingests study level metadata from UKB PPP (EUR). Args: spark (SparkSession): Spark session object. - raw_study_index_path (str): Raw study index path. + raw_study_index_path_from_tsv (str): Raw study index path. raw_summary_stats_path (str): Raw summary stats path. Returns: @@ -39,7 +39,7 @@ def from_source( ) # Now we can read the raw study index and complete the processing. study_index_df = ( - spark.read.csv(raw_study_index_path, sep="\t", header=True) + spark.read.csv(raw_study_index_path_from_tsv, sep="\t", header=True) .select( f.lit("pqtl").alias("studyType"), f.lit("UKB_PPP_EUR").alias("projectId"), diff --git a/src/gentropy/datasource/ukb_ppp_eur/summary_stats.py b/src/gentropy/datasource/ukb_ppp_eur/summary_stats.py index a0480f740..5ded9c891 100644 --- a/src/gentropy/datasource/ukb_ppp_eur/summary_stats.py +++ b/src/gentropy/datasource/ukb_ppp_eur/summary_stats.py @@ -21,6 +21,7 @@ def from_source( raw_summary_stats_path: str, tmp_variant_annotation_path: str, chromosome: str, + study_index_path: str, ) -> SummaryStatistics: """Ingest and harmonise all summary stats for UKB PPP (EUR) data. @@ -29,6 +30,7 @@ def from_source( raw_summary_stats_path (str): Input raw summary stats path. tmp_variant_annotation_path (str): Input variant annotation dataset path. chromosome (str): Which chromosome to process. + study_index_path (str): The path to study index, which is necessary in some cases to populate the sample size column. Returns: SummaryStatistics: Processed summary statistics dataset for a given chromosome. diff --git a/src/gentropy/finngen_ukb_meta.py b/src/gentropy/finngen_ukb_meta.py new file mode 100644 index 000000000..eafd2a659 --- /dev/null +++ b/src/gentropy/finngen_ukb_meta.py @@ -0,0 +1,49 @@ +"""Step to run FinnGen UKB meta-analysis data ingestion.""" + +from __future__ import annotations + +from gentropy.common.per_chromosome import ( + prepare_va, + process_summary_stats_per_chromosome, +) +from gentropy.common.session import Session +from gentropy.datasource.finngen_ukb_meta.study_index import FinngenUkbMetaStudyIndex +from gentropy.datasource.finngen_ukb_meta.summary_stats import ( + FinngenUkbMetaSummaryStats, +) + + +class FinngenUkbMetaIngestionStep: + """FinnGen UKB meta-analysis data ingestion and harmonisation.""" + + def __init__( + self, session: Session, raw_study_index_path_from_tsv: str, raw_summary_stats_path: str, variant_annotation_path: str, tmp_variant_annotation_path: str, study_index_output_path: str, summary_stats_output_path: str + ) -> None: + """Data ingestion and harmonisation step for FinnGen UKB meta-analysis. + + Args: + session (Session): Session object. + raw_study_index_path_from_tsv (str): Input raw study index path. + raw_summary_stats_path (str): Input raw summary stats path. + variant_annotation_path (str): Input variant annotation dataset path. + tmp_variant_annotation_path (str): Temporary output path for variant annotation dataset. + study_index_output_path (str): Study index output path. + summary_stats_output_path (str): Summary stats output path. + """ + session.logger.info("Pre-compute the direct and flipped variant annotation dataset.") + prepare_va(session, variant_annotation_path, tmp_variant_annotation_path) + + session.logger.info("Process study index.") + ( + FinngenUkbMetaStudyIndex.from_source( + spark=session.spark, + raw_study_index_path_from_tsv=raw_study_index_path_from_tsv, + ) + .df + .write + .mode(session.write_mode) + .parquet(study_index_output_path) + ) + + session.logger.info("Process and harmonise summary stats.") + process_summary_stats_per_chromosome(session, FinngenUkbMetaSummaryStats, raw_summary_stats_path, tmp_variant_annotation_path, summary_stats_output_path, study_index_output_path) diff --git a/src/gentropy/ukb_ppp_eur_sumstat_preprocess.py b/src/gentropy/ukb_ppp_eur_sumstat_preprocess.py index b192d963f..3cee45c6a 100644 --- a/src/gentropy/ukb_ppp_eur_sumstat_preprocess.py +++ b/src/gentropy/ukb_ppp_eur_sumstat_preprocess.py @@ -15,13 +15,13 @@ class UkbPppEurStep: """UKB PPP (EUR) data ingestion and harmonisation.""" def __init__( - self, session: Session, raw_study_index_path: str, raw_summary_stats_path: str, variant_annotation_path: str, tmp_variant_annotation_path: str, study_index_output_path: str, summary_stats_output_path: str + self, session: Session, raw_study_index_path_from_tsv: str, raw_summary_stats_path: str, variant_annotation_path: str, tmp_variant_annotation_path: str, study_index_output_path: str, summary_stats_output_path: str ) -> None: """Run UKB PPP (EUR) data ingestion and harmonisation step. Args: session (Session): Session object. - raw_study_index_path (str): Input raw study index path. + raw_study_index_path_from_tsv (str): Input raw study index path. raw_summary_stats_path (str): Input raw summary stats path. variant_annotation_path (str): Input variant annotation dataset path. tmp_variant_annotation_path (str): Temporary output path for variant annotation dataset. @@ -35,7 +35,7 @@ def __init__( ( UkbPppEurStudyIndex.from_source( spark=session.spark, - raw_study_index_path=raw_study_index_path, + raw_study_index_path_from_tsv=raw_study_index_path_from_tsv, raw_summary_stats_path=raw_summary_stats_path, ) .df @@ -45,4 +45,4 @@ def __init__( ) session.logger.info("Process and harmonise summary stats.") - process_summary_stats_per_chromosome(session, UkbPppEurSummaryStats, raw_summary_stats_path, tmp_variant_annotation_path, summary_stats_output_path) + process_summary_stats_per_chromosome(session, UkbPppEurSummaryStats, raw_summary_stats_path, tmp_variant_annotation_path, summary_stats_output_path, study_index_output_path) From 6469bf5dc4311675a90ae60e3ed1a8f0b4da9349 Mon Sep 17 00:00:00 2001 From: Daniel Suveges Date: Thu, 12 Sep 2024 14:17:21 +0100 Subject: [PATCH 032/188] feat(validation): adding credible set variant validation (#757) * feat(validation): adding logic to validate credible sets against variant index * fix: tidying docstrings --- src/gentropy/dataset/study_locus.py | 66 +++++++++++++++- tests/gentropy/dataset/test_study_locus.py | 89 ++++++++++++++++++++++ 2 files changed, 154 insertions(+), 1 deletion(-) diff --git a/src/gentropy/dataset/study_locus.py b/src/gentropy/dataset/study_locus.py index edf9dc8be..b59d57650 100644 --- a/src/gentropy/dataset/study_locus.py +++ b/src/gentropy/dataset/study_locus.py @@ -8,7 +8,7 @@ import numpy as np import pyspark.sql.functions as f -from pyspark.sql.types import FloatType, StringType +from pyspark.sql.types import ArrayType, FloatType, StringType from gentropy.common.schemas import parse_spark_schema from gentropy.common.spark_helpers import ( @@ -18,6 +18,7 @@ from gentropy.common.utils import get_logsum, parse_region from gentropy.dataset.dataset import Dataset from gentropy.dataset.study_locus_overlap import StudyLocusOverlap +from gentropy.dataset.variant_index import VariantIndex from gentropy.method.clump import LDclumping if TYPE_CHECKING: @@ -47,6 +48,7 @@ class StudyLocusQualityCheck(Enum): FAILED_STUDY (str): Flagging study loci if the study has failed QC MISSING_STUDY (str): Flagging study loci if the study is not found in the study index as a reference DUPLICATED_STUDYLOCUS_ID (str): Study-locus identifier is not unique. + INVALID_VARIANT_IDENTIFIER (str): Flagging study loci where identifier of any tagging variant was not found in the variant index """ SUBSIGNIFICANT_FLAG = "Subsignificant p-value" @@ -65,6 +67,9 @@ class StudyLocusQualityCheck(Enum): FAILED_STUDY = "Study has failed quality controls" MISSING_STUDY = "Study not found in the study index" DUPLICATED_STUDYLOCUS_ID = "Non-unique study locus identifier" + INVALID_VARIANT_IDENTIFIER = ( + "Some variant identifiers of this locus were not found in variant index" + ) class CredibleInterval(Enum): @@ -141,6 +146,65 @@ def validate_study(self: StudyLocus, study_index: StudyIndex) -> StudyLocus: _schema=self.get_schema(), ) + def validate_variant_identifiers( + self: StudyLocus, variant_index: VariantIndex + ) -> StudyLocus: + """Flagging study loci, where tagging variant identifiers are not found in variant index. + + Args: + variant_index (VariantIndex): Variant index to resolve variant identifiers. + + Returns: + StudyLocus: Updated study locus with quality control flags. + """ + # QC column might not be present in the variant index schema, so we have to be ready to handle it: + qc_select_expression = ( + f.col("qualityControls") + if "qualityControls" in self.df.columns + else f.lit(None).cast(ArrayType(StringType())) + ) + + # Find out which study loci have variants not in the variant index: + flag = ( + self.df + # Exploding locus: + .select("studyLocusId", f.explode("locus").alias("locus")) + .select("studyLocusId", "locus.variantId") + # Join with variant index variants: + .join( + variant_index.df.select( + "variantId", f.lit(True).alias("inVariantIndex") + ), + on="variantId", + how="left", + ) + # Flagging variants not in the variant index: + .withColumn("inVariantIndex", f.col("inVariantIndex").isNotNull()) + # Flagging study loci with ANY variants not in the variant index: + .groupBy("studyLocusId") + .agg(f.collect_set("inVariantIndex").alias("inVariantIndex")) + .select( + "studyLocusId", + f.array_contains("inVariantIndex", False).alias("toFlag"), + ) + ) + + return StudyLocus( + _df=( + self.df.join(flag, on="studyLocusId", how="left") + .withColumn( + "qualityControls", + self.update_quality_flag( + qc_select_expression, + f.col("toFlag"), + StudyLocusQualityCheck.INVALID_VARIANT_IDENTIFIER, + ), + ) + .drop("toFlag") + ), + _schema=self.get_schema(), + ) + def validate_lead_pvalue(self: StudyLocus, pvalue_cutoff: float) -> StudyLocus: """Flag associations below significant threshold. diff --git a/tests/gentropy/dataset/test_study_locus.py b/tests/gentropy/dataset/test_study_locus.py index 9b40796db..c7538b28b 100644 --- a/tests/gentropy/dataset/test_study_locus.py +++ b/tests/gentropy/dataset/test_study_locus.py @@ -27,6 +27,7 @@ ) from gentropy.dataset.study_locus_overlap import StudyLocusOverlap from gentropy.dataset.summary_statistics import SummaryStatistics +from gentropy.dataset.variant_index import VariantIndex @pytest.mark.parametrize( @@ -562,6 +563,94 @@ def test_annotate_locus_statistics_boundaries( ) +class TestStudyLocusVariantValidation: + """Collection of tests for StudyLocus variant validation.""" + + VARIANT_DATA = [ + ("v1", "c1", 1, "r", "a"), + ("v2", "c1", 2, "r", "a"), + ("v3", "c1", 3, "r", "a"), + ("v4", "c1", 4, "r", "a"), + ] + VARIANT_HEADERS = [ + "variantId", + "chromosome", + "position", + "referenceAllele", + "alternateAllele", + ] + + STUDYLOCUS_DATA = [ + # First studylocus passes qc: + (1, "v1", "s1", "v1"), + (1, "v1", "s1", "v2"), + (1, "v1", "s1", "v3"), + # Second studylocus passes qc: + (2, "v1", "s1", "v1"), + (2, "v1", "s1", "v5"), + ] + STUDYLOCUS_HEADER = ["studyLocusId", "variantId", "studyId", "tagVariantId"] + + @pytest.fixture(autouse=True) + def _setup(self: TestStudyLocusVariantValidation, spark: SparkSession) -> None: + """Setup study locus for testing.""" + self.variant_index = VariantIndex( + _df=spark.createDataFrame( + self.VARIANT_DATA, self.VARIANT_HEADERS + ).withColumn("position", f.col("position").cast(t.IntegerType())), + _schema=VariantIndex.get_schema(), + ) + + self.credible_set = StudyLocus( + _df=( + spark.createDataFrame(self.STUDYLOCUS_DATA, self.STUDYLOCUS_HEADER) + .withColumn("studyLocusId", f.col("studyLocusId").cast(t.LongType())) + .withColumn("qualityControls", f.array()) + .groupBy("studyLocusId", "variantId", "studyId") + .agg( + f.collect_set( + f.struct(f.col("tagVariantId").alias("variantId")) + ).alias("locus") + ) + ), + _schema=StudyLocus.get_schema(), + ) + + def test_validation_return_type(self: TestStudyLocusVariantValidation) -> None: + """Testing if the validation returns the right type.""" + assert isinstance( + self.credible_set.validate_variant_identifiers(self.variant_index), + StudyLocus, + ) + + def test_validation_no_data_loss(self: TestStudyLocusVariantValidation) -> None: + """Testing if the validation returns same number of rows.""" + assert ( + self.credible_set.validate_variant_identifiers( + self.variant_index + ).df.count() + == self.credible_set.df.count() + ) + + def test_validation_correctness(self: TestStudyLocusVariantValidation) -> None: + """Testing if the validation flags the right number of variants.""" + # Execute validation: + validated = self.credible_set.validate_variant_identifiers( + self.variant_index + ).df + + # Make sure there's only one study locus with a failed variants: + assert validated.filter(f.size("qualityControls") > 0).count() == 1 + + # Check that the right one is flagged: + assert ( + validated.filter( + (f.size("qualityControls") > 0) & (f.col("studyLocusId") == 2) + ).count() + == 1 + ) + + class TestStudyLocusValidation: """Collection of tests for StudyLocus validation.""" From d3435bb03682e829fbf9fe1bbe2e2e3df5344528 Mon Sep 17 00:00:00 2001 From: Szymon Szyszkowski <69353402+project-defiant@users.noreply.github.com> Date: Thu, 12 Sep 2024 22:56:24 +0200 Subject: [PATCH 033/188] feat: drop airflow orchestration layer from gentropy (#758) * refactor: drop gentropy config * feat(airflow): removal of airflow orchestration BREAKING CHANGE: see https://github.com/opentargets/orchestration --------- Co-authored-by: Szymon Szyszkowski --- config/__init__.py | 3 - config/datasets/ot_gcp.yaml | 80 - config/ot_config.yaml | 5 - config/step/ot_colocalisation_coloc.yaml | 7 - config/step/ot_colocalisation_ecaviar.yaml | 7 - config/step/ot_eqtl_catalogue.yaml | 10 - config/step/ot_gene_index.yaml | 5 - config/step/ot_gwas_catalog_ingestion.yaml | 12 - .../step/ot_gwas_catalog_study_curation.yaml | 8 - .../step/ot_gwas_catalog_study_inclusion.yaml | 12 - config/step/ot_ld_based_clumping.yaml | 7 - config/step/ot_ld_index.yaml | 20 - config/step/ot_locus_to_gene_predict.yaml | 11 - config/step/ot_locus_to_gene_train.yaml | 19 - .../ot_ukb_ppp_eur_sumstat_preprocess.yaml | 13 - config/step/ot_variant_index.yaml | 6 - config/step/ot_variant_to_gene.yaml | 13 - config/step/session/dataproc.yaml | 5 - docs/development/airflow.md | 124 - docs/development/contributing.md | 36 +- docs/development/workflows.md | 27 - mkdocs.yml | 3 +- poetry.lock | 3737 +---------------- pyproject.toml | 8 +- src/airflow/.env | 6 - src/airflow/Dockerfile | 33 - src/airflow/config/.gitkeep | 0 src/airflow/dags/.gitkeep | 0 src/airflow/dags/common_airflow.py | 490 --- src/airflow/dags/configs/dag.yaml | 17 - src/airflow/dags/configs/variant_sources.yaml | 13 - src/airflow/dags/data_validation.py | 96 - src/airflow/dags/eqtl_preprocess.py | 73 - src/airflow/dags/genetics_etl.py | 154 - src/airflow/dags/gnomad_preprocess.py | 29 - .../dags/gwas_catalog_harmonisation.py | 125 - src/airflow/dags/gwas_catalog_preprocess.py | 223 - src/airflow/dags/gwas_curation_update.py | 34 - src/airflow/dags/ukb_ppp_eur.py | 45 - src/airflow/dags/variant_index.py | 321 -- src/airflow/docker-compose.yaml | 228 - src/airflow/logs/.gitkeep | 0 src/airflow/plugins/.gitkeep | 0 src/airflow/requirements.txt | 3 - tests/airflow/test_dag.py | 51 - 45 files changed, 149 insertions(+), 5970 deletions(-) delete mode 100644 config/__init__.py delete mode 100644 config/datasets/ot_gcp.yaml delete mode 100644 config/ot_config.yaml delete mode 100644 config/step/ot_colocalisation_coloc.yaml delete mode 100644 config/step/ot_colocalisation_ecaviar.yaml delete mode 100644 config/step/ot_eqtl_catalogue.yaml delete mode 100644 config/step/ot_gene_index.yaml delete mode 100644 config/step/ot_gwas_catalog_ingestion.yaml delete mode 100644 config/step/ot_gwas_catalog_study_curation.yaml delete mode 100644 config/step/ot_gwas_catalog_study_inclusion.yaml delete mode 100644 config/step/ot_ld_based_clumping.yaml delete mode 100644 config/step/ot_ld_index.yaml delete mode 100644 config/step/ot_locus_to_gene_predict.yaml delete mode 100644 config/step/ot_locus_to_gene_train.yaml delete mode 100644 config/step/ot_ukb_ppp_eur_sumstat_preprocess.yaml delete mode 100644 config/step/ot_variant_index.yaml delete mode 100644 config/step/ot_variant_to_gene.yaml delete mode 100644 config/step/session/dataproc.yaml delete mode 100644 docs/development/airflow.md delete mode 100644 docs/development/workflows.md delete mode 100644 src/airflow/.env delete mode 100644 src/airflow/Dockerfile delete mode 100644 src/airflow/config/.gitkeep delete mode 100644 src/airflow/dags/.gitkeep delete mode 100644 src/airflow/dags/common_airflow.py delete mode 100644 src/airflow/dags/configs/dag.yaml delete mode 100644 src/airflow/dags/configs/variant_sources.yaml delete mode 100644 src/airflow/dags/data_validation.py delete mode 100644 src/airflow/dags/eqtl_preprocess.py delete mode 100644 src/airflow/dags/genetics_etl.py delete mode 100644 src/airflow/dags/gnomad_preprocess.py delete mode 100644 src/airflow/dags/gwas_catalog_harmonisation.py delete mode 100644 src/airflow/dags/gwas_catalog_preprocess.py delete mode 100644 src/airflow/dags/gwas_curation_update.py delete mode 100644 src/airflow/dags/ukb_ppp_eur.py delete mode 100644 src/airflow/dags/variant_index.py delete mode 100644 src/airflow/docker-compose.yaml delete mode 100644 src/airflow/logs/.gitkeep delete mode 100644 src/airflow/plugins/.gitkeep delete mode 100644 src/airflow/requirements.txt delete mode 100644 tests/airflow/test_dag.py diff --git a/config/__init__.py b/config/__init__.py deleted file mode 100644 index 31939863f..000000000 --- a/config/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -"""Reference configuration yamls.""" - -from __future__ import annotations diff --git a/config/datasets/ot_gcp.yaml b/config/datasets/ot_gcp.yaml deleted file mode 100644 index a8d8886bb..000000000 --- a/config/datasets/ot_gcp.yaml +++ /dev/null @@ -1,80 +0,0 @@ -# Release specific configuration: -release_version: "24.06" -dev_version: XX.XX -release_folder: gs://genetics_etl_python_playground/releases/${datasets.release_version} - -inputs: gs://genetics_etl_python_playground/input -static_assets: gs://genetics_etl_python_playground/static_assets -outputs: gs://genetics_etl_python_playground/output/python_etl/parquet/${datasets.dev_version} - -## Datasets: -# GWAS -gwas_catalog_dataset: gs://gwas_catalog_data -# Ingestion input files: -gwas_catalog_associations: ${datasets.gwas_catalog_dataset}/curated_inputs/gwas_catalog_associations_ontology_annotated.tsv -gwas_catalog_studies: - - ${datasets.gwas_catalog_dataset}/curated_inputs/gwas_catalog_download_studies.tsv - - ${datasets.gwas_catalog_dataset}/curated_inputs/gwas_catalog_unpublished_studies.tsv -gwas_catalog_ancestries: - - ${datasets.gwas_catalog_dataset}/curated_inputs/gwas_catalog_download_ancestries.tsv - - ${datasets.gwas_catalog_dataset}/curated_inputs/gwas_catalog_unpublished_ancestries.tsv -gwas_catalog_sumstats_lut: ${datasets.gwas_catalog_dataset}/curated_inputs/harmonised_list.txt -gwas_catalog_study_curation: ${datasets.gwas_catalog_dataset}/manifests/gwas_catalog_study_curation.tsv -# Harmonised summary statistics list: -gwas_catalog_summary_stats_list: ${datasets.gwas_catalog_dataset}/manifests/gwas_catalog_harmonised_summary_statistics_list.txt -# Inclusion lists: -gwas_catalog_curated_inclusion_list: ${datasets.gwas_catalog_dataset}/manifests/gwas_catalog_curation_included_studies -gwas_catalog_summary_statistics_inclusion_list: ${datasets.gwas_catalog_dataset}/manifests/gwas_catalog_summary_statistics_included_studies -# Ingestion output folders: -gwas_catalog_study_index: ${datasets.gwas_catalog_dataset}/study_index -gwas_catalog_study_locus_folder: ${datasets.gwas_catalog_dataset}/study_locus_datasets -gwas_catalog_credible_set_folder: ${datasets.gwas_catalog_dataset}/credible_set_datasets - -# GnomAD -gnomad_public_bucket: gs://gcp-public-data--gnomad/release/ -# LD generation -# Templates require placeholders {POP} to expand template to match multiple populationwise paths -ld_matrix_template: ${datasets.gnomad_public_bucket}/2.1.1/ld/gnomad.genomes.r2.1.1.{POP}.common.adj.ld.bm -ld_index_raw_template: ${datasets.gnomad_public_bucket}/2.1.1/ld/gnomad.genomes.r2.1.1.{POP}.common.ld.variant_indices.ht -liftover_ht_path: ${datasets.gnomad_public_bucket}/2.1.1/liftover_grch38/ht/genomes/gnomad.genomes.r2.1.1.sites.liftover_grch38.ht -# GnomAD variant set: -gnomad_genomes_path: ${datasets.gnomad_public_bucket}4.0/ht/genomes/gnomad.genomes.v4.0.sites.ht/ - -# Others -chain_38_37: gs://hail-common/references/grch38_to_grch37.over.chain.gz -chain_37_38: ${datasets.static_assets}/grch37_to_grch38.over.chain -vep_consequences: ${datasets.static_assets}/variant_consequence_to_score.tsv -anderson: ${datasets.static_assets}/andersson2014/enhancer_tss_associations.bed -javierre: ${datasets.static_assets}/javierre_2016_preprocessed -jung: ${datasets.static_assets}/jung2019_pchic_tableS3.csv -thurman: ${datasets.static_assets}/thurman2012/genomewideCorrs_above0.7_promoterPlusMinus500kb_withGeneNames_32celltypeCategories.bed8.gz -target_index: ${datasets.static_assets}/targets # OTP 23.12 data -gene_interactions: ${datasets.static_assets}/interaction # OTP 23.12 data - -# Dev output datasets -gnomad_variants: ${datasets.static_assets}/gnomad_variants -study_locus: ${datasets.outputs}/study_locus -summary_statistics: ${datasets.outputs}/summary_statistics -study_locus_overlap: ${datasets.outputs}/study_locus_overlap -susie_finemapping: ${datasets.outputs}/finngen_susie_finemapping - -ld_index: ${datasets.static_assets}/ld_index -catalog_study_index: ${datasets.study_index}/catalog -catalog_study_locus: ${datasets.study_locus}/catalog_study_locus - -from_sumstats_study_locus: ${datasets.study_locus}/from_sumstats -from_sumstats_pics: ${datasets.credible_set}/from_sumstats - -vep_output_path: gs://genetics_etl_python_playground/vep/full_variant_index_vcf - -# ETL output datasets: -l2g_gold_standard_curation: ${datasets.release_folder}/locus_to_gene_gold_standard.json -l2g_model: ${datasets.release_folder}/locus_to_gene_model/classifier.skops -l2g_predictions: ${datasets.release_folder}/locus_to_gene_predictions -l2g_feature_matrix: ${datasets.release_folder}/locus_to_gene_feature_matrix -colocalisation: ${datasets.release_folder}/colocalisation -study_index: ${datasets.release_folder}/study_index -variant_index: ${datasets.release_folder}/variant_index -credible_set: ${datasets.release_folder}/credible_set -gene_index: ${datasets.release_folder}/gene_index -variant_to_gene: ${datasets.release_folder}/variant_to_gene diff --git a/config/ot_config.yaml b/config/ot_config.yaml deleted file mode 100644 index 7f28a58d6..000000000 --- a/config/ot_config.yaml +++ /dev/null @@ -1,5 +0,0 @@ -defaults: - - config - - datasets: ot_gcp - - _self_ - - override step/session: dataproc diff --git a/config/step/ot_colocalisation_coloc.yaml b/config/step/ot_colocalisation_coloc.yaml deleted file mode 100644 index f01335514..000000000 --- a/config/step/ot_colocalisation_coloc.yaml +++ /dev/null @@ -1,7 +0,0 @@ -defaults: - - colocalisation - -credible_set_path: ${datasets.credible_set} -study_index_path: ${datasets.study_index} -coloc_path: ${datasets.colocalisation} -colocalisation_method: Coloc diff --git a/config/step/ot_colocalisation_ecaviar.yaml b/config/step/ot_colocalisation_ecaviar.yaml deleted file mode 100644 index d57887c93..000000000 --- a/config/step/ot_colocalisation_ecaviar.yaml +++ /dev/null @@ -1,7 +0,0 @@ -defaults: - - colocalisation - -credible_set_path: ${datasets.credible_set} -study_index_path: ${datasets.study_index} -coloc_path: ${datasets.colocalisation} -colocalisation_method: ECaviar diff --git a/config/step/ot_eqtl_catalogue.yaml b/config/step/ot_eqtl_catalogue.yaml deleted file mode 100644 index 7d4441864..000000000 --- a/config/step/ot_eqtl_catalogue.yaml +++ /dev/null @@ -1,10 +0,0 @@ -defaults: - - eqtl_catalogue - -eqtl_catalogue_paths_imported: ??? -eqtl_catalogue_study_index_out: ??? -eqtl_catalogue_credible_sets_out: ??? -mqtl_quantification_methods_blacklist: [] -session: - extended_spark_conf: - "spark.sql.shuffle.partitions": "3200" diff --git a/config/step/ot_gene_index.yaml b/config/step/ot_gene_index.yaml deleted file mode 100644 index ce5971bf9..000000000 --- a/config/step/ot_gene_index.yaml +++ /dev/null @@ -1,5 +0,0 @@ -defaults: - - gene_index - -target_path: ${datasets.target_index} -gene_index_path: ${datasets.gene_index} diff --git a/config/step/ot_gwas_catalog_ingestion.yaml b/config/step/ot_gwas_catalog_ingestion.yaml deleted file mode 100644 index 8acc07d62..000000000 --- a/config/step/ot_gwas_catalog_ingestion.yaml +++ /dev/null @@ -1,12 +0,0 @@ -defaults: - - gwas_catalog_ingestion - -catalog_study_files: ${datasets.gwas_catalog_studies} -catalog_ancestry_files: ${datasets.gwas_catalog_ancestries} -catalog_associations_file: ${datasets.gwas_catalog_associations} -catalog_sumstats_lut: ${datasets.gwas_catalog_sumstats_lut} -variant_annotation_path: ${datasets.gnomad_variants} -catalog_studies_out: ${datasets.gwas_catalog_study_index} -catalog_associations_out: ${datasets.gwas_catalog_study_locus_folder}/gwas_catalog_curated_associations -gwas_catalog_study_curation_file: ${datasets.gwas_catalog_study_curation} -inclusion_list_path: ${datasets.gwas_catalog_curated_inclusion_list} diff --git a/config/step/ot_gwas_catalog_study_curation.yaml b/config/step/ot_gwas_catalog_study_curation.yaml deleted file mode 100644 index 77c1d7834..000000000 --- a/config/step/ot_gwas_catalog_study_curation.yaml +++ /dev/null @@ -1,8 +0,0 @@ -defaults: - - gwas_catalog_study_curation - -catalog_study_files: ${datasets.gwas_catalog_studies} -catalog_ancestry_files: ${datasets.gwas_catalog_ancestries} -catalog_sumstats_lut: ${datasets.gwas_catalog_sumstats_lut} -gwas_catalog_study_curation_file: ${datasets.gwas_catalog_study_curation} -gwas_catalog_study_curation_out: ??? diff --git a/config/step/ot_gwas_catalog_study_inclusion.yaml b/config/step/ot_gwas_catalog_study_inclusion.yaml deleted file mode 100644 index 41590333c..000000000 --- a/config/step/ot_gwas_catalog_study_inclusion.yaml +++ /dev/null @@ -1,12 +0,0 @@ -defaults: - - gwas_catalog_study_inclusion - -catalog_study_files: ${datasets.gwas_catalog_studies} -catalog_ancestry_files: ${datasets.gwas_catalog_ancestries} -catalog_associations_file: ${datasets.gwas_catalog_associations} -variant_annotation_path: ${datasets.gnomad_variants} -gwas_catalog_study_curation_file: ${datasets.gwas_catalog_study_curation} -harmonised_study_file: ${datasets.gwas_catalog_summary_stats_list} -criteria: ??? -inclusion_list_path: ??? -exclusion_list_path: ??? diff --git a/config/step/ot_ld_based_clumping.yaml b/config/step/ot_ld_based_clumping.yaml deleted file mode 100644 index f836145c2..000000000 --- a/config/step/ot_ld_based_clumping.yaml +++ /dev/null @@ -1,7 +0,0 @@ -defaults: - - ld_based_clumping - -ld_index_path: ${datasets.ld_index}/2.1.1 -study_locus_input_path: ??? -study_index_path: ??? -clumped_study_locus_output_path: ??? diff --git a/config/step/ot_ld_index.yaml b/config/step/ot_ld_index.yaml deleted file mode 100644 index d17a0777c..000000000 --- a/config/step/ot_ld_index.yaml +++ /dev/null @@ -1,20 +0,0 @@ -defaults: - - ld_index - -ld_index_out: ${datasets.ld_index} -ld_matrix_template: ${datasets.ld_matrix_template} -ld_index_raw_template: ${datasets.ld_index_raw_template} -grch37_to_grch38_chain_path: ${datasets.chain_37_38} -liftover_ht_path: ${datasets.liftover_ht_path} -ld_populations: - - afr # African-American - - amr # American Admixed/Latino - - asj # Ashkenazi Jewish - - eas # East Asian - - est # Estonian - - fin # Finnish - - nfe # Non-Finnish European - - nwe # Northwestern European - - seu # Southeastern European -# The version will of the gnomad will be inferred from ld_matrix_template and appended to the ld_index_out. -use_version_from_input: true diff --git a/config/step/ot_locus_to_gene_predict.yaml b/config/step/ot_locus_to_gene_predict.yaml deleted file mode 100644 index c3cb88b59..000000000 --- a/config/step/ot_locus_to_gene_predict.yaml +++ /dev/null @@ -1,11 +0,0 @@ -defaults: - - locus_to_gene - -run_mode: predict -model_path: null -predictions_path: ${datasets.l2g_predictions} -feature_matrix_path: ${datasets.l2g_feature_matrix} -credible_set_path: ${datasets.credible_set} -variant_gene_path: ${datasets.variant_to_gene} -colocalisation_path: ${datasets.colocalisation} -study_index_path: ${datasets.study_index} diff --git a/config/step/ot_locus_to_gene_train.yaml b/config/step/ot_locus_to_gene_train.yaml deleted file mode 100644 index b59a24dae..000000000 --- a/config/step/ot_locus_to_gene_train.yaml +++ /dev/null @@ -1,19 +0,0 @@ -defaults: - - locus_to_gene - -run_mode: train -wandb_run_name: null -hf_hub_repo_id: opentargets/locus_to_gene -model_path: ${datasets.l2g_model} -predictions_path: ${datasets.l2g_predictions} -credible_set_path: ${datasets.credible_set} -variant_gene_path: ${datasets.variant_to_gene} -colocalisation_path: ${datasets.colocalisation} -study_index_path: ${datasets.study_index} -gold_standard_curation_path: ${datasets.l2g_gold_standard_curation} -gene_interactions_path: ${datasets.gene_interactions} -hyperparameters: - n_estimators: 100 - max_depth: 5 - loss: log_loss -download_from_hub: true diff --git a/config/step/ot_ukb_ppp_eur_sumstat_preprocess.yaml b/config/step/ot_ukb_ppp_eur_sumstat_preprocess.yaml deleted file mode 100644 index 24da7bad0..000000000 --- a/config/step/ot_ukb_ppp_eur_sumstat_preprocess.yaml +++ /dev/null @@ -1,13 +0,0 @@ -defaults: - - ukb_ppp_eur_sumstat_preprocess - -raw_study_index_path_from_tsv: ??? -raw_summary_stats_path: ??? -variant_annotation_path: ??? -tmp_variant_annotation_path: ??? -study_index_output_path: ??? -summary_stats_output_path: ??? - -session: - extended_spark_conf: - "spark.sql.shuffle.partitions": "3200" diff --git a/config/step/ot_variant_index.yaml b/config/step/ot_variant_index.yaml deleted file mode 100644 index 00b6b1602..000000000 --- a/config/step/ot_variant_index.yaml +++ /dev/null @@ -1,6 +0,0 @@ -defaults: - - variant_index - -vep_output_json_path: ${datasets.vep_output_path} -gnomad_variant_annotations_path: ${datasets.gnomad_variants} -variant_index_path: ${datasets.variant_index} diff --git a/config/step/ot_variant_to_gene.yaml b/config/step/ot_variant_to_gene.yaml deleted file mode 100644 index 7187a0625..000000000 --- a/config/step/ot_variant_to_gene.yaml +++ /dev/null @@ -1,13 +0,0 @@ -defaults: - - variant_to_gene - -variant_index_path: ${datasets.variant_index} -gene_index_path: ${datasets.gene_index} -vep_consequences_path: ${datasets.vep_consequences} -liftover_chain_file_path: ${datasets.chain_37_38} -interval_sources: - andersson: ${datasets.anderson} - javierre: ${datasets.javierre} - jung: ${datasets.jung} - thurman: ${datasets.thurman} -v2g_path: ${datasets.variant_to_gene} diff --git a/config/step/session/dataproc.yaml b/config/step/session/dataproc.yaml deleted file mode 100644 index 6ac641718..000000000 --- a/config/step/session/dataproc.yaml +++ /dev/null @@ -1,5 +0,0 @@ -defaults: - - base_session - -spark_uri: yarn -write_mode: errorifexists diff --git a/docs/development/airflow.md b/docs/development/airflow.md deleted file mode 100644 index ff5f7906c..000000000 --- a/docs/development/airflow.md +++ /dev/null @@ -1,124 +0,0 @@ -# Airflow configuration - -This section describes how to set up a local Airflow server which will orchestrate running workflows in Google Cloud Platform. This is useful for testing and debugging, but for production use, it is recommended to run Airflow on a dedicated server. - -## Install pre-requisites - -- [Docker](https://docs.docker.com/get-docker/) -- [Google Cloud SDK](https://cloud.google.com/sdk/docs/install) - -!!! warning macOS Docker memory allocation - - On macOS, the default amount of memory available for Docker might not be enough to get Airflow up and running. Allocate at least 4GB of memory for the Docker Engine (ideally 8GB). [More info](https://airflow.apache.org/docs/apache-airflow/stable/howto/docker-compose/index.html#) - -## Configure Airflow access to Google Cloud Platform - -!!! warning Specifying Google Cloud parameters - - Run the next two command with the appropriate Google Cloud project ID and service account name to ensure the correct Google default application credentials are set up. - -Authenticate to Google Cloud: - -```bash -gcloud auth application-default login --project= -``` - -Create the service account key file that will be used by Airflow to access Google Cloud Platform resources: - -```bash -gcloud iam service-accounts keys create ~/.config/gcloud/service_account_credentials.json --iam-account=@appspot.gserviceaccount.com -``` - -## Set up Airflow - -Change the working directory so that all subsequent commands will work: - -```bash -cd src/airflow -``` - -### Build Docker image - -!!! note Custom Docker image for Airflow - - The custom Dockerfile built by the command below extends the official [Airflow Docker Compose YAML](https://airflow.apache.org/docs/apache-airflow/stable/docker-compose.yaml). We add support for Google Cloud SDK, Google Dataproc operators, and access to GCP credentials. - -```bash -docker build . --tag extending_airflow:latest -``` - -### Set Airflow user ID - -!!! note Setting Airflow user ID - - These commands allow Airflow running inside Docker to access the credentials file which was generated earlier. - -```bash -# If any user ID is already specified in .env, remove it. -grep -v "AIRFLOW_UID" .env > .env.tmp -# Add the correct user ID. -echo "AIRFLOW_UID=$(id -u)" >> .env.tmp -# Move the file. -mv .env.tmp .env -``` - -### Initialise - -Before starting Airflow, initialise the database: - -```bash -docker compose up airflow-init -``` - -Now start all services: - -```bash -docker compose up -d -``` - -Airflow UI will now be available at `http://localhost:8080/`. Default username and password are both `airflow`. - -For additional information on how to use Airflow visit the [official documentation](https://airflow.apache.org/docs/apache-airflow/stable/index.html). - -### Cleaning up - -At any time, you can check the status of your containers with: - -```bash -docker ps -``` - -To stop Airflow, run: - -```bash -docker compose down -``` - -To cleanup the Airflow database, run: - -```bash -docker compose down --volumes --remove-orphans -``` - -### Advanced configuration - -More information on running Airflow with Docker Compose can be found in the [official docs](https://airflow.apache.org/docs/apache-airflow/stable/howto/docker-compose/index.html). - -1. **Increase Airflow concurrency**. Modify the `docker-compose.yaml` and add the following to the x-airflow-common → environment section: - - ```yaml - AIRFLOW__CORE__PARALLELISM: 32 - AIRFLOW__CORE__MAX_ACTIVE_TASKS_PER_DAG: 32 - AIRFLOW__SCHEDULER__MAX_TIS_PER_QUERY: 16 - AIRFLOW__CORE__MAX_ACTIVE_RUNS_PER_DAG: 1 - # Also add the following line if you are using CeleryExecutor (by default, LocalExecutor is used). - AIRFLOW__CELERY__WORKER_CONCURRENCY: 32 - ``` - -1. **Additional pip packages**. They can be added to the `requirements.txt` file. - -## Troubleshooting - -Note that when you a a new workflow under `dags/`, Airflow will not pick that up immediately. By default the filesystem is only scanned for new DAGs every 300s. However, once the DAG is added, updates are applied nearly instantaneously. - -Also, if you edit the DAG while an instance of it is running, it might cause problems with the run, as Airflow will try to update the tasks and their properties in DAG according to the file changes. diff --git a/docs/development/contributing.md b/docs/development/contributing.md index 3a363210f..acbb8f2a7 100644 --- a/docs/development/contributing.md +++ b/docs/development/contributing.md @@ -18,7 +18,7 @@ For Google Cloud configuration: Check that you have the `make` utility installed, and if not (which is unlikely), install it using your system package manager. -Check that you have `java` installed. +Check that you have `java` installed. To be able to use all features including hail support use java 11. ## Environment configuration @@ -26,30 +26,19 @@ Run `make setup-dev` to install/update the necessary packages and activate the d It is recommended to use VS Code as an IDE for development. -## How to run the code +## How to create gentropy step -All pipelines in this repository are intended to be run in Google Dataproc. Running them locally is not currently supported. +All gentropy steps can be invoked after successful environment configuration by running -In order to run the code: +```python +poetry run gentropy step= +``` -1. Manually edit your local `src/airflow/dags/*` file and comment out the steps you do not want to run. +1. Create a new step config in the `src/gentropy/config.py` that inherits from `StepConfig` class. -2. Manually edit your local `pyproject.toml` file and modify the version of the code. +2. Register new step configuration to `ConfigStore`. - - This must be different from the version used by any other people working on the repository to avoid any deployment conflicts, so it's a good idea to use your name, for example: `1.2.3+jdoe`. - - You can also add a brief branch description, for example: `1.2.3+jdoe.myfeature`. - - Note that the version must comply with [PEP440 conventions](https://peps.python.org/pep-0440/#normalization), otherwise Poetry will not allow it to be deployed. - - Do not use underscores or hyphens in your version name. When building the WHL file, they will be automatically converted to dots, which means the file name will no longer match the version and the build will fail. Use dots instead. - -3. Manually edit your local `src/airflow/dags/common_airflow.py` and set `GENTROPY_VERSION` to the same version as you did in the previous step. - -4. Run `make build`. - - - This will create a bundle containing the neccessary code, configuration and dependencies to run the ETL pipeline, and then upload this bundle to Google Cloud. - - A version specific subpath is used, so uploading the code will not affect any branches but your own. - - If there was already a code bundle uploaded with the same version number, it will be replaced. - -5. Open Airflow UI and run the DAG. +3. Create a step class that holds the business logic in new file in the `src/gentropy`. ## Contributing checklist @@ -72,8 +61,7 @@ For more details on each of these steps, see the sections below. ### Configuration -- Input and output paths in `config/datasets/ot_gcp.yaml` -- Step configuration, for example: `config/step/ot_finngen_sumstat_preprocess.yaml` +- step default configuration in the `src/gentropy/config/` `StepConfig` derived classes. ### Classes @@ -87,6 +75,6 @@ For more details on each of these steps, see the sections below. - Test sample data, for example: `tests/gentropy/data_samples/finngen_studies_sample.json` - Test definition, for example: `tests/dataset/test_study_index.py` → `test_study_index_finngen_creation`) -### Orchestration +### Airflow dags -- Airflow DAG, for example: `src/airflow/dags/finngen_harmonisation.py` +- Upstream of version 2.0.0 airflow orchestration layer was moved to the [orchestration repository](https://github.com/opentargets/orchestration) diff --git a/docs/development/workflows.md b/docs/development/workflows.md deleted file mode 100644 index 2269041d8..000000000 --- a/docs/development/workflows.md +++ /dev/null @@ -1,27 +0,0 @@ -# Pipeline workflows - -This page describes the high level components of the pipeline, which are organised as Airflow DAGs (directed acyclic graphs). - -## Note on DAGs and Dataproc clusters - -Each DAG consists of the following general stages: - -1. Create cluster (if it already exists, this step is skipped) - -1. Install dependencies on the cluster - -1. Run data processing steps for this DAG - -1. Delete the cluster - -Within a DAG, all data processing steps run on the same Dataproc cluster as separate jobs. - -There is no need to configure DAGs or steps depending on the size of the input data. Clusters have autoscaling enabled, which means they will increase or decrease the number of worker VMs to accommodate the load. - -## DAG 1: Preprocess - -This DAG contains steps which are only supposed to be run once, or very rarely. They ingest external data and apply bespoke transformations specific for each particular data source. The output is normalised according to the data schemas used by the pipeline. - -## DAG 2: ETL - -The ETL DAG takes the inputs of the previous step and performs the main algorithmic processing. This processing is supposed to be data source agnostic. diff --git a/mkdocs.yml b/mkdocs.yml index 180c6fbe1..3704ed274 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -48,7 +48,8 @@ markdown_extensions: - pymdownx.tabbed: alternate_style: true combine_header_slug: true - + - pymdownx.tasklist: + custom_checkbox: true hooks: - src/utils/schemadocs.py diff --git a/poetry.lock b/poetry.lock index 2ba1390ce..0df0da543 100644 --- a/poetry.lock +++ b/poetry.lock @@ -14,17 +14,6 @@ files = [ [package.dependencies] pycares = ">=3.0.0" -[[package]] -name = "aiofiles" -version = "23.2.1" -description = "File support for asyncio." -optional = false -python-versions = ">=3.7" -files = [ - {file = "aiofiles-23.2.1-py3-none-any.whl", hash = "sha256:19297512c647d4b27a2cf7c34caa7e405c0d60b5560618a29a9fe027b18b0107"}, - {file = "aiofiles-23.2.1.tar.gz", hash = "sha256:84ec2218d8419404abcb9f0c02df3f34c6e0a68ed41072acfb1cef5cbc29051a"}, -] - [[package]] name = "aiohttp" version = "3.9.5" @@ -135,36 +124,6 @@ files = [ [package.dependencies] frozenlist = ">=1.1.0" -[[package]] -name = "alembic" -version = "1.13.1" -description = "A database migration tool for SQLAlchemy." -optional = false -python-versions = ">=3.8" -files = [ - {file = "alembic-1.13.1-py3-none-any.whl", hash = "sha256:2edcc97bed0bd3272611ce3a98d98279e9c209e7186e43e75bbb1b2bdfdbcc43"}, - {file = "alembic-1.13.1.tar.gz", hash = "sha256:4932c8558bf68f2ee92b9bbcb8218671c627064d5b08939437af6d77dc05e595"}, -] - -[package.dependencies] -Mako = "*" -SQLAlchemy = ">=1.3.0" -typing-extensions = ">=4" - -[package.extras] -tz = ["backports.zoneinfo"] - -[[package]] -name = "annotated-types" -version = "0.7.0" -description = "Reusable constraint types to use with typing.Annotated" -optional = false -python-versions = ">=3.8" -files = [ - {file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"}, - {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, -] - [[package]] name = "antlr4-python3-runtime" version = "4.9.3" @@ -175,493 +134,6 @@ files = [ {file = "antlr4-python3-runtime-4.9.3.tar.gz", hash = "sha256:f224469b4168294902bb1efa80a8bf7855f24c99aef99cbefc1bcd3cce77881b"}, ] -[[package]] -name = "anyio" -version = "4.4.0" -description = "High level compatibility layer for multiple asynchronous event loop implementations" -optional = false -python-versions = ">=3.8" -files = [ - {file = "anyio-4.4.0-py3-none-any.whl", hash = "sha256:c1b2d8f46a8a812513012e1107cb0e68c17159a7a594208005a57dc776e1bdc7"}, - {file = "anyio-4.4.0.tar.gz", hash = "sha256:5aadc6a1bbb7cdb0bede386cac5e2940f5e2ff3aa20277e991cf028e0585ce94"}, -] - -[package.dependencies] -exceptiongroup = {version = ">=1.0.2", markers = "python_version < \"3.11\""} -idna = ">=2.8" -sniffio = ">=1.1" -typing-extensions = {version = ">=4.1", markers = "python_version < \"3.11\""} - -[package.extras] -doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] -test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"] -trio = ["trio (>=0.23)"] - -[[package]] -name = "apache-airflow" -version = "2.9.2" -description = "Programmatically author, schedule and monitor data pipelines" -optional = false -python-versions = "<3.13,~=3.8" -files = [ - {file = "apache_airflow-2.9.2-py3-none-any.whl", hash = "sha256:6fd6501b1622ab58f4a3c1fc5bed4c216bd36915243bb9445b54415c3e625200"}, - {file = "apache_airflow-2.9.2.tar.gz", hash = "sha256:c5d7b4bbcbc4d7b2bb3433af2d9307a3f3dc0b142c25fdbe8f187dd4cad5521d"}, -] - -[package.dependencies] -alembic = ">=1.13.1,<2.0" -apache-airflow-providers-common-io = "*" -apache-airflow-providers-common-sql = "*" -apache-airflow-providers-fab = ">=1.0.2" -apache-airflow-providers-ftp = "*" -apache-airflow-providers-http = "*" -apache-airflow-providers-imap = "*" -apache-airflow-providers-smtp = "*" -apache-airflow-providers-sqlite = "*" -argcomplete = ">=1.10" -asgiref = "*" -attrs = ">=22.1.0" -blinker = ">=1.6.2" -colorlog = ">=4.0.2,<5.0" -configupdater = ">=3.1.1" -connexion = {version = ">=2.10.0,<3.0", extras = ["flask"]} -cron-descriptor = ">=1.2.24" -croniter = ">=2.0.2" -cryptography = ">=39.0.0" -deprecated = ">=1.2.13" -dill = ">=0.2.2" -flask = ">=2.2,<2.3" -flask-caching = ">=1.5.0" -flask-session = ">=0.4.0,<0.6" -flask-wtf = ">=0.15" -fsspec = ">=2023.10.0" -google-re2 = ">=1.0" -gunicorn = ">=20.1.0" -httpx = "*" -importlib_metadata = {version = ">=6.5", markers = "python_version < \"3.12\""} -itsdangerous = ">=2.0" -jinja2 = ">=3.0.0" -jsonschema = ">=4.18.0" -lazy-object-proxy = "*" -linkify-it-py = ">=2.0.0" -lockfile = ">=0.12.2" -markdown-it-py = ">=2.1.0" -markupsafe = ">=1.1.1" -marshmallow-oneofschema = ">=2.0.1" -mdit-py-plugins = ">=0.3.0" -methodtools = ">=0.4.7" -opentelemetry-api = ">=1.15.0" -opentelemetry-exporter-otlp = "*" -packaging = ">=14.0" -pathspec = ">=0.9.0" -pendulum = ">=2.1.2,<4.0" -pluggy = ">=1.0" -psutil = ">=4.2.0" -pygments = ">=2.0.1" -pyjwt = ">=2.0.0" -python-daemon = ">=3.0.0" -python-dateutil = ">=2.3" -python-nvd3 = ">=0.15.0" -python-slugify = ">=5.0" -requests = ">=2.27.0,<3" -rfc3339-validator = ">=0.1.4" -rich = ">=12.4.4" -rich-argparse = ">=1.0.0" -setproctitle = ">=1.1.8" -sqlalchemy = ">=1.4.36,<2.0" -sqlalchemy-jsonfield = ">=1.0" -tabulate = ">=0.7.5" -tenacity = ">=6.2.0,<8.2.0 || >8.2.0" -termcolor = ">=1.1.0" -unicodecsv = ">=0.14.1" -universal-pathlib = ">=0.2.2" -werkzeug = ">=2.0,<3" - -[package.extras] -aiobotocore = ["aiobotocore (>=2.7.0)"] -airbyte = ["apache-airflow-providers-airbyte"] -alibaba = ["apache-airflow-providers-alibaba"] -all = ["apache-airflow[aiobotocore]", "apache-airflow[airbyte]", "apache-airflow[alibaba]", "apache-airflow[all-dbs]", "apache-airflow[amazon]", "apache-airflow[apache-atlas]", "apache-airflow[apache-beam]", "apache-airflow[apache-cassandra]", "apache-airflow[apache-drill]", "apache-airflow[apache-druid]", "apache-airflow[apache-flink]", "apache-airflow[apache-hdfs]", "apache-airflow[apache-hive]", "apache-airflow[apache-impala]", "apache-airflow[apache-kafka]", "apache-airflow[apache-kylin]", "apache-airflow[apache-livy]", "apache-airflow[apache-pig]", "apache-airflow[apache-pinot]", "apache-airflow[apache-spark]", "apache-airflow[apache-webhdfs]", "apache-airflow[apprise]", "apache-airflow[arangodb]", "apache-airflow[asana]", "apache-airflow[async]", "apache-airflow[atlassian-jira]", "apache-airflow[celery]", "apache-airflow[cgroups]", "apache-airflow[cloudant]", "apache-airflow[cncf-kubernetes]", "apache-airflow[cohere]", "apache-airflow[common-io]", "apache-airflow[common-sql]", "apache-airflow[databricks]", "apache-airflow[datadog]", "apache-airflow[dbt-cloud]", "apache-airflow[deprecated-api]", "apache-airflow[dingding]", "apache-airflow[discord]", "apache-airflow[docker]", "apache-airflow[elasticsearch]", "apache-airflow[exasol]", "apache-airflow[fab]", "apache-airflow[facebook]", "apache-airflow[ftp]", "apache-airflow[github-enterprise]", "apache-airflow[github]", "apache-airflow[google-auth]", "apache-airflow[google]", "apache-airflow[graphviz]", "apache-airflow[grpc]", "apache-airflow[hashicorp]", "apache-airflow[http]", "apache-airflow[imap]", "apache-airflow[influxdb]", "apache-airflow[jdbc]", "apache-airflow[jenkins]", "apache-airflow[kerberos]", "apache-airflow[ldap]", "apache-airflow[leveldb]", "apache-airflow[microsoft-azure]", "apache-airflow[microsoft-mssql]", "apache-airflow[microsoft-psrp]", "apache-airflow[microsoft-winrm]", "apache-airflow[mongo]", "apache-airflow[mysql]", "apache-airflow[neo4j]", "apache-airflow[odbc]", "apache-airflow[openai]", "apache-airflow[openfaas]", "apache-airflow[openlineage]", "apache-airflow[opensearch]", "apache-airflow[opsgenie]", "apache-airflow[oracle]", "apache-airflow[otel]", "apache-airflow[pagerduty]", "apache-airflow[pandas]", "apache-airflow[papermill]", "apache-airflow[password]", "apache-airflow[pgvector]", "apache-airflow[pinecone]", "apache-airflow[postgres]", "apache-airflow[presto]", "apache-airflow[pydantic]", "apache-airflow[qdrant]", "apache-airflow[rabbitmq]", "apache-airflow[redis]", "apache-airflow[s3fs]", "apache-airflow[salesforce]", "apache-airflow[samba]", "apache-airflow[saml]", "apache-airflow[segment]", "apache-airflow[sendgrid]", "apache-airflow[sentry]", "apache-airflow[sftp]", "apache-airflow[singularity]", "apache-airflow[slack]", "apache-airflow[smtp]", "apache-airflow[snowflake]", "apache-airflow[sqlite]", "apache-airflow[ssh]", "apache-airflow[statsd]", "apache-airflow[tableau]", "apache-airflow[tabular]", "apache-airflow[telegram]", "apache-airflow[teradata]", "apache-airflow[trino]", "apache-airflow[uv]", "apache-airflow[vertica]", "apache-airflow[virtualenv]", "apache-airflow[weaviate]", "apache-airflow[yandex]", "apache-airflow[zendesk]"] -all-core = ["apache-airflow[aiobotocore]", "apache-airflow[apache-atlas]", "apache-airflow[apache-webhdfs]", "apache-airflow[async]", "apache-airflow[cgroups]", "apache-airflow[deprecated-api]", "apache-airflow[github-enterprise]", "apache-airflow[google-auth]", "apache-airflow[graphviz]", "apache-airflow[kerberos]", "apache-airflow[ldap]", "apache-airflow[leveldb]", "apache-airflow[otel]", "apache-airflow[pandas]", "apache-airflow[password]", "apache-airflow[pydantic]", "apache-airflow[rabbitmq]", "apache-airflow[s3fs]", "apache-airflow[saml]", "apache-airflow[sentry]", "apache-airflow[statsd]", "apache-airflow[uv]", "apache-airflow[virtualenv]"] -all-dbs = ["apache-airflow[apache-cassandra]", "apache-airflow[apache-drill]", "apache-airflow[apache-druid]", "apache-airflow[apache-hdfs]", "apache-airflow[apache-hive]", "apache-airflow[apache-impala]", "apache-airflow[apache-pinot]", "apache-airflow[arangodb]", "apache-airflow[cloudant]", "apache-airflow[databricks]", "apache-airflow[exasol]", "apache-airflow[influxdb]", "apache-airflow[microsoft-mssql]", "apache-airflow[mongo]", "apache-airflow[mysql]", "apache-airflow[neo4j]", "apache-airflow[postgres]", "apache-airflow[presto]", "apache-airflow[trino]", "apache-airflow[vertica]"] -amazon = ["apache-airflow-providers-amazon"] -apache-atlas = ["atlasclient (>=0.1.2)"] -apache-beam = ["apache-airflow-providers-apache-beam"] -apache-cassandra = ["apache-airflow-providers-apache-cassandra"] -apache-drill = ["apache-airflow-providers-apache-drill"] -apache-druid = ["apache-airflow-providers-apache-druid"] -apache-flink = ["apache-airflow-providers-apache-flink"] -apache-hdfs = ["apache-airflow-providers-apache-hdfs"] -apache-hive = ["apache-airflow-providers-apache-hive"] -apache-impala = ["apache-airflow-providers-apache-impala"] -apache-kafka = ["apache-airflow-providers-apache-kafka"] -apache-kylin = ["apache-airflow-providers-apache-kylin"] -apache-livy = ["apache-airflow-providers-apache-livy"] -apache-pig = ["apache-airflow-providers-apache-pig"] -apache-pinot = ["apache-airflow-providers-apache-pinot"] -apache-spark = ["apache-airflow-providers-apache-spark"] -apache-webhdfs = ["hdfs[avro,dataframe,kerberos] (>=2.0.4)"] -apprise = ["apache-airflow-providers-apprise"] -arangodb = ["apache-airflow-providers-arangodb"] -asana = ["apache-airflow-providers-asana"] -async = ["eventlet (>=0.33.3)", "gevent (>=0.13)", "greenlet (>=0.4.9)"] -atlas = ["apache-airflow[apache-atlas]"] -atlassian-jira = ["apache-airflow-providers-atlassian-jira"] -aws = ["apache-airflow[amazon]"] -azure = ["apache-airflow[microsoft-azure]"] -cassandra = ["apache-airflow[apache-cassandra]"] -celery = ["apache-airflow-providers-celery"] -cgroups = ["cgroupspy (>=0.2.2)"] -cloudant = ["apache-airflow-providers-cloudant"] -cncf-kubernetes = ["apache-airflow-providers-cncf-kubernetes"] -cohere = ["apache-airflow-providers-cohere"] -common-io = ["apache-airflow-providers-common-io"] -common-sql = ["apache-airflow-providers-common-sql"] -databricks = ["apache-airflow-providers-databricks"] -datadog = ["apache-airflow-providers-datadog"] -dbt-cloud = ["apache-airflow-providers-dbt-cloud"] -deprecated-api = ["requests (>=2.27.0,<3)"] -devel-ci = ["aiobotocore (>=2.7.0)", "aiofiles (>=23.2.0)", "aioresponses (>=0.7.6)", "amqp", "astroid (>=2.12.3,<3.0)", "atlasclient (>=0.1.2)", "authlib (>=1.0.0)", "backports-zoneinfo (>=0.2.1)", "bcrypt (>=2.0.0)", "beautifulsoup4 (>=4.7.1)", "black (>=23.12.0)", "blinker (>=1.1)", "blinker (>=1.7.0)", "cgroupspy (>=0.2.2)", "checksumdir (>=1.2.0)", "click (>=8.0)", "click (>=8.0,!=8.1.4,!=8.1.5)", "coverage (>=7.4.0)", "diagrams (>=0.23.4)", "docutils (>=0.16,<0.17)", "duckdb (>=0.10.0)", "duckdb (>=0.9.0)", "eralchemy2 (>=1.3.8)", "eventlet (>=0.33.3)", "flask-bcrypt (>=0.7.1)", "gevent (>=0.13)", "gitpython (>=3.1.40)", "graphviz (>=0.12)", "greenlet (>=0.4.9)", "hatch (>=1.9.1)", "hdfs[avro,dataframe,kerberos] (>=2.0.4)", "ipdb (>=0.13.13)", "ldap3 (>=2.5.1)", "mypy (==1.9.0)", "opentelemetry-exporter-prometheus", "pandas (>=1.2.5,<2.2)", "pipdeptree (>=2.13.1)", "plyvel", "pre-commit (>=3.5.0)", "pydantic (>=2.3.0)", "pygithub (>=2.1.1)", "pykerberos (>=1.1.13)", "pytest (>=7.4.4,<8.0)", "pytest-asyncio (>=0.23.3)", "pytest-cov (>=4.1.0)", "pytest-custom-exit-code (>=0.3.0)", "pytest-icdiff (>=0.9)", "pytest-instafail (>=0.5.0)", "pytest-mock (>=3.12.0)", "pytest-rerunfailures (>=13.0)", "pytest-timeouts (>=1.2.1)", "pytest-xdist (>=3.5.0)", "python-ldap", "python3-saml (>=1.16.0)", "requests (>=2.27.0,<3)", "requests-kerberos (>=0.10.0)", "requests-mock (>=1.11.0)", "restructuredtext-lint (>=1.4.0)", "rich-click (>=1.7.0)", "ruff (==0.3.3)", "s3fs (>=2023.10.0)", "semver (>=3.0.2)", "sentry-sdk (>=1.32.0,!=1.33.0)", "sphinx (>=5.3.0,<6.0.0)", "sphinx-airflow-theme (>=0.0.12)", "sphinx-argparse (>=0.4.0)", "sphinx-autoapi (>=2.1.1)", "sphinx-copybutton (>=0.5.2)", "sphinx-design (>=0.5.0)", "sphinx-jinja (>=2.0.2)", "sphinx-rtd-theme (>=2.0.0)", "sphinxcontrib-applehelp (>=1.0.4)", "sphinxcontrib-devhelp (>=1.0.2)", "sphinxcontrib-htmlhelp (>=2.0.1)", "sphinxcontrib-httpdomain (>=1.8.1)", "sphinxcontrib-jquery (>=4.1)", "sphinxcontrib-jsmath (>=1.0.1)", "sphinxcontrib-qthelp (>=1.0.3)", "sphinxcontrib-redoc (>=1.6.0)", "sphinxcontrib-serializinghtml (==1.1.5)", "sphinxcontrib-spelling (>=8.0.0)", "statsd (>=3.3.0)", "thrift-sasl (>=0.2.0)", "time-machine (>=2.13.0)", "towncrier (>=23.11.0)", "twine (>=4.0.2)", "types-aiofiles", "types-certifi", "types-croniter", "types-deprecated", "types-docutils", "types-markdown", "types-paramiko", "types-protobuf", "types-pymysql", "types-python-dateutil", "types-python-slugify", "types-pytz", "types-pyyaml", "types-redis", "types-requests", "types-setuptools", "types-tabulate", "types-termcolor", "types-toml", "uv (>=0.1.32)", "virtualenv", "wheel (>=0.42.0)", "yamllint (>=1.33.0)"] -dingding = ["apache-airflow-providers-dingding"] -discord = ["apache-airflow-providers-discord"] -docker = ["apache-airflow-providers-docker"] -druid = ["apache-airflow[apache-druid]"] -elasticsearch = ["apache-airflow-providers-elasticsearch"] -exasol = ["apache-airflow-providers-exasol"] -fab = ["apache-airflow-providers-fab"] -facebook = ["apache-airflow-providers-facebook"] -ftp = ["apache-airflow-providers-ftp"] -gcp = ["apache-airflow[google]"] -gcp-api = ["apache-airflow[google]"] -github = ["apache-airflow-providers-github"] -github-enterprise = ["apache-airflow[fab]", "authlib (>=1.0.0)"] -google = ["apache-airflow-providers-google"] -google-auth = ["apache-airflow[fab]", "authlib (>=1.0.0)"] -graphviz = ["graphviz (>=0.12)"] -grpc = ["apache-airflow-providers-grpc"] -hashicorp = ["apache-airflow-providers-hashicorp"] -hdfs = ["apache-airflow[apache-hdfs]"] -hive = ["apache-airflow[apache-hive]"] -http = ["apache-airflow-providers-http"] -imap = ["apache-airflow-providers-imap"] -influxdb = ["apache-airflow-providers-influxdb"] -jdbc = ["apache-airflow-providers-jdbc"] -jenkins = ["apache-airflow-providers-jenkins"] -kerberos = ["pykerberos (>=1.1.13)", "requests-kerberos (>=0.10.0)", "thrift-sasl (>=0.2.0)"] -kubernetes = ["apache-airflow[cncf-kubernetes]"] -ldap = ["ldap3 (>=2.5.1)", "python-ldap"] -leveldb = ["plyvel"] -microsoft-azure = ["apache-airflow-providers-microsoft-azure"] -microsoft-mssql = ["apache-airflow-providers-microsoft-mssql"] -microsoft-psrp = ["apache-airflow-providers-microsoft-psrp"] -microsoft-winrm = ["apache-airflow-providers-microsoft-winrm"] -mongo = ["apache-airflow-providers-mongo"] -mssql = ["apache-airflow[microsoft-mssql]"] -mysql = ["apache-airflow-providers-mysql"] -neo4j = ["apache-airflow-providers-neo4j"] -odbc = ["apache-airflow-providers-odbc"] -openai = ["apache-airflow-providers-openai"] -openfaas = ["apache-airflow-providers-openfaas"] -openlineage = ["apache-airflow-providers-openlineage"] -opensearch = ["apache-airflow-providers-opensearch"] -opsgenie = ["apache-airflow-providers-opsgenie"] -oracle = ["apache-airflow-providers-oracle"] -otel = ["opentelemetry-exporter-prometheus"] -pagerduty = ["apache-airflow-providers-pagerduty"] -pandas = ["pandas (>=1.2.5,<2.2)"] -papermill = ["apache-airflow-providers-papermill"] -password = ["bcrypt (>=2.0.0)", "flask-bcrypt (>=0.7.1)"] -pgvector = ["apache-airflow-providers-pgvector"] -pinecone = ["apache-airflow-providers-pinecone"] -pinot = ["apache-airflow[apache-pinot]"] -postgres = ["apache-airflow-providers-postgres"] -presto = ["apache-airflow-providers-presto"] -pydantic = ["pydantic (>=2.3.0)"] -qdrant = ["apache-airflow-providers-qdrant"] -rabbitmq = ["amqp"] -redis = ["apache-airflow-providers-redis"] -s3 = ["apache-airflow[amazon]"] -s3fs = ["s3fs (>=2023.10.0)"] -salesforce = ["apache-airflow-providers-salesforce"] -samba = ["apache-airflow-providers-samba"] -saml = ["python3-saml (>=1.16.0)"] -segment = ["apache-airflow-providers-segment"] -sendgrid = ["apache-airflow-providers-sendgrid"] -sentry = ["blinker (>=1.1)", "sentry-sdk (>=1.32.0,!=1.33.0)"] -sftp = ["apache-airflow-providers-sftp"] -singularity = ["apache-airflow-providers-singularity"] -slack = ["apache-airflow-providers-slack"] -smtp = ["apache-airflow-providers-smtp"] -snowflake = ["apache-airflow-providers-snowflake"] -spark = ["apache-airflow[apache-spark]"] -sqlite = ["apache-airflow-providers-sqlite"] -ssh = ["apache-airflow-providers-ssh"] -statsd = ["statsd (>=3.3.0)"] -tableau = ["apache-airflow-providers-tableau"] -tabular = ["apache-airflow-providers-tabular"] -telegram = ["apache-airflow-providers-telegram"] -teradata = ["apache-airflow-providers-teradata"] -trino = ["apache-airflow-providers-trino"] -uv = ["uv (>=0.1.32)"] -vertica = ["apache-airflow-providers-vertica"] -virtualenv = ["virtualenv"] -weaviate = ["apache-airflow-providers-weaviate"] -webhdfs = ["apache-airflow[apache-webhdfs]"] -winrm = ["apache-airflow[microsoft-winrm]"] -yandex = ["apache-airflow-providers-yandex"] -zendesk = ["apache-airflow-providers-zendesk"] - -[[package]] -name = "apache-airflow-providers-common-io" -version = "1.3.2" -description = "Provider package apache-airflow-providers-common-io for Apache Airflow" -optional = false -python-versions = "~=3.8" -files = [ - {file = "apache_airflow_providers_common_io-1.3.2-py3-none-any.whl", hash = "sha256:7c0299d8eb2e3fc7b99f522c4d333e2b888edbf47861a8f3e3ae78707ae77aab"}, - {file = "apache_airflow_providers_common_io-1.3.2.tar.gz", hash = "sha256:1212e484a16ad311bcb979e84ad1fa1cc45d7f5ba4dfcbd7978887bd30809e75"}, -] - -[package.dependencies] -apache-airflow = ">=2.8.0" - -[package.extras] -openlineage = ["apache-airflow-providers-openlineage"] - -[[package]] -name = "apache-airflow-providers-common-sql" -version = "1.14.0" -description = "Provider package apache-airflow-providers-common-sql for Apache Airflow" -optional = false -python-versions = "~=3.8" -files = [ - {file = "apache_airflow_providers_common_sql-1.14.0-py3-none-any.whl", hash = "sha256:620ba5bf559964159b3faf0bf921e666d1c3bb74ade27daa385f9e9ecd413a1c"}, - {file = "apache_airflow_providers_common_sql-1.14.0.tar.gz", hash = "sha256:6179512edf261ede96adda31a535eec024471a5708a7528d27a4ece72f35783f"}, -] - -[package.dependencies] -apache-airflow = ">=2.7.0" -more-itertools = ">=9.0.0" -sqlparse = ">=0.4.2" - -[package.extras] -openlineage = ["apache-airflow-providers-openlineage"] -pandas = ["pandas (>=1.2.5,<2.2)"] - -[[package]] -name = "apache-airflow-providers-fab" -version = "1.1.1" -description = "Provider package apache-airflow-providers-fab for Apache Airflow" -optional = false -python-versions = "~=3.8" -files = [ - {file = "apache_airflow_providers_fab-1.1.1-py3-none-any.whl", hash = "sha256:5d393d209ef432618e1926b019fb7b543d1fc932b592c39b4170779c409a38a5"}, - {file = "apache_airflow_providers_fab-1.1.1.tar.gz", hash = "sha256:60c1722f9985675e65f78c05bca8b4eb708a3140a2ed16d8de2c4cc4a4ecadc3"}, -] - -[package.dependencies] -apache-airflow = ">=2.9.0" -flask = ">=2.2,<2.3" -flask-appbuilder = "4.4.1" -flask-login = ">=0.6.2" -google-re2 = ">=1.0" -jmespath = "*" - -[[package]] -name = "apache-airflow-providers-ftp" -version = "3.9.1" -description = "Provider package apache-airflow-providers-ftp for Apache Airflow" -optional = false -python-versions = "~=3.8" -files = [ - {file = "apache_airflow_providers_ftp-3.9.1-py3-none-any.whl", hash = "sha256:74744b27f356bc42b528605d33a868ed2b4c670a1c90a857fb05402740e6f980"}, - {file = "apache_airflow_providers_ftp-3.9.1.tar.gz", hash = "sha256:b5cc4445a6fabb73f760c678d1b7f1d10586dfc6c9d34746c7462180f1cbb3ce"}, -] - -[package.dependencies] -apache-airflow = ">=2.7.0" - -[package.extras] -openlineage = ["apache-airflow-providers-openlineage"] - -[[package]] -name = "apache-airflow-providers-google" -version = "10.15.0" -description = "Provider package apache-airflow-providers-google for Apache Airflow" -optional = false -python-versions = "~=3.8" -files = [ - {file = "apache_airflow_providers_google-10.15.0-py3-none-any.whl", hash = "sha256:70d2d4feb66f06cd750ea673344f3be20d2d575c9645f7e2b030c73551a297fc"}, - {file = "apache_airflow_providers_google-10.15.0.tar.gz", hash = "sha256:ff48fa0a29abec2645a8008c47d0a84a759b7203412707a5e2fc01558c4052a3"}, -] - -[package.dependencies] -apache-airflow = ">=2.6.0" -apache-airflow-providers-common-sql = ">=1.7.2" -asgiref = ">=3.5.2" -gcloud-aio-auth = ">=4.0.0,<5.0.0" -gcloud-aio-bigquery = ">=6.1.2" -gcloud-aio-storage = ">=9.0.0" -gcsfs = ">=2023.10.0" -google-ads = ">=22.1.0" -google-analytics-admin = "*" -google-api-core = ">=2.11.0,<2.16.0 || >2.16.0" -google-api-python-client = ">=1.6.0" -google-auth = ">=1.0.0" -google-auth-httplib2 = ">=0.0.1" -google-cloud-aiplatform = ">=1.22.1" -google-cloud-automl = ">=2.12.0" -google-cloud-batch = ">=0.13.0" -google-cloud-bigquery-datatransfer = ">=3.13.0" -google-cloud-bigtable = ">=2.17.0" -google-cloud-build = ">=3.22.0" -google-cloud-compute = ">=1.10.0" -google-cloud-container = ">=2.17.4" -google-cloud-datacatalog = ">=3.11.1" -google-cloud-dataflow-client = ">=0.8.6" -google-cloud-dataform = ">=0.5.0" -google-cloud-dataplex = ">=1.10.0" -google-cloud-dataproc = ">=5.8.0" -google-cloud-dataproc-metastore = ">=1.12.0" -google-cloud-dlp = ">=3.12.0" -google-cloud-kms = ">=2.15.0" -google-cloud-language = ">=2.9.0" -google-cloud-logging = ">=3.5.0" -google-cloud-memcache = ">=1.7.0" -google-cloud-monitoring = ">=2.18.0" -google-cloud-orchestration-airflow = ">=1.10.0" -google-cloud-os-login = ">=2.9.1" -google-cloud-pubsub = ">=2.19.0" -google-cloud-redis = ">=2.12.0" -google-cloud-run = ">=0.9.0" -google-cloud-secret-manager = ">=2.16.0" -google-cloud-spanner = ">=3.11.1" -google-cloud-speech = ">=2.18.0" -google-cloud-storage = ">=2.7.0" -google-cloud-storage-transfer = ">=1.4.1" -google-cloud-tasks = ">=2.13.0" -google-cloud-texttospeech = ">=2.14.1" -google-cloud-translate = ">=3.11.0" -google-cloud-videointelligence = ">=2.11.0" -google-cloud-vision = ">=3.4.0" -google-cloud-workflows = ">=1.10.0" -grpcio-gcp = ">=0.2.2" -httpx = "*" -json-merge-patch = ">=0.2" -looker-sdk = ">=22.2.0" -pandas = ">=1.2.5" -pandas-gbq = "*" -proto-plus = ">=1.19.6" -PyOpenSSL = "*" -sqlalchemy-bigquery = ">=1.2.1" -sqlalchemy-spanner = ">=1.6.2" - -[package.extras] -amazon = ["apache-airflow-providers-amazon (>=2.6.0)"] -apache-beam = ["apache-airflow-providers-apache-beam", "apache-beam[gcp]"] -apache-cassandra = ["apache-airflow-providers-apache-cassandra"] -cncf-kubernetes = ["apache-airflow-providers-cncf-kubernetes (>=7.2.0)"] -common-sql = ["apache-airflow-providers-common-sql"] -facebook = ["apache-airflow-providers-facebook (>=2.2.0)"] -leveldb = ["plyvel"] -microsoft-azure = ["apache-airflow-providers-microsoft-azure"] -microsoft-mssql = ["apache-airflow-providers-microsoft-mssql"] -mysql = ["apache-airflow-providers-mysql"] -openlineage = ["apache-airflow-providers-openlineage"] -oracle = ["apache-airflow-providers-oracle (>=3.1.0)"] -postgres = ["apache-airflow-providers-postgres"] -presto = ["apache-airflow-providers-presto"] -salesforce = ["apache-airflow-providers-salesforce"] -sftp = ["apache-airflow-providers-sftp"] -ssh = ["apache-airflow-providers-ssh"] -trino = ["apache-airflow-providers-trino"] - -[[package]] -name = "apache-airflow-providers-http" -version = "4.11.1" -description = "Provider package apache-airflow-providers-http for Apache Airflow" -optional = false -python-versions = "~=3.8" -files = [ - {file = "apache_airflow_providers_http-4.11.1-py3-none-any.whl", hash = "sha256:f8aff8d009d8068654bed6c84c1bf13100ebbda4563c5fdea067047ba85a84bf"}, - {file = "apache_airflow_providers_http-4.11.1.tar.gz", hash = "sha256:401c4c976ca35388574afa85282fa35ed0514a77ef7ca442ea74132b3442a869"}, -] - -[package.dependencies] -aiohttp = ">=3.9.2" -apache-airflow = ">=2.7.0" -asgiref = "*" -requests = ">=2.27.0,<3" -requests_toolbelt = "*" - -[[package]] -name = "apache-airflow-providers-imap" -version = "3.6.1" -description = "Provider package apache-airflow-providers-imap for Apache Airflow" -optional = false -python-versions = "~=3.8" -files = [ - {file = "apache_airflow_providers_imap-3.6.1-py3-none-any.whl", hash = "sha256:1630dfad25a4db28da37ed4cb522674e37d0d981238fdb34ed2933c7f348763a"}, - {file = "apache_airflow_providers_imap-3.6.1.tar.gz", hash = "sha256:20e8052b43f32c3e711cbe0ffe3763cf550ffb06011ed4c57c3e806dd99dfa06"}, -] - -[package.dependencies] -apache-airflow = ">=2.7.0" - -[[package]] -name = "apache-airflow-providers-smtp" -version = "1.7.1" -description = "Provider package apache-airflow-providers-smtp for Apache Airflow" -optional = false -python-versions = "~=3.8" -files = [ - {file = "apache_airflow_providers_smtp-1.7.1-py3-none-any.whl", hash = "sha256:eab0910fa1351e58e1e87bb2489084ad5157e33a8752cce3164fd38f4b50c694"}, - {file = "apache_airflow_providers_smtp-1.7.1.tar.gz", hash = "sha256:707c4e2d75ce328693b55429f1f771e00cd2a2d6b52ce14edc20cb6d785be76e"}, -] - -[package.dependencies] -apache-airflow = ">=2.7.0" - -[[package]] -name = "apache-airflow-providers-sqlite" -version = "3.8.1" -description = "Provider package apache-airflow-providers-sqlite for Apache Airflow" -optional = false -python-versions = "~=3.8" -files = [ - {file = "apache_airflow_providers_sqlite-3.8.1-py3-none-any.whl", hash = "sha256:be9749275ac266245a2973269842674b10c3ad184790f9f0fd75e76e1d3b2440"}, - {file = "apache_airflow_providers_sqlite-3.8.1.tar.gz", hash = "sha256:b958c5aa725fcf6505c77dc3d600f3c6f9255be5405ea51fa966ae1d85842d3e"}, -] - -[package.dependencies] -apache-airflow = ">=2.7.0" -apache-airflow-providers-common-sql = ">=1.3.1" - -[package.extras] -common-sql = ["apache-airflow-providers-common-sql"] - -[[package]] -name = "apispec" -version = "6.6.1" -description = "A pluggable API specification generator. Currently supports the OpenAPI Specification (f.k.a. the Swagger specification)." -optional = false -python-versions = ">=3.8" -files = [ - {file = "apispec-6.6.1-py3-none-any.whl", hash = "sha256:6460315cb38ac6a2ff42d9e2b8dc0435c37d4428d3abeda96ff97b5dc8eb6b94"}, - {file = "apispec-6.6.1.tar.gz", hash = "sha256:f5caa47cee75fe03b9c50b5594048b4c052eeca2c212e0dac12dbb6175d9a659"}, -] - -[package.dependencies] -packaging = ">=21.3" -PyYAML = {version = ">=3.10", optional = true, markers = "extra == \"yaml\""} - -[package.extras] -dev = ["apispec[tests]", "pre-commit (>=3.5,<4.0)", "tox"] -docs = ["apispec[marshmallow]", "pyyaml (==6.0.1)", "sphinx (==7.3.7)", "sphinx-issues (==4.1.0)", "sphinx-rtd-theme (==2.0.0)"] -marshmallow = ["marshmallow (>=3.18.0)"] -tests = ["apispec[marshmallow,yaml]", "openapi-spec-validator (==0.7.1)", "pytest"] -yaml = ["PyYAML (>=3.10)"] - [[package]] name = "appnope" version = "0.1.4" @@ -673,37 +145,6 @@ files = [ {file = "appnope-0.1.4.tar.gz", hash = "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee"}, ] -[[package]] -name = "argcomplete" -version = "3.4.0" -description = "Bash tab completion for argparse" -optional = false -python-versions = ">=3.8" -files = [ - {file = "argcomplete-3.4.0-py3-none-any.whl", hash = "sha256:69a79e083a716173e5532e0fa3bef45f793f4e61096cf52b5a42c0211c8b8aa5"}, - {file = "argcomplete-3.4.0.tar.gz", hash = "sha256:c2abcdfe1be8ace47ba777d4fce319eb13bf8ad9dace8d085dcad6eded88057f"}, -] - -[package.extras] -test = ["coverage", "mypy", "pexpect", "ruff", "wheel"] - -[[package]] -name = "asgiref" -version = "3.8.1" -description = "ASGI specs, helper code, and adapters" -optional = false -python-versions = ">=3.8" -files = [ - {file = "asgiref-3.8.1-py3-none-any.whl", hash = "sha256:3e1e3ecc849832fe52ccf2cb6686b7a55f82bb1d6aee72a58826471390335e47"}, - {file = "asgiref-3.8.1.tar.gz", hash = "sha256:c343bd80a0bec947a9860adb4c432ffa7db769836c64238fc34bdc3fec84d590"}, -] - -[package.dependencies] -typing-extensions = {version = ">=4", markers = "python_version < \"3.11\""} - -[package.extras] -tests = ["mypy (>=0.800)", "pytest", "pytest-asyncio"] - [[package]] name = "asttokens" version = "2.4.1" @@ -878,17 +319,6 @@ files = [ [package.extras] dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"] -[[package]] -name = "backoff" -version = "2.2.1" -description = "Function decoration for backoff and retry" -optional = false -python-versions = ">=3.7,<4.0" -files = [ - {file = "backoff-2.2.1-py3-none-any.whl", hash = "sha256:63579f9a0628e06278f7e47b7d7d5b6ce20dc65c5e96a6f3ca99a6adca0396e8"}, - {file = "backoff-2.2.1.tar.gz", hash = "sha256:03f829f5bb1923180821643f8753b0502c3b682293992485b0eef2807afa5cba"}, -] - [[package]] name = "beautifulsoup4" version = "4.12.3" @@ -910,17 +340,6 @@ charset-normalizer = ["charset-normalizer"] html5lib = ["html5lib"] lxml = ["lxml"] -[[package]] -name = "blinker" -version = "1.8.2" -description = "Fast, simple object-to-object and broadcast signaling" -optional = false -python-versions = ">=3.8" -files = [ - {file = "blinker-1.8.2-py3-none-any.whl", hash = "sha256:1779309f71bf239144b9399d06ae925637cf6634cf6bd131104184531bf67c01"}, - {file = "blinker-1.8.2.tar.gz", hash = "sha256:8f77b09d3bf7c795e969e9486f39c2c5e9c39d4ee07424be2bc594ece9642d83"}, -] - [[package]] name = "bokeh" version = "3.4.1" @@ -992,17 +411,6 @@ files = [ {file = "bracex-2.4.tar.gz", hash = "sha256:a27eaf1df42cf561fed58b7a8f3fdf129d1ea16a81e1fadd1d17989bc6384beb"}, ] -[[package]] -name = "cachelib" -version = "0.9.0" -description = "A collection of cache libraries in the same API interface." -optional = false -python-versions = ">=3.7" -files = [ - {file = "cachelib-0.9.0-py3-none-any.whl", hash = "sha256:811ceeb1209d2fe51cd2b62810bd1eccf70feba5c52641532498be5c675493b3"}, - {file = "cachelib-0.9.0.tar.gz", hash = "sha256:38222cc7c1b79a23606de5c2607f4925779e37cdcea1c2ad21b8bae94b5425a5"}, -] - [[package]] name = "cachetools" version = "5.3.3" @@ -1014,31 +422,6 @@ files = [ {file = "cachetools-5.3.3.tar.gz", hash = "sha256:ba29e2dfa0b8b556606f097407ed1aa62080ee108ab0dc5ec9d6a723a007d105"}, ] -[[package]] -name = "cattrs" -version = "23.2.3" -description = "Composable complex class support for attrs and dataclasses." -optional = false -python-versions = ">=3.8" -files = [ - {file = "cattrs-23.2.3-py3-none-any.whl", hash = "sha256:0341994d94971052e9ee70662542699a3162ea1e0c62f7ce1b4a57f563685108"}, - {file = "cattrs-23.2.3.tar.gz", hash = "sha256:a934090d95abaa9e911dac357e3a8699e0b4b14f8529bcc7d2b1ad9d51672b9f"}, -] - -[package.dependencies] -attrs = ">=23.1.0" -exceptiongroup = {version = ">=1.1.1", markers = "python_version < \"3.11\""} -typing-extensions = {version = ">=4.1.0,<4.6.3 || >4.6.3", markers = "python_version < \"3.11\""} - -[package.extras] -bson = ["pymongo (>=4.4.0)"] -cbor2 = ["cbor2 (>=5.4.6)"] -msgpack = ["msgpack (>=1.0.5)"] -orjson = ["orjson (>=3.9.2)"] -pyyaml = ["pyyaml (>=6.0)"] -tomlkit = ["tomlkit (>=0.11.8)"] -ujson = ["ujson (>=5.7.0)"] - [[package]] name = "certifi" version = "2024.6.2" @@ -1125,17 +508,6 @@ files = [ {file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"}, ] -[[package]] -name = "chardet" -version = "5.2.0" -description = "Universal encoding detector for Python 3" -optional = false -python-versions = ">=3.7" -files = [ - {file = "chardet-5.2.0-py3-none-any.whl", hash = "sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970"}, - {file = "chardet-5.2.0.tar.gz", hash = "sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7"}, -] - [[package]] name = "charset-normalizer" version = "3.3.2" @@ -1249,21 +621,6 @@ files = [ [package.dependencies] colorama = {version = "*", markers = "platform_system == \"Windows\""} -[[package]] -name = "clickclick" -version = "20.10.2" -description = "Click utility functions" -optional = false -python-versions = "*" -files = [ - {file = "clickclick-20.10.2-py2.py3-none-any.whl", hash = "sha256:c8f33e6d9ec83f68416dd2136a7950125bd256ec39ccc9a85c6e280a16be2bb5"}, - {file = "clickclick-20.10.2.tar.gz", hash = "sha256:4efb13e62353e34c5eef7ed6582c4920b418d7dedc86d819e22ee089ba01802c"}, -] - -[package.dependencies] -click = ">=4.0" -PyYAML = ">=3.11" - [[package]] name = "colorama" version = "0.4.6" @@ -1275,20 +632,6 @@ files = [ {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] -[[package]] -name = "colorlog" -version = "4.8.0" -description = "Log formatting with colors!" -optional = false -python-versions = "*" -files = [ - {file = "colorlog-4.8.0-py2.py3-none-any.whl", hash = "sha256:3dd15cb27e8119a24c1a7b5c93f9f3b455855e0f73993b1c25921b2f646f1dcd"}, - {file = "colorlog-4.8.0.tar.gz", hash = "sha256:59b53160c60902c405cdec28d38356e09d40686659048893e026ecbd589516b1"}, -] - -[package.dependencies] -colorama = {version = "*", markers = "sys_platform == \"win32\""} - [[package]] name = "comm" version = "0.2.2" @@ -1320,49 +663,6 @@ files = [ [package.extras] test = ["flake8 (==3.7.8)", "hypothesis (==3.55.3)"] -[[package]] -name = "configupdater" -version = "3.2" -description = "Parser like ConfigParser but for updating configuration files" -optional = false -python-versions = ">=3.6" -files = [ - {file = "ConfigUpdater-3.2-py2.py3-none-any.whl", hash = "sha256:0f65a041627d7693840b4dd743581db4c441c97195298a29d075f91b79539df2"}, - {file = "ConfigUpdater-3.2.tar.gz", hash = "sha256:9fdac53831c1b062929bf398b649b87ca30e7f1a735f3fbf482072804106306b"}, -] - -[package.extras] -testing = ["flake8", "pytest", "pytest-cov", "pytest-randomly", "pytest-xdist", "sphinx"] - -[[package]] -name = "connexion" -version = "2.14.1" -description = "Connexion - API first applications with OpenAPI/Swagger and Flask" -optional = false -python-versions = ">=3.6" -files = [ - {file = "connexion-2.14.1-py2.py3-none-any.whl", hash = "sha256:f343717241b4c4802a694c38fee66fb1693c897fe4ea5a957fa9b3b07caf6394"}, - {file = "connexion-2.14.1.tar.gz", hash = "sha256:99aa5781e70a7b94f8ffae8cf89f309d49cdb811bbd65a8e2f2546f3b19a01e6"}, -] - -[package.dependencies] -clickclick = ">=1.2,<21" -flask = ">=1.0.4,<3" -inflection = ">=0.3.1,<0.6" -itsdangerous = ">=0.24" -jsonschema = ">=2.5.1,<5" -packaging = ">=20" -PyYAML = ">=5.1,<7" -requests = ">=2.9.1,<3" -werkzeug = ">=1.0,<3" - -[package.extras] -aiohttp = ["MarkupSafe (>=0.23)", "aiohttp (>=2.3.10,<4)", "aiohttp-jinja2 (>=0.14.0,<2)"] -docs = ["sphinx-autoapi (==1.8.1)"] -flask = ["flask (>=1.0.4,<3)", "itsdangerous (>=0.24)"] -swagger-ui = ["swagger-ui-bundle (>=0.0.2,<0.1)"] -tests = ["MarkupSafe (>=0.23)", "aiohttp (>=2.3.10,<4)", "aiohttp-jinja2 (>=0.14.0,<2)", "aiohttp-remotes", "decorator (>=5,<6)", "flask (>=1.0.4,<3)", "itsdangerous (>=0.24)", "pytest (>=6,<7)", "pytest-aiohttp", "pytest-cov (>=2,<3)", "swagger-ui-bundle (>=0.0.2,<0.1)", "testfixtures (>=6,<7)"] - [[package]] name = "contourpy" version = "1.2.1" @@ -1493,35 +793,6 @@ tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.1 [package.extras] toml = ["tomli"] -[[package]] -name = "cron-descriptor" -version = "1.4.3" -description = "A Python library that converts cron expressions into human readable strings." -optional = false -python-versions = "*" -files = [ - {file = "cron_descriptor-1.4.3-py3-none-any.whl", hash = "sha256:a67ba21804983b1427ed7f3e1ec27ee77bf24c652b0430239c268c5ddfbf9dc0"}, - {file = "cron_descriptor-1.4.3.tar.gz", hash = "sha256:7b1a00d7d25d6ae6896c0da4457e790b98cba778398a3d48e341e5e0d33f0488"}, -] - -[package.extras] -dev = ["polib"] - -[[package]] -name = "croniter" -version = "2.0.5" -description = "croniter provides iteration for datetime object with cron like format" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.6" -files = [ - {file = "croniter-2.0.5-py2.py3-none-any.whl", hash = "sha256:fdbb44920944045cc323db54599b321325141d82d14fa7453bc0699826bbe9ed"}, - {file = "croniter-2.0.5.tar.gz", hash = "sha256:f1f8ca0af64212fbe99b1bee125ee5a1b53a9c1b433968d8bca8817b79d237f3"}, -] - -[package.dependencies] -python-dateutil = "*" -pytz = ">2021.1" - [[package]] name = "cryptography" version = "41.0.7" @@ -1717,26 +988,6 @@ files = [ {file = "distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64"}, ] -[[package]] -name = "dnspython" -version = "2.6.1" -description = "DNS toolkit" -optional = false -python-versions = ">=3.8" -files = [ - {file = "dnspython-2.6.1-py3-none-any.whl", hash = "sha256:5ef3b9680161f6fa89daf8ad451b5f1a33b18ae8a1c6778cdf4b43f08c0a6e50"}, - {file = "dnspython-2.6.1.tar.gz", hash = "sha256:e8f0f9c23a7b7cb99ded64e6c3a6f3e701d78f50c55e002b839dea7225cff7cc"}, -] - -[package.extras] -dev = ["black (>=23.1.0)", "coverage (>=7.0)", "flake8 (>=7)", "mypy (>=1.8)", "pylint (>=3)", "pytest (>=7.4)", "pytest-cov (>=4.1.0)", "sphinx (>=7.2.0)", "twine (>=4.0.0)", "wheel (>=0.42.0)"] -dnssec = ["cryptography (>=41)"] -doh = ["h2 (>=4.1.0)", "httpcore (>=1.0.0)", "httpx (>=0.26.0)"] -doq = ["aioquic (>=0.9.25)"] -idna = ["idna (>=3.6)"] -trio = ["trio (>=0.23)"] -wmi = ["wmi (>=1.5.1)"] - [[package]] name = "docker-pycreds" version = "0.4.0" @@ -1751,17 +1002,6 @@ files = [ [package.dependencies] six = ">=1.4.0" -[[package]] -name = "docstring-parser" -version = "0.16" -description = "Parse Python docstrings in reST, Google and Numpydoc format" -optional = false -python-versions = ">=3.6,<4.0" -files = [ - {file = "docstring_parser-0.16-py3-none-any.whl", hash = "sha256:bf0a1387354d3691d102edef7ec124f219ef639982d096e26e3b60aeffa90637"}, - {file = "docstring_parser-0.16.tar.gz", hash = "sha256:538beabd0af1e2db0146b6bd3caa526c35a34d61af9fd2887f3a8a27a739aa6e"}, -] - [[package]] name = "docstring-parser-fork" version = "0.0.8" @@ -1774,49 +1014,23 @@ files = [ ] [[package]] -name = "docutils" -version = "0.21.2" -description = "Docutils -- Python Documentation Utilities" +name = "exceptiongroup" +version = "1.2.1" +description = "Backport of PEP 654 (exception groups)" optional = false -python-versions = ">=3.9" +python-versions = ">=3.7" files = [ - {file = "docutils-0.21.2-py3-none-any.whl", hash = "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2"}, - {file = "docutils-0.21.2.tar.gz", hash = "sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f"}, + {file = "exceptiongroup-1.2.1-py3-none-any.whl", hash = "sha256:5258b9ed329c5bbdd31a309f53cbfb0b155341807f6ff7606a1e801a891b29ad"}, + {file = "exceptiongroup-1.2.1.tar.gz", hash = "sha256:a4785e48b045528f5bfe627b6ad554ff32def154f42372786903b7abcfe1aa16"}, ] +[package.extras] +test = ["pytest (>=6)"] + [[package]] -name = "email-validator" -version = "2.2.0" -description = "A robust email address syntax and deliverability validation library." -optional = false -python-versions = ">=3.8" -files = [ - {file = "email_validator-2.2.0-py3-none-any.whl", hash = "sha256:561977c2d73ce3611850a06fa56b414621e0c8faa9d66f2611407d87465da631"}, - {file = "email_validator-2.2.0.tar.gz", hash = "sha256:cb690f344c617a714f22e66ae771445a1ceb46821152df8e165c5f9a364582b7"}, -] - -[package.dependencies] -dnspython = ">=2.0.0" -idna = ">=2.0.0" - -[[package]] -name = "exceptiongroup" -version = "1.2.1" -description = "Backport of PEP 654 (exception groups)" -optional = false -python-versions = ">=3.7" -files = [ - {file = "exceptiongroup-1.2.1-py3-none-any.whl", hash = "sha256:5258b9ed329c5bbdd31a309f53cbfb0b155341807f6ff7606a1e801a891b29ad"}, - {file = "exceptiongroup-1.2.1.tar.gz", hash = "sha256:a4785e48b045528f5bfe627b6ad554ff32def154f42372786903b7abcfe1aa16"}, -] - -[package.extras] -test = ["pytest (>=6)"] - -[[package]] -name = "execnet" -version = "2.1.1" -description = "execnet: rapid multi-Python deployment" +name = "execnet" +version = "2.1.1" +description = "execnet: rapid multi-Python deployment" optional = false python-versions = ">=3.8" files = [ @@ -1873,208 +1087,6 @@ mccabe = ">=0.7.0,<0.8.0" pycodestyle = ">=2.12.0,<2.13.0" pyflakes = ">=3.2.0,<3.3.0" -[[package]] -name = "flask" -version = "2.2.5" -description = "A simple framework for building complex web applications." -optional = false -python-versions = ">=3.7" -files = [ - {file = "Flask-2.2.5-py3-none-any.whl", hash = "sha256:58107ed83443e86067e41eff4631b058178191a355886f8e479e347fa1285fdf"}, - {file = "Flask-2.2.5.tar.gz", hash = "sha256:edee9b0a7ff26621bd5a8c10ff484ae28737a2410d99b0bb9a6850c7fb977aa0"}, -] - -[package.dependencies] -click = ">=8.0" -itsdangerous = ">=2.0" -Jinja2 = ">=3.0" -Werkzeug = ">=2.2.2" - -[package.extras] -async = ["asgiref (>=3.2)"] -dotenv = ["python-dotenv"] - -[[package]] -name = "flask-appbuilder" -version = "4.4.1" -description = "Simple and rapid application development framework, built on top of Flask. includes detailed security, auto CRUD generation for your models, google charts and much more." -optional = false -python-versions = "~=3.7" -files = [ - {file = "Flask-AppBuilder-4.4.1.tar.gz", hash = "sha256:a64d4c3b5197547744c7c41f7eb0fe0206ba1677369ce47903dd08c3c9b753bd"}, - {file = "Flask_AppBuilder-4.4.1-py3-none-any.whl", hash = "sha256:6ebdb384a23c0e111736ac36f6de04f02d40ac2976feedbdd473d8ba0201dd92"}, -] - -[package.dependencies] -apispec = {version = ">=6.0.0,<7", extras = ["yaml"]} -click = ">=8,<9" -colorama = ">=0.3.9,<1" -email-validator = ">=1.0.5" -Flask = ">=2,<3.0.0" -Flask-Babel = ">=1,<3" -Flask-JWT-Extended = ">=4.0.0,<5.0.0" -Flask-Limiter = ">3,<4" -Flask-Login = ">=0.3,<0.7" -Flask-SQLAlchemy = ">=2.4,<3" -Flask-WTF = ">=0.14.2,<2" -jsonschema = ">=3,<5" -marshmallow = ">=3.18.0,<4" -marshmallow-sqlalchemy = ">=0.22.0,<0.29.0" -prison = ">=0.2.1,<1.0.0" -PyJWT = ">=2.0.0,<3.0.0" -python-dateutil = ">=2.3,<3" -SQLAlchemy = "<1.5" -sqlalchemy-utils = ">=0.32.21,<1" -werkzeug = "<4" -WTForms = "<4" - -[package.extras] -jmespath = ["jmespath (>=0.9.5)"] -oauth = ["Authlib (>=0.14,<2.0.0)"] -openid = ["Flask-OpenID (>=1.2.5,<2)"] -talisman = ["flask-talisman (>=1.0.0,<2.0)"] - -[[package]] -name = "flask-babel" -version = "2.0.0" -description = "Adds i18n/l10n support to Flask applications" -optional = false -python-versions = "*" -files = [ - {file = "Flask-Babel-2.0.0.tar.gz", hash = "sha256:f9faf45cdb2e1a32ea2ec14403587d4295108f35017a7821a2b1acb8cfd9257d"}, - {file = "Flask_Babel-2.0.0-py3-none-any.whl", hash = "sha256:e6820a052a8d344e178cdd36dd4bb8aea09b4bda3d5f9fa9f008df2c7f2f5468"}, -] - -[package.dependencies] -Babel = ">=2.3" -Flask = "*" -Jinja2 = ">=2.5" -pytz = "*" - -[package.extras] -dev = ["Pallets-Sphinx-Themes", "bumpversion", "ghp-import", "pytest", "pytest-mock", "sphinx"] - -[[package]] -name = "flask-caching" -version = "2.3.0" -description = "Adds caching support to Flask applications." -optional = false -python-versions = ">=3.8" -files = [ - {file = "Flask_Caching-2.3.0-py3-none-any.whl", hash = "sha256:51771c75682e5abc1483b78b96d9131d7941dc669b073852edfa319dd4e29b6e"}, - {file = "flask_caching-2.3.0.tar.gz", hash = "sha256:d7e4ca64a33b49feb339fcdd17e6ba25f5e01168cf885e53790e885f83a4d2cf"}, -] - -[package.dependencies] -cachelib = ">=0.9.0,<0.10.0" -Flask = "*" - -[[package]] -name = "flask-jwt-extended" -version = "4.6.0" -description = "Extended JWT integration with Flask" -optional = false -python-versions = ">=3.7,<4" -files = [ - {file = "Flask-JWT-Extended-4.6.0.tar.gz", hash = "sha256:9215d05a9413d3855764bcd67035e75819d23af2fafb6b55197eb5a3313fdfb2"}, - {file = "Flask_JWT_Extended-4.6.0-py2.py3-none-any.whl", hash = "sha256:63a28fc9731bcc6c4b8815b6f954b5904caa534fc2ae9b93b1d3ef12930dca95"}, -] - -[package.dependencies] -Flask = ">=2.0,<4.0" -PyJWT = ">=2.0,<3.0" -Werkzeug = ">=0.14" - -[package.extras] -asymmetric-crypto = ["cryptography (>=3.3.1)"] - -[[package]] -name = "flask-limiter" -version = "3.7.0" -description = "Rate limiting for flask applications" -optional = false -python-versions = ">=3.8" -files = [ - {file = "Flask_Limiter-3.7.0-py3-none-any.whl", hash = "sha256:4318382f17ecb09848bc6d0f7bc4bb1bf89bcf162200bf47b7b969126693bfda"}, - {file = "flask_limiter-3.7.0.tar.gz", hash = "sha256:e474462505f6dd0d776db16c46092e9a065ebcb30b10aed0caf54c6b9a4a471a"}, -] - -[package.dependencies] -Flask = ">=2" -limits = ">=2.8" -ordered-set = ">4,<5" -rich = ">=12,<14" -typing-extensions = ">=4" - -[package.extras] -memcached = ["limits[memcached]"] -mongodb = ["limits[mongodb]"] -redis = ["limits[redis]"] - -[[package]] -name = "flask-login" -version = "0.6.3" -description = "User authentication and session management for Flask." -optional = false -python-versions = ">=3.7" -files = [ - {file = "Flask-Login-0.6.3.tar.gz", hash = "sha256:5e23d14a607ef12806c699590b89d0f0e0d67baeec599d75947bf9c147330333"}, - {file = "Flask_Login-0.6.3-py3-none-any.whl", hash = "sha256:849b25b82a436bf830a054e74214074af59097171562ab10bfa999e6b78aae5d"}, -] - -[package.dependencies] -Flask = ">=1.0.4" -Werkzeug = ">=1.0.1" - -[[package]] -name = "flask-session" -version = "0.5.0" -description = "Server-side session support for Flask" -optional = false -python-versions = ">=3.7" -files = [ - {file = "Flask-Session-0.5.0.tar.gz", hash = "sha256:190875e6aebf2953c6803d42379ef3b934bc209ef8ef006f97aecb08f5aaeb86"}, - {file = "flask_session-0.5.0-py3-none-any.whl", hash = "sha256:1619bcbc16f04f64e90f8e0b17145ba5c9700090bb1294e889956c1282d58631"}, -] - -[package.dependencies] -cachelib = "*" -flask = ">=2.2" - -[[package]] -name = "flask-sqlalchemy" -version = "2.5.1" -description = "Adds SQLAlchemy support to your Flask application." -optional = false -python-versions = ">= 2.7, != 3.0.*, != 3.1.*, != 3.2.*, != 3.3.*" -files = [ - {file = "Flask-SQLAlchemy-2.5.1.tar.gz", hash = "sha256:2bda44b43e7cacb15d4e05ff3cc1f8bc97936cc464623424102bfc2c35e95912"}, - {file = "Flask_SQLAlchemy-2.5.1-py2.py3-none-any.whl", hash = "sha256:f12c3d4cc5cc7fdcc148b9527ea05671718c3ea45d50c7e732cceb33f574b390"}, -] - -[package.dependencies] -Flask = ">=0.10" -SQLAlchemy = ">=0.8.0" - -[[package]] -name = "flask-wtf" -version = "1.2.1" -description = "Form rendering, validation, and CSRF protection for Flask with WTForms." -optional = false -python-versions = ">=3.8" -files = [ - {file = "flask_wtf-1.2.1-py3-none-any.whl", hash = "sha256:fa6793f2fb7e812e0fe9743b282118e581fb1b6c45d414b8af05e659bd653287"}, - {file = "flask_wtf-1.2.1.tar.gz", hash = "sha256:8bb269eb9bb46b87e7c8233d7e7debdf1f8b74bf90cc1789988c29b37a97b695"}, -] - -[package.dependencies] -flask = "*" -itsdangerous = "*" -wtforms = "*" - -[package.extras] -email = ["email-validator"] - [[package]] name = "frozenlist" version = "1.4.1" @@ -2200,56 +1212,6 @@ test-downstream = ["aiobotocore (>=2.5.4,<3.0.0)", "dask-expr", "dask[dataframe, test-full = ["adlfs", "aiohttp (!=4.0.0a0,!=4.0.0a1)", "cloudpickle", "dask", "distributed", "dropbox", "dropboxdrivefs", "fastparquet", "fusepy", "gcsfs", "jinja2", "kerchunk", "libarchive-c", "lz4", "notebook", "numpy", "ocifs", "pandas", "panel", "paramiko", "pyarrow", "pyarrow (>=1)", "pyftpdlib", "pygit2", "pytest", "pytest-asyncio (!=0.22.0)", "pytest-benchmark", "pytest-cov", "pytest-mock", "pytest-recording", "pytest-rerunfailures", "python-snappy", "requests", "smbprotocol", "tqdm", "urllib3", "zarr", "zstandard"] tqdm = ["tqdm"] -[[package]] -name = "gcloud-aio-auth" -version = "4.2.3" -description = "Python Client for Google Cloud Auth" -optional = false -python-versions = ">=3.7,<4.0" -files = [ - {file = "gcloud_aio_auth-4.2.3-py3-none-any.whl", hash = "sha256:e4adadd36e35eeeb8537b926840372c3080c2f5a6909d44aa1bacbced2260bb1"}, - {file = "gcloud_aio_auth-4.2.3.tar.gz", hash = "sha256:8e12297c5b45cfc20d629b83e1233f83a1c7d5f830f24f31bc5bb8816c0cda1b"}, -] - -[package.dependencies] -aiohttp = ">=3.3.0,<4.0.0" -backoff = ">=1.0.0,<3.0.0" -chardet = ">=2.0,<6.0" -cryptography = ">=2.0.0,<42.0.0" -pyjwt = ">=1.5.3,<3.0.0" -setuptools = ">=66.0.0,<67.0.0" - -[[package]] -name = "gcloud-aio-bigquery" -version = "7.1.0" -description = "Python Client for Google Cloud BigQuery" -optional = false -python-versions = ">=3.8,<4.0" -files = [ - {file = "gcloud_aio_bigquery-7.1.0-py3-none-any.whl", hash = "sha256:524ae3cc14c1af6977a358829cc673b4471159caa7d62bba7f2d9334262bcd4a"}, - {file = "gcloud_aio_bigquery-7.1.0.tar.gz", hash = "sha256:4a3c775c2677c0588e9caeb2df40d81a54b31c174e562a527cb08e023c4408a3"}, -] - -[package.dependencies] -gcloud-aio-auth = ">=3.1.0,<6.0.0" - -[[package]] -name = "gcloud-aio-storage" -version = "9.2.0" -description = "Python Client for Google Cloud Storage" -optional = false -python-versions = ">=3.8,<4.0" -files = [ - {file = "gcloud_aio_storage-9.2.0-py3-none-any.whl", hash = "sha256:0a8cc27223cea05ad27117fa574ce8697ec32a252382cbfdfe54df0678e92d03"}, - {file = "gcloud_aio_storage-9.2.0.tar.gz", hash = "sha256:47be865222d22fdf873cd5a4af9a285d7b64b176d4d92f1773ecacd52a6a8c6f"}, -] - -[package.dependencies] -aiofiles = ">=0.6.0,<24.0.0" -gcloud-aio-auth = ">=3.6.0,<6.0.0" -pyasn1-modules = ">=0.2.1,<0.4.0" -rsa = ">=3.1.4,<5.0.0" - [[package]] name = "gcsfs" version = "2024.6.0" @@ -2324,944 +1286,191 @@ doc = ["sphinx (==4.3.2)", "sphinx-autodoc-typehints", "sphinx-rtd-theme", "sphi test = ["coverage[toml]", "ddt (>=1.1.1,!=1.4.3)", "mock", "mypy", "pre-commit", "pytest (>=7.3.1)", "pytest-cov", "pytest-instafail", "pytest-mock", "pytest-sugar", "typing-extensions"] [[package]] -name = "google" -version = "3.0.0" -description = "Python bindings to the Google search engine." -optional = false -python-versions = "*" -files = [ - {file = "google-3.0.0-py2.py3-none-any.whl", hash = "sha256:889cf695f84e4ae2c55fbc0cfdaf4c1e729417fa52ab1db0485202ba173e4935"}, - {file = "google-3.0.0.tar.gz", hash = "sha256:143530122ee5130509ad5e989f0512f7cb218b2d4eddbafbad40fd10e8d8ccbe"}, -] - -[package.dependencies] -beautifulsoup4 = "*" - -[[package]] -name = "google-ads" -version = "22.1.0" -description = "Client library for the Google Ads API" -optional = false -python-versions = ">=3.7, <3.12" -files = [ - {file = "google-ads-22.1.0.tar.gz", hash = "sha256:cfab38b40eb8424a4a514823bd8b911a57ef55dd64e2112cfa46a70d8090de98"}, - {file = "google_ads-22.1.0-py3-none-any.whl", hash = "sha256:6fdd3fb635678fbb3c8f87271afc81f0e139882b83b48505160fc4daacf33ad0"}, -] - -[package.dependencies] -google-api-core = ">=2.8.0,<=3.0.0" -google-auth-oauthlib = ">=0.3.0,<2.0.0" -googleapis-common-protos = ">=1.56.0,<2.0.0" -grpcio = ">=1.38.1,<2.0.0" -grpcio-status = ">=1.38.1,<2.0.0" -proto-plus = ">=1.19.6,<2.0.0" -protobuf = ">=3.12.0,<3.18.dev0 || >=3.20.dev0,<5.0.0" -PyYAML = ">=5.1,<7.0" -setuptools = ">=40.3.0" - -[package.extras] -tests = ["nox (>=2020.12.31,<2022.6)"] - -[[package]] -name = "google-analytics-admin" -version = "0.22.7" -description = "Google Analytics Admin API client library" -optional = false -python-versions = ">=3.7" -files = [ - {file = "google-analytics-admin-0.22.7.tar.gz", hash = "sha256:9546afaddf7ee275ec4729de6da8b15f27d4d245ee8896f80800e22572fc7987"}, - {file = "google_analytics_admin-0.22.7-py2.py3-none-any.whl", hash = "sha256:09463653ecb42306c34fb07c9ff27193737aae8e63c52b8f695bf705e8589b46"}, -] - -[package.dependencies] -google-api-core = {version = ">=1.34.1,<2.0.dev0 || >=2.11.dev0,<3.0.0dev", extras = ["grpc"]} -google-auth = ">=2.14.1,<2.24.0 || >2.24.0,<2.25.0 || >2.25.0,<3.0.0dev" -proto-plus = ">=1.22.3,<2.0.0dev" -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" - -[[package]] -name = "google-api-core" -version = "2.19.0" -description = "Google API client core library" -optional = false -python-versions = ">=3.7" -files = [ - {file = "google-api-core-2.19.0.tar.gz", hash = "sha256:cf1b7c2694047886d2af1128a03ae99e391108a08804f87cfd35970e49c9cd10"}, - {file = "google_api_core-2.19.0-py3-none-any.whl", hash = "sha256:8661eec4078c35428fd3f69a2c7ee29e342896b70f01d1a1cbcb334372dd6251"}, -] - -[package.dependencies] -google-auth = ">=2.14.1,<3.0.dev0" -googleapis-common-protos = ">=1.56.2,<2.0.dev0" -grpcio = {version = ">=1.33.2,<2.0dev", optional = true, markers = "extra == \"grpc\""} -grpcio-status = {version = ">=1.33.2,<2.0.dev0", optional = true, markers = "extra == \"grpc\""} -proto-plus = ">=1.22.3,<2.0.0dev" -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0.dev0" -requests = ">=2.18.0,<3.0.0.dev0" - -[package.extras] -grpc = ["grpcio (>=1.33.2,<2.0dev)", "grpcio (>=1.49.1,<2.0dev)", "grpcio-status (>=1.33.2,<2.0.dev0)", "grpcio-status (>=1.49.1,<2.0.dev0)"] -grpcgcp = ["grpcio-gcp (>=0.2.2,<1.0.dev0)"] -grpcio-gcp = ["grpcio-gcp (>=0.2.2,<1.0.dev0)"] - -[[package]] -name = "google-api-python-client" -version = "2.134.0" -description = "Google API Client Library for Python" -optional = false -python-versions = ">=3.7" -files = [ - {file = "google-api-python-client-2.134.0.tar.gz", hash = "sha256:4a8f0bea651a212997cc83c0f271fc86f80ef93d1cee9d84de7dfaeef2a858b6"}, - {file = "google_api_python_client-2.134.0-py2.py3-none-any.whl", hash = "sha256:ba05d60f6239990b7994f6328f17bb154c602d31860fb553016dc9f8ce886945"}, -] - -[package.dependencies] -google-api-core = ">=1.31.5,<2.0.dev0 || >2.3.0,<3.0.0.dev0" -google-auth = ">=1.32.0,<2.24.0 || >2.24.0,<2.25.0 || >2.25.0,<3.0.0.dev0" -google-auth-httplib2 = ">=0.2.0,<1.0.0" -httplib2 = ">=0.19.0,<1.dev0" -uritemplate = ">=3.0.1,<5" - -[[package]] -name = "google-auth" -version = "2.30.0" -description = "Google Authentication Library" -optional = false -python-versions = ">=3.7" -files = [ - {file = "google-auth-2.30.0.tar.gz", hash = "sha256:ab630a1320f6720909ad76a7dbdb6841cdf5c66b328d690027e4867bdfb16688"}, - {file = "google_auth-2.30.0-py2.py3-none-any.whl", hash = "sha256:8df7da660f62757388b8a7f249df13549b3373f24388cb5d2f1dd91cc18180b5"}, -] - -[package.dependencies] -cachetools = ">=2.0.0,<6.0" -pyasn1-modules = ">=0.2.1" -rsa = ">=3.1.4,<5" - -[package.extras] -aiohttp = ["aiohttp (>=3.6.2,<4.0.0.dev0)", "requests (>=2.20.0,<3.0.0.dev0)"] -enterprise-cert = ["cryptography (==36.0.2)", "pyopenssl (==22.0.0)"] -pyopenssl = ["cryptography (>=38.0.3)", "pyopenssl (>=20.0.0)"] -reauth = ["pyu2f (>=0.1.5)"] -requests = ["requests (>=2.20.0,<3.0.0.dev0)"] - -[[package]] -name = "google-auth-httplib2" -version = "0.2.0" -description = "Google Authentication Library: httplib2 transport" -optional = false -python-versions = "*" -files = [ - {file = "google-auth-httplib2-0.2.0.tar.gz", hash = "sha256:38aa7badf48f974f1eb9861794e9c0cb2a0511a4ec0679b1f886d108f5640e05"}, - {file = "google_auth_httplib2-0.2.0-py2.py3-none-any.whl", hash = "sha256:b65a0a2123300dd71281a7bf6e64d65a0759287df52729bdd1ae2e47dc311a3d"}, -] - -[package.dependencies] -google-auth = "*" -httplib2 = ">=0.19.0" - -[[package]] -name = "google-auth-oauthlib" -version = "0.8.0" -description = "Google Authentication Library" -optional = false -python-versions = ">=3.6" -files = [ - {file = "google-auth-oauthlib-0.8.0.tar.gz", hash = "sha256:81056a310fb1c4a3e5a7e1a443e1eb96593c6bbc55b26c0261e4d3295d3e6593"}, - {file = "google_auth_oauthlib-0.8.0-py2.py3-none-any.whl", hash = "sha256:40cc612a13c3336d5433e94e2adb42a0c88f6feb6c55769e44500fc70043a576"}, -] - -[package.dependencies] -google-auth = ">=2.15.0" -requests-oauthlib = ">=0.7.0" - -[package.extras] -tool = ["click (>=6.0.0)"] - -[[package]] -name = "google-cloud-aiplatform" -version = "1.56.0" -description = "Vertex AI API client library" -optional = false -python-versions = ">=3.8" -files = [ - {file = "google-cloud-aiplatform-1.56.0.tar.gz", hash = "sha256:d4cfb085427dac01142915f523949ac2955d6c7f148d95017d3286a77caf5d5e"}, - {file = "google_cloud_aiplatform-1.56.0-py2.py3-none-any.whl", hash = "sha256:ee1ab3bd115c3caebf8ddfd3e47eeb8396a3ec2fc5f5baf1a5c295c8d64333ab"}, -] - -[package.dependencies] -docstring-parser = "<1" -google-api-core = {version = ">=1.34.1,<2.0.dev0 || >=2.8.dev0,<3.0.0dev", extras = ["grpc"]} -google-auth = ">=2.14.1,<3.0.0dev" -google-cloud-bigquery = ">=1.15.0,<3.20.0 || >3.20.0,<4.0.0dev" -google-cloud-resource-manager = ">=1.3.3,<3.0.0dev" -google-cloud-storage = ">=1.32.0,<3.0.0dev" -packaging = ">=14.3" -proto-plus = ">=1.22.0,<2.0.0dev" -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" -pydantic = "<3" -shapely = "<3.0.0dev" - -[package.extras] -autologging = ["mlflow (>=1.27.0,<=2.1.1)"] -cloud-profiler = ["tensorboard-plugin-profile (>=2.4.0,<3.0.0dev)", "tensorflow (>=2.4.0,<3.0.0dev)", "werkzeug (>=2.0.0,<2.1.0dev)"] -datasets = ["pyarrow (>=10.0.1)", "pyarrow (>=14.0.0)", "pyarrow (>=3.0.0,<8.0dev)"] -endpoint = ["requests (>=2.28.1)"] -full = ["cloudpickle (<3.0)", "docker (>=5.0.3)", "explainable-ai-sdk (>=1.0.0)", "fastapi (>=0.71.0,<=0.109.1)", "google-cloud-bigquery", "google-cloud-bigquery-storage", "google-cloud-logging (<4.0)", "google-vizier (>=0.1.6)", "httpx (>=0.23.0,<0.25.0)", "immutabledict", "lit-nlp (==0.4.0)", "mlflow (>=1.27.0,<=2.1.1)", "nest-asyncio (>=1.0.0,<1.6.0)", "numpy (>=1.15.0)", "pandas (>=1.0.0)", "pandas (>=1.0.0,<2.2.0)", "pyarrow (>=10.0.1)", "pyarrow (>=14.0.0)", "pyarrow (>=3.0.0,<8.0dev)", "pyarrow (>=6.0.1)", "pydantic (<2)", "pyyaml (>=5.3.1,<7)", "ray[default] (>=2.4,<2.5.dev0 || >2.9.0,!=2.9.1,!=2.9.2,<=2.9.3)", "ray[default] (>=2.5,<=2.9.3)", "requests (>=2.28.1)", "setuptools (<70.0.0)", "starlette (>=0.17.1)", "tensorboard-plugin-profile (>=2.4.0,<3.0.0dev)", "tensorflow (>=2.3.0,<3.0.0dev)", "tensorflow (>=2.3.0,<3.0.0dev)", "tensorflow (>=2.4.0,<3.0.0dev)", "urllib3 (>=1.21.1,<1.27)", "uvicorn[standard] (>=0.16.0)", "werkzeug (>=2.0.0,<2.1.0dev)"] -langchain = ["langchain (>=0.1.16,<0.3)", "langchain-core (<0.2)", "langchain-google-vertexai (<2)", "openinference-instrumentation-langchain (>=0.1.19,<0.2)", "tenacity (<=8.3)"] -langchain-testing = ["absl-py", "cloudpickle (>=3.0,<4.0)", "langchain (>=0.1.16,<0.3)", "langchain-core (<0.2)", "langchain-google-vertexai (<2)", "openinference-instrumentation-langchain (>=0.1.19,<0.2)", "opentelemetry-exporter-gcp-trace (<2)", "opentelemetry-sdk (<2)", "pydantic (>=2.6.3,<3)", "pytest-xdist", "tenacity (<=8.3)"] -lit = ["explainable-ai-sdk (>=1.0.0)", "lit-nlp (==0.4.0)", "pandas (>=1.0.0)", "tensorflow (>=2.3.0,<3.0.0dev)"] -metadata = ["numpy (>=1.15.0)", "pandas (>=1.0.0)"] -pipelines = ["pyyaml (>=5.3.1,<7)"] -prediction = ["docker (>=5.0.3)", "fastapi (>=0.71.0,<=0.109.1)", "httpx (>=0.23.0,<0.25.0)", "starlette (>=0.17.1)", "uvicorn[standard] (>=0.16.0)"] -preview = ["cloudpickle (<3.0)", "google-cloud-logging (<4.0)"] -private-endpoints = ["requests (>=2.28.1)", "urllib3 (>=1.21.1,<1.27)"] -rapid-evaluation = ["nest-asyncio (>=1.0.0,<1.6.0)", "pandas (>=1.0.0,<2.2.0)"] -ray = ["google-cloud-bigquery", "google-cloud-bigquery-storage", "immutabledict", "pandas (>=1.0.0,<2.2.0)", "pyarrow (>=6.0.1)", "pydantic (<2)", "ray[default] (>=2.4,<2.5.dev0 || >2.9.0,!=2.9.1,!=2.9.2,<=2.9.3)", "ray[default] (>=2.5,<=2.9.3)", "setuptools (<70.0.0)"] -ray-testing = ["google-cloud-bigquery", "google-cloud-bigquery-storage", "immutabledict", "pandas (>=1.0.0,<2.2.0)", "pyarrow (>=6.0.1)", "pydantic (<2)", "pytest-xdist", "ray[default] (>=2.4,<2.5.dev0 || >2.9.0,!=2.9.1,!=2.9.2,<=2.9.3)", "ray[default] (>=2.5,<=2.9.3)", "ray[train] (==2.9.3)", "scikit-learn", "setuptools (<70.0.0)", "tensorflow", "torch (>=2.0.0,<2.1.0)", "xgboost", "xgboost-ray"] -reasoningengine = ["cloudpickle (>=3.0,<4.0)", "opentelemetry-exporter-gcp-trace (<2)", "opentelemetry-sdk (<2)", "pydantic (>=2.6.3,<3)"] -tensorboard = ["tensorboard-plugin-profile (>=2.4.0,<3.0.0dev)", "tensorflow (>=2.3.0,<3.0.0dev)", "tensorflow (>=2.4.0,<3.0.0dev)", "werkzeug (>=2.0.0,<2.1.0dev)"] -testing = ["bigframes", "cloudpickle (<3.0)", "docker (>=5.0.3)", "explainable-ai-sdk (>=1.0.0)", "fastapi (>=0.71.0,<=0.109.1)", "google-api-core (>=2.11,<3.0.0)", "google-cloud-bigquery", "google-cloud-bigquery-storage", "google-cloud-logging (<4.0)", "google-vizier (>=0.1.6)", "grpcio-testing", "httpx (>=0.23.0,<0.25.0)", "immutabledict", "ipython", "kfp (>=2.6.0,<3.0.0)", "lit-nlp (==0.4.0)", "mlflow (>=1.27.0,<=2.1.1)", "nest-asyncio (>=1.0.0,<1.6.0)", "numpy (>=1.15.0)", "pandas (>=1.0.0)", "pandas (>=1.0.0,<2.2.0)", "pyarrow (>=10.0.1)", "pyarrow (>=14.0.0)", "pyarrow (>=3.0.0,<8.0dev)", "pyarrow (>=6.0.1)", "pydantic (<2)", "pyfakefs", "pytest-asyncio", "pytest-xdist", "pyyaml (>=5.3.1,<7)", "ray[default] (>=2.4,<2.5.dev0 || >2.9.0,!=2.9.1,!=2.9.2,<=2.9.3)", "ray[default] (>=2.5,<=2.9.3)", "requests (>=2.28.1)", "requests-toolbelt (<1.0.0)", "scikit-learn", "setuptools (<70.0.0)", "starlette (>=0.17.1)", "tensorboard-plugin-profile (>=2.4.0,<3.0.0dev)", "tensorflow (==2.13.0)", "tensorflow (==2.16.1)", "tensorflow (>=2.3.0,<3.0.0dev)", "tensorflow (>=2.3.0,<3.0.0dev)", "tensorflow (>=2.4.0,<3.0.0dev)", "torch (>=2.0.0,<2.1.0)", "torch (>=2.2.0)", "urllib3 (>=1.21.1,<1.27)", "uvicorn[standard] (>=0.16.0)", "werkzeug (>=2.0.0,<2.1.0dev)", "xgboost"] -vizier = ["google-vizier (>=0.1.6)"] -xai = ["tensorflow (>=2.3.0,<3.0.0dev)"] - -[[package]] -name = "google-cloud-appengine-logging" -version = "1.4.3" -description = "Google Cloud Appengine Logging API client library" -optional = false -python-versions = ">=3.7" -files = [ - {file = "google-cloud-appengine-logging-1.4.3.tar.gz", hash = "sha256:fb504e6199fe8de85baa9d31cecf6776877851fe58867de603317ec7cc739987"}, - {file = "google_cloud_appengine_logging-1.4.3-py2.py3-none-any.whl", hash = "sha256:8e30af51d853f219caf29e8b8b342b9ce8214b29f334dafae38d39aaaff7d372"}, -] - -[package.dependencies] -google-api-core = {version = ">=1.34.1,<2.0.dev0 || >=2.11.dev0,<3.0.0dev", extras = ["grpc"]} -google-auth = ">=2.14.1,<2.24.0 || >2.24.0,<2.25.0 || >2.25.0,<3.0.0dev" -proto-plus = ">=1.22.3,<2.0.0dev" -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" - -[[package]] -name = "google-cloud-audit-log" -version = "0.2.5" -description = "Google Cloud Audit Protos" -optional = false -python-versions = ">=3.7" -files = [ - {file = "google-cloud-audit-log-0.2.5.tar.gz", hash = "sha256:86e2faba3383adc8fd04a5bd7fd4f960b3e4aedaa7ed950f2f891ce16902eb6b"}, - {file = "google_cloud_audit_log-0.2.5-py2.py3-none-any.whl", hash = "sha256:18b94d4579002a450b7902cd2e8b8fdcb1ea2dd4df3b41f8f82be6d9f7fcd746"}, -] - -[package.dependencies] -googleapis-common-protos = ">=1.56.2,<2.0dev" -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" - -[[package]] -name = "google-cloud-automl" -version = "2.13.3" -description = "Google Cloud Automl API client library" -optional = false -python-versions = ">=3.7" -files = [ - {file = "google-cloud-automl-2.13.3.tar.gz", hash = "sha256:891a9082eaedeb17bc5bb724fc150b7702c684d7420f9f22ae3f7c5fc611c71a"}, - {file = "google_cloud_automl-2.13.3-py2.py3-none-any.whl", hash = "sha256:8117943ad1534f1d11d40e0937ade7965c56a6d7fd2c2314e56942361727a6a2"}, -] - -[package.dependencies] -google-api-core = {version = ">=1.34.1,<2.0.dev0 || >=2.11.dev0,<3.0.0dev", extras = ["grpc"]} -google-auth = ">=2.14.1,<2.24.0 || >2.24.0,<2.25.0 || >2.25.0,<3.0.0dev" -proto-plus = ">=1.22.3,<2.0.0dev" -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" - -[package.extras] -libcst = ["libcst (>=0.2.5)"] -pandas = ["pandas (>=1.0.5)"] -storage = ["google-cloud-storage (>=1.18.0,<3.0.0dev)"] - -[[package]] -name = "google-cloud-batch" -version = "0.17.21" -description = "Google Cloud Batch API client library" -optional = false -python-versions = ">=3.7" -files = [ - {file = "google-cloud-batch-0.17.21.tar.gz", hash = "sha256:ead5fd10553280a2fa9a05d892ff0446198ba381ad2895c88a80803e34e38a0a"}, - {file = "google_cloud_batch-0.17.21-py2.py3-none-any.whl", hash = "sha256:a202defeb82ed30479c80d13e6ef2d3952cc6f47d28bdf8376d12fa36ad407ac"}, -] - -[package.dependencies] -google-api-core = {version = ">=1.34.1,<2.0.dev0 || >=2.11.dev0,<3.0.0dev", extras = ["grpc"]} -google-auth = ">=2.14.1,<2.24.0 || >2.24.0,<2.25.0 || >2.25.0,<3.0.0dev" -proto-plus = ">=1.22.3,<2.0.0dev" -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" - -[[package]] -name = "google-cloud-bigquery" -version = "3.25.0" -description = "Google BigQuery API client library" -optional = false -python-versions = ">=3.7" -files = [ - {file = "google-cloud-bigquery-3.25.0.tar.gz", hash = "sha256:5b2aff3205a854481117436836ae1403f11f2594e6810a98886afd57eda28509"}, - {file = "google_cloud_bigquery-3.25.0-py2.py3-none-any.whl", hash = "sha256:7f0c371bc74d2a7fb74dacbc00ac0f90c8c2bec2289b51dd6685a275873b1ce9"}, -] - -[package.dependencies] -google-api-core = {version = ">=1.34.1,<2.0.dev0 || >=2.11.dev0,<3.0.0dev", extras = ["grpc"]} -google-auth = ">=2.14.1,<3.0.0dev" -google-cloud-core = ">=1.6.0,<3.0.0dev" -google-resumable-media = ">=0.6.0,<3.0dev" -packaging = ">=20.0.0" -python-dateutil = ">=2.7.2,<3.0dev" -requests = ">=2.21.0,<3.0.0dev" - -[package.extras] -all = ["Shapely (>=1.8.4,<3.0.0dev)", "db-dtypes (>=0.3.0,<2.0.0dev)", "geopandas (>=0.9.0,<1.0dev)", "google-cloud-bigquery-storage (>=2.6.0,<3.0.0dev)", "grpcio (>=1.47.0,<2.0dev)", "grpcio (>=1.49.1,<2.0dev)", "importlib-metadata (>=1.0.0)", "ipykernel (>=6.0.0)", "ipython (>=7.23.1,!=8.1.0)", "ipywidgets (>=7.7.0)", "opentelemetry-api (>=1.1.0)", "opentelemetry-instrumentation (>=0.20b0)", "opentelemetry-sdk (>=1.1.0)", "pandas (>=1.1.0)", "proto-plus (>=1.15.0,<2.0.0dev)", "protobuf (>=3.19.5,!=3.20.0,!=3.20.1,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5,<5.0.0dev)", "pyarrow (>=3.0.0)", "tqdm (>=4.7.4,<5.0.0dev)"] -bigquery-v2 = ["proto-plus (>=1.15.0,<2.0.0dev)", "protobuf (>=3.19.5,!=3.20.0,!=3.20.1,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5,<5.0.0dev)"] -bqstorage = ["google-cloud-bigquery-storage (>=2.6.0,<3.0.0dev)", "grpcio (>=1.47.0,<2.0dev)", "grpcio (>=1.49.1,<2.0dev)", "pyarrow (>=3.0.0)"] -geopandas = ["Shapely (>=1.8.4,<3.0.0dev)", "geopandas (>=0.9.0,<1.0dev)"] -ipython = ["ipykernel (>=6.0.0)", "ipython (>=7.23.1,!=8.1.0)"] -ipywidgets = ["ipykernel (>=6.0.0)", "ipywidgets (>=7.7.0)"] -opentelemetry = ["opentelemetry-api (>=1.1.0)", "opentelemetry-instrumentation (>=0.20b0)", "opentelemetry-sdk (>=1.1.0)"] -pandas = ["db-dtypes (>=0.3.0,<2.0.0dev)", "importlib-metadata (>=1.0.0)", "pandas (>=1.1.0)", "pyarrow (>=3.0.0)"] -tqdm = ["tqdm (>=4.7.4,<5.0.0dev)"] - -[[package]] -name = "google-cloud-bigquery-datatransfer" -version = "3.15.3" -description = "Google Cloud Bigquery Datatransfer API client library" -optional = false -python-versions = ">=3.7" -files = [ - {file = "google-cloud-bigquery-datatransfer-3.15.3.tar.gz", hash = "sha256:e4c84eed31209c43b43f08dda7307eec0666a2431d8c087acf4a682ad41f3ab1"}, - {file = "google_cloud_bigquery_datatransfer-3.15.3-py2.py3-none-any.whl", hash = "sha256:cb8a0bf980d7d9386af638c42c006093f948147fc4bca3f11f724969517651dd"}, -] - -[package.dependencies] -google-api-core = {version = ">=1.34.1,<2.0.dev0 || >=2.11.dev0,<3.0.0dev", extras = ["grpc"]} -google-auth = ">=2.14.1,<2.24.0 || >2.24.0,<2.25.0 || >2.25.0,<3.0.0dev" -proto-plus = ">=1.22.3,<2.0.0dev" -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" - -[[package]] -name = "google-cloud-bigtable" -version = "2.24.0" -description = "Google Cloud Bigtable API client library" -optional = false -python-versions = ">=3.7" -files = [ - {file = "google-cloud-bigtable-2.24.0.tar.gz", hash = "sha256:ace75f62ca3c52d6619d4ff7aed982129cae508baf776d81b33313f4f9ea5ed4"}, - {file = "google_cloud_bigtable-2.24.0-py2.py3-none-any.whl", hash = "sha256:09f35c1afcd57fec405ca5713919f09122a9beaf60a4f6952af6d4ac03065c91"}, -] - -[package.dependencies] -google-api-core = {version = ">=2.16.0,<3.0.0dev", extras = ["grpc"]} -google-cloud-core = ">=1.4.4,<3.0.0dev" -grpc-google-iam-v1 = ">=0.12.4,<1.0.0dev" -proto-plus = ">=1.22.0,<2.0.0dev" -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" - -[package.extras] -libcst = ["libcst (>=0.2.5)"] - -[[package]] -name = "google-cloud-build" -version = "3.24.0" -description = "Google Cloud Build API client library" -optional = false -python-versions = ">=3.7" -files = [ - {file = "google-cloud-build-3.24.0.tar.gz", hash = "sha256:dbaf1c0df4bd8579a16b985332412847a3fd6f58bd2b72b38fbd791b80d0a900"}, - {file = "google_cloud_build-3.24.0-py2.py3-none-any.whl", hash = "sha256:1ba689730b5e27b8e226f3c7ba38e5af006321dcfbae211f995f26f9294fb19a"}, -] - -[package.dependencies] -google-api-core = {version = ">=1.34.1,<2.0.dev0 || >=2.11.dev0,<3.0.0dev", extras = ["grpc"]} -google-auth = ">=2.14.1,<2.24.0 || >2.24.0,<2.25.0 || >2.25.0,<3.0.0dev" -grpc-google-iam-v1 = ">=0.12.4,<1.0.0dev" -proto-plus = ">=1.22.3,<2.0.0dev" -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" - -[[package]] -name = "google-cloud-compute" -version = "1.19.0" -description = "Google Cloud Compute API client library" -optional = false -python-versions = ">=3.7" -files = [ - {file = "google-cloud-compute-1.19.0.tar.gz", hash = "sha256:a07b3408b3f77786dcb196669ff3767bc51080718a7c2d3fd779defc8d817b4d"}, - {file = "google_cloud_compute-1.19.0-py2.py3-none-any.whl", hash = "sha256:48d5582dd257fc817113556ab40990ec7a50fb6b2e341bc8a55ef90e2e66501d"}, -] - -[package.dependencies] -google-api-core = {version = ">=1.34.1,<2.0.dev0 || >=2.11.dev0,<3.0.0dev", extras = ["grpc"]} -google-auth = ">=2.14.1,<2.24.0 || >2.24.0,<2.25.0 || >2.25.0,<3.0.0dev" -proto-plus = ">=1.22.3,<2.0.0dev" -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" - -[[package]] -name = "google-cloud-container" -version = "2.47.0" -description = "Google Cloud Container API client library" -optional = false -python-versions = ">=3.7" -files = [ - {file = "google-cloud-container-2.47.0.tar.gz", hash = "sha256:b6fcce293bb69f96fd243a3d109c38f0152b26e3b0391f492ba3d0ca2e381df2"}, - {file = "google_cloud_container-2.47.0-py2.py3-none-any.whl", hash = "sha256:327e7b3ff68dbaca367c1840e8c2b0fc8a3d922264faf96dd0233c98785ee42a"}, -] - -[package.dependencies] -google-api-core = {version = ">=1.34.1,<2.0.dev0 || >=2.11.dev0,<3.0.0dev", extras = ["grpc"]} -google-auth = ">=2.14.1,<2.24.0 || >2.24.0,<2.25.0 || >2.25.0,<3.0.0dev" -proto-plus = ">=1.22.3,<2.0.0dev" -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" - -[[package]] -name = "google-cloud-core" -version = "2.4.1" -description = "Google Cloud API client core library" -optional = false -python-versions = ">=3.7" -files = [ - {file = "google-cloud-core-2.4.1.tar.gz", hash = "sha256:9b7749272a812bde58fff28868d0c5e2f585b82f37e09a1f6ed2d4d10f134073"}, - {file = "google_cloud_core-2.4.1-py2.py3-none-any.whl", hash = "sha256:a9e6a4422b9ac5c29f79a0ede9485473338e2ce78d91f2370c01e730eab22e61"}, -] - -[package.dependencies] -google-api-core = ">=1.31.6,<2.0.dev0 || >2.3.0,<3.0.0dev" -google-auth = ">=1.25.0,<3.0dev" - -[package.extras] -grpc = ["grpcio (>=1.38.0,<2.0dev)", "grpcio-status (>=1.38.0,<2.0.dev0)"] - -[[package]] -name = "google-cloud-datacatalog" -version = "3.19.0" -description = "Google Cloud Datacatalog API client library" -optional = false -python-versions = ">=3.7" -files = [ - {file = "google-cloud-datacatalog-3.19.0.tar.gz", hash = "sha256:3a8d0ef787f0edd4703e7e27c91a1b5f85bdbe04d61609132ec77269f7d52692"}, - {file = "google_cloud_datacatalog-3.19.0-py2.py3-none-any.whl", hash = "sha256:c76ccf0d98d150c2feb1552518f6efde441c820664742ccbe4daf749e009f58d"}, -] - -[package.dependencies] -google-api-core = {version = ">=1.34.1,<2.0.dev0 || >=2.11.dev0,<3.0.0dev", extras = ["grpc"]} -google-auth = ">=2.14.1,<2.24.0 || >2.24.0,<2.25.0 || >2.25.0,<3.0.0dev" -grpc-google-iam-v1 = ">=0.12.4,<1.0.0dev" -proto-plus = ">=1.22.3,<2.0.0dev" -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" - -[[package]] -name = "google-cloud-dataflow-client" -version = "0.8.10" -description = "Google Cloud Dataflow Client API client library" -optional = false -python-versions = ">=3.7" -files = [ - {file = "google-cloud-dataflow-client-0.8.10.tar.gz", hash = "sha256:6aa8178743bce4b6c9142b492e649db84f55db70a88ec29a3d889054c4752144"}, - {file = "google_cloud_dataflow_client-0.8.10-py2.py3-none-any.whl", hash = "sha256:4b0dce886ec65fbf3195f87e956d559f6d4bd88a03b527aa8498c303e2d4d39a"}, -] - -[package.dependencies] -google-api-core = {version = ">=1.34.1,<2.0.dev0 || >=2.11.dev0,<3.0.0dev", extras = ["grpc"]} -google-auth = ">=2.14.1,<2.24.0 || >2.24.0,<2.25.0 || >2.25.0,<3.0.0dev" -proto-plus = ">=1.22.3,<2.0.0dev" -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" - -[[package]] -name = "google-cloud-dataform" -version = "0.5.9" -description = "Google Cloud Dataform API client library" -optional = false -python-versions = ">=3.7" -files = [ - {file = "google-cloud-dataform-0.5.9.tar.gz", hash = "sha256:2733c3fbda4f0134629e2d6554db93e1840683567043906268718b1a874eb9ac"}, - {file = "google_cloud_dataform-0.5.9-py2.py3-none-any.whl", hash = "sha256:c94e61358a68de389803bb06b936f815108211b3324e1f143db9a8bd2bb6a081"}, -] - -[package.dependencies] -google-api-core = {version = ">=1.34.1,<2.0.dev0 || >=2.11.dev0,<3.0.0dev", extras = ["grpc"]} -google-auth = ">=2.14.1,<2.24.0 || >2.24.0,<2.25.0 || >2.25.0,<3.0.0dev" -grpc-google-iam-v1 = ">=0.12.4,<1.0.0dev" -proto-plus = ">=1.22.3,<2.0.0dev" -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" - -[[package]] -name = "google-cloud-dataplex" -version = "2.0.1" -description = "Google Cloud Dataplex API client library" -optional = false -python-versions = ">=3.7" -files = [ - {file = "google-cloud-dataplex-2.0.1.tar.gz", hash = "sha256:f4ccb1f76eb7b8a2ae01cdcb2041bb613045d262b57bd65d2c7522e766923c15"}, - {file = "google_cloud_dataplex-2.0.1-py2.py3-none-any.whl", hash = "sha256:ebe732dcf54b372c4af8ee40e2f43e3eff329b98d2060b1a803a0e9e656f5da6"}, -] - -[package.dependencies] -google-api-core = {version = ">=1.34.1,<2.0.dev0 || >=2.11.dev0,<3.0.0dev", extras = ["grpc"]} -google-auth = ">=2.14.1,<2.24.0 || >2.24.0,<2.25.0 || >2.25.0,<3.0.0dev" -grpc-google-iam-v1 = ">=0.12.4,<1.0.0dev" -proto-plus = ">=1.22.3,<2.0.0dev" -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" - -[[package]] -name = "google-cloud-dataproc" -version = "5.10.1" -description = "Google Cloud Dataproc API client library" -optional = false -python-versions = ">=3.7" -files = [ - {file = "google-cloud-dataproc-5.10.1.tar.gz", hash = "sha256:f3f0f0f3933328e80273774540368432550e296c255928657069a31a2de01c39"}, - {file = "google_cloud_dataproc-5.10.1-py2.py3-none-any.whl", hash = "sha256:28b763c9b019ca7d7c3e917ade04647c00494e77d4e682ca221d53e8d36f70af"}, -] - -[package.dependencies] -google-api-core = {version = ">=1.34.1,<2.0.dev0 || >=2.11.dev0,<3.0.0dev", extras = ["grpc"]} -google-auth = ">=2.14.1,<2.24.0 || >2.24.0,<2.25.0 || >2.25.0,<3.0.0dev" -grpc-google-iam-v1 = ">=0.12.4,<1.0.0dev" -proto-plus = ">=1.22.3,<2.0.0dev" -protobuf = ">=3.20.2,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<6.0.0dev" - -[[package]] -name = "google-cloud-dataproc-metastore" -version = "1.15.3" -description = "Google Cloud Dataproc Metastore API client library" -optional = false -python-versions = ">=3.7" -files = [ - {file = "google-cloud-dataproc-metastore-1.15.3.tar.gz", hash = "sha256:1f8a5a66e43a4d1c119e9be225ba66b041f432d046b5c4da6717fbd56fcfb4f5"}, - {file = "google_cloud_dataproc_metastore-1.15.3-py2.py3-none-any.whl", hash = "sha256:871dcea73ae2ab2ecfb6da1fe1bc82206eee817b744755f7b24aaef554b8d896"}, -] - -[package.dependencies] -google-api-core = {version = ">=1.34.1,<2.0.dev0 || >=2.11.dev0,<3.0.0dev", extras = ["grpc"]} -google-auth = ">=2.14.1,<2.24.0 || >2.24.0,<2.25.0 || >2.25.0,<3.0.0dev" -grpc-google-iam-v1 = ">=0.12.4,<1.0.0dev" -proto-plus = ">=1.22.3,<2.0.0dev" -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" - -[[package]] -name = "google-cloud-dlp" -version = "3.18.0" -description = "Google Cloud Dlp API client library" -optional = false -python-versions = ">=3.7" -files = [ - {file = "google-cloud-dlp-3.18.0.tar.gz", hash = "sha256:47408cc75e8398c7dce93c3f62a3ed8582b20f125cc8e0dd331015ae3eb62f7e"}, - {file = "google_cloud_dlp-3.18.0-py2.py3-none-any.whl", hash = "sha256:68c5c3767b9d96597b6c51c97fe4d824439ca71622048b3d44b89ed7d6eecf0d"}, -] - -[package.dependencies] -google-api-core = {version = ">=1.34.1,<2.0.dev0 || >=2.11.dev0,<3.0.0dev", extras = ["grpc"]} -google-auth = ">=2.14.1,<2.24.0 || >2.24.0,<2.25.0 || >2.25.0,<3.0.0dev" -proto-plus = ">=1.22.3,<2.0.0dev" -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" - -[[package]] -name = "google-cloud-kms" -version = "2.23.0" -description = "Google Cloud Kms API client library" -optional = false -python-versions = ">=3.7" -files = [ - {file = "google-cloud-kms-2.23.0.tar.gz", hash = "sha256:52b5fc6f70b163516fad610aafc088fbe788f501d5bbe1d5f458cdc3fcbafd2c"}, - {file = "google_cloud_kms-2.23.0-py2.py3-none-any.whl", hash = "sha256:cbf68592a5626ac4de43d8149f7933e9b9bd311e1c88d0d16d9e56a49d7a21c0"}, -] - -[package.dependencies] -google-api-core = {version = ">=1.34.1,<2.0.dev0 || >=2.11.dev0,<3.0.0dev", extras = ["grpc"]} -google-auth = ">=2.14.1,<2.24.0 || >2.24.0,<2.25.0 || >2.25.0,<3.0.0dev" -grpc-google-iam-v1 = ">=0.12.4,<1.0.0dev" -proto-plus = ">=1.22.3,<2.0.0dev" -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" - -[[package]] -name = "google-cloud-language" -version = "2.13.3" -description = "Google Cloud Language API client library" -optional = false -python-versions = ">=3.7" -files = [ - {file = "google-cloud-language-2.13.3.tar.gz", hash = "sha256:569d35260af906de25b8e2a76b6364e05809b8453afd89da738d4a4fcb90846f"}, - {file = "google_cloud_language-2.13.3-py2.py3-none-any.whl", hash = "sha256:b060de20d8ed2b20b7b7ebd8a46ae240df36c9977db383db5155276d2b1f6b9a"}, -] - -[package.dependencies] -google-api-core = {version = ">=1.34.1,<2.0.dev0 || >=2.11.dev0,<3.0.0dev", extras = ["grpc"]} -google-auth = ">=2.14.1,<2.24.0 || >2.24.0,<2.25.0 || >2.25.0,<3.0.0dev" -proto-plus = ">=1.22.3,<2.0.0dev" -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" - -[[package]] -name = "google-cloud-logging" -version = "3.10.0" -description = "Stackdriver Logging API client library" -optional = false -python-versions = ">=3.7" -files = [ - {file = "google-cloud-logging-3.10.0.tar.gz", hash = "sha256:d93d347351240ddb14cfe201987a2d32cf9d7f478b8b2fabed3015b425b3274f"}, - {file = "google_cloud_logging-3.10.0-py2.py3-none-any.whl", hash = "sha256:132192beb45731130a2ffbcd4b2b5cbd87370e7dcfa7397ae4002154f542bd20"}, -] - -[package.dependencies] -google-api-core = {version = ">=1.34.1,<2.0.dev0 || >=2.11.dev0,<3.0.0dev", extras = ["grpc"]} -google-auth = ">=2.14.1,<2.24.0 || >2.24.0,<2.25.0 || >2.25.0,<3.0.0dev" -google-cloud-appengine-logging = ">=0.1.0,<2.0.0dev" -google-cloud-audit-log = ">=0.1.0,<1.0.0dev" -google-cloud-core = ">=2.0.0,<3.0.0dev" -grpc-google-iam-v1 = ">=0.12.4,<1.0.0dev" -proto-plus = ">=1.22.0,<2.0.0dev" -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" - -[[package]] -name = "google-cloud-memcache" -version = "1.9.3" -description = "Google Cloud Memcache API client library" -optional = false -python-versions = ">=3.7" -files = [ - {file = "google-cloud-memcache-1.9.3.tar.gz", hash = "sha256:ee5ff95afe47efc1a0746ba13b2f56996bc018f158f6b0cad69d835b0447d6e8"}, - {file = "google_cloud_memcache-1.9.3-py2.py3-none-any.whl", hash = "sha256:d1574670dcdb861cc772e2b797f7e5fb83b9dd7ef2ce34fbe4ff54d454a816d3"}, -] - -[package.dependencies] -google-api-core = {version = ">=1.34.1,<2.0.dev0 || >=2.11.dev0,<3.0.0dev", extras = ["grpc"]} -google-auth = ">=2.14.1,<2.24.0 || >2.24.0,<2.25.0 || >2.25.0,<3.0.0dev" -proto-plus = ">=1.22.3,<2.0.0dev" -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" - -[[package]] -name = "google-cloud-monitoring" -version = "2.21.0" -description = "Google Cloud Monitoring API client library" -optional = false -python-versions = ">=3.7" -files = [ - {file = "google-cloud-monitoring-2.21.0.tar.gz", hash = "sha256:e7b1c8758fc3563ffb9a347bc5172e2782f44c121bc80fc15283e289cff675bf"}, - {file = "google_cloud_monitoring-2.21.0-py2.py3-none-any.whl", hash = "sha256:1b174e656a3bfd767c269bf2ba023b40e0a80a85e36ed0b75bb272be65e76904"}, -] - -[package.dependencies] -google-api-core = {version = ">=1.34.1,<2.0.dev0 || >=2.11.dev0,<3.0.0dev", extras = ["grpc"]} -google-auth = ">=2.14.1,<2.24.0 || >2.24.0,<2.25.0 || >2.25.0,<3.0.0dev" -proto-plus = ">=1.22.3,<2.0.0dev" -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" - -[package.extras] -pandas = ["pandas (>=0.23.2)"] - -[[package]] -name = "google-cloud-orchestration-airflow" -version = "1.12.1" -description = "Google Cloud Orchestration Airflow API client library" -optional = false -python-versions = ">=3.7" -files = [ - {file = "google-cloud-orchestration-airflow-1.12.1.tar.gz", hash = "sha256:659a72f506a9441f1938664e98cdced9a4a852dc5d8c533a5c2f822cefe72eb1"}, - {file = "google_cloud_orchestration_airflow-1.12.1-py2.py3-none-any.whl", hash = "sha256:9dab139528860c3d10b9affe6a7e34848f10e15f5800554792c1bab37f713e3d"}, -] - -[package.dependencies] -google-api-core = {version = ">=1.34.1,<2.0.dev0 || >=2.11.dev0,<3.0.0dev", extras = ["grpc"]} -google-auth = ">=2.14.1,<2.24.0 || >2.24.0,<2.25.0 || >2.25.0,<3.0.0dev" -proto-plus = ">=1.22.3,<2.0.0dev" -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" - -[[package]] -name = "google-cloud-os-login" -version = "2.14.3" -description = "Google Cloud Os Login API client library" -optional = false -python-versions = ">=3.7" -files = [ - {file = "google-cloud-os-login-2.14.3.tar.gz", hash = "sha256:b1a15ec7ee306de890750822dc4aab04c64e5bcf76447590f45551bf1afcf1e8"}, - {file = "google_cloud_os_login-2.14.3-py2.py3-none-any.whl", hash = "sha256:de19bb2ade36e982256050972b5f68be34a0f4c70365c76a7cd91de3f0e7985f"}, -] - -[package.dependencies] -google-api-core = {version = ">=1.34.1,<2.0.dev0 || >=2.11.dev0,<3.0.0dev", extras = ["grpc"]} -google-auth = ">=2.14.1,<2.24.0 || >2.24.0,<2.25.0 || >2.25.0,<3.0.0dev" -proto-plus = ">=1.22.3,<2.0.0dev" -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" - -[[package]] -name = "google-cloud-pubsub" -version = "2.21.5" -description = "Google Cloud Pub/Sub API client library" -optional = false -python-versions = ">=3.7" -files = [ - {file = "google-cloud-pubsub-2.21.5.tar.gz", hash = "sha256:4fa96e7f200359ccc49cf6657e31ac35f5e6e55d00fbb3cedfa672903cf75b24"}, - {file = "google_cloud_pubsub-2.21.5-py2.py3-none-any.whl", hash = "sha256:fbd6b00a1e28ea47609b2a5562aeecbaf31ad9cf4f7a83f91c3605e869c6447c"}, -] - -[package.dependencies] -google-api-core = {version = ">=1.34.0,<2.0.dev0 || >=2.11.dev0,<3.0.0dev", extras = ["grpc"]} -google-auth = ">=2.14.1,<3.0.0dev" -grpc-google-iam-v1 = ">=0.12.4,<1.0.0dev" -grpcio = ">=1.51.3,<2.0dev" -grpcio-status = ">=1.33.2" -proto-plus = ">=1.22.0,<2.0.0dev" -protobuf = ">=3.20.2,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<6.0.0dev" - -[package.extras] -libcst = ["libcst (>=0.3.10)"] - -[[package]] -name = "google-cloud-redis" -version = "2.15.3" -description = "Google Cloud Redis API client library" -optional = false -python-versions = ">=3.7" -files = [ - {file = "google-cloud-redis-2.15.3.tar.gz", hash = "sha256:e6a231e45107038cfe498dfad1f6dad2ca7bdca3a931323730be03ab7a000a8f"}, - {file = "google_cloud_redis-2.15.3-py2.py3-none-any.whl", hash = "sha256:df79f6f8a81f948d2d5343a76e7c9108ab56eab9279be0763da6968f497b2bdb"}, -] - -[package.dependencies] -google-api-core = {version = ">=1.34.1,<2.0.dev0 || >=2.11.dev0,<3.0.0dev", extras = ["grpc"]} -google-auth = ">=2.14.1,<2.24.0 || >2.24.0,<2.25.0 || >2.25.0,<3.0.0dev" -proto-plus = ">=1.22.3,<2.0.0dev" -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" - -[[package]] -name = "google-cloud-resource-manager" -version = "1.12.3" -description = "Google Cloud Resource Manager API client library" -optional = false -python-versions = ">=3.7" -files = [ - {file = "google-cloud-resource-manager-1.12.3.tar.gz", hash = "sha256:809851824119834e4f2310b2c4f38621c1d16b2bb14d5b9f132e69c79d355e7f"}, - {file = "google_cloud_resource_manager-1.12.3-py2.py3-none-any.whl", hash = "sha256:92be7d6959927b76d90eafc4028985c37975a46ded5466a018f02e8649e113d4"}, -] - -[package.dependencies] -google-api-core = {version = ">=1.34.1,<2.0.dev0 || >=2.11.dev0,<3.0.0dev", extras = ["grpc"]} -google-auth = ">=2.14.1,<2.24.0 || >2.24.0,<2.25.0 || >2.25.0,<3.0.0dev" -grpc-google-iam-v1 = ">=0.12.4,<1.0.0dev" -proto-plus = ">=1.22.3,<2.0.0dev" -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" - -[[package]] -name = "google-cloud-run" -version = "0.10.5" -description = "Google Cloud Run API client library" -optional = false -python-versions = ">=3.7" -files = [ - {file = "google-cloud-run-0.10.5.tar.gz", hash = "sha256:d6c546693ad1232794b75c617871f2e46283c0cd0c4cc3886b85b8f0a3ba575f"}, - {file = "google_cloud_run-0.10.5-py2.py3-none-any.whl", hash = "sha256:0f68125f13d1a87f74e1e78c37fa6afb4b094d76dad2b9f951d5526648e8939c"}, -] - -[package.dependencies] -google-api-core = {version = ">=1.34.1,<2.0.dev0 || >=2.11.dev0,<3.0.0dev", extras = ["grpc"]} -google-auth = ">=2.14.1,<2.24.0 || >2.24.0,<2.25.0 || >2.25.0,<3.0.0dev" -grpc-google-iam-v1 = ">=0.12.4,<1.0.0dev" -proto-plus = ">=1.22.3,<2.0.0dev" -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" - -[[package]] -name = "google-cloud-secret-manager" -version = "2.20.0" -description = "Google Cloud Secret Manager API client library" -optional = false -python-versions = ">=3.7" -files = [ - {file = "google-cloud-secret-manager-2.20.0.tar.gz", hash = "sha256:a086a7413aaf4fffbd1c4fe9229ef0ce9bcf48f5a8df5b449c4a32deb5a2cfde"}, - {file = "google_cloud_secret_manager-2.20.0-py2.py3-none-any.whl", hash = "sha256:c20bf22e59d220c51aa84a1db3411b14b83aa71f788fae8d273c03a4bf3e77ed"}, -] - -[package.dependencies] -google-api-core = {version = ">=1.34.1,<2.0.dev0 || >=2.11.dev0,<3.0.0dev", extras = ["grpc"]} -google-auth = ">=2.14.1,<2.24.0 || >2.24.0,<2.25.0 || >2.25.0,<3.0.0dev" -grpc-google-iam-v1 = ">=0.12.4,<1.0.0dev" -proto-plus = ">=1.22.3,<2.0.0dev" -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" - -[[package]] -name = "google-cloud-spanner" -version = "3.47.0" -description = "Google Cloud Spanner API client library" -optional = false -python-versions = ">=3.7" -files = [ - {file = "google_cloud_spanner-3.47.0-py2.py3-none-any.whl", hash = "sha256:b05fa4ffccf08af3f32c3c5c77edd1486a76ddbd42db8ad8865830fab3cfda80"}, -] - -[package.dependencies] -google-api-core = {version = ">=1.34.0,<2.0.dev0 || >=2.11.dev0,<3.0.0dev", extras = ["grpc"]} -google-cloud-core = ">=1.4.4,<3.0dev" -grpc-google-iam-v1 = ">=0.12.4,<1.0.0dev" -grpc-interceptor = ">=0.15.4" -proto-plus = ">=1.22.0,<2.0.0dev" -protobuf = ">=3.20.2,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" -sqlparse = ">=0.4.4" - -[package.extras] -libcst = ["libcst (>=0.2.5)"] -tracing = ["opentelemetry-api (>=1.1.0)", "opentelemetry-instrumentation (>=0.20b0,<0.23dev)", "opentelemetry-sdk (>=1.1.0)"] - -[[package]] -name = "google-cloud-speech" -version = "2.26.0" -description = "Google Cloud Speech API client library" +name = "google" +version = "3.0.0" +description = "Python bindings to the Google search engine." optional = false -python-versions = ">=3.7" +python-versions = "*" files = [ - {file = "google-cloud-speech-2.26.0.tar.gz", hash = "sha256:d3156a78496aeacff403429408a1b13efe996da6f0544a25567904ad801671d5"}, - {file = "google_cloud_speech-2.26.0-py2.py3-none-any.whl", hash = "sha256:8b61aebcbcc9bd5450933c94c431584a07667e022d12834f9037bb2c0e673c87"}, + {file = "google-3.0.0-py2.py3-none-any.whl", hash = "sha256:889cf695f84e4ae2c55fbc0cfdaf4c1e729417fa52ab1db0485202ba173e4935"}, + {file = "google-3.0.0.tar.gz", hash = "sha256:143530122ee5130509ad5e989f0512f7cb218b2d4eddbafbad40fd10e8d8ccbe"}, ] [package.dependencies] -google-api-core = {version = ">=1.34.1,<2.0.dev0 || >=2.11.dev0,<3.0.0dev", extras = ["grpc"]} -google-auth = ">=2.14.1,<2.24.0 || >2.24.0,<2.25.0 || >2.25.0,<3.0.0dev" -proto-plus = ">=1.22.3,<2.0.0dev" -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" +beautifulsoup4 = "*" [[package]] -name = "google-cloud-storage" -version = "2.17.0" -description = "Google Cloud Storage API client library" +name = "google-api-core" +version = "2.19.0" +description = "Google API client core library" optional = false python-versions = ">=3.7" files = [ - {file = "google-cloud-storage-2.17.0.tar.gz", hash = "sha256:49378abff54ef656b52dca5ef0f2eba9aa83dc2b2c72c78714b03a1a95fe9388"}, - {file = "google_cloud_storage-2.17.0-py2.py3-none-any.whl", hash = "sha256:5b393bc766b7a3bc6f5407b9e665b2450d36282614b7945e570b3480a456d1e1"}, + {file = "google-api-core-2.19.0.tar.gz", hash = "sha256:cf1b7c2694047886d2af1128a03ae99e391108a08804f87cfd35970e49c9cd10"}, + {file = "google_api_core-2.19.0-py3-none-any.whl", hash = "sha256:8661eec4078c35428fd3f69a2c7ee29e342896b70f01d1a1cbcb334372dd6251"}, ] [package.dependencies] -google-api-core = ">=2.15.0,<3.0.0dev" -google-auth = ">=2.26.1,<3.0dev" -google-cloud-core = ">=2.3.0,<3.0dev" -google-crc32c = ">=1.0,<2.0dev" -google-resumable-media = ">=2.6.0" -requests = ">=2.18.0,<3.0.0dev" +google-auth = ">=2.14.1,<3.0.dev0" +googleapis-common-protos = ">=1.56.2,<2.0.dev0" +grpcio = {version = ">=1.33.2,<2.0dev", optional = true, markers = "extra == \"grpc\""} +grpcio-status = {version = ">=1.33.2,<2.0.dev0", optional = true, markers = "extra == \"grpc\""} +proto-plus = ">=1.22.3,<2.0.0dev" +protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0.dev0" +requests = ">=2.18.0,<3.0.0.dev0" [package.extras] -protobuf = ["protobuf (<5.0.0dev)"] +grpc = ["grpcio (>=1.33.2,<2.0dev)", "grpcio (>=1.49.1,<2.0dev)", "grpcio-status (>=1.33.2,<2.0.dev0)", "grpcio-status (>=1.49.1,<2.0.dev0)"] +grpcgcp = ["grpcio-gcp (>=0.2.2,<1.0.dev0)"] +grpcio-gcp = ["grpcio-gcp (>=0.2.2,<1.0.dev0)"] [[package]] -name = "google-cloud-storage-transfer" -version = "1.11.3" -description = "Google Cloud Storage Transfer API client library" +name = "google-auth" +version = "2.30.0" +description = "Google Authentication Library" optional = false python-versions = ">=3.7" files = [ - {file = "google-cloud-storage-transfer-1.11.3.tar.gz", hash = "sha256:c4564749492f41957f44c41b76f61f72c12b519424b841895bfe2d932c6f1490"}, - {file = "google_cloud_storage_transfer-1.11.3-py2.py3-none-any.whl", hash = "sha256:698e1b21c9dc710f543b2e6dc3c70334b872d4a80fafc0b2718fc91b6f45858e"}, + {file = "google-auth-2.30.0.tar.gz", hash = "sha256:ab630a1320f6720909ad76a7dbdb6841cdf5c66b328d690027e4867bdfb16688"}, + {file = "google_auth-2.30.0-py2.py3-none-any.whl", hash = "sha256:8df7da660f62757388b8a7f249df13549b3373f24388cb5d2f1dd91cc18180b5"}, ] [package.dependencies] -google-api-core = {version = ">=1.34.1,<2.0.dev0 || >=2.11.dev0,<3.0.0dev", extras = ["grpc"]} -google-auth = ">=2.14.1,<2.24.0 || >2.24.0,<2.25.0 || >2.25.0,<3.0.0dev" -proto-plus = ">=1.22.3,<2.0.0dev" -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" +cachetools = ">=2.0.0,<6.0" +pyasn1-modules = ">=0.2.1" +rsa = ">=3.1.4,<5" + +[package.extras] +aiohttp = ["aiohttp (>=3.6.2,<4.0.0.dev0)", "requests (>=2.20.0,<3.0.0.dev0)"] +enterprise-cert = ["cryptography (==36.0.2)", "pyopenssl (==22.0.0)"] +pyopenssl = ["cryptography (>=38.0.3)", "pyopenssl (>=20.0.0)"] +reauth = ["pyu2f (>=0.1.5)"] +requests = ["requests (>=2.20.0,<3.0.0.dev0)"] [[package]] -name = "google-cloud-tasks" -version = "2.16.3" -description = "Google Cloud Tasks API client library" +name = "google-auth-oauthlib" +version = "0.8.0" +description = "Google Authentication Library" optional = false -python-versions = ">=3.7" +python-versions = ">=3.6" files = [ - {file = "google-cloud-tasks-2.16.3.tar.gz", hash = "sha256:d891fe7006db4d6122838aa6de4aca6e0077bab224edcae684666ae3e303c45f"}, - {file = "google_cloud_tasks-2.16.3-py2.py3-none-any.whl", hash = "sha256:a1a8473f5c76907525b51ae4c20182a42333b5c3e1dc5782d7af6c2f58241a0c"}, + {file = "google-auth-oauthlib-0.8.0.tar.gz", hash = "sha256:81056a310fb1c4a3e5a7e1a443e1eb96593c6bbc55b26c0261e4d3295d3e6593"}, + {file = "google_auth_oauthlib-0.8.0-py2.py3-none-any.whl", hash = "sha256:40cc612a13c3336d5433e94e2adb42a0c88f6feb6c55769e44500fc70043a576"}, ] [package.dependencies] -google-api-core = {version = ">=1.34.1,<2.0.dev0 || >=2.11.dev0,<3.0.0dev", extras = ["grpc"]} -google-auth = ">=2.14.1,<2.24.0 || >2.24.0,<2.25.0 || >2.25.0,<3.0.0dev" -grpc-google-iam-v1 = ">=0.12.4,<1.0.0dev" -proto-plus = ">=1.22.3,<2.0.0dev" -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" +google-auth = ">=2.15.0" +requests-oauthlib = ">=0.7.0" + +[package.extras] +tool = ["click (>=6.0.0)"] [[package]] -name = "google-cloud-texttospeech" -version = "2.16.3" -description = "Google Cloud Texttospeech API client library" +name = "google-cloud-bigquery" +version = "3.25.0" +description = "Google BigQuery API client library" optional = false python-versions = ">=3.7" files = [ - {file = "google-cloud-texttospeech-2.16.3.tar.gz", hash = "sha256:fabc315032d137da0710bb4c268734d336212d8fa8316b23b277dd3a84ce721c"}, - {file = "google_cloud_texttospeech-2.16.3-py2.py3-none-any.whl", hash = "sha256:5d1e23f9270908a5d7ecf2af04105fbd3a7ddde60fe48506e397bd18c1ece499"}, + {file = "google-cloud-bigquery-3.25.0.tar.gz", hash = "sha256:5b2aff3205a854481117436836ae1403f11f2594e6810a98886afd57eda28509"}, + {file = "google_cloud_bigquery-3.25.0-py2.py3-none-any.whl", hash = "sha256:7f0c371bc74d2a7fb74dacbc00ac0f90c8c2bec2289b51dd6685a275873b1ce9"}, ] [package.dependencies] google-api-core = {version = ">=1.34.1,<2.0.dev0 || >=2.11.dev0,<3.0.0dev", extras = ["grpc"]} -google-auth = ">=2.14.1,<2.24.0 || >2.24.0,<2.25.0 || >2.25.0,<3.0.0dev" -proto-plus = ">=1.22.3,<2.0.0dev" -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" +google-auth = ">=2.14.1,<3.0.0dev" +google-cloud-core = ">=1.6.0,<3.0.0dev" +google-resumable-media = ">=0.6.0,<3.0dev" +packaging = ">=20.0.0" +python-dateutil = ">=2.7.2,<3.0dev" +requests = ">=2.21.0,<3.0.0dev" + +[package.extras] +all = ["Shapely (>=1.8.4,<3.0.0dev)", "db-dtypes (>=0.3.0,<2.0.0dev)", "geopandas (>=0.9.0,<1.0dev)", "google-cloud-bigquery-storage (>=2.6.0,<3.0.0dev)", "grpcio (>=1.47.0,<2.0dev)", "grpcio (>=1.49.1,<2.0dev)", "importlib-metadata (>=1.0.0)", "ipykernel (>=6.0.0)", "ipython (>=7.23.1,!=8.1.0)", "ipywidgets (>=7.7.0)", "opentelemetry-api (>=1.1.0)", "opentelemetry-instrumentation (>=0.20b0)", "opentelemetry-sdk (>=1.1.0)", "pandas (>=1.1.0)", "proto-plus (>=1.15.0,<2.0.0dev)", "protobuf (>=3.19.5,!=3.20.0,!=3.20.1,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5,<5.0.0dev)", "pyarrow (>=3.0.0)", "tqdm (>=4.7.4,<5.0.0dev)"] +bigquery-v2 = ["proto-plus (>=1.15.0,<2.0.0dev)", "protobuf (>=3.19.5,!=3.20.0,!=3.20.1,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5,<5.0.0dev)"] +bqstorage = ["google-cloud-bigquery-storage (>=2.6.0,<3.0.0dev)", "grpcio (>=1.47.0,<2.0dev)", "grpcio (>=1.49.1,<2.0dev)", "pyarrow (>=3.0.0)"] +geopandas = ["Shapely (>=1.8.4,<3.0.0dev)", "geopandas (>=0.9.0,<1.0dev)"] +ipython = ["ipykernel (>=6.0.0)", "ipython (>=7.23.1,!=8.1.0)"] +ipywidgets = ["ipykernel (>=6.0.0)", "ipywidgets (>=7.7.0)"] +opentelemetry = ["opentelemetry-api (>=1.1.0)", "opentelemetry-instrumentation (>=0.20b0)", "opentelemetry-sdk (>=1.1.0)"] +pandas = ["db-dtypes (>=0.3.0,<2.0.0dev)", "importlib-metadata (>=1.0.0)", "pandas (>=1.1.0)", "pyarrow (>=3.0.0)"] +tqdm = ["tqdm (>=4.7.4,<5.0.0dev)"] [[package]] -name = "google-cloud-translate" -version = "3.15.3" -description = "Google Cloud Translate API client library" +name = "google-cloud-core" +version = "2.4.1" +description = "Google Cloud API client core library" optional = false python-versions = ">=3.7" files = [ - {file = "google-cloud-translate-3.15.3.tar.gz", hash = "sha256:ed587a1e60cf847c3b1add6b28256e2d1722fa73a4285334f5ec5ca933e616f2"}, - {file = "google_cloud_translate-3.15.3-py2.py3-none-any.whl", hash = "sha256:2e92cd286fb25d5cf9fc0e8710f524fdf80656b6b64947d244e91696e69346ad"}, + {file = "google-cloud-core-2.4.1.tar.gz", hash = "sha256:9b7749272a812bde58fff28868d0c5e2f585b82f37e09a1f6ed2d4d10f134073"}, + {file = "google_cloud_core-2.4.1-py2.py3-none-any.whl", hash = "sha256:a9e6a4422b9ac5c29f79a0ede9485473338e2ce78d91f2370c01e730eab22e61"}, ] [package.dependencies] -google-api-core = {version = ">=1.34.1,<2.0.dev0 || >=2.11.dev0,<3.0.0dev", extras = ["grpc"]} -google-auth = ">=2.14.1,<2.24.0 || >2.24.0,<2.25.0 || >2.25.0,<3.0.0dev" -google-cloud-core = ">=1.4.4,<3.0.0dev" -proto-plus = ">=1.22.3,<2.0.0dev" -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" +google-api-core = ">=1.31.6,<2.0.dev0 || >2.3.0,<3.0.0dev" +google-auth = ">=1.25.0,<3.0dev" + +[package.extras] +grpc = ["grpcio (>=1.38.0,<2.0dev)", "grpcio-status (>=1.38.0,<2.0.dev0)"] [[package]] -name = "google-cloud-videointelligence" -version = "2.13.3" -description = "Google Cloud Videointelligence API client library" +name = "google-cloud-dataproc" +version = "5.10.1" +description = "Google Cloud Dataproc API client library" optional = false python-versions = ">=3.7" files = [ - {file = "google-cloud-videointelligence-2.13.3.tar.gz", hash = "sha256:1460721d8120661c477c01af0edd3db03845857f52146a4a39f16b4acfb36f6d"}, - {file = "google_cloud_videointelligence-2.13.3-py2.py3-none-any.whl", hash = "sha256:2eddfc42c4ef60378b638a5f4dfe466fadefae5cd6b1134eee377b5937be2c9e"}, + {file = "google-cloud-dataproc-5.10.1.tar.gz", hash = "sha256:f3f0f0f3933328e80273774540368432550e296c255928657069a31a2de01c39"}, + {file = "google_cloud_dataproc-5.10.1-py2.py3-none-any.whl", hash = "sha256:28b763c9b019ca7d7c3e917ade04647c00494e77d4e682ca221d53e8d36f70af"}, ] [package.dependencies] google-api-core = {version = ">=1.34.1,<2.0.dev0 || >=2.11.dev0,<3.0.0dev", extras = ["grpc"]} google-auth = ">=2.14.1,<2.24.0 || >2.24.0,<2.25.0 || >2.25.0,<3.0.0dev" +grpc-google-iam-v1 = ">=0.12.4,<1.0.0dev" proto-plus = ">=1.22.3,<2.0.0dev" -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" +protobuf = ">=3.20.2,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<6.0.0dev" [[package]] -name = "google-cloud-vision" -version = "3.7.2" -description = "Google Cloud Vision API client library" +name = "google-cloud-secret-manager" +version = "2.20.0" +description = "Google Cloud Secret Manager API client library" optional = false python-versions = ">=3.7" files = [ - {file = "google-cloud-vision-3.7.2.tar.gz", hash = "sha256:044330ad618c810333ff2296cd27ffd145f249638d1b35b270de6b460b00e8d2"}, - {file = "google_cloud_vision-3.7.2-py2.py3-none-any.whl", hash = "sha256:a313088fcd9c016af0427c2447eea1ad01bc192ca4cc33babaace1be587bbf75"}, + {file = "google-cloud-secret-manager-2.20.0.tar.gz", hash = "sha256:a086a7413aaf4fffbd1c4fe9229ef0ce9bcf48f5a8df5b449c4a32deb5a2cfde"}, + {file = "google_cloud_secret_manager-2.20.0-py2.py3-none-any.whl", hash = "sha256:c20bf22e59d220c51aa84a1db3411b14b83aa71f788fae8d273c03a4bf3e77ed"}, ] [package.dependencies] google-api-core = {version = ">=1.34.1,<2.0.dev0 || >=2.11.dev0,<3.0.0dev", extras = ["grpc"]} google-auth = ">=2.14.1,<2.24.0 || >2.24.0,<2.25.0 || >2.25.0,<3.0.0dev" +grpc-google-iam-v1 = ">=0.12.4,<1.0.0dev" proto-plus = ">=1.22.3,<2.0.0dev" protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" [[package]] -name = "google-cloud-workflows" -version = "1.14.3" -description = "Google Cloud Workflows API client library" +name = "google-cloud-storage" +version = "2.17.0" +description = "Google Cloud Storage API client library" optional = false python-versions = ">=3.7" files = [ - {file = "google-cloud-workflows-1.14.3.tar.gz", hash = "sha256:2140b97f78037b967d4185576886772fe17be77d2ae9996d207a334ed5a77ffe"}, - {file = "google_cloud_workflows-1.14.3-py2.py3-none-any.whl", hash = "sha256:8e700e1e6e9e9ca6375d16cad6230c52cd123beca4597c86a956940bcce996d1"}, + {file = "google-cloud-storage-2.17.0.tar.gz", hash = "sha256:49378abff54ef656b52dca5ef0f2eba9aa83dc2b2c72c78714b03a1a95fe9388"}, + {file = "google_cloud_storage-2.17.0-py2.py3-none-any.whl", hash = "sha256:5b393bc766b7a3bc6f5407b9e665b2450d36282614b7945e570b3480a456d1e1"}, ] [package.dependencies] -google-api-core = {version = ">=1.34.1,<2.0.dev0 || >=2.11.dev0,<3.0.0dev", extras = ["grpc"]} -google-auth = ">=2.14.1,<2.24.0 || >2.24.0,<2.25.0 || >2.25.0,<3.0.0dev" -proto-plus = ">=1.22.3,<2.0.0dev" -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" +google-api-core = ">=2.15.0,<3.0.0dev" +google-auth = ">=2.26.1,<3.0dev" +google-cloud-core = ">=2.3.0,<3.0dev" +google-crc32c = ">=1.0,<2.0dev" +google-resumable-media = ">=2.6.0" +requests = ">=2.18.0,<3.0.0dev" + +[package.extras] +protobuf = ["protobuf (<5.0.0dev)"] [[package]] name = "google-crc32c" @@ -3343,129 +1552,6 @@ files = [ [package.extras] testing = ["pytest"] -[[package]] -name = "google-re2" -version = "1.1.20240601" -description = "RE2 Python bindings" -optional = false -python-versions = "~=3.8" -files = [ - {file = "google_re2-1.1.20240601-1-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:7f2034ac5fc866b507a9fd8d0419f190d967b5c19dac11292347ab25ca3a5d09"}, - {file = "google_re2-1.1.20240601-1-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:1906dd4a00cb1130eab588a20fa00962e631043bb8ed74474525841730312024"}, - {file = "google_re2-1.1.20240601-1-cp310-cp310-macosx_13_0_arm64.whl", hash = "sha256:88858d1e8855d845590b6199cad9035738de98942fcd9acc26be4de7f076e011"}, - {file = "google_re2-1.1.20240601-1-cp310-cp310-macosx_13_0_x86_64.whl", hash = "sha256:f1b312054643fc705743ebd11b083b32575f4bdf11cbe8fb5d7898e0aabf4969"}, - {file = "google_re2-1.1.20240601-1-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:44dc3d9f085d5c122d9bb2efb5d0a98b1c0b0e8073b57fb77738496f6bf398d7"}, - {file = "google_re2-1.1.20240601-1-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:9f77b0a6ad9e47af3a85fc6f43a7c9316fcd53f04641a73e19d8a15691561773"}, - {file = "google_re2-1.1.20240601-1-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e50cf20b0ec36210d7550fd28a3713cdac4ac8a8cc57d038194de2b9a8749ff"}, - {file = "google_re2-1.1.20240601-1-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ad0775d9114980a0b78d60be778e3c57c2e2e666ac2ce6621b7cc1cf59f89cf9"}, - {file = "google_re2-1.1.20240601-1-cp310-cp310-win32.whl", hash = "sha256:37728529376aeb27b414eba497a70faeed5febf46f1ce06119c34ec6cf7998c8"}, - {file = "google_re2-1.1.20240601-1-cp310-cp310-win_amd64.whl", hash = "sha256:cbb834f68e3a0cbc4ad1a28f6b0b93668ceca9571d2b083e9438128452dd74ca"}, - {file = "google_re2-1.1.20240601-1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:c6a6f8e769b76089d19a3f87be0f64355d85be6519e5a44f8600ab53dc1afa4b"}, - {file = "google_re2-1.1.20240601-1-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:7eafa78ab0fbc915173043b898ed9c74d7d55768503d8b2f4e37a7267585b000"}, - {file = "google_re2-1.1.20240601-1-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:766a3d241b73f2e678e853212ab61c12d23fec54c4f61c636453b7dee97a3f4d"}, - {file = "google_re2-1.1.20240601-2-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:b2633f8db3f6eeaccd52f38fe32690f434e4c41ab1c84735252df11883b1972b"}, - {file = "google_re2-1.1.20240601-2-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:389beabe9244f0008a79b5deedb38eaf3c2ae9259785746d8b8a5579ad46bb71"}, - {file = "google_re2-1.1.20240601-2-cp310-cp310-macosx_13_0_arm64.whl", hash = "sha256:f9ed2a0e92ed79f944d836c533e69ca6e3e9dd85ac7af6f7adf715ee9793e28b"}, - {file = "google_re2-1.1.20240601-2-cp310-cp310-macosx_13_0_x86_64.whl", hash = "sha256:9ec8533a75d4bc8a6d1f6cce3a8489667d6c75e10b64c94f2091ac8eda0d9c26"}, - {file = "google_re2-1.1.20240601-2-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:c73266bd88c8cde2af9b183f03f2b8d52587956138c918d9378e66fbe5315744"}, - {file = "google_re2-1.1.20240601-2-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:68e71346c60486ce9075ea87983c8ab19ec1eae8202dae21e1ba3146ae6a4328"}, - {file = "google_re2-1.1.20240601-2-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:376c62ea5c669bf1cf17e5005f73802265eb5b60ba8dfe239f6acd4f3043a1f8"}, - {file = "google_re2-1.1.20240601-2-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8fe4d50da0db4e63388a9b8222d73f29d6f40cb6188e28d70c4126c96e194d5"}, - {file = "google_re2-1.1.20240601-2-cp310-cp310-win32.whl", hash = "sha256:362a42c407ceae7b76890e8cd40b5428be811282d66e3d962b4181c5c8101c20"}, - {file = "google_re2-1.1.20240601-2-cp310-cp310-win_amd64.whl", hash = "sha256:ae4cce9bd7ec7fc110b6db8dedc43905abf6d3cad357c93dec815e1e6310ef59"}, - {file = "google_re2-1.1.20240601-2-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:67ff76bd1cae55720285a4b1889f42690008101e9b6628d8a84080474dceef23"}, - {file = "google_re2-1.1.20240601-2-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:f44179b03e5047f1ae1eca321d9fffa2841914cc1e8524cde2c25d3feb93eb99"}, - {file = "google_re2-1.1.20240601-2-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:7470e394925926a1b0233dc77971354667292c3c6a75b680952e8242b0ddc6dd"}, - {file = "google_re2-1.1.20240601-2-cp311-cp311-macosx_13_0_x86_64.whl", hash = "sha256:edc1c22fc52561615f9347763c19649568f0d984f6a000e3c954243c662c41a2"}, - {file = "google_re2-1.1.20240601-2-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:625b0ebbcc64dfcd5b7cacf4c68ee5679361cb7b9d0915df262bceca98744760"}, - {file = "google_re2-1.1.20240601-2-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:c40dd618164e285880ce2c56f150fb5fd54d3508ce2fd97b28e503b4e72e8655"}, - {file = "google_re2-1.1.20240601-2-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:363632640c8b95d94c5d563fa14bcba793501dac3fe9f18f25ac13b75265cdfb"}, - {file = "google_re2-1.1.20240601-2-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8e0a5a5b0f153b348bf121ee4ea2ea51bc2bbdd4bec71ff9ec28b3725a28cfbd"}, - {file = "google_re2-1.1.20240601-2-cp311-cp311-win32.whl", hash = "sha256:82b980f6ccfcc23a7c7761be08b49ad6835d8f20f612befb739f28d91fe8290b"}, - {file = "google_re2-1.1.20240601-2-cp311-cp311-win_amd64.whl", hash = "sha256:15d7517727aa3e7d23d6692ca6e44545f09ca8ae7bb3608509ea5729f23179b3"}, - {file = "google_re2-1.1.20240601-2-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:087fca3f81eb9dbd411a24ed4dbe4fdd5f64b10a1db3cfd183527e7044ff5835"}, - {file = "google_re2-1.1.20240601-2-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:c2a52a88819cdcb38fa9124e5e9ede6fd76945ee4bb408d59e78c6e25012d276"}, - {file = "google_re2-1.1.20240601-2-cp312-cp312-macosx_13_0_arm64.whl", hash = "sha256:9c7114b4481deafaba66b236f54c24b35753228afd1b1ca93aa47e8601d037f7"}, - {file = "google_re2-1.1.20240601-2-cp312-cp312-macosx_13_0_x86_64.whl", hash = "sha256:a827b7c8008f5c3b2ae6750a93e5a289bfc52eb66d3db9ca40b6b6ea617ac603"}, - {file = "google_re2-1.1.20240601-2-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:aa067e14de6fdd16a2e4832d07445a8d9ef9f888e616c0b246bd6df81b21b66f"}, - {file = "google_re2-1.1.20240601-2-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:c51f3e66a982927810acb5ad7f2c255595ca67159f3777ab30becf6c39cea9c0"}, - {file = "google_re2-1.1.20240601-2-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ec277e51b45133d32bfdc6f3ef3a7dcbb835da2e33ce3e4622f9ba734e6e12fa"}, - {file = "google_re2-1.1.20240601-2-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:78d9974fb0a7a942277385106dcf887710e3a3c65ce04f21d8e850d8950d5f0e"}, - {file = "google_re2-1.1.20240601-2-cp312-cp312-win32.whl", hash = "sha256:c8189aad330cf21ecf822c618ae4bd6156309bcc2d5bfa46471cf18e518e8a88"}, - {file = "google_re2-1.1.20240601-2-cp312-cp312-win_amd64.whl", hash = "sha256:de31b81ab64a91486240442fcbde367129925eb524c02aaa6afdf02856b300fe"}, - {file = "google_re2-1.1.20240601-2-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:9e2b73edf865a5eb4d7cb9833ae978c535434b0e27303742109f9d4c72006bd4"}, - {file = "google_re2-1.1.20240601-2-cp38-cp38-macosx_12_0_x86_64.whl", hash = "sha256:02b25f81f739d9370280c8e949844dd602a72d0ade914ca62c5a658d0c23a87d"}, - {file = "google_re2-1.1.20240601-2-cp38-cp38-macosx_13_0_arm64.whl", hash = "sha256:c6d61c33ff7754dc6054e3dbae8f7fc85aa925f5a7ae4c07d0668627cbca4657"}, - {file = "google_re2-1.1.20240601-2-cp38-cp38-macosx_13_0_x86_64.whl", hash = "sha256:544cc5421124def304ab442b326e322454906b0348b3416c728c6f88266a4fbb"}, - {file = "google_re2-1.1.20240601-2-cp38-cp38-macosx_14_0_arm64.whl", hash = "sha256:0013ddbbae8d42bd8ab42213c5da3741630eae98b6eca816d72bc77fdda3d356"}, - {file = "google_re2-1.1.20240601-2-cp38-cp38-macosx_14_0_x86_64.whl", hash = "sha256:41638ba091c79af68af29374dc250948ec3c0413012c5a1ba9a0807bb7819641"}, - {file = "google_re2-1.1.20240601-2-cp38-cp38-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:864d16144f2a044107ef0fda304678874483b504605a2f4b53f5c9b01d431cb5"}, - {file = "google_re2-1.1.20240601-2-cp38-cp38-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:48cac1cf44389155e21b601f3d388d9d7cca58d8f45e221a039f877783c48419"}, - {file = "google_re2-1.1.20240601-2-cp38-cp38-win32.whl", hash = "sha256:32757eb4da382a7173da3944d2c9473787b82d76a2a122dc30713f4030c5619e"}, - {file = "google_re2-1.1.20240601-2-cp38-cp38-win_amd64.whl", hash = "sha256:bf58d89749a0dcd689d87a56c8ae8604adbb28ad063ae652f03e074057b00012"}, - {file = "google_re2-1.1.20240601-2-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:6abc7debc08a51810d1d3cd57031f543e50e402c05235eb7e7f1e464442ca637"}, - {file = "google_re2-1.1.20240601-2-cp39-cp39-macosx_12_0_x86_64.whl", hash = "sha256:2f19de42708b11aaa91e14dd05dacb9cdcbe6f9579c9a434757a4b6baea22fd0"}, - {file = "google_re2-1.1.20240601-2-cp39-cp39-macosx_13_0_arm64.whl", hash = "sha256:4c1d4974da79dec3c0b064393d555fb5c185fe29bc30ec4521fa208f5357bcd0"}, - {file = "google_re2-1.1.20240601-2-cp39-cp39-macosx_13_0_x86_64.whl", hash = "sha256:515854058ac39685bd8b3dc7543a702ffe855f701fe6ea99e96ba3152a333420"}, - {file = "google_re2-1.1.20240601-2-cp39-cp39-macosx_14_0_arm64.whl", hash = "sha256:69edab9f90761ed5855e2d05cdfcb7d7dd6411f22d8ff4f6ff57c4836ec0aa49"}, - {file = "google_re2-1.1.20240601-2-cp39-cp39-macosx_14_0_x86_64.whl", hash = "sha256:e3aae4047f2891450f09073c16408a96b214ce63b6d98a58367685d7bdb7df79"}, - {file = "google_re2-1.1.20240601-2-cp39-cp39-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ba3a21de393247ffff3b0b35a1c3916cc486a688626f1baaa8deac6eb4d1a6bd"}, - {file = "google_re2-1.1.20240601-2-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:df08589bdbab42e169adc0d860f0b4cc7a64f576587c2b33ae1f028689c18d71"}, - {file = "google_re2-1.1.20240601-2-cp39-cp39-win32.whl", hash = "sha256:3f639baa417b64afd9f1c9513975ef3b821678046695eed258a833247c1c6fef"}, - {file = "google_re2-1.1.20240601-2-cp39-cp39-win_amd64.whl", hash = "sha256:f6e0093c5832135cba465c3eb01de2472a933222359a30d2f2119123b563f2aa"}, - {file = "google_re2-1.1.20240601-3-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:39867a553b4a521fcb2bccae81130b027b499d229c473e78dfa5ffd3a8b69367"}, - {file = "google_re2-1.1.20240601-3-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:b568f0817ad4ae701ed2ebadaaa306fe4ea848612ebc731f4cda65e22a64686f"}, - {file = "google_re2-1.1.20240601-3-cp310-cp310-macosx_13_0_arm64.whl", hash = "sha256:84c95604371386081fe90cbb1b0e430cfc46a31d5e18fe4dcbb66af1eafae6f3"}, - {file = "google_re2-1.1.20240601-3-cp310-cp310-macosx_13_0_x86_64.whl", hash = "sha256:a44c93eaf651d1b20394d8987bb58b3febcd4be3726438d96146782b031ad9b5"}, - {file = "google_re2-1.1.20240601-3-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:77e17daff9f8b1207264098d48b99448966d16fec2b5dd50689c9526de3419e9"}, - {file = "google_re2-1.1.20240601-3-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:dd70c81ec855d84e0e7af875263d0136a8da8be2f33721f60f74a14db8662d99"}, - {file = "google_re2-1.1.20240601-3-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f58bbde74f4329f9ef5d130a47f1786b9c39fcffba4408171c5f03e6fc80afd6"}, - {file = "google_re2-1.1.20240601-3-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b4388b4d3161e8c7799f425cd894db440ec8ef2046b433b5fe4d97a0f1da708b"}, - {file = "google_re2-1.1.20240601-3-cp310-cp310-win32.whl", hash = "sha256:1325738300c4bc30b22e4db17d6248c2da186b52707f76bd3e2e9fc38718460a"}, - {file = "google_re2-1.1.20240601-3-cp310-cp310-win_amd64.whl", hash = "sha256:68862630d86f9c97268f65dd4b485cb18ab755920d0a878d7846d9f64d3a3a60"}, - {file = "google_re2-1.1.20240601-3-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:a382f6562c0fb7140cc4a276f3ae1de93652a1a337710d7b643ed8ed11bf24d1"}, - {file = "google_re2-1.1.20240601-3-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:c421e929ceb86d954c584868049884cacb43b9388f3488e1029317f4ba9458f8"}, - {file = "google_re2-1.1.20240601-3-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:23cf5b38f57f41f76dec335f4847ab0acc2a58452c6cca67fc516db98e10c8ad"}, - {file = "google_re2-1.1.20240601-3-cp311-cp311-macosx_13_0_x86_64.whl", hash = "sha256:7e7545db6d053a69c5f82a605aabe9e60293ab59d744c206488f3b0da6ce01da"}, - {file = "google_re2-1.1.20240601-3-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:e78ab5ee714c4d912e7c039ac4373d0a1a8dbc08149409db265c8243c01ce852"}, - {file = "google_re2-1.1.20240601-3-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:c9b30c50f202ca1618e24ab70a7afcc5b8686e04f12a3c7f1107a06656b1d636"}, - {file = "google_re2-1.1.20240601-3-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2854f9f8b475d321342dc91f4b6e30848e93bc0db21b93ac6e93769557022cfc"}, - {file = "google_re2-1.1.20240601-3-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3ece158c1bdda0fb0d9a297102dc7420f7658090141a298a2d005357e0a767ce"}, - {file = "google_re2-1.1.20240601-3-cp311-cp311-win32.whl", hash = "sha256:ae34ffecb4e5d5e7a66187da8d8b07fb4f7d850cbfd327f12ed07ed369d9478e"}, - {file = "google_re2-1.1.20240601-3-cp311-cp311-win_amd64.whl", hash = "sha256:ed68a6548ccdf1af6db731bde1b03e453d0ce183d0ec6733bd4a5c153ab9fa03"}, - {file = "google_re2-1.1.20240601-3-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:6680c9f2c8b98195ca346d0df03aa41a42c940b4694ca1b393c4fc387de2ebc2"}, - {file = "google_re2-1.1.20240601-3-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:933e6ada02c26ff14b47abe78ffc74859019b8723f610a1ddc6e33e2bc6d2d79"}, - {file = "google_re2-1.1.20240601-3-cp312-cp312-macosx_13_0_arm64.whl", hash = "sha256:4fd74967dfed3dc3fbf90bb8398eb88f6381f39bf8acd5ea038814605e527c01"}, - {file = "google_re2-1.1.20240601-3-cp312-cp312-macosx_13_0_x86_64.whl", hash = "sha256:50272ba8d5fba4f576c171cab9cd306546121c6155cc525cbf601fb5954dda21"}, - {file = "google_re2-1.1.20240601-3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:83475203103521bd1647adaf7f7592dfc73fad9fbbcfa9756a2dc53ff183ca00"}, - {file = "google_re2-1.1.20240601-3-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:3174d348683751bd13a12cb998fbb47b2302f2fe6c35d0dc9cdaf430442ea266"}, - {file = "google_re2-1.1.20240601-3-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:79f3cac915446aa44d3aec612befb09f8aed5cb834ffa3e21542fe174e8333a6"}, - {file = "google_re2-1.1.20240601-3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c960ddee4416d78d50490da660660499a6e5920a65862e3e9e08ffac7ce957fe"}, - {file = "google_re2-1.1.20240601-3-cp312-cp312-win32.whl", hash = "sha256:7293bd39e8e69310ae5517221313f94ba0cc06fe1248dbfdd03cf98c46746907"}, - {file = "google_re2-1.1.20240601-3-cp312-cp312-win_amd64.whl", hash = "sha256:fb495ac61628b0c8747cb3d4deb0d941f081bcf3d913083475fafd0a4d826582"}, - {file = "google_re2-1.1.20240601-3-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:96f7be3e3a3349c99d51078e6e47e691a91d07b86f2c21e12ec6a069f1d2f58e"}, - {file = "google_re2-1.1.20240601-3-cp38-cp38-macosx_12_0_x86_64.whl", hash = "sha256:1b1789ca35c46318cbb09adb6030fb5e097a67cc2073f483bd67c7ef8de10357"}, - {file = "google_re2-1.1.20240601-3-cp38-cp38-macosx_13_0_arm64.whl", hash = "sha256:9b818d9eae04c595e58e015255a68a1bc6fc19f47d687d24f76dda6dffc8ecc2"}, - {file = "google_re2-1.1.20240601-3-cp38-cp38-macosx_13_0_x86_64.whl", hash = "sha256:f7fa2d737c9968a6738b0b2d06981f02f95b9ca8b9d838c877cbb0f7b1cb4546"}, - {file = "google_re2-1.1.20240601-3-cp38-cp38-macosx_14_0_arm64.whl", hash = "sha256:f03f71abeeb61600027d90c65f6512f0bdea04692e88dd16808014371da4a8ef"}, - {file = "google_re2-1.1.20240601-3-cp38-cp38-macosx_14_0_x86_64.whl", hash = "sha256:985a9b29513a3ed116acaa9abe51fcca28776d27dcd71aa62dbe7c025c6f1761"}, - {file = "google_re2-1.1.20240601-3-cp38-cp38-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:93d6b28ab695d8ca6a8b2889622ad46ad577f9d304379c3aad42ce3dee93fb08"}, - {file = "google_re2-1.1.20240601-3-cp38-cp38-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d76ce0a1c0ad7a9ed9659df582fc60b7c2a9eb2b837e9db57dd44c77bd9a0dd1"}, - {file = "google_re2-1.1.20240601-3-cp38-cp38-win32.whl", hash = "sha256:378daba7d5918d08e2d91ce16f0ae935edbfca739cb31acb699bdb8b40704e8e"}, - {file = "google_re2-1.1.20240601-3-cp38-cp38-win_amd64.whl", hash = "sha256:5719e37dd11b3b5d432439d986a119ea96dc2988908ffe3a493da97f7db5964d"}, - {file = "google_re2-1.1.20240601-3-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:5b56c1686271f7e8762a5e23b76faf2071daa7a74d900474790271be1730e858"}, - {file = "google_re2-1.1.20240601-3-cp39-cp39-macosx_12_0_x86_64.whl", hash = "sha256:f95caca5de4ac6ead5821b5a17e281721662b8eecc37036f42a5fe8741136e47"}, - {file = "google_re2-1.1.20240601-3-cp39-cp39-macosx_13_0_arm64.whl", hash = "sha256:01297cbe44df033adec9d21a2241a7b50efb77bce625f196bf33bc0a87d6906d"}, - {file = "google_re2-1.1.20240601-3-cp39-cp39-macosx_13_0_x86_64.whl", hash = "sha256:c38e71f60ce1de30410790a3036dcb18f0fa3d8fb163218b2e8f4a55342101d1"}, - {file = "google_re2-1.1.20240601-3-cp39-cp39-macosx_14_0_arm64.whl", hash = "sha256:15fa53562218ac897ad1df784cba3625cff2ccfa0f4e18b839ccf1e800e8d335"}, - {file = "google_re2-1.1.20240601-3-cp39-cp39-macosx_14_0_x86_64.whl", hash = "sha256:73ec934dcd803b32b3394b15cccab5017c3a403b137794b73cea2cf31d8b3f2e"}, - {file = "google_re2-1.1.20240601-3-cp39-cp39-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96e74a21304caffbfee0afe5291d3180ec65e9ba28f2ea8a32ad58369e3028dc"}, - {file = "google_re2-1.1.20240601-3-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:22e99029ecea3273fd2213b759aeb01f5b906de2e28d2f4e9316ed2391e9ad40"}, - {file = "google_re2-1.1.20240601-3-cp39-cp39-win32.whl", hash = "sha256:868de13b7cf57710bf3ee9f43dd63332a3ed7880f4e5202771056fc0fa3b8fea"}, - {file = "google_re2-1.1.20240601-3-cp39-cp39-win_amd64.whl", hash = "sha256:52beae3d11b15bd3a13d669c728fd423999a77bf7a8f132425322ba4dbe3c61c"}, - {file = "google_re2-1.1.20240601.tar.gz", hash = "sha256:3187f68855307754d49f398e583853d5b08d783d3fe662f6916b999075f7e095"}, -] - [[package]] name = "google-resumable-media" version = "2.7.1" @@ -3502,77 +1588,6 @@ protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.1 || >4.21.1,<4 [package.extras] grpc = ["grpcio (>=1.44.0,<2.0.0.dev0)"] -[[package]] -name = "greenlet" -version = "3.0.3" -description = "Lightweight in-process concurrent programming" -optional = false -python-versions = ">=3.7" -files = [ - {file = "greenlet-3.0.3-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:9da2bd29ed9e4f15955dd1595ad7bc9320308a3b766ef7f837e23ad4b4aac31a"}, - {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d353cadd6083fdb056bb46ed07e4340b0869c305c8ca54ef9da3421acbdf6881"}, - {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dca1e2f3ca00b84a396bc1bce13dd21f680f035314d2379c4160c98153b2059b"}, - {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3ed7fb269f15dc662787f4119ec300ad0702fa1b19d2135a37c2c4de6fadfd4a"}, - {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd4f49ae60e10adbc94b45c0b5e6a179acc1736cf7a90160b404076ee283cf83"}, - {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:73a411ef564e0e097dbe7e866bb2dda0f027e072b04da387282b02c308807405"}, - {file = "greenlet-3.0.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:7f362975f2d179f9e26928c5b517524e89dd48530a0202570d55ad6ca5d8a56f"}, - {file = "greenlet-3.0.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:649dde7de1a5eceb258f9cb00bdf50e978c9db1b996964cd80703614c86495eb"}, - {file = "greenlet-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:68834da854554926fbedd38c76e60c4a2e3198c6fbed520b106a8986445caaf9"}, - {file = "greenlet-3.0.3-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:b1b5667cced97081bf57b8fa1d6bfca67814b0afd38208d52538316e9422fc61"}, - {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:52f59dd9c96ad2fc0d5724107444f76eb20aaccb675bf825df6435acb7703559"}, - {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:afaff6cf5200befd5cec055b07d1c0a5a06c040fe5ad148abcd11ba6ab9b114e"}, - {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fe754d231288e1e64323cfad462fcee8f0288654c10bdf4f603a39ed923bef33"}, - {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2797aa5aedac23af156bbb5a6aa2cd3427ada2972c828244eb7d1b9255846379"}, - {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b7f009caad047246ed379e1c4dbcb8b020f0a390667ea74d2387be2998f58a22"}, - {file = "greenlet-3.0.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c5e1536de2aad7bf62e27baf79225d0d64360d4168cf2e6becb91baf1ed074f3"}, - {file = "greenlet-3.0.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:894393ce10ceac937e56ec00bb71c4c2f8209ad516e96033e4b3b1de270e200d"}, - {file = "greenlet-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:1ea188d4f49089fc6fb283845ab18a2518d279c7cd9da1065d7a84e991748728"}, - {file = "greenlet-3.0.3-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:70fb482fdf2c707765ab5f0b6655e9cfcf3780d8d87355a063547b41177599be"}, - {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4d1ac74f5c0c0524e4a24335350edad7e5f03b9532da7ea4d3c54d527784f2e"}, - {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:149e94a2dd82d19838fe4b2259f1b6b9957d5ba1b25640d2380bea9c5df37676"}, - {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:15d79dd26056573940fcb8c7413d84118086f2ec1a8acdfa854631084393efcc"}, - {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:881b7db1ebff4ba09aaaeae6aa491daeb226c8150fc20e836ad00041bcb11230"}, - {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fcd2469d6a2cf298f198f0487e0a5b1a47a42ca0fa4dfd1b6862c999f018ebbf"}, - {file = "greenlet-3.0.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1f672519db1796ca0d8753f9e78ec02355e862d0998193038c7073045899f305"}, - {file = "greenlet-3.0.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2516a9957eed41dd8f1ec0c604f1cdc86758b587d964668b5b196a9db5bfcde6"}, - {file = "greenlet-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:bba5387a6975598857d86de9eac14210a49d554a77eb8261cc68b7d082f78ce2"}, - {file = "greenlet-3.0.3-cp37-cp37m-macosx_11_0_universal2.whl", hash = "sha256:5b51e85cb5ceda94e79d019ed36b35386e8c37d22f07d6a751cb659b180d5274"}, - {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:daf3cb43b7cf2ba96d614252ce1684c1bccee6b2183a01328c98d36fcd7d5cb0"}, - {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99bf650dc5d69546e076f413a87481ee1d2d09aaaaaca058c9251b6d8c14783f"}, - {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2dd6e660effd852586b6a8478a1d244b8dc90ab5b1321751d2ea15deb49ed414"}, - {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e3391d1e16e2a5a1507d83e4a8b100f4ee626e8eca43cf2cadb543de69827c4c"}, - {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e1f145462f1fa6e4a4ae3c0f782e580ce44d57c8f2c7aae1b6fa88c0b2efdb41"}, - {file = "greenlet-3.0.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:1a7191e42732df52cb5f39d3527217e7ab73cae2cb3694d241e18f53d84ea9a7"}, - {file = "greenlet-3.0.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:0448abc479fab28b00cb472d278828b3ccca164531daab4e970a0458786055d6"}, - {file = "greenlet-3.0.3-cp37-cp37m-win32.whl", hash = "sha256:b542be2440edc2d48547b5923c408cbe0fc94afb9f18741faa6ae970dbcb9b6d"}, - {file = "greenlet-3.0.3-cp37-cp37m-win_amd64.whl", hash = "sha256:01bc7ea167cf943b4c802068e178bbf70ae2e8c080467070d01bfa02f337ee67"}, - {file = "greenlet-3.0.3-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:1996cb9306c8595335bb157d133daf5cf9f693ef413e7673cb07e3e5871379ca"}, - {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ddc0f794e6ad661e321caa8d2f0a55ce01213c74722587256fb6566049a8b04"}, - {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c9db1c18f0eaad2f804728c67d6c610778456e3e1cc4ab4bbd5eeb8e6053c6fc"}, - {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7170375bcc99f1a2fbd9c306f5be8764eaf3ac6b5cb968862cad4c7057756506"}, - {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b66c9c1e7ccabad3a7d037b2bcb740122a7b17a53734b7d72a344ce39882a1b"}, - {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:098d86f528c855ead3479afe84b49242e174ed262456c342d70fc7f972bc13c4"}, - {file = "greenlet-3.0.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:81bb9c6d52e8321f09c3d165b2a78c680506d9af285bfccbad9fb7ad5a5da3e5"}, - {file = "greenlet-3.0.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fd096eb7ffef17c456cfa587523c5f92321ae02427ff955bebe9e3c63bc9f0da"}, - {file = "greenlet-3.0.3-cp38-cp38-win32.whl", hash = "sha256:d46677c85c5ba00a9cb6f7a00b2bfa6f812192d2c9f7d9c4f6a55b60216712f3"}, - {file = "greenlet-3.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:419b386f84949bf0e7c73e6032e3457b82a787c1ab4a0e43732898a761cc9dbf"}, - {file = "greenlet-3.0.3-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:da70d4d51c8b306bb7a031d5cff6cc25ad253affe89b70352af5f1cb68e74b53"}, - {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:086152f8fbc5955df88382e8a75984e2bb1c892ad2e3c80a2508954e52295257"}, - {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d73a9fe764d77f87f8ec26a0c85144d6a951a6c438dfe50487df5595c6373eac"}, - {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7dcbe92cc99f08c8dd11f930de4d99ef756c3591a5377d1d9cd7dd5e896da71"}, - {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1551a8195c0d4a68fac7a4325efac0d541b48def35feb49d803674ac32582f61"}, - {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:64d7675ad83578e3fc149b617a444fab8efdafc9385471f868eb5ff83e446b8b"}, - {file = "greenlet-3.0.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b37eef18ea55f2ffd8f00ff8fe7c8d3818abd3e25fb73fae2ca3b672e333a7a6"}, - {file = "greenlet-3.0.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:77457465d89b8263bca14759d7c1684df840b6811b2499838cc5b040a8b5b113"}, - {file = "greenlet-3.0.3-cp39-cp39-win32.whl", hash = "sha256:57e8974f23e47dac22b83436bdcf23080ade568ce77df33159e019d161ce1d1e"}, - {file = "greenlet-3.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:c5ee858cfe08f34712f548c3c363e807e7186f03ad7a5039ebadb29e8c6be067"}, - {file = "greenlet-3.0.3.tar.gz", hash = "sha256:43374442353259554ce33599da8b692d5aa96f8976d567d4badf263371fbe491"}, -] - -[package.extras] -docs = ["Sphinx", "furo"] -test = ["objgraph", "psutil"] - [[package]] name = "griffe" version = "0.47.0" @@ -3603,23 +1618,6 @@ googleapis-common-protos = {version = ">=1.56.0,<2.0.0dev", extras = ["grpc"]} grpcio = ">=1.44.0,<2.0.0dev" protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" -[[package]] -name = "grpc-interceptor" -version = "0.15.4" -description = "Simplifies gRPC interceptors" -optional = false -python-versions = ">=3.7,<4.0" -files = [ - {file = "grpc-interceptor-0.15.4.tar.gz", hash = "sha256:1f45c0bcb58b6f332f37c637632247c9b02bc6af0fdceb7ba7ce8d2ebbfb0926"}, - {file = "grpc_interceptor-0.15.4-py3-none-any.whl", hash = "sha256:0035f33228693ed3767ee49d937bac424318db173fef4d2d0170b3215f254d9d"}, -] - -[package.dependencies] -grpcio = ">=1.49.1,<2.0.0" - -[package.extras] -testing = ["protobuf (>=4.21.9)"] - [[package]] name = "grpcio" version = "1.64.1" @@ -3678,20 +1676,6 @@ files = [ [package.extras] protobuf = ["grpcio-tools (>=1.64.1)"] -[[package]] -name = "grpcio-gcp" -version = "0.2.2" -description = "gRPC extensions for Google Cloud Platform" -optional = false -python-versions = "*" -files = [ - {file = "grpcio-gcp-0.2.2.tar.gz", hash = "sha256:e292605effc7da39b7a8734c719afb12ec4b5362add3528d8afad3aa3aa9057c"}, - {file = "grpcio_gcp-0.2.2-py2.py3-none-any.whl", hash = "sha256:1ef8e8531eab11356a3eb4c5b84e79e0d923d6782d19e1b1a45e1cabe4e783d7"}, -] - -[package.dependencies] -grpcio = ">=1.12.0" - [[package]] name = "grpcio-status" version = "1.48.2" @@ -3708,38 +1692,6 @@ googleapis-common-protos = ">=1.5.5" grpcio = ">=1.48.2" protobuf = ">=3.12.0" -[[package]] -name = "gunicorn" -version = "22.0.0" -description = "WSGI HTTP Server for UNIX" -optional = false -python-versions = ">=3.7" -files = [ - {file = "gunicorn-22.0.0-py3-none-any.whl", hash = "sha256:350679f91b24062c86e386e198a15438d53a7a8207235a78ba1b53df4c4378d9"}, - {file = "gunicorn-22.0.0.tar.gz", hash = "sha256:4a0b436239ff76fb33f11c07a16482c521a7e09c1ce3cc293c2330afe01bec63"}, -] - -[package.dependencies] -packaging = "*" - -[package.extras] -eventlet = ["eventlet (>=0.24.1,!=0.36.0)"] -gevent = ["gevent (>=1.4.0)"] -setproctitle = ["setproctitle"] -testing = ["coverage", "eventlet", "gevent", "pytest", "pytest-cov"] -tornado = ["tornado (>=0.2)"] - -[[package]] -name = "h11" -version = "0.14.0" -description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" -optional = false -python-versions = ">=3.7" -files = [ - {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, - {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, -] - [[package]] name = "hail" version = "0.2.127" @@ -3787,65 +1739,6 @@ tabulate = ">=0.8.9,<1" typer = ">=0.9.0,<1" uvloop = {version = ">=0.19.0,<1", markers = "sys_platform != \"win32\""} -[[package]] -name = "httpcore" -version = "1.0.5" -description = "A minimal low-level HTTP client." -optional = false -python-versions = ">=3.8" -files = [ - {file = "httpcore-1.0.5-py3-none-any.whl", hash = "sha256:421f18bac248b25d310f3cacd198d55b8e6125c107797b609ff9b7a6ba7991b5"}, - {file = "httpcore-1.0.5.tar.gz", hash = "sha256:34a38e2f9291467ee3b44e89dd52615370e152954ba21721378a87b2960f7a61"}, -] - -[package.dependencies] -certifi = "*" -h11 = ">=0.13,<0.15" - -[package.extras] -asyncio = ["anyio (>=4.0,<5.0)"] -http2 = ["h2 (>=3,<5)"] -socks = ["socksio (==1.*)"] -trio = ["trio (>=0.22.0,<0.26.0)"] - -[[package]] -name = "httplib2" -version = "0.22.0" -description = "A comprehensive HTTP client library." -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -files = [ - {file = "httplib2-0.22.0-py3-none-any.whl", hash = "sha256:14ae0a53c1ba8f3d37e9e27cf37eabb0fb9980f435ba405d546948b009dd64dc"}, - {file = "httplib2-0.22.0.tar.gz", hash = "sha256:d7a10bc5ef5ab08322488bde8c726eeee5c8618723fdb399597ec58f3d82df81"}, -] - -[package.dependencies] -pyparsing = {version = ">=2.4.2,<3.0.0 || >3.0.0,<3.0.1 || >3.0.1,<3.0.2 || >3.0.2,<3.0.3 || >3.0.3,<4", markers = "python_version > \"3.0\""} - -[[package]] -name = "httpx" -version = "0.27.0" -description = "The next generation HTTP client." -optional = false -python-versions = ">=3.8" -files = [ - {file = "httpx-0.27.0-py3-none-any.whl", hash = "sha256:71d5465162c13681bff01ad59b2cc68dd838ea1f10e51574bac27103f00c91a5"}, - {file = "httpx-0.27.0.tar.gz", hash = "sha256:a0cb88a46f32dc874e04ee956e4c2764aba2aa228f650b06788ba6bda2962ab5"}, -] - -[package.dependencies] -anyio = "*" -certifi = "*" -httpcore = "==1.*" -idna = "*" -sniffio = "*" - -[package.extras] -brotli = ["brotli", "brotlicffi"] -cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] -http2 = ["h2 (>=3,<5)"] -socks = ["socksio (==1.*)"] - [[package]] name = "huggingface-hub" version = "0.23.4" @@ -3918,66 +1811,21 @@ optional = false python-versions = ">=3.8" files = [ {file = "identify-2.5.36-py2.py3-none-any.whl", hash = "sha256:37d93f380f4de590500d9dba7db359d0d3da95ffe7f9de1753faa159e71e7dfa"}, - {file = "identify-2.5.36.tar.gz", hash = "sha256:e5e00f54165f9047fbebeb4a560f9acfb8af4c88232be60a488e9b68d122745d"}, -] - -[package.extras] -license = ["ukkonen"] - -[[package]] -name = "idna" -version = "3.7" -description = "Internationalized Domain Names in Applications (IDNA)" -optional = false -python-versions = ">=3.5" -files = [ - {file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"}, - {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"}, -] - -[[package]] -name = "importlib-metadata" -version = "7.1.0" -description = "Read metadata from Python packages" -optional = false -python-versions = ">=3.8" -files = [ - {file = "importlib_metadata-7.1.0-py3-none-any.whl", hash = "sha256:30962b96c0c223483ed6cc7280e7f0199feb01a0e40cfae4d4450fc6fab1f570"}, - {file = "importlib_metadata-7.1.0.tar.gz", hash = "sha256:b78938b926ee8d5f020fc4772d487045805a55ddbad2ecf21c6d60938dc7fcd2"}, -] - -[package.dependencies] -zipp = ">=0.5" - -[package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -perf = ["ipython"] -testing = ["flufl.flake8", "importlib-resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-perf (>=0.9.2)", "pytest-ruff (>=0.2.1)"] - -[[package]] -name = "importlib-resources" -version = "6.4.0" -description = "Read resources from Python packages" -optional = false -python-versions = ">=3.8" -files = [ - {file = "importlib_resources-6.4.0-py3-none-any.whl", hash = "sha256:50d10f043df931902d4194ea07ec57960f66a80449ff867bfe782b4c486ba78c"}, - {file = "importlib_resources-6.4.0.tar.gz", hash = "sha256:cdb2b453b8046ca4e3798eb1d84f3cce1446a0e8e7b5ef4efb600f19fc398145"}, + {file = "identify-2.5.36.tar.gz", hash = "sha256:e5e00f54165f9047fbebeb4a560f9acfb8af4c88232be60a488e9b68d122745d"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["jaraco.test (>=5.4)", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)", "zipp (>=3.17)"] +license = ["ukkonen"] [[package]] -name = "inflection" -version = "0.5.1" -description = "A port of Ruby on Rails inflector to Python" +name = "idna" +version = "3.7" +description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.5" files = [ - {file = "inflection-0.5.1-py2.py3-none-any.whl", hash = "sha256:f38b2b640938a4f35ade69ac3d053042959b62a0f1076a5bbaa1b9526605a8a2"}, - {file = "inflection-0.5.1.tar.gz", hash = "sha256:1a29730d366e996aaacffb2f1f1cb9593dc38e2ddd30c91250c6dde09ea9b417"}, + {file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"}, + {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"}, ] [[package]] @@ -4115,17 +1963,6 @@ files = [ [package.extras] colors = ["colorama (>=0.4.6)"] -[[package]] -name = "itsdangerous" -version = "2.2.0" -description = "Safely pass data to untrusted environments and back." -optional = false -python-versions = ">=3.8" -files = [ - {file = "itsdangerous-2.2.0-py3-none-any.whl", hash = "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef"}, - {file = "itsdangerous-2.2.0.tar.gz", hash = "sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173"}, -] - [[package]] name = "janus" version = "1.0.0" @@ -4212,51 +2049,6 @@ files = [ [package.dependencies] six = ">=1.13,<2.0" -[[package]] -name = "json-merge-patch" -version = "0.2" -description = "JSON Merge Patch library (https://tools.ietf.org/html/rfc7386)" -optional = false -python-versions = "*" -files = [ - {file = "json-merge-patch-0.2.tar.gz", hash = "sha256:09898b6d427c08754e2a97c709cf2dfd7e28bd10c5683a538914975eab778d39"}, -] - -[[package]] -name = "jsonschema" -version = "4.22.0" -description = "An implementation of JSON Schema validation for Python" -optional = false -python-versions = ">=3.8" -files = [ - {file = "jsonschema-4.22.0-py3-none-any.whl", hash = "sha256:ff4cfd6b1367a40e7bc6411caec72effadd3db0bbe5017de188f2d6108335802"}, - {file = "jsonschema-4.22.0.tar.gz", hash = "sha256:5b22d434a45935119af990552c862e5d6d564e8f6601206b305a61fdf661a2b7"}, -] - -[package.dependencies] -attrs = ">=22.2.0" -jsonschema-specifications = ">=2023.03.6" -referencing = ">=0.28.4" -rpds-py = ">=0.7.1" - -[package.extras] -format = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3987", "uri-template", "webcolors (>=1.11)"] -format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "uri-template", "webcolors (>=1.11)"] - -[[package]] -name = "jsonschema-specifications" -version = "2023.12.1" -description = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry" -optional = false -python-versions = ">=3.8" -files = [ - {file = "jsonschema_specifications-2023.12.1-py3-none-any.whl", hash = "sha256:87e4fdf3a94858b8a2ba2778d9ba57d8a9cafca7c7489c46ba0d30a8bc6a9c3c"}, - {file = "jsonschema_specifications-2023.12.1.tar.gz", hash = "sha256:48a76787b3e70f5ed53f1160d2b81f586e4ca6d1548c5de7085d1682674764cc"}, -] - -[package.dependencies] -referencing = ">=0.31.0" - [[package]] name = "jupyter-client" version = "8.6.2" @@ -4299,129 +2091,6 @@ traitlets = ">=5.3" docs = ["myst-parser", "pydata-sphinx-theme", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-spelling", "traitlets"] test = ["ipykernel", "pre-commit", "pytest (<8)", "pytest-cov", "pytest-timeout"] -[[package]] -name = "lazy-object-proxy" -version = "1.10.0" -description = "A fast and thorough lazy object proxy." -optional = false -python-versions = ">=3.8" -files = [ - {file = "lazy-object-proxy-1.10.0.tar.gz", hash = "sha256:78247b6d45f43a52ef35c25b5581459e85117225408a4128a3daf8bf9648ac69"}, - {file = "lazy_object_proxy-1.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:855e068b0358ab916454464a884779c7ffa312b8925c6f7401e952dcf3b89977"}, - {file = "lazy_object_proxy-1.10.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ab7004cf2e59f7c2e4345604a3e6ea0d92ac44e1c2375527d56492014e690c3"}, - {file = "lazy_object_proxy-1.10.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc0d2fc424e54c70c4bc06787e4072c4f3b1aa2f897dfdc34ce1013cf3ceef05"}, - {file = "lazy_object_proxy-1.10.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e2adb09778797da09d2b5ebdbceebf7dd32e2c96f79da9052b2e87b6ea495895"}, - {file = "lazy_object_proxy-1.10.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b1f711e2c6dcd4edd372cf5dec5c5a30d23bba06ee012093267b3376c079ec83"}, - {file = "lazy_object_proxy-1.10.0-cp310-cp310-win32.whl", hash = "sha256:76a095cfe6045c7d0ca77db9934e8f7b71b14645f0094ffcd842349ada5c5fb9"}, - {file = "lazy_object_proxy-1.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:b4f87d4ed9064b2628da63830986c3d2dca7501e6018347798313fcf028e2fd4"}, - {file = "lazy_object_proxy-1.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:fec03caabbc6b59ea4a638bee5fce7117be8e99a4103d9d5ad77f15d6f81020c"}, - {file = "lazy_object_proxy-1.10.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:02c83f957782cbbe8136bee26416686a6ae998c7b6191711a04da776dc9e47d4"}, - {file = "lazy_object_proxy-1.10.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:009e6bb1f1935a62889ddc8541514b6a9e1fcf302667dcb049a0be5c8f613e56"}, - {file = "lazy_object_proxy-1.10.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:75fc59fc450050b1b3c203c35020bc41bd2695ed692a392924c6ce180c6f1dc9"}, - {file = "lazy_object_proxy-1.10.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:782e2c9b2aab1708ffb07d4bf377d12901d7a1d99e5e410d648d892f8967ab1f"}, - {file = "lazy_object_proxy-1.10.0-cp311-cp311-win32.whl", hash = "sha256:edb45bb8278574710e68a6b021599a10ce730d156e5b254941754a9cc0b17d03"}, - {file = "lazy_object_proxy-1.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:e271058822765ad5e3bca7f05f2ace0de58a3f4e62045a8c90a0dfd2f8ad8cc6"}, - {file = "lazy_object_proxy-1.10.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:e98c8af98d5707dcdecc9ab0863c0ea6e88545d42ca7c3feffb6b4d1e370c7ba"}, - {file = "lazy_object_proxy-1.10.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:952c81d415b9b80ea261d2372d2a4a2332a3890c2b83e0535f263ddfe43f0d43"}, - {file = "lazy_object_proxy-1.10.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80b39d3a151309efc8cc48675918891b865bdf742a8616a337cb0090791a0de9"}, - {file = "lazy_object_proxy-1.10.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:e221060b701e2aa2ea991542900dd13907a5c90fa80e199dbf5a03359019e7a3"}, - {file = "lazy_object_proxy-1.10.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:92f09ff65ecff3108e56526f9e2481b8116c0b9e1425325e13245abfd79bdb1b"}, - {file = "lazy_object_proxy-1.10.0-cp312-cp312-win32.whl", hash = "sha256:3ad54b9ddbe20ae9f7c1b29e52f123120772b06dbb18ec6be9101369d63a4074"}, - {file = "lazy_object_proxy-1.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:127a789c75151db6af398b8972178afe6bda7d6f68730c057fbbc2e96b08d282"}, - {file = "lazy_object_proxy-1.10.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9e4ed0518a14dd26092614412936920ad081a424bdcb54cc13349a8e2c6d106a"}, - {file = "lazy_object_proxy-1.10.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ad9e6ed739285919aa9661a5bbed0aaf410aa60231373c5579c6b4801bd883c"}, - {file = "lazy_object_proxy-1.10.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2fc0a92c02fa1ca1e84fc60fa258458e5bf89d90a1ddaeb8ed9cc3147f417255"}, - {file = "lazy_object_proxy-1.10.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:0aefc7591920bbd360d57ea03c995cebc204b424524a5bd78406f6e1b8b2a5d8"}, - {file = "lazy_object_proxy-1.10.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5faf03a7d8942bb4476e3b62fd0f4cf94eaf4618e304a19865abf89a35c0bbee"}, - {file = "lazy_object_proxy-1.10.0-cp38-cp38-win32.whl", hash = "sha256:e333e2324307a7b5d86adfa835bb500ee70bfcd1447384a822e96495796b0ca4"}, - {file = "lazy_object_proxy-1.10.0-cp38-cp38-win_amd64.whl", hash = "sha256:cb73507defd385b7705c599a94474b1d5222a508e502553ef94114a143ec6696"}, - {file = "lazy_object_proxy-1.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:366c32fe5355ef5fc8a232c5436f4cc66e9d3e8967c01fb2e6302fd6627e3d94"}, - {file = "lazy_object_proxy-1.10.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2297f08f08a2bb0d32a4265e98a006643cd7233fb7983032bd61ac7a02956b3b"}, - {file = "lazy_object_proxy-1.10.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18dd842b49456aaa9a7cf535b04ca4571a302ff72ed8740d06b5adcd41fe0757"}, - {file = "lazy_object_proxy-1.10.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:217138197c170a2a74ca0e05bddcd5f1796c735c37d0eee33e43259b192aa424"}, - {file = "lazy_object_proxy-1.10.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9a3a87cf1e133e5b1994144c12ca4aa3d9698517fe1e2ca82977781b16955658"}, - {file = "lazy_object_proxy-1.10.0-cp39-cp39-win32.whl", hash = "sha256:30b339b2a743c5288405aa79a69e706a06e02958eab31859f7f3c04980853b70"}, - {file = "lazy_object_proxy-1.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:a899b10e17743683b293a729d3a11f2f399e8a90c73b089e29f5d0fe3509f0dd"}, - {file = "lazy_object_proxy-1.10.0-pp310.pp311.pp312.pp38.pp39-none-any.whl", hash = "sha256:80fa48bd89c8f2f456fc0765c11c23bf5af827febacd2f523ca5bc1893fcc09d"}, -] - -[[package]] -name = "limits" -version = "3.13.0" -description = "Rate limiting utilities" -optional = false -python-versions = ">=3.8" -files = [ - {file = "limits-3.13.0-py3-none-any.whl", hash = "sha256:9767f7233da4255e9904b79908a728e8ec0984c0b086058b4cbbd309aea553f6"}, - {file = "limits-3.13.0.tar.gz", hash = "sha256:6571b0c567bfa175a35fed9f8a954c0c92f1c3200804282f1b8f1de4ad98a953"}, -] - -[package.dependencies] -deprecated = ">=1.2" -importlib-resources = ">=1.3" -packaging = ">=21,<25" -typing-extensions = "*" - -[package.extras] -all = ["aetcd", "coredis (>=3.4.0,<5)", "emcache (>=0.6.1)", "emcache (>=1)", "etcd3", "motor (>=3,<4)", "pymemcache (>3,<5.0.0)", "pymongo (>4.1,<5)", "redis (>3,!=4.5.2,!=4.5.3,<6.0.0)", "redis (>=4.2.0,!=4.5.2,!=4.5.3)"] -async-etcd = ["aetcd"] -async-memcached = ["emcache (>=0.6.1)", "emcache (>=1)"] -async-mongodb = ["motor (>=3,<4)"] -async-redis = ["coredis (>=3.4.0,<5)"] -etcd = ["etcd3"] -memcached = ["pymemcache (>3,<5.0.0)"] -mongodb = ["pymongo (>4.1,<5)"] -redis = ["redis (>3,!=4.5.2,!=4.5.3,<6.0.0)"] -rediscluster = ["redis (>=4.2.0,!=4.5.2,!=4.5.3)"] - -[[package]] -name = "linkify-it-py" -version = "2.0.3" -description = "Links recognition library with FULL unicode support." -optional = false -python-versions = ">=3.7" -files = [ - {file = "linkify-it-py-2.0.3.tar.gz", hash = "sha256:68cda27e162e9215c17d786649d1da0021a451bdc436ef9e0fa0ba5234b9b048"}, - {file = "linkify_it_py-2.0.3-py3-none-any.whl", hash = "sha256:6bcbc417b0ac14323382aef5c5192c0075bf8a9d6b41820a2b66371eac6b6d79"}, -] - -[package.dependencies] -uc-micro-py = "*" - -[package.extras] -benchmark = ["pytest", "pytest-benchmark"] -dev = ["black", "flake8", "isort", "pre-commit", "pyproject-flake8"] -doc = ["myst-parser", "sphinx", "sphinx-book-theme"] -test = ["coverage", "pytest", "pytest-cov"] - -[[package]] -name = "lockfile" -version = "0.12.2" -description = "Platform-independent file locking module" -optional = false -python-versions = "*" -files = [ - {file = "lockfile-0.12.2-py2.py3-none-any.whl", hash = "sha256:6c3cb24f344923d30b2785d5ad75182c8ea7ac1b6171b08657258ec7429d50fa"}, - {file = "lockfile-0.12.2.tar.gz", hash = "sha256:6aed02de03cba24efabcd600b30540140634fc06cfa603822d508d5361e9f799"}, -] - -[[package]] -name = "looker-sdk" -version = "24.10.0" -description = "Looker REST API" -optional = false -python-versions = ">=3.6" -files = [ - {file = "looker_sdk-24.10.0-py3-none-any.whl", hash = "sha256:26b4c919a0ec81bfa4d9c5eadddfad4c64ae46a20b0f299e7eabe300feaa1842"}, - {file = "looker_sdk-24.10.0.tar.gz", hash = "sha256:a6fe1e47912d10c90dadba0da33150dd694e24d65b84cb149a025ca26e3046cb"}, -] - -[package.dependencies] -attrs = {version = ">=20.1.0", markers = "python_version >= \"3.7\""} -cattrs = {version = ">=1.3", markers = "python_version >= \"3.7\""} -requests = ">=2.22" -typing-extensions = ">=4.1.1" - [[package]] name = "lxml" version = "5.3.0" @@ -4576,25 +2245,6 @@ html5 = ["html5lib"] htmlsoup = ["BeautifulSoup4"] source = ["Cython (>=3.0.11)"] -[[package]] -name = "mako" -version = "1.3.5" -description = "A super-fast templating language that borrows the best ideas from the existing templating languages." -optional = false -python-versions = ">=3.8" -files = [ - {file = "Mako-1.3.5-py3-none-any.whl", hash = "sha256:260f1dbc3a519453a9c856dedfe4beb4e50bd5a26d96386cb6c80856556bb91a"}, - {file = "Mako-1.3.5.tar.gz", hash = "sha256:48dbc20568c1d276a2698b36d968fa76161bf127194907ea6fc594fa81f943bc"}, -] - -[package.dependencies] -MarkupSafe = ">=0.9.2" - -[package.extras] -babel = ["Babel"] -lingua = ["lingua"] -testing = ["pytest"] - [[package]] name = "markdown" version = "3.6" @@ -4610,30 +2260,6 @@ files = [ docs = ["mdx-gh-links (>=0.2)", "mkdocs (>=1.5)", "mkdocs-gen-files", "mkdocs-literate-nav", "mkdocs-nature (>=0.6)", "mkdocs-section-index", "mkdocstrings[python]"] testing = ["coverage", "pyyaml"] -[[package]] -name = "markdown-it-py" -version = "3.0.0" -description = "Python port of markdown-it. Markdown parsing, done right!" -optional = false -python-versions = ">=3.8" -files = [ - {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"}, - {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"}, -] - -[package.dependencies] -mdurl = ">=0.1,<1.0" - -[package.extras] -benchmarking = ["psutil", "pytest", "pytest-benchmark"] -code-style = ["pre-commit (>=3.0,<4.0)"] -compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "mistletoe (>=1.0,<2.0)", "mistune (>=2.0,<3.0)", "panflute (>=2.3,<3.0)"] -linkify = ["linkify-it-py (>=1,<3)"] -plugins = ["mdit-py-plugins"] -profiling = ["gprof2dot"] -rtd = ["jupyter_sphinx", "mdit-py-plugins", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"] -testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] - [[package]] name = "markupsafe" version = "2.1.5" @@ -4703,65 +2329,6 @@ files = [ {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, ] -[[package]] -name = "marshmallow" -version = "3.21.3" -description = "A lightweight library for converting complex datatypes to and from native Python datatypes." -optional = false -python-versions = ">=3.8" -files = [ - {file = "marshmallow-3.21.3-py3-none-any.whl", hash = "sha256:86ce7fb914aa865001a4b2092c4c2872d13bc347f3d42673272cabfdbad386f1"}, - {file = "marshmallow-3.21.3.tar.gz", hash = "sha256:4f57c5e050a54d66361e826f94fba213eb10b67b2fdb02c3e0343ce207ba1662"}, -] - -[package.dependencies] -packaging = ">=17.0" - -[package.extras] -dev = ["marshmallow[tests]", "pre-commit (>=3.5,<4.0)", "tox"] -docs = ["alabaster (==0.7.16)", "autodocsumm (==0.2.12)", "sphinx (==7.3.7)", "sphinx-issues (==4.1.0)", "sphinx-version-warning (==1.1.2)"] -tests = ["pytest", "pytz", "simplejson"] - -[[package]] -name = "marshmallow-oneofschema" -version = "3.1.1" -description = "marshmallow multiplexing schema" -optional = false -python-versions = ">=3.8" -files = [ - {file = "marshmallow_oneofschema-3.1.1-py3-none-any.whl", hash = "sha256:ff4cb2a488785ee8edd521a765682c2c80c78b9dc48894124531bdfa1ec9303b"}, - {file = "marshmallow_oneofschema-3.1.1.tar.gz", hash = "sha256:68b4a57d0281a04ac25d4eb7a4c5865a57090a0a8fd30fd6362c8e833ac6a6d9"}, -] - -[package.dependencies] -marshmallow = ">=3.0.0,<4.0.0" - -[package.extras] -dev = ["marshmallow-oneofschema[tests]", "pre-commit (>=3.5,<4.0)", "tox"] -tests = ["pytest"] - -[[package]] -name = "marshmallow-sqlalchemy" -version = "0.28.2" -description = "SQLAlchemy integration with the marshmallow (de)serialization library" -optional = false -python-versions = ">=3.7" -files = [ - {file = "marshmallow-sqlalchemy-0.28.2.tar.gz", hash = "sha256:2ab0f1280c793e5aec81deab3e63ec23688ddfe05e5f38ac960368a1079520a1"}, - {file = "marshmallow_sqlalchemy-0.28.2-py2.py3-none-any.whl", hash = "sha256:c31b3bdf794de1d78c53e1c495502cbb3eeb06ed216869980c71d6159e7e9e66"}, -] - -[package.dependencies] -marshmallow = ">=3.0.0" -packaging = ">=21.3" -SQLAlchemy = ">=1.3.0,<2.0" - -[package.extras] -dev = ["flake8 (==6.0.0)", "flake8-bugbear (==23.2.13)", "pre-commit (==3.1.0)", "pytest", "pytest-lazy-fixture (>=0.6.2)", "tox"] -docs = ["alabaster (==0.7.13)", "sphinx (==6.1.3)", "sphinx-issues (==3.0.1)"] -lint = ["flake8 (==6.0.0)", "flake8-bugbear (==23.2.13)", "pre-commit (==3.1.0)"] -tests = ["pytest", "pytest-lazy-fixture (>=0.6.2)"] - [[package]] name = "matplotlib-inline" version = "0.1.7" @@ -4787,36 +2354,6 @@ files = [ {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, ] -[[package]] -name = "mdit-py-plugins" -version = "0.4.1" -description = "Collection of plugins for markdown-it-py" -optional = false -python-versions = ">=3.8" -files = [ - {file = "mdit_py_plugins-0.4.1-py3-none-any.whl", hash = "sha256:1020dfe4e6bfc2c79fb49ae4e3f5b297f5ccd20f010187acc52af2921e27dc6a"}, - {file = "mdit_py_plugins-0.4.1.tar.gz", hash = "sha256:834b8ac23d1cd60cec703646ffd22ae97b7955a6d596eb1d304be1e251ae499c"}, -] - -[package.dependencies] -markdown-it-py = ">=1.0.0,<4.0.0" - -[package.extras] -code-style = ["pre-commit"] -rtd = ["myst-parser", "sphinx-book-theme"] -testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] - -[[package]] -name = "mdurl" -version = "0.1.2" -description = "Markdown URL utilities" -optional = false -python-versions = ">=3.7" -files = [ - {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, - {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, -] - [[package]] name = "mergedeep" version = "1.3.4" @@ -4828,24 +2365,6 @@ files = [ {file = "mergedeep-1.3.4.tar.gz", hash = "sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8"}, ] -[[package]] -name = "methodtools" -version = "0.4.7" -description = "Expand standard functools to methods" -optional = false -python-versions = "*" -files = [ - {file = "methodtools-0.4.7-py2.py3-none-any.whl", hash = "sha256:5e188c780b236adc12e75b5f078c5afb419ef99eb648569fc6d7071f053a1f11"}, - {file = "methodtools-0.4.7.tar.gz", hash = "sha256:e213439dd64cfe60213f7015da6efe5dd4003fd89376db3baa09fe13ec2bb0ba"}, -] - -[package.dependencies] -wirerope = ">=0.4.7" - -[package.extras] -doc = ["sphinx"] -test = ["functools32 (>=3.2.3-2)", "pytest (>=4.6.7)", "pytest-cov (>=2.6.1)"] - [[package]] name = "mkdocs" version = "1.6.0" @@ -5079,17 +2598,6 @@ files = [ griffe = ">=0.47" mkdocstrings = ">=0.25" -[[package]] -name = "more-itertools" -version = "10.3.0" -description = "More routines for operating on iterables, beyond itertools" -optional = false -python-versions = ">=3.8" -files = [ - {file = "more-itertools-10.3.0.tar.gz", hash = "sha256:e5d93ef411224fbcef366a6e8ddc4c5781bc6359d43412a65dd5964e46111463"}, - {file = "more_itertools-10.3.0-py3-none-any.whl", hash = "sha256:ea6a02e24a9161e51faad17a8782b92a0df82c12c1c8886fec7f0c3fa1a1b320"}, -] - [[package]] name = "msal" version = "1.29.0" @@ -5415,148 +2923,6 @@ files = [ antlr4-python3-runtime = "==4.9.*" PyYAML = ">=5.1.0" -[[package]] -name = "opentelemetry-api" -version = "1.25.0" -description = "OpenTelemetry Python API" -optional = false -python-versions = ">=3.8" -files = [ - {file = "opentelemetry_api-1.25.0-py3-none-any.whl", hash = "sha256:757fa1aa020a0f8fa139f8959e53dec2051cc26b832e76fa839a6d76ecefd737"}, - {file = "opentelemetry_api-1.25.0.tar.gz", hash = "sha256:77c4985f62f2614e42ce77ee4c9da5fa5f0bc1e1821085e9a47533a9323ae869"}, -] - -[package.dependencies] -deprecated = ">=1.2.6" -importlib-metadata = ">=6.0,<=7.1" - -[[package]] -name = "opentelemetry-exporter-otlp" -version = "1.25.0" -description = "OpenTelemetry Collector Exporters" -optional = false -python-versions = ">=3.8" -files = [ - {file = "opentelemetry_exporter_otlp-1.25.0-py3-none-any.whl", hash = "sha256:d67a831757014a3bc3174e4cd629ae1493b7ba8d189e8a007003cacb9f1a6b60"}, - {file = "opentelemetry_exporter_otlp-1.25.0.tar.gz", hash = "sha256:ce03199c1680a845f82e12c0a6a8f61036048c07ec7a0bd943142aca8fa6ced0"}, -] - -[package.dependencies] -opentelemetry-exporter-otlp-proto-grpc = "1.25.0" -opentelemetry-exporter-otlp-proto-http = "1.25.0" - -[[package]] -name = "opentelemetry-exporter-otlp-proto-common" -version = "1.25.0" -description = "OpenTelemetry Protobuf encoding" -optional = false -python-versions = ">=3.8" -files = [ - {file = "opentelemetry_exporter_otlp_proto_common-1.25.0-py3-none-any.whl", hash = "sha256:15637b7d580c2675f70246563363775b4e6de947871e01d0f4e3881d1848d693"}, - {file = "opentelemetry_exporter_otlp_proto_common-1.25.0.tar.gz", hash = "sha256:c93f4e30da4eee02bacd1e004eb82ce4da143a2f8e15b987a9f603e0a85407d3"}, -] - -[package.dependencies] -opentelemetry-proto = "1.25.0" - -[[package]] -name = "opentelemetry-exporter-otlp-proto-grpc" -version = "1.25.0" -description = "OpenTelemetry Collector Protobuf over gRPC Exporter" -optional = false -python-versions = ">=3.8" -files = [ - {file = "opentelemetry_exporter_otlp_proto_grpc-1.25.0-py3-none-any.whl", hash = "sha256:3131028f0c0a155a64c430ca600fd658e8e37043cb13209f0109db5c1a3e4eb4"}, - {file = "opentelemetry_exporter_otlp_proto_grpc-1.25.0.tar.gz", hash = "sha256:c0b1661415acec5af87625587efa1ccab68b873745ca0ee96b69bb1042087eac"}, -] - -[package.dependencies] -deprecated = ">=1.2.6" -googleapis-common-protos = ">=1.52,<2.0" -grpcio = ">=1.0.0,<2.0.0" -opentelemetry-api = ">=1.15,<2.0" -opentelemetry-exporter-otlp-proto-common = "1.25.0" -opentelemetry-proto = "1.25.0" -opentelemetry-sdk = ">=1.25.0,<1.26.0" - -[[package]] -name = "opentelemetry-exporter-otlp-proto-http" -version = "1.25.0" -description = "OpenTelemetry Collector Protobuf over HTTP Exporter" -optional = false -python-versions = ">=3.8" -files = [ - {file = "opentelemetry_exporter_otlp_proto_http-1.25.0-py3-none-any.whl", hash = "sha256:2eca686ee11b27acd28198b3ea5e5863a53d1266b91cda47c839d95d5e0541a6"}, - {file = "opentelemetry_exporter_otlp_proto_http-1.25.0.tar.gz", hash = "sha256:9f8723859e37c75183ea7afa73a3542f01d0fd274a5b97487ea24cb683d7d684"}, -] - -[package.dependencies] -deprecated = ">=1.2.6" -googleapis-common-protos = ">=1.52,<2.0" -opentelemetry-api = ">=1.15,<2.0" -opentelemetry-exporter-otlp-proto-common = "1.25.0" -opentelemetry-proto = "1.25.0" -opentelemetry-sdk = ">=1.25.0,<1.26.0" -requests = ">=2.7,<3.0" - -[[package]] -name = "opentelemetry-proto" -version = "1.25.0" -description = "OpenTelemetry Python Proto" -optional = false -python-versions = ">=3.8" -files = [ - {file = "opentelemetry_proto-1.25.0-py3-none-any.whl", hash = "sha256:f07e3341c78d835d9b86665903b199893befa5e98866f63d22b00d0b7ca4972f"}, - {file = "opentelemetry_proto-1.25.0.tar.gz", hash = "sha256:35b6ef9dc4a9f7853ecc5006738ad40443701e52c26099e197895cbda8b815a3"}, -] - -[package.dependencies] -protobuf = ">=3.19,<5.0" - -[[package]] -name = "opentelemetry-sdk" -version = "1.25.0" -description = "OpenTelemetry Python SDK" -optional = false -python-versions = ">=3.8" -files = [ - {file = "opentelemetry_sdk-1.25.0-py3-none-any.whl", hash = "sha256:d97ff7ec4b351692e9d5a15af570c693b8715ad78b8aafbec5c7100fe966b4c9"}, - {file = "opentelemetry_sdk-1.25.0.tar.gz", hash = "sha256:ce7fc319c57707ef5bf8b74fb9f8ebdb8bfafbe11898410e0d2a761d08a98ec7"}, -] - -[package.dependencies] -opentelemetry-api = "1.25.0" -opentelemetry-semantic-conventions = "0.46b0" -typing-extensions = ">=3.7.4" - -[[package]] -name = "opentelemetry-semantic-conventions" -version = "0.46b0" -description = "OpenTelemetry Semantic Conventions" -optional = false -python-versions = ">=3.8" -files = [ - {file = "opentelemetry_semantic_conventions-0.46b0-py3-none-any.whl", hash = "sha256:6daef4ef9fa51d51855d9f8e0ccd3a1bd59e0e545abe99ac6203804e36ab3e07"}, - {file = "opentelemetry_semantic_conventions-0.46b0.tar.gz", hash = "sha256:fbc982ecbb6a6e90869b15c1673be90bd18c8a56ff1cffc0864e38e2edffaefa"}, -] - -[package.dependencies] -opentelemetry-api = "1.25.0" - -[[package]] -name = "ordered-set" -version = "4.1.0" -description = "An OrderedSet is a custom MutableSet that remembers its order, so that every" -optional = false -python-versions = ">=3.7" -files = [ - {file = "ordered-set-4.1.0.tar.gz", hash = "sha256:694a8e44c87657c59292ede72891eb91d34131f6531463aab3009191c77364a8"}, - {file = "ordered_set-4.1.0-py3-none-any.whl", hash = "sha256:046e1132c71fcf3330438a539928932caf51ddbc582496833e23de611de14562"}, -] - -[package.extras] -dev = ["black", "mypy", "pytest"] - [[package]] name = "orjson" version = "3.10.5" @@ -5773,105 +3139,6 @@ files = [ {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, ] -[[package]] -name = "pendulum" -version = "3.0.0" -description = "Python datetimes made easy" -optional = false -python-versions = ">=3.8" -files = [ - {file = "pendulum-3.0.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2cf9e53ef11668e07f73190c805dbdf07a1939c3298b78d5a9203a86775d1bfd"}, - {file = "pendulum-3.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fb551b9b5e6059377889d2d878d940fd0bbb80ae4810543db18e6f77b02c5ef6"}, - {file = "pendulum-3.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c58227ac260d5b01fc1025176d7b31858c9f62595737f350d22124a9a3ad82d"}, - {file = "pendulum-3.0.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:60fb6f415fea93a11c52578eaa10594568a6716602be8430b167eb0d730f3332"}, - {file = "pendulum-3.0.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b69f6b4dbcb86f2c2fe696ba991e67347bcf87fe601362a1aba6431454b46bde"}, - {file = "pendulum-3.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:138afa9c373ee450ede206db5a5e9004fd3011b3c6bbe1e57015395cd076a09f"}, - {file = "pendulum-3.0.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:83d9031f39c6da9677164241fd0d37fbfc9dc8ade7043b5d6d62f56e81af8ad2"}, - {file = "pendulum-3.0.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0c2308af4033fa534f089595bcd40a95a39988ce4059ccd3dc6acb9ef14ca44a"}, - {file = "pendulum-3.0.0-cp310-none-win_amd64.whl", hash = "sha256:9a59637cdb8462bdf2dbcb9d389518c0263799189d773ad5c11db6b13064fa79"}, - {file = "pendulum-3.0.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:3725245c0352c95d6ca297193192020d1b0c0f83d5ee6bb09964edc2b5a2d508"}, - {file = "pendulum-3.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6c035f03a3e565ed132927e2c1b691de0dbf4eb53b02a5a3c5a97e1a64e17bec"}, - {file = "pendulum-3.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:597e66e63cbd68dd6d58ac46cb7a92363d2088d37ccde2dae4332ef23e95cd00"}, - {file = "pendulum-3.0.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99a0f8172e19f3f0c0e4ace0ad1595134d5243cf75985dc2233e8f9e8de263ca"}, - {file = "pendulum-3.0.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:77d8839e20f54706aed425bec82a83b4aec74db07f26acd039905d1237a5e1d4"}, - {file = "pendulum-3.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afde30e8146292b059020fbc8b6f8fd4a60ae7c5e6f0afef937bbb24880bdf01"}, - {file = "pendulum-3.0.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:660434a6fcf6303c4efd36713ca9212c753140107ee169a3fc6c49c4711c2a05"}, - {file = "pendulum-3.0.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:dee9e5a48c6999dc1106eb7eea3e3a50e98a50651b72c08a87ee2154e544b33e"}, - {file = "pendulum-3.0.0-cp311-none-win_amd64.whl", hash = "sha256:d4cdecde90aec2d67cebe4042fd2a87a4441cc02152ed7ed8fb3ebb110b94ec4"}, - {file = "pendulum-3.0.0-cp311-none-win_arm64.whl", hash = "sha256:773c3bc4ddda2dda9f1b9d51fe06762f9200f3293d75c4660c19b2614b991d83"}, - {file = "pendulum-3.0.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:409e64e41418c49f973d43a28afe5df1df4f1dd87c41c7c90f1a63f61ae0f1f7"}, - {file = "pendulum-3.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a38ad2121c5ec7c4c190c7334e789c3b4624798859156b138fcc4d92295835dc"}, - {file = "pendulum-3.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fde4d0b2024b9785f66b7f30ed59281bd60d63d9213cda0eb0910ead777f6d37"}, - {file = "pendulum-3.0.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4b2c5675769fb6d4c11238132962939b960fcb365436b6d623c5864287faa319"}, - {file = "pendulum-3.0.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8af95e03e066826f0f4c65811cbee1b3123d4a45a1c3a2b4fc23c4b0dff893b5"}, - {file = "pendulum-3.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2165a8f33cb15e06c67070b8afc87a62b85c5a273e3aaa6bc9d15c93a4920d6f"}, - {file = "pendulum-3.0.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ad5e65b874b5e56bd942546ea7ba9dd1d6a25121db1c517700f1c9de91b28518"}, - {file = "pendulum-3.0.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:17fe4b2c844bbf5f0ece69cfd959fa02957c61317b2161763950d88fed8e13b9"}, - {file = "pendulum-3.0.0-cp312-none-win_amd64.whl", hash = "sha256:78f8f4e7efe5066aca24a7a57511b9c2119f5c2b5eb81c46ff9222ce11e0a7a5"}, - {file = "pendulum-3.0.0-cp312-none-win_arm64.whl", hash = "sha256:28f49d8d1e32aae9c284a90b6bb3873eee15ec6e1d9042edd611b22a94ac462f"}, - {file = "pendulum-3.0.0-cp37-cp37m-macosx_10_12_x86_64.whl", hash = "sha256:d4e2512f4e1a4670284a153b214db9719eb5d14ac55ada5b76cbdb8c5c00399d"}, - {file = "pendulum-3.0.0-cp37-cp37m-macosx_11_0_arm64.whl", hash = "sha256:3d897eb50883cc58d9b92f6405245f84b9286cd2de6e8694cb9ea5cb15195a32"}, - {file = "pendulum-3.0.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e169cc2ca419517f397811bbe4589cf3cd13fca6dc38bb352ba15ea90739ebb"}, - {file = "pendulum-3.0.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f17c3084a4524ebefd9255513692f7e7360e23c8853dc6f10c64cc184e1217ab"}, - {file = "pendulum-3.0.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:826d6e258052715f64d05ae0fc9040c0151e6a87aae7c109ba9a0ed930ce4000"}, - {file = "pendulum-3.0.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2aae97087872ef152a0c40e06100b3665d8cb86b59bc8471ca7c26132fccd0f"}, - {file = "pendulum-3.0.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:ac65eeec2250d03106b5e81284ad47f0d417ca299a45e89ccc69e36130ca8bc7"}, - {file = "pendulum-3.0.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a5346d08f3f4a6e9e672187faa179c7bf9227897081d7121866358af369f44f9"}, - {file = "pendulum-3.0.0-cp37-none-win_amd64.whl", hash = "sha256:235d64e87946d8f95c796af34818c76e0f88c94d624c268693c85b723b698aa9"}, - {file = "pendulum-3.0.0-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:6a881d9c2a7f85bc9adafcfe671df5207f51f5715ae61f5d838b77a1356e8b7b"}, - {file = "pendulum-3.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d7762d2076b9b1cb718a6631ad6c16c23fc3fac76cbb8c454e81e80be98daa34"}, - {file = "pendulum-3.0.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e8e36a8130819d97a479a0e7bf379b66b3b1b520e5dc46bd7eb14634338df8c"}, - {file = "pendulum-3.0.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7dc843253ac373358ffc0711960e2dd5b94ab67530a3e204d85c6e8cb2c5fa10"}, - {file = "pendulum-3.0.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0a78ad3635d609ceb1e97d6aedef6a6a6f93433ddb2312888e668365908c7120"}, - {file = "pendulum-3.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b30a137e9e0d1f751e60e67d11fc67781a572db76b2296f7b4d44554761049d6"}, - {file = "pendulum-3.0.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:c95984037987f4a457bb760455d9ca80467be792236b69d0084f228a8ada0162"}, - {file = "pendulum-3.0.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d29c6e578fe0f893766c0d286adbf0b3c726a4e2341eba0917ec79c50274ec16"}, - {file = "pendulum-3.0.0-cp38-none-win_amd64.whl", hash = "sha256:deaba8e16dbfcb3d7a6b5fabdd5a38b7c982809567479987b9c89572df62e027"}, - {file = "pendulum-3.0.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:b11aceea5b20b4b5382962b321dbc354af0defe35daa84e9ff3aae3c230df694"}, - {file = "pendulum-3.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a90d4d504e82ad236afac9adca4d6a19e4865f717034fc69bafb112c320dcc8f"}, - {file = "pendulum-3.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:825799c6b66e3734227756fa746cc34b3549c48693325b8b9f823cb7d21b19ac"}, - {file = "pendulum-3.0.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad769e98dc07972e24afe0cff8d365cb6f0ebc7e65620aa1976fcfbcadc4c6f3"}, - {file = "pendulum-3.0.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6fc26907eb5fb8cc6188cc620bc2075a6c534d981a2f045daa5f79dfe50d512"}, - {file = "pendulum-3.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c717eab1b6d898c00a3e0fa7781d615b5c5136bbd40abe82be100bb06df7a56"}, - {file = "pendulum-3.0.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:3ddd1d66d1a714ce43acfe337190be055cdc221d911fc886d5a3aae28e14b76d"}, - {file = "pendulum-3.0.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:822172853d7a9cf6da95d7b66a16c7160cb99ae6df55d44373888181d7a06edc"}, - {file = "pendulum-3.0.0-cp39-none-win_amd64.whl", hash = "sha256:840de1b49cf1ec54c225a2a6f4f0784d50bd47f68e41dc005b7f67c7d5b5f3ae"}, - {file = "pendulum-3.0.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:3b1f74d1e6ffe5d01d6023870e2ce5c2191486928823196f8575dcc786e107b1"}, - {file = "pendulum-3.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:729e9f93756a2cdfa77d0fc82068346e9731c7e884097160603872686e570f07"}, - {file = "pendulum-3.0.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e586acc0b450cd21cbf0db6bae386237011b75260a3adceddc4be15334689a9a"}, - {file = "pendulum-3.0.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22e7944ffc1f0099a79ff468ee9630c73f8c7835cd76fdb57ef7320e6a409df4"}, - {file = "pendulum-3.0.0-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:fa30af36bd8e50686846bdace37cf6707bdd044e5cb6e1109acbad3277232e04"}, - {file = "pendulum-3.0.0-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:440215347b11914ae707981b9a57ab9c7b6983ab0babde07063c6ee75c0dc6e7"}, - {file = "pendulum-3.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:314c4038dc5e6a52991570f50edb2f08c339debdf8cea68ac355b32c4174e820"}, - {file = "pendulum-3.0.0-pp37-pypy37_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5acb1d386337415f74f4d1955c4ce8d0201978c162927d07df8eb0692b2d8533"}, - {file = "pendulum-3.0.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a789e12fbdefaffb7b8ac67f9d8f22ba17a3050ceaaa635cd1cc4645773a4b1e"}, - {file = "pendulum-3.0.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:860aa9b8a888e5913bd70d819306749e5eb488e6b99cd6c47beb701b22bdecf5"}, - {file = "pendulum-3.0.0-pp37-pypy37_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:5ebc65ea033ef0281368217fbf59f5cb05b338ac4dd23d60959c7afcd79a60a0"}, - {file = "pendulum-3.0.0-pp37-pypy37_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:d9fef18ab0386ef6a9ac7bad7e43ded42c83ff7ad412f950633854f90d59afa8"}, - {file = "pendulum-3.0.0-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:1c134ba2f0571d0b68b83f6972e2307a55a5a849e7dac8505c715c531d2a8795"}, - {file = "pendulum-3.0.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:385680812e7e18af200bb9b4a49777418c32422d05ad5a8eb85144c4a285907b"}, - {file = "pendulum-3.0.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9eec91cd87c59fb32ec49eb722f375bd58f4be790cae11c1b70fac3ee4f00da0"}, - {file = "pendulum-3.0.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4386bffeca23c4b69ad50a36211f75b35a4deb6210bdca112ac3043deb7e494a"}, - {file = "pendulum-3.0.0-pp38-pypy38_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:dfbcf1661d7146d7698da4b86e7f04814221081e9fe154183e34f4c5f5fa3bf8"}, - {file = "pendulum-3.0.0-pp38-pypy38_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:04a1094a5aa1daa34a6b57c865b25f691848c61583fb22722a4df5699f6bf74c"}, - {file = "pendulum-3.0.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:5b0ec85b9045bd49dd3a3493a5e7ddfd31c36a2a60da387c419fa04abcaecb23"}, - {file = "pendulum-3.0.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:0a15b90129765b705eb2039062a6daf4d22c4e28d1a54fa260892e8c3ae6e157"}, - {file = "pendulum-3.0.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:bb8f6d7acd67a67d6fedd361ad2958ff0539445ef51cbe8cd288db4306503cd0"}, - {file = "pendulum-3.0.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fd69b15374bef7e4b4440612915315cc42e8575fcda2a3d7586a0d88192d0c88"}, - {file = "pendulum-3.0.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc00f8110db6898360c53c812872662e077eaf9c75515d53ecc65d886eec209a"}, - {file = "pendulum-3.0.0-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:83a44e8b40655d0ba565a5c3d1365d27e3e6778ae2a05b69124db9e471255c4a"}, - {file = "pendulum-3.0.0-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:1a3604e9fbc06b788041b2a8b78f75c243021e0f512447806a6d37ee5214905d"}, - {file = "pendulum-3.0.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:92c307ae7accebd06cbae4729f0ba9fa724df5f7d91a0964b1b972a22baa482b"}, - {file = "pendulum-3.0.0.tar.gz", hash = "sha256:5d034998dea404ec31fae27af6b22cff1708f830a1ed7353be4d1019bb9f584e"}, -] - -[package.dependencies] -python-dateutil = ">=2.6" -tzdata = ">=2020.1" - -[package.extras] -test = ["time-machine (>=2.6.0)"] - [[package]] name = "pep8-naming" version = "0.14.1" @@ -6070,33 +3337,16 @@ pyyaml = ">=5.1" virtualenv = ">=20.10.0" [[package]] -name = "prettier" -version = "0.0.7" -description = "Properly pprint of nested objects" -optional = false -python-versions = "*" -files = [ - {file = "prettier-0.0.7-py3-none-any.whl", hash = "sha256:20e76791de41cafe481328dd49552303f29ca192151cee1b120c26f66cae9bfc"}, - {file = "prettier-0.0.7.tar.gz", hash = "sha256:6c34b8cd09fd9c8956c05d6395ea3f575e0122dce494ba57685c07065abed427"}, -] - -[[package]] -name = "prison" -version = "0.2.1" -description = "Rison encoder/decoder" +name = "prettier" +version = "0.0.7" +description = "Properly pprint of nested objects" optional = false python-versions = "*" files = [ - {file = "prison-0.2.1-py2.py3-none-any.whl", hash = "sha256:f90bab63fca497aa0819a852f64fb21a4e181ed9f6114deaa5dc04001a7555c5"}, - {file = "prison-0.2.1.tar.gz", hash = "sha256:e6cd724044afcb1a8a69340cad2f1e3151a5839fd3a8027fd1357571e797c599"}, + {file = "prettier-0.0.7-py3-none-any.whl", hash = "sha256:20e76791de41cafe481328dd49552303f29ca192151cee1b120c26f66cae9bfc"}, + {file = "prettier-0.0.7.tar.gz", hash = "sha256:6c34b8cd09fd9c8956c05d6395ea3f575e0122dce494ba57685c07065abed427"}, ] -[package.dependencies] -six = "*" - -[package.extras] -dev = ["nose", "pipreqs", "twine"] - [[package]] name = "prompt-toolkit" version = "3.0.47" @@ -6396,116 +3646,6 @@ files = [ {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, ] -[[package]] -name = "pydantic" -version = "2.7.4" -description = "Data validation using Python type hints" -optional = false -python-versions = ">=3.8" -files = [ - {file = "pydantic-2.7.4-py3-none-any.whl", hash = "sha256:ee8538d41ccb9c0a9ad3e0e5f07bf15ed8015b481ced539a1759d8cc89ae90d0"}, - {file = "pydantic-2.7.4.tar.gz", hash = "sha256:0c84efd9548d545f63ac0060c1e4d39bb9b14db8b3c0652338aecc07b5adec52"}, -] - -[package.dependencies] -annotated-types = ">=0.4.0" -pydantic-core = "2.18.4" -typing-extensions = ">=4.6.1" - -[package.extras] -email = ["email-validator (>=2.0.0)"] - -[[package]] -name = "pydantic-core" -version = "2.18.4" -description = "Core functionality for Pydantic validation and serialization" -optional = false -python-versions = ">=3.8" -files = [ - {file = "pydantic_core-2.18.4-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:f76d0ad001edd426b92233d45c746fd08f467d56100fd8f30e9ace4b005266e4"}, - {file = "pydantic_core-2.18.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:59ff3e89f4eaf14050c8022011862df275b552caef8082e37b542b066ce1ff26"}, - {file = "pydantic_core-2.18.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a55b5b16c839df1070bc113c1f7f94a0af4433fcfa1b41799ce7606e5c79ce0a"}, - {file = "pydantic_core-2.18.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4d0dcc59664fcb8974b356fe0a18a672d6d7cf9f54746c05f43275fc48636851"}, - {file = "pydantic_core-2.18.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8951eee36c57cd128f779e641e21eb40bc5073eb28b2d23f33eb0ef14ffb3f5d"}, - {file = "pydantic_core-2.18.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4701b19f7e3a06ea655513f7938de6f108123bf7c86bbebb1196eb9bd35cf724"}, - {file = "pydantic_core-2.18.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e00a3f196329e08e43d99b79b286d60ce46bed10f2280d25a1718399457e06be"}, - {file = "pydantic_core-2.18.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:97736815b9cc893b2b7f663628e63f436018b75f44854c8027040e05230eeddb"}, - {file = "pydantic_core-2.18.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6891a2ae0e8692679c07728819b6e2b822fb30ca7445f67bbf6509b25a96332c"}, - {file = "pydantic_core-2.18.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bc4ff9805858bd54d1a20efff925ccd89c9d2e7cf4986144b30802bf78091c3e"}, - {file = "pydantic_core-2.18.4-cp310-none-win32.whl", hash = "sha256:1b4de2e51bbcb61fdebd0ab86ef28062704f62c82bbf4addc4e37fa4b00b7cbc"}, - {file = "pydantic_core-2.18.4-cp310-none-win_amd64.whl", hash = "sha256:6a750aec7bf431517a9fd78cb93c97b9b0c496090fee84a47a0d23668976b4b0"}, - {file = "pydantic_core-2.18.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:942ba11e7dfb66dc70f9ae66b33452f51ac7bb90676da39a7345e99ffb55402d"}, - {file = "pydantic_core-2.18.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b2ebef0e0b4454320274f5e83a41844c63438fdc874ea40a8b5b4ecb7693f1c4"}, - {file = "pydantic_core-2.18.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a642295cd0c8df1b86fc3dced1d067874c353a188dc8e0f744626d49e9aa51c4"}, - {file = "pydantic_core-2.18.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f09baa656c904807e832cf9cce799c6460c450c4ad80803517032da0cd062e2"}, - {file = "pydantic_core-2.18.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:98906207f29bc2c459ff64fa007afd10a8c8ac080f7e4d5beff4c97086a3dabd"}, - {file = "pydantic_core-2.18.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:19894b95aacfa98e7cb093cd7881a0c76f55731efad31073db4521e2b6ff5b7d"}, - {file = "pydantic_core-2.18.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0fbbdc827fe5e42e4d196c746b890b3d72876bdbf160b0eafe9f0334525119c8"}, - {file = "pydantic_core-2.18.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f85d05aa0918283cf29a30b547b4df2fbb56b45b135f9e35b6807cb28bc47951"}, - {file = "pydantic_core-2.18.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e85637bc8fe81ddb73fda9e56bab24560bdddfa98aa64f87aaa4e4b6730c23d2"}, - {file = "pydantic_core-2.18.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:2f5966897e5461f818e136b8451d0551a2e77259eb0f73a837027b47dc95dab9"}, - {file = "pydantic_core-2.18.4-cp311-none-win32.whl", hash = "sha256:44c7486a4228413c317952e9d89598bcdfb06399735e49e0f8df643e1ccd0558"}, - {file = "pydantic_core-2.18.4-cp311-none-win_amd64.whl", hash = "sha256:8a7164fe2005d03c64fd3b85649891cd4953a8de53107940bf272500ba8a788b"}, - {file = "pydantic_core-2.18.4-cp311-none-win_arm64.whl", hash = "sha256:4e99bc050fe65c450344421017f98298a97cefc18c53bb2f7b3531eb39bc7805"}, - {file = "pydantic_core-2.18.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:6f5c4d41b2771c730ea1c34e458e781b18cc668d194958e0112455fff4e402b2"}, - {file = "pydantic_core-2.18.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2fdf2156aa3d017fddf8aea5adfba9f777db1d6022d392b682d2a8329e087cef"}, - {file = "pydantic_core-2.18.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4748321b5078216070b151d5271ef3e7cc905ab170bbfd27d5c83ee3ec436695"}, - {file = "pydantic_core-2.18.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:847a35c4d58721c5dc3dba599878ebbdfd96784f3fb8bb2c356e123bdcd73f34"}, - {file = "pydantic_core-2.18.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3c40d4eaad41f78e3bbda31b89edc46a3f3dc6e171bf0ecf097ff7a0ffff7cb1"}, - {file = "pydantic_core-2.18.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:21a5e440dbe315ab9825fcd459b8814bb92b27c974cbc23c3e8baa2b76890077"}, - {file = "pydantic_core-2.18.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:01dd777215e2aa86dfd664daed5957704b769e726626393438f9c87690ce78c3"}, - {file = "pydantic_core-2.18.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4b06beb3b3f1479d32befd1f3079cc47b34fa2da62457cdf6c963393340b56e9"}, - {file = "pydantic_core-2.18.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:564d7922e4b13a16b98772441879fcdcbe82ff50daa622d681dd682175ea918c"}, - {file = "pydantic_core-2.18.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:0eb2a4f660fcd8e2b1c90ad566db2b98d7f3f4717c64fe0a83e0adb39766d5b8"}, - {file = "pydantic_core-2.18.4-cp312-none-win32.whl", hash = "sha256:8b8bab4c97248095ae0c4455b5a1cd1cdd96e4e4769306ab19dda135ea4cdb07"}, - {file = "pydantic_core-2.18.4-cp312-none-win_amd64.whl", hash = "sha256:14601cdb733d741b8958224030e2bfe21a4a881fb3dd6fbb21f071cabd48fa0a"}, - {file = "pydantic_core-2.18.4-cp312-none-win_arm64.whl", hash = "sha256:c1322d7dd74713dcc157a2b7898a564ab091ca6c58302d5c7b4c07296e3fd00f"}, - {file = "pydantic_core-2.18.4-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:823be1deb01793da05ecb0484d6c9e20baebb39bd42b5d72636ae9cf8350dbd2"}, - {file = "pydantic_core-2.18.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ebef0dd9bf9b812bf75bda96743f2a6c5734a02092ae7f721c048d156d5fabae"}, - {file = "pydantic_core-2.18.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ae1d6df168efb88d7d522664693607b80b4080be6750c913eefb77e34c12c71a"}, - {file = "pydantic_core-2.18.4-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f9899c94762343f2cc2fc64c13e7cae4c3cc65cdfc87dd810a31654c9b7358cc"}, - {file = "pydantic_core-2.18.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99457f184ad90235cfe8461c4d70ab7dd2680e28821c29eca00252ba90308c78"}, - {file = "pydantic_core-2.18.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18f469a3d2a2fdafe99296a87e8a4c37748b5080a26b806a707f25a902c040a8"}, - {file = "pydantic_core-2.18.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b7cdf28938ac6b8b49ae5e92f2735056a7ba99c9b110a474473fd71185c1af5d"}, - {file = "pydantic_core-2.18.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:938cb21650855054dc54dfd9120a851c974f95450f00683399006aa6e8abb057"}, - {file = "pydantic_core-2.18.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:44cd83ab6a51da80fb5adbd9560e26018e2ac7826f9626bc06ca3dc074cd198b"}, - {file = "pydantic_core-2.18.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:972658f4a72d02b8abfa2581d92d59f59897d2e9f7e708fdabe922f9087773af"}, - {file = "pydantic_core-2.18.4-cp38-none-win32.whl", hash = "sha256:1d886dc848e60cb7666f771e406acae54ab279b9f1e4143babc9c2258213daa2"}, - {file = "pydantic_core-2.18.4-cp38-none-win_amd64.whl", hash = "sha256:bb4462bd43c2460774914b8525f79b00f8f407c945d50881568f294c1d9b4443"}, - {file = "pydantic_core-2.18.4-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:44a688331d4a4e2129140a8118479443bd6f1905231138971372fcde37e43528"}, - {file = "pydantic_core-2.18.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a2fdd81edd64342c85ac7cf2753ccae0b79bf2dfa063785503cb85a7d3593223"}, - {file = "pydantic_core-2.18.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:86110d7e1907ab36691f80b33eb2da87d780f4739ae773e5fc83fb272f88825f"}, - {file = "pydantic_core-2.18.4-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:46387e38bd641b3ee5ce247563b60c5ca098da9c56c75c157a05eaa0933ed154"}, - {file = "pydantic_core-2.18.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:123c3cec203e3f5ac7b000bd82235f1a3eced8665b63d18be751f115588fea30"}, - {file = "pydantic_core-2.18.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dc1803ac5c32ec324c5261c7209e8f8ce88e83254c4e1aebdc8b0a39f9ddb443"}, - {file = "pydantic_core-2.18.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:53db086f9f6ab2b4061958d9c276d1dbe3690e8dd727d6abf2321d6cce37fa94"}, - {file = "pydantic_core-2.18.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:abc267fa9837245cc28ea6929f19fa335f3dc330a35d2e45509b6566dc18be23"}, - {file = "pydantic_core-2.18.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:a0d829524aaefdebccb869eed855e2d04c21d2d7479b6cada7ace5448416597b"}, - {file = "pydantic_core-2.18.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:509daade3b8649f80d4e5ff21aa5673e4ebe58590b25fe42fac5f0f52c6f034a"}, - {file = "pydantic_core-2.18.4-cp39-none-win32.whl", hash = "sha256:ca26a1e73c48cfc54c4a76ff78df3727b9d9f4ccc8dbee4ae3f73306a591676d"}, - {file = "pydantic_core-2.18.4-cp39-none-win_amd64.whl", hash = "sha256:c67598100338d5d985db1b3d21f3619ef392e185e71b8d52bceacc4a7771ea7e"}, - {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:574d92eac874f7f4db0ca653514d823a0d22e2354359d0759e3f6a406db5d55d"}, - {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1f4d26ceb5eb9eed4af91bebeae4b06c3fb28966ca3a8fb765208cf6b51102ab"}, - {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77450e6d20016ec41f43ca4a6c63e9fdde03f0ae3fe90e7c27bdbeaece8b1ed4"}, - {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d323a01da91851a4f17bf592faf46149c9169d68430b3146dcba2bb5e5719abc"}, - {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:43d447dd2ae072a0065389092a231283f62d960030ecd27565672bd40746c507"}, - {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:578e24f761f3b425834f297b9935e1ce2e30f51400964ce4801002435a1b41ef"}, - {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:81b5efb2f126454586d0f40c4d834010979cb80785173d1586df845a632e4e6d"}, - {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ab86ce7c8f9bea87b9d12c7f0af71102acbf5ecbc66c17796cff45dae54ef9a5"}, - {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:90afc12421df2b1b4dcc975f814e21bc1754640d502a2fbcc6d41e77af5ec312"}, - {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:51991a89639a912c17bef4b45c87bd83593aee0437d8102556af4885811d59f5"}, - {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:293afe532740370aba8c060882f7d26cfd00c94cae32fd2e212a3a6e3b7bc15e"}, - {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b48ece5bde2e768197a2d0f6e925f9d7e3e826f0ad2271120f8144a9db18d5c8"}, - {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:eae237477a873ab46e8dd748e515c72c0c804fb380fbe6c85533c7de51f23a8f"}, - {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:834b5230b5dfc0c1ec37b2fda433b271cbbc0e507560b5d1588e2cc1148cf1ce"}, - {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:e858ac0a25074ba4bce653f9b5d0a85b7456eaddadc0ce82d3878c22489fa4ee"}, - {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2fd41f6eff4c20778d717af1cc50eca52f5afe7805ee530a4fbd0bae284f16e9"}, - {file = "pydantic_core-2.18.4.tar.gz", hash = "sha256:ec3beeada09ff865c344ff3bc2f427f5e6c26401cc6113d77e372c3fdac73864"}, -] - -[package.dependencies] -typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" - [[package]] name = "pydata-google-auth" version = "1.8.2" @@ -6615,24 +3755,6 @@ pyyaml = "*" [package.extras] extra = ["pygments (>=2.12)"] -[[package]] -name = "pyopenssl" -version = "24.1.0" -description = "Python wrapper module around the OpenSSL library" -optional = false -python-versions = ">=3.7" -files = [ - {file = "pyOpenSSL-24.1.0-py3-none-any.whl", hash = "sha256:17ed5be5936449c5418d1cd269a1a9e9081bc54c17aed272b45856a3d3dc86ad"}, - {file = "pyOpenSSL-24.1.0.tar.gz", hash = "sha256:cabed4bfaa5df9f1a16c0ef64a0cb65318b5cd077a7eda7d6970131ca2f41a6f"}, -] - -[package.dependencies] -cryptography = ">=41.0.5,<43" - -[package.extras] -docs = ["sphinx (!=5.2.0,!=5.2.0.post0,!=7.2.5)", "sphinx-rtd-theme"] -test = ["pretend", "pytest (>=3.0.1)", "pytest-rerunfailures"] - [[package]] name = "pyparsing" version = "3.1.2" @@ -6745,26 +3867,6 @@ psutil = ["psutil (>=3.0)"] setproctitle = ["setproctitle"] testing = ["filelock"] -[[package]] -name = "python-daemon" -version = "3.0.1" -description = "Library to implement a well-behaved Unix daemon process." -optional = false -python-versions = ">=3" -files = [ - {file = "python-daemon-3.0.1.tar.gz", hash = "sha256:6c57452372f7eaff40934a1c03ad1826bf5e793558e87fef49131e6464b4dae5"}, - {file = "python_daemon-3.0.1-py3-none-any.whl", hash = "sha256:42bb848a3260a027fa71ad47ecd959e471327cb34da5965962edd5926229f341"}, -] - -[package.dependencies] -docutils = "*" -lockfile = ">=0.10" -setuptools = ">=62.4.0" - -[package.extras] -devel = ["coverage", "docutils", "isort", "testscenarios (>=0.4)", "testtools", "twine"] -test = ["coverage", "docutils", "testscenarios (>=0.4)", "testtools"] - [[package]] name = "python-dateutil" version = "2.9.0.post0" @@ -6790,37 +3892,6 @@ files = [ {file = "python_json_logger-2.0.7-py3-none-any.whl", hash = "sha256:f380b826a991ebbe3de4d897aeec42760035ac760345e57b812938dc8b35e2bd"}, ] -[[package]] -name = "python-nvd3" -version = "0.16.0" -description = "Python NVD3 - Chart Library for d3.js" -optional = false -python-versions = "*" -files = [ - {file = "python-nvd3-0.16.0.tar.gz", hash = "sha256:0115887289b3f751716ddd05c7b53ac5f05e71201e52496decdac453a50dcf7e"}, -] - -[package.dependencies] -Jinja2 = ">=2.8" -python-slugify = ">=1.2.5" - -[[package]] -name = "python-slugify" -version = "8.0.4" -description = "A Python slugify application that also handles Unicode" -optional = false -python-versions = ">=3.7" -files = [ - {file = "python-slugify-8.0.4.tar.gz", hash = "sha256:59202371d1d05b54a9e7720c5e038f928f45daaffe41dd10822f3907b937c856"}, - {file = "python_slugify-8.0.4-py2.py3-none-any.whl", hash = "sha256:276540b79961052b66b7d116620b36518847f52d5fd9e3a70164fc8c50faa6b8"}, -] - -[package.dependencies] -text-unidecode = ">=1.3" - -[package.extras] -unidecode = ["Unidecode (>=1.1.1)"] - [[package]] name = "pytz" version = "2024.1" @@ -7029,21 +4100,6 @@ files = [ [package.dependencies] cffi = {version = "*", markers = "implementation_name == \"pypy\""} -[[package]] -name = "referencing" -version = "0.35.1" -description = "JSON Referencing + Python" -optional = false -python-versions = ">=3.8" -files = [ - {file = "referencing-0.35.1-py3-none-any.whl", hash = "sha256:eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de"}, - {file = "referencing-0.35.1.tar.gz", hash = "sha256:25b42124a6c8b632a425174f24087783efb348a6f1e0008e63cd4466fedf703c"}, -] - -[package.dependencies] -attrs = ">=22.2.0" -rpds-py = ">=0.7.0" - [[package]] name = "regex" version = "2024.5.15" @@ -7171,34 +4227,6 @@ requests = ">=2.0.0" [package.extras] rsa = ["oauthlib[signedtoken] (>=3.0.0)"] -[[package]] -name = "requests-toolbelt" -version = "1.0.0" -description = "A utility belt for advanced users of python-requests" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -files = [ - {file = "requests-toolbelt-1.0.0.tar.gz", hash = "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6"}, - {file = "requests_toolbelt-1.0.0-py2.py3-none-any.whl", hash = "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06"}, -] - -[package.dependencies] -requests = ">=2.0.1,<3.0.0" - -[[package]] -name = "rfc3339-validator" -version = "0.1.4" -description = "A pure python RFC3339 validator" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -files = [ - {file = "rfc3339_validator-0.1.4-py2.py3-none-any.whl", hash = "sha256:24f6ec1eda14ef823da9e36ec7113124b39c04d50a4d3d3a3c2859577e7791fa"}, - {file = "rfc3339_validator-0.1.4.tar.gz", hash = "sha256:138a2abdf93304ad60530167e51d2dfb9549521a836871b88d7f4695d0022f6b"}, -] - -[package.dependencies] -six = "*" - [[package]] name = "rich" version = "12.6.0" @@ -7217,128 +4245,6 @@ pygments = ">=2.6.0,<3.0.0" [package.extras] jupyter = ["ipywidgets (>=7.5.1,<8.0.0)"] -[[package]] -name = "rich-argparse" -version = "1.5.2" -description = "Rich help formatters for argparse and optparse" -optional = false -python-versions = ">=3.8" -files = [ - {file = "rich_argparse-1.5.2-py3-none-any.whl", hash = "sha256:7027503d5849e27fc7cc85fb58504363606f2ec1c8b3c27d9a8ad28788faf877"}, - {file = "rich_argparse-1.5.2.tar.gz", hash = "sha256:84d348d5b6dafe99fffe2c7ea1ca0afe14096c921693445b9eee65ee4fcbfd2c"}, -] - -[package.dependencies] -rich = ">=11.0.0" - -[[package]] -name = "rpds-py" -version = "0.18.1" -description = "Python bindings to Rust's persistent data structures (rpds)" -optional = false -python-versions = ">=3.8" -files = [ - {file = "rpds_py-0.18.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:d31dea506d718693b6b2cffc0648a8929bdc51c70a311b2770f09611caa10d53"}, - {file = "rpds_py-0.18.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:732672fbc449bab754e0b15356c077cc31566df874964d4801ab14f71951ea80"}, - {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a98a1f0552b5f227a3d6422dbd61bc6f30db170939bd87ed14f3c339aa6c7c9"}, - {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7f1944ce16401aad1e3f7d312247b3d5de7981f634dc9dfe90da72b87d37887d"}, - {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:38e14fb4e370885c4ecd734f093a2225ee52dc384b86fa55fe3f74638b2cfb09"}, - {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08d74b184f9ab6289b87b19fe6a6d1a97fbfea84b8a3e745e87a5de3029bf944"}, - {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d70129cef4a8d979caa37e7fe957202e7eee8ea02c5e16455bc9808a59c6b2f0"}, - {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ce0bb20e3a11bd04461324a6a798af34d503f8d6f1aa3d2aa8901ceaf039176d"}, - {file = "rpds_py-0.18.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:81c5196a790032e0fc2464c0b4ab95f8610f96f1f2fa3d4deacce6a79852da60"}, - {file = "rpds_py-0.18.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:f3027be483868c99b4985fda802a57a67fdf30c5d9a50338d9db646d590198da"}, - {file = "rpds_py-0.18.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d44607f98caa2961bab4fa3c4309724b185b464cdc3ba6f3d7340bac3ec97cc1"}, - {file = "rpds_py-0.18.1-cp310-none-win32.whl", hash = "sha256:c273e795e7a0f1fddd46e1e3cb8be15634c29ae8ff31c196debb620e1edb9333"}, - {file = "rpds_py-0.18.1-cp310-none-win_amd64.whl", hash = "sha256:8352f48d511de5f973e4f2f9412736d7dea76c69faa6d36bcf885b50c758ab9a"}, - {file = "rpds_py-0.18.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:6b5ff7e1d63a8281654b5e2896d7f08799378e594f09cf3674e832ecaf396ce8"}, - {file = "rpds_py-0.18.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8927638a4d4137a289e41d0fd631551e89fa346d6dbcfc31ad627557d03ceb6d"}, - {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:154bf5c93d79558b44e5b50cc354aa0459e518e83677791e6adb0b039b7aa6a7"}, - {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:07f2139741e5deb2c5154a7b9629bc5aa48c766b643c1a6750d16f865a82c5fc"}, - {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8c7672e9fba7425f79019db9945b16e308ed8bc89348c23d955c8c0540da0a07"}, - {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:489bdfe1abd0406eba6b3bb4fdc87c7fa40f1031de073d0cfb744634cc8fa261"}, - {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c20f05e8e3d4fc76875fc9cb8cf24b90a63f5a1b4c5b9273f0e8225e169b100"}, - {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:967342e045564cef76dfcf1edb700b1e20838d83b1aa02ab313e6a497cf923b8"}, - {file = "rpds_py-0.18.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2cc7c1a47f3a63282ab0f422d90ddac4aa3034e39fc66a559ab93041e6505da7"}, - {file = "rpds_py-0.18.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f7afbfee1157e0f9376c00bb232e80a60e59ed716e3211a80cb8506550671e6e"}, - {file = "rpds_py-0.18.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9e6934d70dc50f9f8ea47081ceafdec09245fd9f6032669c3b45705dea096b88"}, - {file = "rpds_py-0.18.1-cp311-none-win32.whl", hash = "sha256:c69882964516dc143083d3795cb508e806b09fc3800fd0d4cddc1df6c36e76bb"}, - {file = "rpds_py-0.18.1-cp311-none-win_amd64.whl", hash = "sha256:70a838f7754483bcdc830444952fd89645569e7452e3226de4a613a4c1793fb2"}, - {file = "rpds_py-0.18.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:3dd3cd86e1db5aadd334e011eba4e29d37a104b403e8ca24dcd6703c68ca55b3"}, - {file = "rpds_py-0.18.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:05f3d615099bd9b13ecf2fc9cf2d839ad3f20239c678f461c753e93755d629ee"}, - {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:35b2b771b13eee8729a5049c976197ff58a27a3829c018a04341bcf1ae409b2b"}, - {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ee17cd26b97d537af8f33635ef38be873073d516fd425e80559f4585a7b90c43"}, - {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b646bf655b135ccf4522ed43d6902af37d3f5dbcf0da66c769a2b3938b9d8184"}, - {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:19ba472b9606c36716062c023afa2484d1e4220548751bda14f725a7de17b4f6"}, - {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e30ac5e329098903262dc5bdd7e2086e0256aa762cc8b744f9e7bf2a427d3f8"}, - {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d58ad6317d188c43750cb76e9deacf6051d0f884d87dc6518e0280438648a9ac"}, - {file = "rpds_py-0.18.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e1735502458621921cee039c47318cb90b51d532c2766593be6207eec53e5c4c"}, - {file = "rpds_py-0.18.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:f5bab211605d91db0e2995a17b5c6ee5edec1270e46223e513eaa20da20076ac"}, - {file = "rpds_py-0.18.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2fc24a329a717f9e2448f8cd1f960f9dac4e45b6224d60734edeb67499bab03a"}, - {file = "rpds_py-0.18.1-cp312-none-win32.whl", hash = "sha256:1805d5901779662d599d0e2e4159d8a82c0b05faa86ef9222bf974572286b2b6"}, - {file = "rpds_py-0.18.1-cp312-none-win_amd64.whl", hash = "sha256:720edcb916df872d80f80a1cc5ea9058300b97721efda8651efcd938a9c70a72"}, - {file = "rpds_py-0.18.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:c827576e2fa017a081346dce87d532a5310241648eb3700af9a571a6e9fc7e74"}, - {file = "rpds_py-0.18.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:aa3679e751408d75a0b4d8d26d6647b6d9326f5e35c00a7ccd82b78ef64f65f8"}, - {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0abeee75434e2ee2d142d650d1e54ac1f8b01e6e6abdde8ffd6eeac6e9c38e20"}, - {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed402d6153c5d519a0faf1bb69898e97fb31613b49da27a84a13935ea9164dfc"}, - {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:338dee44b0cef8b70fd2ef54b4e09bb1b97fc6c3a58fea5db6cc083fd9fc2724"}, - {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7750569d9526199c5b97e5a9f8d96a13300950d910cf04a861d96f4273d5b104"}, - {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:607345bd5912aacc0c5a63d45a1f73fef29e697884f7e861094e443187c02be5"}, - {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:207c82978115baa1fd8d706d720b4a4d2b0913df1c78c85ba73fe6c5804505f0"}, - {file = "rpds_py-0.18.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:6d1e42d2735d437e7e80bab4d78eb2e459af48c0a46e686ea35f690b93db792d"}, - {file = "rpds_py-0.18.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:5463c47c08630007dc0fe99fb480ea4f34a89712410592380425a9b4e1611d8e"}, - {file = "rpds_py-0.18.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:06d218939e1bf2ca50e6b0ec700ffe755e5216a8230ab3e87c059ebb4ea06afc"}, - {file = "rpds_py-0.18.1-cp38-none-win32.whl", hash = "sha256:312fe69b4fe1ffbe76520a7676b1e5ac06ddf7826d764cc10265c3b53f96dbe9"}, - {file = "rpds_py-0.18.1-cp38-none-win_amd64.whl", hash = "sha256:9437ca26784120a279f3137ee080b0e717012c42921eb07861b412340f85bae2"}, - {file = "rpds_py-0.18.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:19e515b78c3fc1039dd7da0a33c28c3154458f947f4dc198d3c72db2b6b5dc93"}, - {file = "rpds_py-0.18.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a7b28c5b066bca9a4eb4e2f2663012debe680f097979d880657f00e1c30875a0"}, - {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:673fdbbf668dd958eff750e500495ef3f611e2ecc209464f661bc82e9838991e"}, - {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d960de62227635d2e61068f42a6cb6aae91a7fe00fca0e3aeed17667c8a34611"}, - {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:352a88dc7892f1da66b6027af06a2e7e5d53fe05924cc2cfc56495b586a10b72"}, - {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4e0ee01ad8260184db21468a6e1c37afa0529acc12c3a697ee498d3c2c4dcaf3"}, - {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4c39ad2f512b4041343ea3c7894339e4ca7839ac38ca83d68a832fc8b3748ab"}, - {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:aaa71ee43a703c321906813bb252f69524f02aa05bf4eec85f0c41d5d62d0f4c"}, - {file = "rpds_py-0.18.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:6cd8098517c64a85e790657e7b1e509b9fe07487fd358e19431cb120f7d96338"}, - {file = "rpds_py-0.18.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:4adec039b8e2928983f885c53b7cc4cda8965b62b6596501a0308d2703f8af1b"}, - {file = "rpds_py-0.18.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:32b7daaa3e9389db3695964ce8e566e3413b0c43e3394c05e4b243a4cd7bef26"}, - {file = "rpds_py-0.18.1-cp39-none-win32.whl", hash = "sha256:2625f03b105328729f9450c8badda34d5243231eef6535f80064d57035738360"}, - {file = "rpds_py-0.18.1-cp39-none-win_amd64.whl", hash = "sha256:bf18932d0003c8c4d51a39f244231986ab23ee057d235a12b2684ea26a353590"}, - {file = "rpds_py-0.18.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:cbfbea39ba64f5e53ae2915de36f130588bba71245b418060ec3330ebf85678e"}, - {file = "rpds_py-0.18.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:a3d456ff2a6a4d2adcdf3c1c960a36f4fd2fec6e3b4902a42a384d17cf4e7a65"}, - {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7700936ef9d006b7ef605dc53aa364da2de5a3aa65516a1f3ce73bf82ecfc7ae"}, - {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:51584acc5916212e1bf45edd17f3a6b05fe0cbb40482d25e619f824dccb679de"}, - {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:942695a206a58d2575033ff1e42b12b2aece98d6003c6bc739fbf33d1773b12f"}, - {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b906b5f58892813e5ba5c6056d6a5ad08f358ba49f046d910ad992196ea61397"}, - {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6f8e3fecca256fefc91bb6765a693d96692459d7d4c644660a9fff32e517843"}, - {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7732770412bab81c5a9f6d20aeb60ae943a9b36dcd990d876a773526468e7163"}, - {file = "rpds_py-0.18.1-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:bd1105b50ede37461c1d51b9698c4f4be6e13e69a908ab7751e3807985fc0346"}, - {file = "rpds_py-0.18.1-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:618916f5535784960f3ecf8111581f4ad31d347c3de66d02e728de460a46303c"}, - {file = "rpds_py-0.18.1-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:17c6d2155e2423f7e79e3bb18151c686d40db42d8645e7977442170c360194d4"}, - {file = "rpds_py-0.18.1-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:6c4c4c3f878df21faf5fac86eda32671c27889e13570645a9eea0a1abdd50922"}, - {file = "rpds_py-0.18.1-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:fab6ce90574645a0d6c58890e9bcaac8d94dff54fb51c69e5522a7358b80ab64"}, - {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:531796fb842b53f2695e94dc338929e9f9dbf473b64710c28af5a160b2a8927d"}, - {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:740884bc62a5e2bbb31e584f5d23b32320fd75d79f916f15a788d527a5e83644"}, - {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:998125738de0158f088aef3cb264a34251908dd2e5d9966774fdab7402edfab7"}, - {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e2be6e9dd4111d5b31ba3b74d17da54a8319d8168890fbaea4b9e5c3de630ae5"}, - {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d0cee71bc618cd93716f3c1bf56653740d2d13ddbd47673efa8bf41435a60daa"}, - {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2c3caec4ec5cd1d18e5dd6ae5194d24ed12785212a90b37f5f7f06b8bedd7139"}, - {file = "rpds_py-0.18.1-pp38-pypy38_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:27bba383e8c5231cd559affe169ca0b96ec78d39909ffd817f28b166d7ddd4d8"}, - {file = "rpds_py-0.18.1-pp38-pypy38_pp73-musllinux_1_2_i686.whl", hash = "sha256:a888e8bdb45916234b99da2d859566f1e8a1d2275a801bb8e4a9644e3c7e7909"}, - {file = "rpds_py-0.18.1-pp38-pypy38_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:6031b25fb1b06327b43d841f33842b383beba399884f8228a6bb3df3088485ff"}, - {file = "rpds_py-0.18.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:48c2faaa8adfacefcbfdb5f2e2e7bdad081e5ace8d182e5f4ade971f128e6bb3"}, - {file = "rpds_py-0.18.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:d85164315bd68c0806768dc6bb0429c6f95c354f87485ee3593c4f6b14def2bd"}, - {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6afd80f6c79893cfc0574956f78a0add8c76e3696f2d6a15bca2c66c415cf2d4"}, - {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fa242ac1ff583e4ec7771141606aafc92b361cd90a05c30d93e343a0c2d82a89"}, - {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d21be4770ff4e08698e1e8e0bce06edb6ea0626e7c8f560bc08222880aca6a6f"}, - {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c45a639e93a0c5d4b788b2613bd637468edd62f8f95ebc6fcc303d58ab3f0a8"}, - {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:910e71711d1055b2768181efa0a17537b2622afeb0424116619817007f8a2b10"}, - {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b9bb1f182a97880f6078283b3505a707057c42bf55d8fca604f70dedfdc0772a"}, - {file = "rpds_py-0.18.1-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:1d54f74f40b1f7aaa595a02ff42ef38ca654b1469bef7d52867da474243cc633"}, - {file = "rpds_py-0.18.1-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:8d2e182c9ee01135e11e9676e9a62dfad791a7a467738f06726872374a83db49"}, - {file = "rpds_py-0.18.1-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:636a15acc588f70fda1661234761f9ed9ad79ebed3f2125d44be0862708b666e"}, - {file = "rpds_py-0.18.1.tar.gz", hash = "sha256:dc48b479d540770c811fbd1eb9ba2bb66951863e448efec2e2c102625328e92f"}, -] - [[package]] name = "rsa" version = "4.9" @@ -7650,63 +4556,6 @@ docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-g testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8 (<5)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] -[[package]] -name = "shapely" -version = "2.0.4" -description = "Manipulation and analysis of geometric objects" -optional = false -python-versions = ">=3.7" -files = [ - {file = "shapely-2.0.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:011b77153906030b795791f2fdfa2d68f1a8d7e40bce78b029782ade3afe4f2f"}, - {file = "shapely-2.0.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9831816a5d34d5170aa9ed32a64982c3d6f4332e7ecfe62dc97767e163cb0b17"}, - {file = "shapely-2.0.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5c4849916f71dc44e19ed370421518c0d86cf73b26e8656192fcfcda08218fbd"}, - {file = "shapely-2.0.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:841f93a0e31e4c64d62ea570d81c35de0f6cea224568b2430d832967536308e6"}, - {file = "shapely-2.0.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b4431f522b277c79c34b65da128029a9955e4481462cbf7ebec23aab61fc58"}, - {file = "shapely-2.0.4-cp310-cp310-win32.whl", hash = "sha256:92a41d936f7d6743f343be265ace93b7c57f5b231e21b9605716f5a47c2879e7"}, - {file = "shapely-2.0.4-cp310-cp310-win_amd64.whl", hash = "sha256:30982f79f21bb0ff7d7d4a4e531e3fcaa39b778584c2ce81a147f95be1cd58c9"}, - {file = "shapely-2.0.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:de0205cb21ad5ddaef607cda9a3191eadd1e7a62a756ea3a356369675230ac35"}, - {file = "shapely-2.0.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7d56ce3e2a6a556b59a288771cf9d091470116867e578bebced8bfc4147fbfd7"}, - {file = "shapely-2.0.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:58b0ecc505bbe49a99551eea3f2e8a9b3b24b3edd2a4de1ac0dc17bc75c9ec07"}, - {file = "shapely-2.0.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:790a168a808bd00ee42786b8ba883307c0e3684ebb292e0e20009588c426da47"}, - {file = "shapely-2.0.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4310b5494271e18580d61022c0857eb85d30510d88606fa3b8314790df7f367d"}, - {file = "shapely-2.0.4-cp311-cp311-win32.whl", hash = "sha256:63f3a80daf4f867bd80f5c97fbe03314348ac1b3b70fb1c0ad255a69e3749879"}, - {file = "shapely-2.0.4-cp311-cp311-win_amd64.whl", hash = "sha256:c52ed79f683f721b69a10fb9e3d940a468203f5054927215586c5d49a072de8d"}, - {file = "shapely-2.0.4-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:5bbd974193e2cc274312da16b189b38f5f128410f3377721cadb76b1e8ca5328"}, - {file = "shapely-2.0.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:41388321a73ba1a84edd90d86ecc8bfed55e6a1e51882eafb019f45895ec0f65"}, - {file = "shapely-2.0.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0776c92d584f72f1e584d2e43cfc5542c2f3dd19d53f70df0900fda643f4bae6"}, - {file = "shapely-2.0.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c75c98380b1ede1cae9a252c6dc247e6279403fae38c77060a5e6186c95073ac"}, - {file = "shapely-2.0.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c3e700abf4a37b7b8b90532fa6ed5c38a9bfc777098bc9fbae5ec8e618ac8f30"}, - {file = "shapely-2.0.4-cp312-cp312-win32.whl", hash = "sha256:4f2ab0faf8188b9f99e6a273b24b97662194160cc8ca17cf9d1fb6f18d7fb93f"}, - {file = "shapely-2.0.4-cp312-cp312-win_amd64.whl", hash = "sha256:03152442d311a5e85ac73b39680dd64a9892fa42bb08fd83b3bab4fe6999bfa0"}, - {file = "shapely-2.0.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:994c244e004bc3cfbea96257b883c90a86e8cbd76e069718eb4c6b222a56f78b"}, - {file = "shapely-2.0.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05ffd6491e9e8958b742b0e2e7c346635033d0a5f1a0ea083547fcc854e5d5cf"}, - {file = "shapely-2.0.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2fbdc1140a7d08faa748256438291394967aa54b40009f54e8d9825e75ef6113"}, - {file = "shapely-2.0.4-cp37-cp37m-win32.whl", hash = "sha256:5af4cd0d8cf2912bd95f33586600cac9c4b7c5053a036422b97cfe4728d2eb53"}, - {file = "shapely-2.0.4-cp37-cp37m-win_amd64.whl", hash = "sha256:464157509ce4efa5ff285c646a38b49f8c5ef8d4b340f722685b09bb033c5ccf"}, - {file = "shapely-2.0.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:489c19152ec1f0e5c5e525356bcbf7e532f311bff630c9b6bc2db6f04da6a8b9"}, - {file = "shapely-2.0.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b79bbd648664aa6f44ef018474ff958b6b296fed5c2d42db60078de3cffbc8aa"}, - {file = "shapely-2.0.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:674d7baf0015a6037d5758496d550fc1946f34bfc89c1bf247cabdc415d7747e"}, - {file = "shapely-2.0.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6cd4ccecc5ea5abd06deeaab52fcdba372f649728050c6143cc405ee0c166679"}, - {file = "shapely-2.0.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb5cdcbbe3080181498931b52a91a21a781a35dcb859da741c0345c6402bf00c"}, - {file = "shapely-2.0.4-cp38-cp38-win32.whl", hash = "sha256:55a38dcd1cee2f298d8c2ebc60fc7d39f3b4535684a1e9e2f39a80ae88b0cea7"}, - {file = "shapely-2.0.4-cp38-cp38-win_amd64.whl", hash = "sha256:ec555c9d0db12d7fd777ba3f8b75044c73e576c720a851667432fabb7057da6c"}, - {file = "shapely-2.0.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:3f9103abd1678cb1b5f7e8e1af565a652e036844166c91ec031eeb25c5ca8af0"}, - {file = "shapely-2.0.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:263bcf0c24d7a57c80991e64ab57cba7a3906e31d2e21b455f493d4aab534aaa"}, - {file = "shapely-2.0.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ddf4a9bfaac643e62702ed662afc36f6abed2a88a21270e891038f9a19bc08fc"}, - {file = "shapely-2.0.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:485246fcdb93336105c29a5cfbff8a226949db37b7473c89caa26c9bae52a242"}, - {file = "shapely-2.0.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8de4578e838a9409b5b134a18ee820730e507b2d21700c14b71a2b0757396acc"}, - {file = "shapely-2.0.4-cp39-cp39-win32.whl", hash = "sha256:9dab4c98acfb5fb85f5a20548b5c0abe9b163ad3525ee28822ffecb5c40e724c"}, - {file = "shapely-2.0.4-cp39-cp39-win_amd64.whl", hash = "sha256:31c19a668b5a1eadab82ff070b5a260478ac6ddad3a5b62295095174a8d26398"}, - {file = "shapely-2.0.4.tar.gz", hash = "sha256:5dc736127fac70009b8d309a0eeb74f3e08979e530cf7017f2f507ef62e6cfb8"}, -] - -[package.dependencies] -numpy = ">=1.14,<3" - -[package.extras] -docs = ["matplotlib", "numpydoc (==1.1.*)", "sphinx", "sphinx-book-theme", "sphinx-remove-toctrees"] -test = ["pytest", "pytest-cov"] - [[package]] name = "shellingham" version = "1.5.4" @@ -7762,17 +4611,6 @@ files = [ {file = "smmap-5.0.1.tar.gz", hash = "sha256:dceeb6c0028fdb6734471eb07c0cd2aae706ccaecab45965ee83f11c8d3b1f62"}, ] -[[package]] -name = "sniffio" -version = "1.3.1" -description = "Sniff out which async library your code is running under" -optional = false -python-versions = ">=3.7" -files = [ - {file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"}, - {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, -] - [[package]] name = "sortedcontainers" version = "2.4.0" @@ -7795,186 +4633,6 @@ files = [ {file = "soupsieve-2.5.tar.gz", hash = "sha256:5663d5a7b3bfaeee0bc4372e7fc48f9cff4940b3eec54a6451cc5299f1097690"}, ] -[[package]] -name = "sqlalchemy" -version = "1.4.52" -description = "Database Abstraction Library" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" -files = [ - {file = "SQLAlchemy-1.4.52-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:f68016f9a5713684c1507cc37133c28035f29925c75c0df2f9d0f7571e23720a"}, - {file = "SQLAlchemy-1.4.52-cp310-cp310-manylinux1_x86_64.manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_5_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24bb0f81fbbb13d737b7f76d1821ec0b117ce8cbb8ee5e8641ad2de41aa916d3"}, - {file = "SQLAlchemy-1.4.52-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e93983cc0d2edae253b3f2141b0a3fb07e41c76cd79c2ad743fc27eb79c3f6db"}, - {file = "SQLAlchemy-1.4.52-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:84e10772cfc333eb08d0b7ef808cd76e4a9a30a725fb62a0495877a57ee41d81"}, - {file = "SQLAlchemy-1.4.52-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:427988398d2902de042093d17f2b9619a5ebc605bf6372f7d70e29bde6736842"}, - {file = "SQLAlchemy-1.4.52-cp310-cp310-win32.whl", hash = "sha256:1296f2cdd6db09b98ceb3c93025f0da4835303b8ac46c15c2136e27ee4d18d94"}, - {file = "SQLAlchemy-1.4.52-cp310-cp310-win_amd64.whl", hash = "sha256:80e7f697bccc56ac6eac9e2df5c98b47de57e7006d2e46e1a3c17c546254f6ef"}, - {file = "SQLAlchemy-1.4.52-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2f251af4c75a675ea42766880ff430ac33291c8d0057acca79710f9e5a77383d"}, - {file = "SQLAlchemy-1.4.52-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb8f9e4c4718f111d7b530c4e6fb4d28f9f110eb82e7961412955b3875b66de0"}, - {file = "SQLAlchemy-1.4.52-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afb1672b57f58c0318ad2cff80b384e816735ffc7e848d8aa51e0b0fc2f4b7bb"}, - {file = "SQLAlchemy-1.4.52-cp311-cp311-win32.whl", hash = "sha256:6e41cb5cda641f3754568d2ed8962f772a7f2b59403b95c60c89f3e0bd25f15e"}, - {file = "SQLAlchemy-1.4.52-cp311-cp311-win_amd64.whl", hash = "sha256:5bed4f8c3b69779de9d99eb03fd9ab67a850d74ab0243d1be9d4080e77b6af12"}, - {file = "SQLAlchemy-1.4.52-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:49e3772eb3380ac88d35495843daf3c03f094b713e66c7d017e322144a5c6b7c"}, - {file = "SQLAlchemy-1.4.52-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:618827c1a1c243d2540314c6e100aee7af09a709bd005bae971686fab6723554"}, - {file = "SQLAlchemy-1.4.52-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de9acf369aaadb71a725b7e83a5ef40ca3de1cf4cdc93fa847df6b12d3cd924b"}, - {file = "SQLAlchemy-1.4.52-cp312-cp312-win32.whl", hash = "sha256:763bd97c4ebc74136ecf3526b34808c58945023a59927b416acebcd68d1fc126"}, - {file = "SQLAlchemy-1.4.52-cp312-cp312-win_amd64.whl", hash = "sha256:f12aaf94f4d9679ca475975578739e12cc5b461172e04d66f7a3c39dd14ffc64"}, - {file = "SQLAlchemy-1.4.52-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:853fcfd1f54224ea7aabcf34b227d2b64a08cbac116ecf376907968b29b8e763"}, - {file = "SQLAlchemy-1.4.52-cp36-cp36m-manylinux1_x86_64.manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_5_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f98dbb8fcc6d1c03ae8ec735d3c62110949a3b8bc6e215053aa27096857afb45"}, - {file = "SQLAlchemy-1.4.52-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e135fff2e84103bc15c07edd8569612ce317d64bdb391f49ce57124a73f45c5"}, - {file = "SQLAlchemy-1.4.52-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5b5de6af8852500d01398f5047d62ca3431d1e29a331d0b56c3e14cb03f8094c"}, - {file = "SQLAlchemy-1.4.52-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3491c85df263a5c2157c594f54a1a9c72265b75d3777e61ee13c556d9e43ffc9"}, - {file = "SQLAlchemy-1.4.52-cp36-cp36m-win32.whl", hash = "sha256:427c282dd0deba1f07bcbf499cbcc9fe9a626743f5d4989bfdfd3ed3513003dd"}, - {file = "SQLAlchemy-1.4.52-cp36-cp36m-win_amd64.whl", hash = "sha256:ca5ce82b11731492204cff8845c5e8ca1a4bd1ade85e3b8fcf86e7601bfc6a39"}, - {file = "SQLAlchemy-1.4.52-cp37-cp37m-macosx_11_0_x86_64.whl", hash = "sha256:29d4247313abb2015f8979137fe65f4eaceead5247d39603cc4b4a610936cd2b"}, - {file = "SQLAlchemy-1.4.52-cp37-cp37m-manylinux1_x86_64.manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_5_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a752bff4796bf22803d052d4841ebc3c55c26fb65551f2c96e90ac7c62be763a"}, - {file = "SQLAlchemy-1.4.52-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f7ea11727feb2861deaa293c7971a4df57ef1c90e42cb53f0da40c3468388000"}, - {file = "SQLAlchemy-1.4.52-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d913f8953e098ca931ad7f58797f91deed26b435ec3756478b75c608aa80d139"}, - {file = "SQLAlchemy-1.4.52-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a251146b921725547ea1735b060a11e1be705017b568c9f8067ca61e6ef85f20"}, - {file = "SQLAlchemy-1.4.52-cp37-cp37m-win32.whl", hash = "sha256:1f8e1c6a6b7f8e9407ad9afc0ea41c1f65225ce505b79bc0342159de9c890782"}, - {file = "SQLAlchemy-1.4.52-cp37-cp37m-win_amd64.whl", hash = "sha256:346ed50cb2c30f5d7a03d888e25744154ceac6f0e6e1ab3bc7b5b77138d37710"}, - {file = "SQLAlchemy-1.4.52-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:4dae6001457d4497736e3bc422165f107ecdd70b0d651fab7f731276e8b9e12d"}, - {file = "SQLAlchemy-1.4.52-cp38-cp38-manylinux1_x86_64.manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_5_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a5d2e08d79f5bf250afb4a61426b41026e448da446b55e4770c2afdc1e200fce"}, - {file = "SQLAlchemy-1.4.52-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5bbce5dd7c7735e01d24f5a60177f3e589078f83c8a29e124a6521b76d825b85"}, - {file = "SQLAlchemy-1.4.52-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:bdb7b4d889631a3b2a81a3347c4c3f031812eb4adeaa3ee4e6b0d028ad1852b5"}, - {file = "SQLAlchemy-1.4.52-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c294ae4e6bbd060dd79e2bd5bba8b6274d08ffd65b58d106394cb6abbf35cf45"}, - {file = "SQLAlchemy-1.4.52-cp38-cp38-win32.whl", hash = "sha256:bcdfb4b47fe04967669874fb1ce782a006756fdbebe7263f6a000e1db969120e"}, - {file = "SQLAlchemy-1.4.52-cp38-cp38-win_amd64.whl", hash = "sha256:7d0dbc56cb6af5088f3658982d3d8c1d6a82691f31f7b0da682c7b98fa914e91"}, - {file = "SQLAlchemy-1.4.52-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:a551d5f3dc63f096ed41775ceec72fdf91462bb95abdc179010dc95a93957800"}, - {file = "SQLAlchemy-1.4.52-cp39-cp39-manylinux1_x86_64.manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_5_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ab773f9ad848118df7a9bbabca53e3f1002387cdbb6ee81693db808b82aaab0"}, - {file = "SQLAlchemy-1.4.52-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d2de46f5d5396d5331127cfa71f837cca945f9a2b04f7cb5a01949cf676db7d1"}, - {file = "SQLAlchemy-1.4.52-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7027be7930a90d18a386b25ee8af30514c61f3852c7268899f23fdfbd3107181"}, - {file = "SQLAlchemy-1.4.52-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:99224d621affbb3c1a4f72b631f8393045f4ce647dd3262f12fe3576918f8bf3"}, - {file = "SQLAlchemy-1.4.52-cp39-cp39-win32.whl", hash = "sha256:c124912fd4e1bb9d1e7dc193ed482a9f812769cb1e69363ab68e01801e859821"}, - {file = "SQLAlchemy-1.4.52-cp39-cp39-win_amd64.whl", hash = "sha256:2c286fab42e49db23c46ab02479f328b8bdb837d3e281cae546cc4085c83b680"}, - {file = "SQLAlchemy-1.4.52.tar.gz", hash = "sha256:80e63bbdc5217dad3485059bdf6f65a7d43f33c8bde619df5c220edf03d87296"}, -] - -[package.dependencies] -greenlet = {version = "!=0.4.17", markers = "python_version >= \"3\" and (platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\")"} - -[package.extras] -aiomysql = ["aiomysql (>=0.2.0)", "greenlet (!=0.4.17)"] -aiosqlite = ["aiosqlite", "greenlet (!=0.4.17)", "typing_extensions (!=3.10.0.1)"] -asyncio = ["greenlet (!=0.4.17)"] -asyncmy = ["asyncmy (>=0.2.3,!=0.2.4)", "greenlet (!=0.4.17)"] -mariadb-connector = ["mariadb (>=1.0.1,!=1.1.2)"] -mssql = ["pyodbc"] -mssql-pymssql = ["pymssql"] -mssql-pyodbc = ["pyodbc"] -mypy = ["mypy (>=0.910)", "sqlalchemy2-stubs"] -mysql = ["mysqlclient (>=1.4.0)", "mysqlclient (>=1.4.0,<2)"] -mysql-connector = ["mysql-connector-python"] -oracle = ["cx_oracle (>=7)", "cx_oracle (>=7,<8)"] -postgresql = ["psycopg2 (>=2.7)"] -postgresql-asyncpg = ["asyncpg", "greenlet (!=0.4.17)"] -postgresql-pg8000 = ["pg8000 (>=1.16.6,!=1.29.0)"] -postgresql-psycopg2binary = ["psycopg2-binary"] -postgresql-psycopg2cffi = ["psycopg2cffi"] -pymysql = ["pymysql", "pymysql (<1)"] -sqlcipher = ["sqlcipher3_binary"] - -[[package]] -name = "sqlalchemy-bigquery" -version = "1.11.0" -description = "SQLAlchemy dialect for BigQuery" -optional = false -python-versions = "<3.13,>=3.8" -files = [ - {file = "sqlalchemy-bigquery-1.11.0.tar.gz", hash = "sha256:09a2b99b8591d441eef66d34d13057d0f09423fe259fef98c0502df61419d242"}, - {file = "sqlalchemy_bigquery-1.11.0-py2.py3-none-any.whl", hash = "sha256:99f868cfdd103b13f921ec1c1b748826b4b1187457dda48040da5ab5ba63c705"}, -] - -[package.dependencies] -google-api-core = ">=1.31.5,<2.0.dev0 || >2.3.0,<3.0.0dev" -google-auth = ">=1.25.0,<3.0.0dev" -google-cloud-bigquery = ">=3.3.6,<4.0.0dev" -packaging = "*" -sqlalchemy = ">=1.4.16,<3.0.0dev" - -[package.extras] -alembic = ["alembic"] -all = ["GeoAlchemy2", "alembic", "google-cloud-bigquery-storage (>=2.0.0,<3.0.0dev)", "grpcio (>=1.47.0,<2.0dev)", "grpcio (>=1.49.1,<2.0dev)", "packaging", "pyarrow (>=3.0.0)", "pytz", "shapely"] -bqstorage = ["google-cloud-bigquery-storage (>=2.0.0,<3.0.0dev)", "grpcio (>=1.47.0,<2.0dev)", "grpcio (>=1.49.1,<2.0dev)", "pyarrow (>=3.0.0)"] -geography = ["GeoAlchemy2", "shapely"] -tests = ["packaging", "pytz"] - -[[package]] -name = "sqlalchemy-jsonfield" -version = "1.0.2" -description = "SQLALchemy JSONField implementation for storing dicts at SQL" -optional = false -python-versions = ">=3.7.0" -files = [ - {file = "SQLAlchemy-JSONField-1.0.2.tar.gz", hash = "sha256:dab3abc9d75a1640e7f3d4875564a4199f665d27863da8d5a089e4eaca5e67f2"}, - {file = "SQLAlchemy_JSONField-1.0.2-py3-none-any.whl", hash = "sha256:b2945fa1e60b07d5764a7c73b18da427948b35dd4c07c0e94939001dc2dacf77"}, -] - -[package.dependencies] -sqlalchemy = "*" - -[[package]] -name = "sqlalchemy-spanner" -version = "1.7.0" -description = "SQLAlchemy dialect integrated into Cloud Spanner database" -optional = false -python-versions = "*" -files = [ - {file = "sqlalchemy_spanner-1.7.0-py3-none-any.whl", hash = "sha256:9925037a50b94eda358d462b694aebde61bcbeca1bb7c5a0cf247f672a340d7c"}, - {file = "sqlalchemy_spanner-1.7.0.tar.gz", hash = "sha256:c5a184710d289a3ab8e20f10998928d08b5b89838cf39c7ed0b5f52e8ee6e13b"}, -] - -[package.dependencies] -alembic = "*" -google-cloud-spanner = ">=3.12.0" -sqlalchemy = ">=1.1.13" - -[package.extras] -tracing = ["opentelemetry-api (>=1.1.0)", "opentelemetry-instrumentation (>=0.20b0)", "opentelemetry-sdk (>=1.1.0)"] - -[[package]] -name = "sqlalchemy-utils" -version = "0.41.2" -description = "Various utility functions for SQLAlchemy." -optional = false -python-versions = ">=3.7" -files = [ - {file = "SQLAlchemy-Utils-0.41.2.tar.gz", hash = "sha256:bc599c8c3b3319e53ce6c5c3c471120bd325d0071fb6f38a10e924e3d07b9990"}, - {file = "SQLAlchemy_Utils-0.41.2-py3-none-any.whl", hash = "sha256:85cf3842da2bf060760f955f8467b87983fb2e30f1764fd0e24a48307dc8ec6e"}, -] - -[package.dependencies] -SQLAlchemy = ">=1.3" - -[package.extras] -arrow = ["arrow (>=0.3.4)"] -babel = ["Babel (>=1.3)"] -color = ["colour (>=0.0.4)"] -encrypted = ["cryptography (>=0.6)"] -intervals = ["intervals (>=0.7.1)"] -password = ["passlib (>=1.6,<2.0)"] -pendulum = ["pendulum (>=2.0.5)"] -phone = ["phonenumbers (>=5.9.2)"] -test = ["Jinja2 (>=2.3)", "Pygments (>=1.2)", "backports.zoneinfo", "docutils (>=0.10)", "flake8 (>=2.4.0)", "flexmock (>=0.9.7)", "isort (>=4.2.2)", "pg8000 (>=1.12.4)", "psycopg (>=3.1.8)", "psycopg2 (>=2.5.1)", "psycopg2cffi (>=2.8.1)", "pymysql", "pyodbc", "pytest (==7.4.4)", "python-dateutil (>=2.6)", "pytz (>=2014.2)"] -test-all = ["Babel (>=1.3)", "Jinja2 (>=2.3)", "Pygments (>=1.2)", "arrow (>=0.3.4)", "backports.zoneinfo", "colour (>=0.0.4)", "cryptography (>=0.6)", "docutils (>=0.10)", "flake8 (>=2.4.0)", "flexmock (>=0.9.7)", "furl (>=0.4.1)", "intervals (>=0.7.1)", "isort (>=4.2.2)", "passlib (>=1.6,<2.0)", "pendulum (>=2.0.5)", "pg8000 (>=1.12.4)", "phonenumbers (>=5.9.2)", "psycopg (>=3.1.8)", "psycopg2 (>=2.5.1)", "psycopg2cffi (>=2.8.1)", "pymysql", "pyodbc", "pytest (==7.4.4)", "python-dateutil", "python-dateutil (>=2.6)", "pytz (>=2014.2)"] -timezone = ["python-dateutil"] -url = ["furl (>=0.4.1)"] - -[[package]] -name = "sqlparse" -version = "0.5.0" -description = "A non-validating SQL parser." -optional = false -python-versions = ">=3.8" -files = [ - {file = "sqlparse-0.5.0-py3-none-any.whl", hash = "sha256:c204494cd97479d0e39f28c93d46c0b2d5959c7b9ab904762ea6c7af211c8663"}, - {file = "sqlparse-0.5.0.tar.gz", hash = "sha256:714d0a4932c059d16189f58ef5411ec2287a4360f17cdd0edd2d09d4c5087c93"}, -] - -[package.extras] -dev = ["build", "hatch"] -doc = ["sphinx"] - [[package]] name = "stack-data" version = "0.6.3" @@ -8037,17 +4695,6 @@ files = [ [package.extras] tests = ["pytest", "pytest-cov"] -[[package]] -name = "text-unidecode" -version = "1.3" -description = "The most basic Text::Unidecode port" -optional = false -python-versions = "*" -files = [ - {file = "text-unidecode-1.3.tar.gz", hash = "sha256:bad6603bb14d279193107714b288be206cac565dfa49aa5b105294dd5c4aab93"}, - {file = "text_unidecode-1.3-py2.py3-none-any.whl", hash = "sha256:1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8"}, -] - [[package]] name = "threadpoolctl" version = "3.5.0" @@ -8164,59 +4811,6 @@ files = [ {file = "tzdata-2024.1.tar.gz", hash = "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd"}, ] -[[package]] -name = "uc-micro-py" -version = "1.0.3" -description = "Micro subset of unicode data files for linkify-it-py projects." -optional = false -python-versions = ">=3.7" -files = [ - {file = "uc-micro-py-1.0.3.tar.gz", hash = "sha256:d321b92cff673ec58027c04015fcaa8bb1e005478643ff4a500882eaab88c48a"}, - {file = "uc_micro_py-1.0.3-py3-none-any.whl", hash = "sha256:db1dffff340817673d7b466ec86114a9dc0e9d4d9b5ba229d9d60e5c12600cd5"}, -] - -[package.extras] -test = ["coverage", "pytest", "pytest-cov"] - -[[package]] -name = "unicodecsv" -version = "0.14.1" -description = "Python2's stdlib csv module is nice, but it doesn't support unicode. This module is a drop-in replacement which *does*." -optional = false -python-versions = "*" -files = [ - {file = "unicodecsv-0.14.1.tar.gz", hash = "sha256:018c08037d48649a0412063ff4eda26eaa81eff1546dbffa51fa5293276ff7fc"}, -] - -[[package]] -name = "universal-pathlib" -version = "0.2.2" -description = "pathlib api extended to use fsspec backends" -optional = false -python-versions = ">=3.8" -files = [ - {file = "universal_pathlib-0.2.2-py3-none-any.whl", hash = "sha256:9bc176112d593348bb29806a47e409eda78dff8d95391d66dd6f85e443aaa75d"}, - {file = "universal_pathlib-0.2.2.tar.gz", hash = "sha256:6bc215548792ad5db3553708b1c19bafd9e2fa1667dc925ed404c95e52ae2f13"}, -] - -[package.dependencies] -fsspec = ">=2022.1.0" - -[package.extras] -dev = ["adlfs", "aiohttp", "cheroot", "gcsfs", "moto[s3,server] (<5)", "mypy (==1.8.0)", "packaging", "pydantic", "pydantic-settings", "pylint (==2.17.4)", "pytest (==8.0.0)", "pytest-cov (==4.1.0)", "pytest-mock (==3.12.0)", "pytest-sugar (==0.9.7)", "requests", "s3fs", "webdav4[fsspec]", "wsgidav"] -tests = ["mypy (==1.8.0)", "packaging", "pylint (==2.17.4)", "pytest (==8.0.0)", "pytest-cov (==4.1.0)", "pytest-mock (==3.12.0)", "pytest-sugar (==0.9.7)"] - -[[package]] -name = "uritemplate" -version = "4.1.1" -description = "Implementation of RFC 6570 URI Templates" -optional = false -python-versions = ">=3.6" -files = [ - {file = "uritemplate-4.1.1-py2.py3-none-any.whl", hash = "sha256:830c08b8d99bdd312ea4ead05994a38e8936266f84b9a7878232db50b044e02e"}, - {file = "uritemplate-4.1.1.tar.gz", hash = "sha256:4346edfc5c3b79f694bccd6d6099a322bbeb628dbf2cd86eea55a456ce5124f0"}, -] - [[package]] name = "urllib3" version = "2.2.2" @@ -8409,41 +5003,6 @@ files = [ {file = "wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5"}, ] -[[package]] -name = "werkzeug" -version = "2.3.8" -description = "The comprehensive WSGI web application library." -optional = false -python-versions = ">=3.8" -files = [ - {file = "werkzeug-2.3.8-py3-none-any.whl", hash = "sha256:bba1f19f8ec89d4d607a3bd62f1904bd2e609472d93cd85e9d4e178f472c3748"}, - {file = "werkzeug-2.3.8.tar.gz", hash = "sha256:554b257c74bbeb7a0d254160a4f8ffe185243f52a52035060b761ca62d977f03"}, -] - -[package.dependencies] -MarkupSafe = ">=2.1.1" - -[package.extras] -watchdog = ["watchdog (>=2.3)"] - -[[package]] -name = "wirerope" -version = "0.4.7" -description = "'Turn functions and methods into fully controllable objects'" -optional = false -python-versions = "*" -files = [ - {file = "wirerope-0.4.7-py2.py3-none-any.whl", hash = "sha256:332973a3be6898f02fd0e73b2e20414c5102cc6c811d75856a938206677495c8"}, - {file = "wirerope-0.4.7.tar.gz", hash = "sha256:f3961039218276283c5037da0fa164619def0327595f10892d562a61a8603990"}, -] - -[package.dependencies] -six = ">=1.11.0" - -[package.extras] -doc = ["sphinx"] -test = ["pytest (>=4.6.7)", "pytest-cov (>=2.6.1)"] - [[package]] name = "wrapt" version = "1.16.0" @@ -8523,23 +5082,6 @@ files = [ {file = "wrapt-1.16.0.tar.gz", hash = "sha256:5f370f952971e7d17c7d1ead40e49f32345a7f7a5373571ef44d800d06b1899d"}, ] -[[package]] -name = "wtforms" -version = "3.1.2" -description = "Form validation and rendering for Python web development." -optional = false -python-versions = ">=3.8" -files = [ - {file = "wtforms-3.1.2-py3-none-any.whl", hash = "sha256:bf831c042829c8cdbad74c27575098d541d039b1faa74c771545ecac916f2c07"}, - {file = "wtforms-3.1.2.tar.gz", hash = "sha256:f8d76180d7239c94c6322f7990ae1216dae3659b7aa1cee94b6318bdffb474b9"}, -] - -[package.dependencies] -markupsafe = "*" - -[package.extras] -email = ["email-validator"] - [[package]] name = "xyzservices" version = "2024.6.0" @@ -8672,22 +5214,7 @@ files = [ idna = ">=2.0" multidict = ">=4.0" -[[package]] -name = "zipp" -version = "3.19.2" -description = "Backport of pathlib-compatible object wrapper for zip files" -optional = false -python-versions = ">=3.8" -files = [ - {file = "zipp-3.19.2-py3-none-any.whl", hash = "sha256:f091755f667055f2d02b32c53771a7a6c8b47e1fdbc4b72a8b9072b3eef8015c"}, - {file = "zipp-3.19.2.tar.gz", hash = "sha256:bf1dcf6450f873a13e952a29504887c89e6de7506209e5b1bcc3460135d4de19"}, -] - -[package.extras] -doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy", "pytest-ruff (>=0.2.1)"] - [metadata] lock-version = "2.0" python-versions = "^3.10, <3.11" -content-hash = "489d535e828faa827aa6cedc3bb739eff1c3b841770d3b9e94bdde44e572e621" +content-hash = "5b7e79eb2ca58918d786e61b6331115376a24705da5478c6feef85d37f24685e" diff --git a/pyproject.toml b/pyproject.toml index d91629ab3..094ca1f6e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -71,8 +71,6 @@ pytest-xdist = "^3.5.0" ipython = "^8.19.0" ipykernel = "^6.28.0" google-cloud-dataproc = "^5.8.0" -apache-airflow = "^2.8.0" -apache-airflow-providers-google = "^10.13.1" pydoclint = ">=0.3.8,<0.6.0" prettier = "^0.0.7" deptry = ">=0.12,<0.21" @@ -113,7 +111,7 @@ requires = ["poetry-core>=1.0.0"] build-backend = "poetry.core.masonry.api" [tool.deptry] -extend_exclude = ["src/conftest.py", "src/airflow", "src/utils"] +extend_exclude = ["src/conftest.py", "src/utils"] [tool.deptry.per_rule_ignores] DEP001 = ["gentropy"] @@ -126,8 +124,8 @@ exclude = ["dist"] [tool.pytest.ini_options] addopts = "-n auto --doctest-modules --cov=src/ --cov-report=xml" -pythonpath = [".", "./src/airflow/dags"] -testpaths = ["tests/gentropy", "src/gentropy/"] +pythonpath = ["."] +testpaths = ["tests/gentropy", "src/gentropy"] # Semi-strict mode for mypy [tool.mypy] diff --git a/src/airflow/.env b/src/airflow/.env deleted file mode 100644 index 2bcd8244f..000000000 --- a/src/airflow/.env +++ /dev/null @@ -1,6 +0,0 @@ -AIRFLOW_IMAGE_NAME=extending_airflow:latest -GOOGLE_LOCAL_CREDENTIALS_PATH=~/.config/gcloud -GOOGLE_DOCKER_CREDENTIALS_PATH=/.config/gcloud -GOOGLE_APPLICATION_CREDENTIALS=/.config/gcloud/service_account_credentials.json -AIRFLOW_CONN_GOOGLE_CLOUD_DEFAULT='google-cloud-platform://?extra__google_cloud_platform__key_path=/.config/gcloud/service_account_credentials.json' -GCP_PROJECT_ID=open-targets-genetics-dev diff --git a/src/airflow/Dockerfile b/src/airflow/Dockerfile deleted file mode 100644 index 9ca7c9193..000000000 --- a/src/airflow/Dockerfile +++ /dev/null @@ -1,33 +0,0 @@ -FROM apache/airflow:slim-2.7.3-python3.10 - -# Install additional Python requirements. -# --no-cache-dir is a good practice when installing packages using pip, because it helps to keep the image lightweight. -COPY requirements.txt /requirements.txt -RUN pip install --quiet --user --no-cache-dir --upgrade pip setuptools && \ - pip install --quiet --user --no-cache-dir -r /requirements.txt - -# Source: https://airflow.apache.org/docs/docker-stack/recipes.html -# Installing the GCP CLI in the container -SHELL ["/bin/bash", "-o", "pipefail", "-e", "-u", "-x", "-c"] - -USER 0 -ARG CLOUD_SDK_VERSION=452.0.0 -ENV GCLOUD_HOME=/home/google-cloud-sdk - -ENV PATH="${GCLOUD_HOME}/bin/:${PATH}" - -RUN DOWNLOAD_URL="https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-sdk-${CLOUD_SDK_VERSION}-linux-x86_64.tar.gz" \ - && TMP_DIR="$(mktemp -d)" \ - && curl -fL "${DOWNLOAD_URL}" --output "${TMP_DIR}/google-cloud-sdk.tar.gz" \ - && mkdir -p "${GCLOUD_HOME}" \ - && tar xzf "${TMP_DIR}/google-cloud-sdk.tar.gz" -C "${GCLOUD_HOME}" --strip-components=1 \ - && "${GCLOUD_HOME}/install.sh" \ - --bash-completion=false \ - --path-update=false \ - --usage-reporting=false \ - --quiet \ - && rm -rf "${TMP_DIR}" \ - && gcloud --version - -# Switch back to a non-root user for security purposes -USER airflow diff --git a/src/airflow/config/.gitkeep b/src/airflow/config/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/airflow/dags/.gitkeep b/src/airflow/dags/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/airflow/dags/common_airflow.py b/src/airflow/dags/common_airflow.py deleted file mode 100644 index 9c3c2f91c..000000000 --- a/src/airflow/dags/common_airflow.py +++ /dev/null @@ -1,490 +0,0 @@ -"""Airflow boilerplate code which can be shared by several DAGs.""" - -from __future__ import annotations - -from typing import TYPE_CHECKING, Any, Optional - -import pendulum -import yaml -from google.cloud import batch_v1, dataproc_v1, storage - -from airflow.providers.google.cloud.operators.dataproc import ( - ClusterGenerator, - DataprocCreateClusterOperator, - DataprocDeleteClusterOperator, - DataprocSubmitJobOperator, -) -from airflow.utils.trigger_rule import TriggerRule - -if TYPE_CHECKING: - from pathlib import Path - -# Code version. It has to be repeated here as well as in `pyproject.toml`, because Airflow isn't able to look at files outside of its `dags/` directory. -GENTROPY_VERSION = "0.0.0" - -# Cloud configuration. -GCP_PROJECT = "open-targets-genetics-dev" -GCP_REGION = "europe-west1" -GCP_ZONE = "europe-west1-d" -GCP_DATAPROC_IMAGE = "2.1" -GCP_AUTOSCALING_POLICY = "otg-etl" - -# Cluster init configuration. -INITIALISATION_BASE_PATH = ( - f"gs://genetics_etl_python_playground/initialisation/{GENTROPY_VERSION}" -) -CONFIG_TAG = f"{INITIALISATION_BASE_PATH}/config.tar.gz" -PACKAGE_WHEEL = ( - f"{INITIALISATION_BASE_PATH}/gentropy-{GENTROPY_VERSION}-py3-none-any.whl" -) -INITIALISATION_EXECUTABLE_FILE = [ - f"{INITIALISATION_BASE_PATH}/install_dependencies_on_cluster.sh" -] - -# CLI configuration. -CLUSTER_CONFIG_DIR = "/config" -CONFIG_NAME = "ot_config" -PYTHON_CLI = "cli.py" - -# Shared DAG construction parameters. -shared_dag_args = { - "owner": "Open Targets Data Team", - "retries": 0, -} - -shared_dag_kwargs = { - "tags": ["genetics_etl", "experimental"], - "start_date": pendulum.now(tz="Europe/London").subtract(days=1), - "schedule": "@once", - "catchup": False, -} - -MACHINES = { - "VEPMACHINE": { - "machine_type": "e2-standard-4", - "cpu_milli": 2000, - "memory_mib": 2000, - "boot_disk_mib": 10000, - }, -} - - -def check_gcp_folder_exists(bucket_name: str, folder_path: str) -> bool: - """Check if a folder exists in a Google Cloud bucket. - - Args: - bucket_name (str): The name of the Google Cloud bucket. - folder_path (str): The path of the folder to check. - - Returns: - bool: True if the folder exists, False otherwise. - """ - client = storage.Client() - bucket = client.get_bucket(bucket_name) - blobs = bucket.list_blobs(prefix=folder_path) - return any(blobs) - - -def create_cluster( - cluster_name: str, - master_machine_type: str = "n1-highmem-16", - worker_machine_type: str = "n1-standard-16", - num_workers: int = 2, - num_preemptible_workers: int = 0, - num_local_ssds: int = 1, - autoscaling_policy: str = GCP_AUTOSCALING_POLICY, - master_disk_size: int = 500, -) -> DataprocCreateClusterOperator: - """Generate an Airflow task to create a Dataproc cluster. Common parameters are reused, and varying parameters can be specified as needed. - - Args: - cluster_name (str): Name of the cluster. - master_machine_type (str): Machine type for the master node. Defaults to "n1-highmem-8". - worker_machine_type (str): Machine type for the worker nodes. Defaults to "n1-standard-16". - num_workers (int): Number of worker nodes. Defaults to 2. - num_preemptible_workers (int): Number of preemptible worker nodes. Defaults to 0. - num_local_ssds (int): How many local SSDs to attach to each worker node, both primary and secondary. Defaults to 1. - autoscaling_policy (str): Name of the autoscaling policy to use. Defaults to GCP_AUTOSCALING_POLICY. - master_disk_size (int): Size of the master node's boot disk in GB. Defaults to 500. - - Returns: - DataprocCreateClusterOperator: Airflow task to create a Dataproc cluster. - """ - # Create base cluster configuration. - cluster_config = ClusterGenerator( - project_id=GCP_PROJECT, - zone=GCP_ZONE, - master_machine_type=master_machine_type, - worker_machine_type=worker_machine_type, - master_disk_size=master_disk_size, - worker_disk_size=500, - num_preemptible_workers=num_preemptible_workers, - num_workers=num_workers, - image_version=GCP_DATAPROC_IMAGE, - enable_component_gateway=True, - optional_components=["JUPYTER"], - init_actions_uris=INITIALISATION_EXECUTABLE_FILE, - metadata={ - "CONFIGTAR": CONFIG_TAG, - "PACKAGE": PACKAGE_WHEEL, - }, - idle_delete_ttl=30 * 60, # In seconds. - autoscaling_policy=f"projects/{GCP_PROJECT}/regions/{GCP_REGION}/autoscalingPolicies/{autoscaling_policy}", - ).make() - - # If specified, amend the configuration to include local SSDs for worker nodes. - if num_local_ssds: - for worker_section in ("worker_config", "secondary_worker_config"): - # Create a disk config section if it does not exist. - cluster_config[worker_section].setdefault("disk_config", {}) - # Specify the number of local SSDs. - cluster_config[worker_section]["disk_config"]["num_local_ssds"] = ( - num_local_ssds - ) - - # Return the cluster creation operator. - return DataprocCreateClusterOperator( - task_id="create_cluster", - project_id=GCP_PROJECT, - cluster_config=cluster_config, - region=GCP_REGION, - cluster_name=cluster_name, - trigger_rule=TriggerRule.ALL_SUCCESS, - ) - - -def submit_job( - cluster_name: str, - task_id: str, - job_type: str, - job_specification: dict[str, Any], - trigger_rule: TriggerRule = TriggerRule.ALL_SUCCESS, -) -> DataprocSubmitJobOperator: - """Submit an arbitrary job to a Dataproc cluster. - - Args: - cluster_name (str): Name of the cluster. - task_id (str): Name of the task. - job_type (str): Type of the job to submit. - job_specification (dict[str, Any]): Specification of the job to submit. - trigger_rule (TriggerRule): Trigger rule for the task. Defaults to TriggerRule.ALL_SUCCESS. - - Returns: - DataprocSubmitJobOperator: Airflow task to submit an arbitrary job to a Dataproc cluster. - """ - return DataprocSubmitJobOperator( - task_id=task_id, - region=GCP_REGION, - project_id=GCP_PROJECT, - job={ - "job_uuid": f"airflow-{task_id}", - "reference": {"project_id": GCP_PROJECT}, - "placement": {"cluster_name": cluster_name}, - job_type: job_specification, - }, - trigger_rule=trigger_rule, - ) - - -def submit_pyspark_job( - cluster_name: str, - task_id: str, - python_module_path: str, - args: list[str], - trigger_rule: TriggerRule = TriggerRule.ALL_SUCCESS, -) -> DataprocSubmitJobOperator: - """Submit a PySpark job to a Dataproc cluster. - - Args: - cluster_name (str): Name of the cluster. - task_id (str): Name of the task. - python_module_path (str): Path to the Python module to run. - args (list[str]): Arguments to pass to the Python module. - trigger_rule (TriggerRule): Trigger rule for the task. Defaults to TriggerRule.ALL_SUCCESS. - - Returns: - DataprocSubmitJobOperator: Airflow task to submit a PySpark job to a Dataproc cluster. - """ - return submit_job( - cluster_name=cluster_name, - task_id=task_id, - job_type="pyspark_job", - trigger_rule=trigger_rule, - job_specification={ - "main_python_file_uri": python_module_path, - "args": args, - "properties": { - "spark.jars": "/opt/conda/miniconda3/lib/python3.10/site-packages/hail/backend/hail-all-spark.jar", - "spark.driver.extraClassPath": "/opt/conda/miniconda3/lib/python3.10/site-packages/hail/backend/hail-all-spark.jar", - "spark.executor.extraClassPath": "./hail-all-spark.jar", - "spark.serializer": "org.apache.spark.serializer.KryoSerializer", - "spark.kryo.registrator": "is.hail.kryo.HailKryoRegistrator", - }, - }, - ) - - -def submit_step( - cluster_name: str, - step_id: str, - task_id: str = "", - trigger_rule: TriggerRule = TriggerRule.ALL_SUCCESS, - other_args: Optional[list[str]] = None, -) -> DataprocSubmitJobOperator: - """Submit a PySpark job to execute a specific CLI step. - - Args: - cluster_name (str): Name of the cluster. - step_id (str): Name of the step in gentropy. - task_id (str): Name of the task. Defaults to step_id. - trigger_rule (TriggerRule): Trigger rule for the task. Defaults to TriggerRule.ALL_SUCCESS. - other_args (Optional[list[str]]): Other arguments to pass to the CLI step. Defaults to None. - - Returns: - DataprocSubmitJobOperator: Airflow task to submit a PySpark job to execute a specific CLI step. - """ - if task_id == "": - task_id = step_id - return submit_pyspark_job( - cluster_name=cluster_name, - task_id=task_id, - python_module_path=f"{INITIALISATION_BASE_PATH}/{PYTHON_CLI}", - trigger_rule=trigger_rule, - args=[f"step={step_id}"] - + (other_args if other_args is not None else []) - + [ - f"--config-dir={CLUSTER_CONFIG_DIR}", - f"--config-name={CONFIG_NAME}", - ], - ) - - -def install_dependencies(cluster_name: str) -> DataprocSubmitJobOperator: - """Install dependencies on a Dataproc cluster. - - Args: - cluster_name (str): Name of the cluster. - - Returns: - DataprocSubmitJobOperator: Airflow task to install dependencies on a Dataproc cluster. - """ - return submit_job( - cluster_name=cluster_name, - task_id="install_dependencies", - job_type="pig_job", - job_specification={ - "jar_file_uris": [ - f"gs://genetics_etl_python_playground/initialisation/{GENTROPY_VERSION}/install_dependencies_on_cluster.sh" - ], - "query_list": { - "queries": [ - "sh chmod 750 ${PWD}/install_dependencies_on_cluster.sh", - "sh ${PWD}/install_dependencies_on_cluster.sh", - ] - }, - }, - ) - - -def delete_cluster(cluster_name: str) -> DataprocDeleteClusterOperator: - """Generate an Airflow task to delete a Dataproc cluster. - - Args: - cluster_name (str): Name of the cluster. - - Returns: - DataprocDeleteClusterOperator: Airflow task to delete a Dataproc cluster. - """ - return DataprocDeleteClusterOperator( - task_id="delete_cluster", - project_id=GCP_PROJECT, - cluster_name=cluster_name, - region=GCP_REGION, - trigger_rule=TriggerRule.ALL_DONE, - ) - - -def read_yaml_config(config_path: Path) -> Any: - """Parse a YAMl config file and do all necessary checks. - - Args: - config_path (Path): Path to the YAML config file. - - Returns: - Any: Parsed YAML config file. - """ - assert config_path.exists(), f"YAML config path {config_path} does not exist." - with open(config_path) as config_file: - return yaml.safe_load(config_file) - - -def generate_dag(cluster_name: str, tasks: list[DataprocSubmitJobOperator]) -> Any: - """For a list of tasks, generate a complete DAG. - - Args: - cluster_name (str): Name of the cluster. - tasks (list[DataprocSubmitJobOperator]): List of tasks to execute. - - Returns: - Any: Airflow DAG. - """ - return ( - create_cluster(cluster_name) - >> install_dependencies(cluster_name) - >> tasks - >> delete_cluster(cluster_name) - ) - - -def submit_pyspark_job_no_operator( - cluster_name: str, - step_id: str, - other_args: Optional[list[str]] = None, -) -> None: - """Submits the Pyspark job to the cluster. - - Args: - cluster_name (str): Cluster name - step_id (str): Step id - other_args (Optional[list[str]]): Other arguments to pass to the CLI step. Defaults to None. - """ - # Create the job client. - job_client = dataproc_v1.JobControllerClient( - client_options={"api_endpoint": f"{GCP_REGION}-dataproc.googleapis.com:443"} - ) - - python_uri = f"{INITIALISATION_BASE_PATH}/{PYTHON_CLI}" - # Create the job config. 'main_jar_file_uri' can also be a - # Google Cloud Storage URL. - job_description = { - "placement": {"cluster_name": cluster_name}, - "pyspark_job": { - "main_python_file_uri": python_uri, - "args": [f"step={step_id}"] - + (other_args if other_args is not None else []) - + [ - f"--config-dir={CLUSTER_CONFIG_DIR}", - f"--config-name={CONFIG_NAME}", - ], - "properties": { - "spark.jars": "/opt/conda/miniconda3/lib/python3.10/site-packages/hail/backend/hail-all-spark.jar", - "spark.driver.extraClassPath": "/opt/conda/miniconda3/lib/python3.10/site-packages/hail/backend/hail-all-spark.jar", - "spark.executor.extraClassPath": "./hail-all-spark.jar", - "spark.serializer": "org.apache.spark.serializer.KryoSerializer", - "spark.kryo.registrator": "is.hail.kryo.HailKryoRegistrator", - }, - }, - } - job_client.submit_job( - project_id=GCP_PROJECT, region=GCP_REGION, job=job_description - ) - - -def create_container_runnable( - image: str, commands: list[str], **kwargs: Any -) -> batch_v1.Runnable: - """Create a container runnable for a Batch job with additional optional parameters. - - Args: - image (str): The Docker image to use. - commands (list[str]): The commands to run in the container. - **kwargs (Any): Additional optional parameters to set on the container. - - Returns: - batch_v1.Runnable: The container runnable. - """ - container = batch_v1.Runnable.Container( - image_uri=image, entrypoint="/bin/sh", commands=commands, **kwargs - ) - return batch_v1.Runnable(container=container) - - -def create_task_spec( - image: str, commands: list[str], **kwargs: Any -) -> batch_v1.TaskSpec: - """Create a task for a Batch job. - - Args: - image (str): The Docker image to use. - commands (list[str]): The commands to run in the container. - **kwargs (Any): Any additional parameter to pass to the container runnable - - Returns: - batch_v1.TaskSpec: The task specification. - """ - task = batch_v1.TaskSpec() - task.runnables = [create_container_runnable(image, commands, **kwargs)] - return task - - -def set_up_mounting_points( - mounting_points: list[dict[str, str]], -) -> list[batch_v1.Volume]: - """Set up the mounting points for the container. - - Args: - mounting_points (list[dict[str, str]]): The mounting points. - - Returns: - list[batch_v1.Volume]: The volumes. - """ - volumes = [] - for mount in mounting_points: - gcs_bucket = batch_v1.GCS() - gcs_bucket.remote_path = mount["remote_path"] - gcs_volume = batch_v1.Volume() - gcs_volume.gcs = gcs_bucket - gcs_volume.mount_path = mount["mount_point"] - volumes.append(gcs_volume) - return volumes - - -def create_batch_job( - task: batch_v1.TaskSpec, - machine: str, - task_env: list[batch_v1.Environment], - mounting_points: list[dict[str, str]] | None = None, -) -> batch_v1.Job: - """Create a Google Batch job. - - Args: - task (batch_v1.TaskSpec): The task specification. - machine (str): The machine type to use. - task_env (list[batch_v1.Environment]): The environment variables for the task. - mounting_points (list[dict[str, str]] | None): List of mounting points. - - Returns: - batch_v1.Job: The Batch job. - """ - resources = batch_v1.ComputeResource() - resources.cpu_milli = MACHINES[machine]["cpu_milli"] - resources.memory_mib = MACHINES[machine]["memory_mib"] - resources.boot_disk_mib = MACHINES[machine]["boot_disk_mib"] - task.compute_resource = resources - - task.max_retry_count = 3 - task.max_run_duration = "43200s" - - # The mounting points are set up and assigned to the task: - task.volumes = set_up_mounting_points(mounting_points) if mounting_points else None - - group = batch_v1.TaskGroup() - group.task_spec = task - group.task_environments = task_env - - policy = batch_v1.AllocationPolicy.InstancePolicy() - policy.machine_type = MACHINES[machine]["machine_type"] - policy.provisioning_model = "SPOT" - - instances = batch_v1.AllocationPolicy.InstancePolicyOrTemplate() - instances.policy = policy - allocation_policy = batch_v1.AllocationPolicy() - allocation_policy.instances = [instances] - - job = batch_v1.Job() - job.task_groups = [group] - job.allocation_policy = allocation_policy - job.logs_policy = batch_v1.LogsPolicy() - job.logs_policy.destination = batch_v1.LogsPolicy.Destination.CLOUD_LOGGING - - return job diff --git a/src/airflow/dags/configs/dag.yaml b/src/airflow/dags/configs/dag.yaml deleted file mode 100644 index 24d185c1e..000000000 --- a/src/airflow/dags/configs/dag.yaml +++ /dev/null @@ -1,17 +0,0 @@ -- id: "ot_gene_index" -- id: "ot_variant_to_gene" - prerequisites: - - "ot_gene_index" -- id: "ot_colocalisation_ecaviar" -- id: "ot_colocalisation_coloc" -- id: "ot_locus_to_gene_train" - prerequisites: - - "ot_variant_to_gene" - - "ot_colocalisation_ecaviar" - - "ot_colocalisation_coloc" -- id: "ot_locus_to_gene_predict" - prerequisites: - - "ot_locus_to_gene_train" - - "ot_variant_to_gene" - - "ot_colocalisation_ecaviar" - - "ot_colocalisation_coloc" diff --git a/src/airflow/dags/configs/variant_sources.yaml b/src/airflow/dags/configs/variant_sources.yaml deleted file mode 100644 index 233eb0ccf..000000000 --- a/src/airflow/dags/configs/variant_sources.yaml +++ /dev/null @@ -1,13 +0,0 @@ -sources_inclusion_list: - - name: uniprot - location: gs://open-targets-pre-data-releases/24.09/input/evidence-files/uniprot.json.gz ## input - format: json - - name: clinvar - location: gs://open-targets-pre-data-releases/24.09/input/evidence-files/eva.json.gz - format: json - - name: pharmgkb - location: gs://open-targets-pre-data-releases/24.09/input/pharmacogenomics-inputs/pharmacogenomics.json.gz - format: json - - name: gentropy_credible_sets - location: gs://genetics_etl_python_playground/releases/24.06/credible_set - format: parquet diff --git a/src/airflow/dags/data_validation.py b/src/airflow/dags/data_validation.py deleted file mode 100644 index 875a169dc..000000000 --- a/src/airflow/dags/data_validation.py +++ /dev/null @@ -1,96 +0,0 @@ -"""DAG to validate study locus and study index datasets.""" - -from __future__ import annotations - -from pathlib import Path - -import common_airflow as common - -from airflow.models.dag import DAG - -CLUSTER_NAME = "otg-validation" - -# Input datasets: -STUDY_INDICES = [ - "gs://gwas_catalog_data/study_index", - "gs://eqtl_catalogue_data/study_index", - "gs://finngen_data/r10/study_index", -] -STUDY_LOCI = [ - "gs://gwas_catalog_data/credible_set_datasets/gwas_catalog_PICSed_curated_associations", - "gs://gwas_catalog_data/credible_set_datasets/gwas_catalog_PICSed_summary_statistics", - "gs://eqtl_catalogue_data/credible_set_datasets/susie", - "gs://finngen_data/r10/credible_set_datasets/finngen_susie_processed", -] -TARGET_INDEX = "gs://genetics_etl_python_playground/releases/24.06/gene_index" -DISEASE_INDEX = "gs://open-targets-pre-data-releases/24.06/output/etl/parquet/diseases" - -# Output datasets: -VALIDATED_STUDY = "gs://ot-team/dsuveges/otg-data/validated_study_index" -INVALID_STUDY = f"{VALIDATED_STUDY}_invalid" -INVALID_STUDY_QC = [ - "UNRESOLVED_TARGET", - "UNRESOLVED_DISEASE", - "UNKNOWN_STUDY_TYPE", - "DUPLICATED_STUDY", - "NO_GENE_PROVIDED", -] - -VALIDATED_STUDY_LOCI = "gs://ot-team/dsuveges/otg-data/validated_credible_set" -INVALID_STUDY_LOCI = f"{VALIDATED_STUDY_LOCI}_invalid" -INVALID_STUDY_LOCUS_QC = [ - "DUPLICATED_STUDYLOCUS_ID", - "AMBIGUOUS_STUDY", - "FAILED_STUDY", - "MISSING_STUDY", - "NO_GENOMIC_LOCATION_FLAG", - "COMPOSITE_FLAG", - "INCONSISTENCY_FLAG", - "PALINDROMIC_ALLELE_FLAG", -] - -with DAG( - dag_id=Path(__file__).stem, - description="Open Targets Genetics — Study locus and study index validation", - default_args=common.shared_dag_args, - **common.shared_dag_kwargs, -) as dag: - # Definition of the study index validation step: - validate_studies = common.submit_step( - cluster_name=CLUSTER_NAME, - step_id="study_validation", - task_id="study_validation", - other_args=[ - f"step.study_index_path={STUDY_INDICES}", - f"step.target_index_path={TARGET_INDEX}", - f"step.disease_index_path={DISEASE_INDEX}", - f"step.valid_study_index_path={VALIDATED_STUDY}", - f"step.invalid_study_index_path={INVALID_STUDY_LOCI}", - f"step.invalid_qc_reasons={INVALID_STUDY_QC}", - ], - ) - - # Definition of the study locus validation step: - validate_study_loci = common.submit_step( - cluster_name=CLUSTER_NAME, - step_id="credible_set_validation", - task_id="credible_set_validation", - other_args=[ - f"step.study_index_path={VALIDATED_STUDY}", - f"step.study_locus_path={STUDY_LOCI}", - f"step.valid_study_locus_path={VALIDATED_STUDY_LOCI}", - f"step.invalid_study_locus_path={INVALID_STUDY_LOCI}", - f"step.invalid_qc_reasons={INVALID_STUDY_LOCUS_QC}", - ], - ) - - ( - common.create_cluster( - CLUSTER_NAME, - master_machine_type="n1-highmem-32", - ) - >> common.install_dependencies(CLUSTER_NAME) - >> validate_studies - >> validate_study_loci - # >> common.delete_cluster(CLUSTER_NAME) - ) diff --git a/src/airflow/dags/eqtl_preprocess.py b/src/airflow/dags/eqtl_preprocess.py deleted file mode 100644 index 309604e09..000000000 --- a/src/airflow/dags/eqtl_preprocess.py +++ /dev/null @@ -1,73 +0,0 @@ -"""Airflow DAG to extract credible sets and a study index from eQTL Catalogue's finemapping results.""" - -from __future__ import annotations - -from pathlib import Path - -import common_airflow as common - -from airflow.models.dag import DAG -from airflow.providers.google.cloud.operators.dataflow import ( - DataflowTemplatedJobStartOperator, -) -from airflow.providers.google.cloud.operators.gcs import GCSDeleteObjectsOperator - -CLUSTER_NAME = "otg-preprocess-eqtl" -AUTOSCALING = "eqtl-preprocess" -PROJECT_ID = "open-targets-genetics-dev" - -EQTL_CATALOGUE_SUSIE_LOCATION = "gs://eqtl_catalogue_data/ebi_ftp/susie" -TEMP_DECOMPRESS_LOCATION = f"{EQTL_CATALOGUE_SUSIE_LOCATION}_decompressed_tmp" -DECOMPRESS_FAILED_LOG = f"{TEMP_DECOMPRESS_LOCATION}/logs.log" -STUDY_INDEX_PATH = "gs://eqtl_catalogue_data/study_index" -CREDIBLE_SET_PATH = "gs://eqtl_catalogue_data/credible_set_datasets/susie" - -with DAG( - dag_id=Path(__file__).stem, - description="Open Targets Genetics — eQTL preprocess", - default_args=common.shared_dag_args, - **common.shared_dag_kwargs, -): - # SuSIE fine mapping results are stored as gzipped files in a GCS bucket. - # To improve processing performance, we decompress the files before processing to a temporary location in GCS. - decompression_job = DataflowTemplatedJobStartOperator( - task_id="decompress_susie_outputs", - template="gs://dataflow-templates/latest/Bulk_Decompress_GCS_Files", - location="europe-west1", - project_id=PROJECT_ID, - parameters={ - "inputFilePattern": f"{EQTL_CATALOGUE_SUSIE_LOCATION}/**/*.gz", - "outputDirectory": TEMP_DECOMPRESS_LOCATION, - "outputFailureFile": DECOMPRESS_FAILED_LOG, - }, - ) - - ingestion_job = common.submit_step( - cluster_name=CLUSTER_NAME, - step_id="ot_eqtl_catalogue", - task_id="ot_eqtl_ingestion", - other_args=[ - f"step.eqtl_catalogue_paths_imported={TEMP_DECOMPRESS_LOCATION}", - f"step.eqtl_catalogue_study_index_out={STUDY_INDEX_PATH}", - f"step.eqtl_catalogue_credible_sets_out={CREDIBLE_SET_PATH}", - ], - ) - - delete_decompressed_job = GCSDeleteObjectsOperator( - task_id="delete_decompressed_files", - bucket_name=TEMP_DECOMPRESS_LOCATION.split("/")[2], - prefix=f"{TEMP_DECOMPRESS_LOCATION.split('/')[-1]}/", - ) - - ( - decompression_job - >> common.create_cluster( - CLUSTER_NAME, - autoscaling_policy=AUTOSCALING, - num_workers=4, - worker_machine_type="n1-highmem-8", - ) - >> common.install_dependencies(CLUSTER_NAME) - >> ingestion_job - >> [delete_decompressed_job, common.delete_cluster(CLUSTER_NAME)] - ) diff --git a/src/airflow/dags/genetics_etl.py b/src/airflow/dags/genetics_etl.py deleted file mode 100644 index aeb87398c..000000000 --- a/src/airflow/dags/genetics_etl.py +++ /dev/null @@ -1,154 +0,0 @@ -"""Test DAG to prototype data transfer.""" - -from __future__ import annotations - -from pathlib import Path - -import common_airflow as common - -from airflow.models.dag import DAG -from airflow.operators.python import ShortCircuitOperator -from airflow.providers.google.cloud.transfers.gcs_to_gcs import GCSToGCSOperator -from airflow.utils.task_group import TaskGroup - -CLUSTER_NAME = "otg-etl" -SOURCE_CONFIG_FILE_PATH = Path(__file__).parent / "configs" / "dag.yaml" - -# Release specific variables: -RELEASE_VERSION = "24.06" -RELEASE_BUCKET_NAME = "genetics_etl_python_playground" - -# Datasource paths: -GWAS_CATALOG_BUCKET_NAME = "gwas_catalog_data" -EQTL_BUCKET_NAME = "eqtl_catalogue_data" -FINNGEN_BUCKET_NAME = "finngen_data" -FINNGEN_RELEASE = "r10" - -# Files to move: -DATA_TO_MOVE = { - # GWAS Catalog summary study index: - "gwas_catalog_study_index": { - "source_bucket": GWAS_CATALOG_BUCKET_NAME, - "source_object": "study_index", - "destination_bucket": RELEASE_BUCKET_NAME, - "destination_object": f"releases/{RELEASE_VERSION}/study_index/gwas_catalog", - }, - # PICS credible sets from GWAS Catalog curated associations: - "gwas_catalog_curated_credible_set": { - "source_bucket": GWAS_CATALOG_BUCKET_NAME, - "source_object": "credible_set_datasets/gwas_catalog_PICSed_curated_associations", - "destination_bucket": RELEASE_BUCKET_NAME, - "destination_object": f"releases/{RELEASE_VERSION}/credible_set/gwas_catalog_PICSed_curated_associations", - }, - # PICS credible sets from GWAS Catalog summary statistics: - "gwas_catalog_sumstats_credible_set": { - "source_bucket": GWAS_CATALOG_BUCKET_NAME, - "source_object": "credible_set_datasets/gwas_catalog_PICSed_summary_statistics", - "destination_bucket": RELEASE_BUCKET_NAME, - "destination_object": f"releases/{RELEASE_VERSION}/credible_set/gwas_catalog_PICSed_summary_statistics", - }, - # GWAS Catalog manifest files: - "gwas_catalog_manifests": { - "source_bucket": GWAS_CATALOG_BUCKET_NAME, - "source_object": "manifests", - "destination_bucket": RELEASE_BUCKET_NAME, - "destination_object": f"releases/{RELEASE_VERSION}/manifests", - }, - # eQTL Catalog study index: - "eqtl_catalogue_study_index": { - "source_bucket": EQTL_BUCKET_NAME, - "source_object": "study_index", - "destination_bucket": RELEASE_BUCKET_NAME, - "destination_object": f"releases/{RELEASE_VERSION}/study_index/eqtl_catalogue", - }, - # eQTL Catalog SuSiE credible sets: - "eqtl_catalogue_susie_credible_set": { - "source_bucket": EQTL_BUCKET_NAME, - "source_object": "credible_set_datasets/susie", - "destination_bucket": RELEASE_BUCKET_NAME, - "destination_object": f"releases/{RELEASE_VERSION}/credible_set/eqtl_catalogue_susie", - }, - # Finngen study index: - "finngen_study_index": { - "source_bucket": FINNGEN_BUCKET_NAME, - "source_object": f"{FINNGEN_RELEASE}/study_index", - "destination_bucket": RELEASE_BUCKET_NAME, - "destination_object": f"releases/{RELEASE_VERSION}/study_index/finngen", - }, - # Finngen SuSiE credible sets: - "finngen_susie_credible_set": { - "source_bucket": FINNGEN_BUCKET_NAME, - "source_object": f"{FINNGEN_RELEASE}/credible_set_datasets/finngen_susie_processed", - "destination_bucket": RELEASE_BUCKET_NAME, - "destination_object": f"releases/{RELEASE_VERSION}/credible_set/finngen_susie", - }, - # L2G gold standard: - "gold_standard": { - "source_bucket": "genetics_etl_python_playground", - "source_object": "input/l2g/gold_standard/curation.json", - "destination_bucket": RELEASE_BUCKET_NAME, - "destination_object": f"releases/{RELEASE_VERSION}/locus_to_gene_gold_standard.json", - }, -} - - -# This operator meant to fail the DAG if the release folder exists: -ensure_release_folder_not_exists = ShortCircuitOperator( - task_id="test_release_folder_exists", - python_callable=lambda bucket, path: not common.check_gcp_folder_exists( - bucket, path - ), - op_kwargs={ - "bucket": RELEASE_BUCKET_NAME, - "path": f"releases/{RELEASE_VERSION}", - }, -) - -with DAG( - dag_id=Path(__file__).stem, - description="Open Targets Genetics ETL workflow", - default_args=common.shared_dag_args, - **common.shared_dag_kwargs, -): - # Compiling tasks for moving data to the right place: - with TaskGroup(group_id="data_transfer") as data_transfer: - # Defining the tasks to execute in the task group: - [ - GCSToGCSOperator( - task_id=f"move_{data_name}", - source_bucket=data["source_bucket"], - source_object=data["source_object"], - destination_bucket=data["destination_bucket"], - destination_object=data["destination_object"], - ) - for data_name, data in DATA_TO_MOVE.items() - ] - - with TaskGroup(group_id="genetics_etl") as genetics_etl: - # Parse and define all steps and their prerequisites. - tasks = {} - steps = common.read_yaml_config(SOURCE_CONFIG_FILE_PATH) - for step in steps: - # Define task for the current step. - step_id = step["id"] - this_task = common.submit_step( - cluster_name=CLUSTER_NAME, - step_id=step_id, - task_id=step_id, - ) - # Chain prerequisites. - tasks[step_id] = this_task - for prerequisite in step.get("prerequisites", []): - this_task.set_upstream(tasks[prerequisite]) - - common.generate_dag(cluster_name=CLUSTER_NAME, tasks=list(tasks.values())) - - # DAG description: - ( - # Test that the release folder doesn't exist: - ensure_release_folder_not_exists - # Run data transfer: - >> data_transfer - # Once datasets are transferred, run the rest of the steps: - >> genetics_etl - ) diff --git a/src/airflow/dags/gnomad_preprocess.py b/src/airflow/dags/gnomad_preprocess.py deleted file mode 100644 index 54e6b6bf4..000000000 --- a/src/airflow/dags/gnomad_preprocess.py +++ /dev/null @@ -1,29 +0,0 @@ -"""Airflow DAG for the Preprocess GnomAD datasets - LD index and GnomAD variant set.""" - -from __future__ import annotations - -from pathlib import Path - -import common_airflow as common - -from airflow.models.dag import DAG - -CLUSTER_NAME = "gnomad-preprocess" - -ALL_STEPS = [ - "ot_ld_index", - "ot_gnomad_variants", -] - - -with DAG( - dag_id=Path(__file__).stem, - description="Open Targets Genetics — GnomAD Preprocess", - default_args=common.shared_dag_args, - **common.shared_dag_kwargs, -): - all_tasks = [ - common.submit_step(cluster_name=CLUSTER_NAME, step_id=step, task_id=step) - for step in ALL_STEPS - ] - dag = common.generate_dag(cluster_name=CLUSTER_NAME, tasks=all_tasks) diff --git a/src/airflow/dags/gwas_catalog_harmonisation.py b/src/airflow/dags/gwas_catalog_harmonisation.py deleted file mode 100644 index e6399e957..000000000 --- a/src/airflow/dags/gwas_catalog_harmonisation.py +++ /dev/null @@ -1,125 +0,0 @@ -"""Airflow DAG for the harmonisation part of the pipeline.""" - -from __future__ import annotations - -import re -import time -from pathlib import Path -from typing import Any - -import common_airflow as common - -from airflow.decorators import task -from airflow.models.dag import DAG -from airflow.providers.google.cloud.operators.gcs import GCSListObjectsOperator - -CLUSTER_NAME = "otg-gwascatalog-harmonisation" -AUTOSCALING = "gwascatalog-harmonisation" - -SUMMARY_STATS_BUCKET_NAME = "gwas_catalog_data" -RAW_SUMMARY_STATISTICS_PREFIX = "raw_summary_statistics" -HARMONISED_SUMMARY_STATISTICS_PREFIX = "harmonised_summary_statistics" - -with DAG( - dag_id=Path(__file__).stem, - description="Open Targets Genetics — GWAS Catalog harmonisation", - default_args=common.shared_dag_args, - **common.shared_dag_kwargs, -): - # List raw harmonised files from GWAS Catalog - list_inputs = GCSListObjectsOperator( - task_id="list_raw_harmonised", - bucket=SUMMARY_STATS_BUCKET_NAME, - prefix=RAW_SUMMARY_STATISTICS_PREFIX, - match_glob="**/*.h.tsv.gz", - ) - # List parquet files that have been previously processed - list_outputs = GCSListObjectsOperator( - task_id="list_harmonised_parquet", - bucket=SUMMARY_STATS_BUCKET_NAME, - prefix=HARMONISED_SUMMARY_STATISTICS_PREFIX, - match_glob="**/_SUCCESS", - ) - - # Create list of pending jobs - @task(task_id="create_to_do_list") - def create_to_do_list(**kwargs: Any) -> Any: - """Create the to-do list of studies. - - Args: - **kwargs (Any): Keyword arguments. - - Returns: - Any: To-do list. - """ - ti = kwargs["ti"] - raw_harmonised = ti.xcom_pull( - task_ids="list_raw_harmonised", key="return_value" - ) - print("Number of raw harmonised files: ", len(raw_harmonised)) # noqa: T201 - to_do_list = [] - # Remove the ones that have been processed - parquets = ti.xcom_pull(task_ids="list_harmonised_parquet", key="return_value") - print("Number of parquet files: ", len(parquets)) # noqa: T201 - for path in raw_harmonised: - match_result = re.search( - rf"{RAW_SUMMARY_STATISTICS_PREFIX}/(.*)/(GCST\d+)/harmonised/(.*)\.h\.tsv\.gz", - path, - ) - if match_result: - study_id = match_result.group(2) - if ( - f"{HARMONISED_SUMMARY_STATISTICS_PREFIX}/{study_id}.parquet/_SUCCESS" - not in parquets - ): - to_do_list.append(path) - print("Number of jobs to submit: ", len(to_do_list)) # noqa: T201 - ti.xcom_push(key="to_do_list", value=to_do_list) - - # Submit jobs to dataproc - @task(task_id="submit_jobs") - def submit_jobs(**kwargs: Any) -> None: - """Submit jobs to dataproc. - - Args: - **kwargs (Any): Keyword arguments. - """ - ti = kwargs["ti"] - todo = ti.xcom_pull(task_ids="create_to_do_list", key="to_do_list") - print("Number of jobs to submit: ", len(todo)) # noqa: T201 - for i in range(len(todo)): - # Not to exceed default quota 400 jobs per minute - if i > 0 and i % 399 == 0: - time.sleep(60) - input_path = todo[i] - match_result = re.search( - rf"{RAW_SUMMARY_STATISTICS_PREFIX}/(.*)/(GCST\d+)/harmonised/(.*)\.h\.tsv\.gz", - input_path, - ) - if match_result: - study_id = match_result.group(2) - print("Submitting job for study: ", study_id) # noqa: T201 - common.submit_pyspark_job_no_operator( - cluster_name=CLUSTER_NAME, - step_id="gwas_catalog_sumstat_preprocess", - other_args=[ - f"step.raw_sumstats_path=gs://{SUMMARY_STATS_BUCKET_NAME}/{input_path}", - f"step.out_sumstats_path=gs://{SUMMARY_STATS_BUCKET_NAME}/{HARMONISED_SUMMARY_STATISTICS_PREFIX}/{study_id}.parquet", - ], - ) - - ( - [list_inputs, list_outputs] - >> create_to_do_list() - >> common.create_cluster( - CLUSTER_NAME, - autoscaling_policy=AUTOSCALING, - num_workers=8, - num_preemptible_workers=8, - master_machine_type="n1-highmem-64", - worker_machine_type="n1-standard-2", - ) - >> common.install_dependencies(CLUSTER_NAME) - >> submit_jobs() - # >> common.delete_cluster(CLUSTER_NAME) - ) diff --git a/src/airflow/dags/gwas_catalog_preprocess.py b/src/airflow/dags/gwas_catalog_preprocess.py deleted file mode 100644 index 7f6280242..000000000 --- a/src/airflow/dags/gwas_catalog_preprocess.py +++ /dev/null @@ -1,223 +0,0 @@ -"""Airflow DAG for the preprocessing of GWAS Catalog's harmonised summary statistics and curated associations.""" - -from __future__ import annotations - -from pathlib import Path - -import common_airflow as common - -from airflow.models.dag import DAG -from airflow.operators.python import PythonOperator -from airflow.providers.google.cloud.hooks.gcs import GCSHook -from airflow.providers.google.cloud.operators.gcs import GCSListObjectsOperator -from airflow.utils.task_group import TaskGroup - -CLUSTER_NAME = "otg-preprocess-gwascatalog" -AUTOSCALING = "otg-preprocess-gwascatalog" - -# Setting up bucket name and output object names: -GWAS_CATALOG_BUCKET_NAME = "gwas_catalog_data" -HARMONISED_SUMSTATS_PREFIX = "harmonised_summary_statistics" - -# Manifest paths: -MANIFESTS_PATH = f"gs://{GWAS_CATALOG_BUCKET_NAME}/manifests/" - -# The name of the manifest files have to be consistent with the config file: -HARMONISED_SUMSTATS_LIST_OBJECT_NAME = ( - "manifests/gwas_catalog_harmonised_summary_statistics_list.txt" -) -HARMONISED_SUMSTATS_LIST_FULL_NAME = ( - f"gs://{GWAS_CATALOG_BUCKET_NAME}/{HARMONISED_SUMSTATS_LIST_OBJECT_NAME}" -) -CURATION_INCLUSION_NAME = f"{MANIFESTS_PATH}/gwas_catalog_curation_included_studies" -CURATION_EXCLUSION_NAME = f"{MANIFESTS_PATH}/gwas_catalog_curation_excluded_studies" -SUMMARY_STATISTICS_INCLUSION_NAME = ( - f"{MANIFESTS_PATH}/gwas_catalog_summary_statistics_included_studies" -) -SUMMARY_STATISTICS_EXCLUSION_NAME = ( - f"{MANIFESTS_PATH}/gwas_catalog_summary_statistics_excluded_studies" -) - -# Study index: -STUDY_INDEX = f"gs://{GWAS_CATALOG_BUCKET_NAME}/study_index" - -# Study loci: -CURATED_STUDY_LOCI = f"gs://{GWAS_CATALOG_BUCKET_NAME}/study_locus_datasets/gwas_catalog_curated_associations" -CURATED_LD_CLUMPED = f"gs://{GWAS_CATALOG_BUCKET_NAME}/study_locus_datasets/gwas_catalog_curated_associations_ld_clumped" -WINDOW_BASED_CLUMPED = f"gs://{GWAS_CATALOG_BUCKET_NAME}/study_locus_datasets/gwas_catalog_summary_stats_window_clumped" -LD_BASED_CLUMPED = f"gs://{GWAS_CATALOG_BUCKET_NAME}/study_locus_datasets/gwas_catalog_summary_stats_ld_clumped" -# Credible sets: -CURATED_CREDIBLE_SETS = f"gs://{GWAS_CATALOG_BUCKET_NAME}/credible_set_datasets/gwas_catalog_PICSed_curated_associations" -SUMMARY_STATISTICS_CREDIBLE_SETS = f"gs://{GWAS_CATALOG_BUCKET_NAME}/credible_set_datasets/gwas_catalog_PICSed_summary_statistics" - - -def upload_harmonized_study_list( - concatenated_studies: str, bucket_name: str, object_name: str -) -> None: - """This function uploads file to GCP. - - Args: - concatenated_studies (str): Concatenated list of harmonized summary statistics. - bucket_name (str): Bucket name - object_name (str): Name of the object - """ - hook = GCSHook(gcp_conn_id="google_cloud_default") - hook.upload( - bucket_name=bucket_name, - object_name=object_name, - data=concatenated_studies, - encoding="utf-8", - ) - - -with DAG( - dag_id=Path(__file__).stem, - description="Open Targets Genetics — GWAS Catalog preprocess", - default_args=common.shared_dag_args, - **common.shared_dag_kwargs, -): - # Getting list of folders (each a gwas study with summary statistics) - list_harmonised_sumstats = GCSListObjectsOperator( - task_id="list_harmonised_parquet", - bucket=GWAS_CATALOG_BUCKET_NAME, - prefix=HARMONISED_SUMSTATS_PREFIX, - match_glob="**/_SUCCESS", - ) - - # Upload resuling list to a bucket: - upload_task = PythonOperator( - task_id="uploader", - python_callable=upload_harmonized_study_list, - op_kwargs={ - "concatenated_studies": '{{ "\n".join(ti.xcom_pull( key="return_value", task_ids="list_harmonised_parquet")) }}', - "bucket_name": GWAS_CATALOG_BUCKET_NAME, - "object_name": HARMONISED_SUMSTATS_LIST_OBJECT_NAME, - }, - ) - - # Processing curated GWAS Catalog top-bottom: - with TaskGroup(group_id="curation_processing") as curation_processing: - # Generate inclusion list: - curation_calculate_inclusion_list = common.submit_step( - cluster_name=CLUSTER_NAME, - step_id="ot_gwas_catalog_study_inclusion", - task_id="catalog_curation_inclusion_list", - other_args=[ - "step.criteria=curation", - f"step.inclusion_list_path={CURATION_INCLUSION_NAME}", - f"step.exclusion_list_path={CURATION_EXCLUSION_NAME}", - f"step.harmonised_study_file={HARMONISED_SUMSTATS_LIST_FULL_NAME}", - ], - ) - - # Ingest curated associations from GWAS Catalog: - curation_ingest_data = common.submit_step( - cluster_name=CLUSTER_NAME, - step_id="ot_gwas_catalog_ingestion", - task_id="ingest_curated_gwas_catalog_data", - other_args=[f"step.inclusion_list_path={CURATION_INCLUSION_NAME}"], - ) - - # Run LD-annotation and clumping on curated data: - curation_ld_clumping = common.submit_step( - cluster_name=CLUSTER_NAME, - step_id="ot_ld_based_clumping", - task_id="catalog_curation_ld_clumping", - other_args=[ - f"step.study_locus_input_path={CURATED_STUDY_LOCI}", - f"step.study_index_path={STUDY_INDEX}", - f"step.clumped_study_locus_output_path={CURATED_LD_CLUMPED}", - ], - ) - - # Do PICS based finemapping: - curation_pics = common.submit_step( - cluster_name=CLUSTER_NAME, - step_id="pics", - task_id="catalog_curation_pics", - other_args=[ - f"step.study_locus_ld_annotated_in={CURATED_LD_CLUMPED}", - f"step.picsed_study_locus_out={CURATED_CREDIBLE_SETS}", - ], - ) - - # Define order of steps: - ( - curation_calculate_inclusion_list - >> curation_ingest_data - >> curation_ld_clumping - >> curation_pics - ) - - # Processing summary statistics from GWAS Catalog: - with TaskGroup( - group_id="summary_statistics_processing" - ) as summary_statistics_processing: - # Generate inclusion study lists: - summary_stats_calculate_inclusion_list = common.submit_step( - cluster_name=CLUSTER_NAME, - step_id="ot_gwas_catalog_study_inclusion", - task_id="catalog_sumstats_inclusion_list", - other_args=[ - "step.criteria=summary_stats", - f"step.inclusion_list_path={SUMMARY_STATISTICS_INCLUSION_NAME}", - f"step.exclusion_list_path={SUMMARY_STATISTICS_EXCLUSION_NAME}", - f"step.harmonised_study_file={HARMONISED_SUMSTATS_LIST_FULL_NAME}", - ], - ) - - # Run window-based clumping: - summary_stats_window_based_clumping = common.submit_step( - cluster_name=CLUSTER_NAME, - step_id="window_based_clumping", - task_id="catalog_sumstats_window_clumping", - other_args=[ - f"step.summary_statistics_input_path=gs://{GWAS_CATALOG_BUCKET_NAME}/{HARMONISED_SUMSTATS_PREFIX}", - f"step.inclusion_list_path={SUMMARY_STATISTICS_INCLUSION_NAME}", - f"step.study_locus_output_path={WINDOW_BASED_CLUMPED}", - ], - ) - - # Run LD based clumping: - summary_stats_ld_clumping = common.submit_step( - cluster_name=CLUSTER_NAME, - step_id="ot_ld_based_clumping", - task_id="catalog_sumstats_ld_clumping", - other_args=[ - f"step.study_locus_input_path={WINDOW_BASED_CLUMPED}", - f"step.study_index_path={STUDY_INDEX}", - f"step.clumped_study_locus_output_path={LD_BASED_CLUMPED}", - ], - ) - - # Run PICS finemapping: - summary_stats_pics = common.submit_step( - cluster_name=CLUSTER_NAME, - step_id="pics", - task_id="catalog_sumstats_pics", - other_args=[ - f"step.study_locus_ld_annotated_in={LD_BASED_CLUMPED}", - f"step.picsed_study_locus_out={SUMMARY_STATISTICS_CREDIBLE_SETS}", - ], - ) - - # Order of steps within the group: - ( - summary_stats_calculate_inclusion_list - >> summary_stats_window_based_clumping - >> summary_stats_ld_clumping - >> summary_stats_pics - ) - - # DAG description: - ( - common.create_cluster( - CLUSTER_NAME, autoscaling_policy=AUTOSCALING, num_workers=5 - ) - >> common.install_dependencies(CLUSTER_NAME) - >> list_harmonised_sumstats - >> upload_task - >> curation_processing - >> summary_statistics_processing - >> common.delete_cluster(CLUSTER_NAME) - ) diff --git a/src/airflow/dags/gwas_curation_update.py b/src/airflow/dags/gwas_curation_update.py deleted file mode 100644 index d5fd38e35..000000000 --- a/src/airflow/dags/gwas_curation_update.py +++ /dev/null @@ -1,34 +0,0 @@ -"""DAG for updating GWAS Catalog curation table.""" -from __future__ import annotations - -from datetime import datetime -from pathlib import Path - -import common_airflow as common - -from airflow.models.dag import DAG - -CLUSTER_NAME = "otg-gwascatalog-curation" -RUN_DATE = datetime.today().strftime("%Y-%m-%d") - -with DAG( - dag_id=Path(__file__).stem, - description="Open Targets Genetics — GWAS Catalog curation update", - default_args=common.shared_dag_args, - **common.shared_dag_kwargs, -): - update_gwas_curation = common.submit_step( - cluster_name=CLUSTER_NAME, - step_id="ot_gwas_catalog_study_curation", - task_id="gwas_catalog_curation_update", - other_args=[ - f"step.gwas_catalog_study_curation_out=gs://genetics_etl_python_playground/input/v2d/GWAS_Catalog_study_curation_{RUN_DATE}.tsv", - ], - ) - - # DAG description: - ( - common.create_cluster(CLUSTER_NAME, num_workers=2) - >> common.install_dependencies(CLUSTER_NAME) - >> update_gwas_curation - ) diff --git a/src/airflow/dags/ukb_ppp_eur.py b/src/airflow/dags/ukb_ppp_eur.py deleted file mode 100644 index c8df8cf5b..000000000 --- a/src/airflow/dags/ukb_ppp_eur.py +++ /dev/null @@ -1,45 +0,0 @@ -"""Airflow DAG to ingest and harmonise UKB PPP (EUR) data.""" - -from __future__ import annotations - -from pathlib import Path - -import common_airflow as common - -from airflow.models.dag import DAG - -CLUSTER_NAME = "otg-ukb-ppp-eur" - -# Input location. -UKB_PPP_EUR_STUDY_INDEX = "gs://gentropy-tmp/batch/output/ukb_ppp_eur/study_index.tsv" -UKB_PPP_EUR_SUMMARY_STATS = "gs://gentropy-tmp/batch/output/ukb_ppp_eur/summary_stats.parquet" -VARIANT_ANNOTATION = "gs://genetics_etl_python_playground/output/python_etl/parquet/XX.XX/variant_annotation" - -# Output locations. -TMP_VARIANT_ANNOTATION = "gs://gentropy-tmp/variant_annotation" -UKB_PPP_EUR_OUTPUT_STUDY_INDEX = "gs://ukb_ppp_eur_data/study_index" -UKB_PPP_EUR_OUTPUT_SUMMARY_STATS = "gs://ukb_ppp_eur_data/summary_stats" - -with DAG( - dag_id=Path(__file__).stem, - description="Open Targets Genetics — Ingest UKB PPP (EUR)", - default_args=common.shared_dag_args, - **common.shared_dag_kwargs, -): - dag = common.generate_dag( - cluster_name=CLUSTER_NAME, - tasks=[ - common.submit_step( - cluster_name=CLUSTER_NAME, - step_id="ot_ukb_ppp_eur_sumstat_preprocess", - other_args=[ - f"step.raw_study_index_path_from_tsv={UKB_PPP_EUR_STUDY_INDEX}", - f"step.raw_summary_stats_path={UKB_PPP_EUR_SUMMARY_STATS}", - f"step.variant_annotation_path={VARIANT_ANNOTATION}", - f"step.tmp_variant_annotation_path={TMP_VARIANT_ANNOTATION}", - f"step.study_index_output_path={UKB_PPP_EUR_OUTPUT_STUDY_INDEX}", - f"step.summary_stats_output_path={UKB_PPP_EUR_OUTPUT_SUMMARY_STATS}", - ] - ) - ] - ) diff --git a/src/airflow/dags/variant_index.py b/src/airflow/dags/variant_index.py deleted file mode 100644 index 98ba48198..000000000 --- a/src/airflow/dags/variant_index.py +++ /dev/null @@ -1,321 +0,0 @@ -"""DAG that generates a variant index dataset based on several sources.""" - -from __future__ import annotations - -import os -import time -from dataclasses import dataclass -from pathlib import Path -from typing import Any - -import pandas as pd -from common_airflow import ( - create_batch_job, - create_cluster, - create_task_spec, - delete_cluster, - install_dependencies, - read_yaml_config, - shared_dag_args, - shared_dag_kwargs, - submit_step, -) -from google.cloud import batch_v1 - -from airflow.decorators import task -from airflow.models.dag import DAG -from airflow.providers.google.cloud.operators.cloud_batch import ( - CloudBatchSubmitJobOperator, -) -from airflow.providers.google.cloud.operators.gcs import GCSListObjectsOperator -from airflow.utils.trigger_rule import TriggerRule - -PROJECT_ID = "open-targets-genetics-dev" -REGION = "europe-west1" -GCS_BUCKET = "genetics_etl_python_playground" -CONFIG_FILE_PATH = Path(__file__).parent / "configs" / "variant_sources.yaml" -GENTROPY_DOCKER_IMAGE = "europe-west1-docker.pkg.dev/open-targets-genetics-dev/gentropy-app/gentropy:il-variant-idx" # TODO: change to dev -VEP_DOCKER_IMAGE = "europe-west1-docker.pkg.dev/open-targets-genetics-dev/gentropy-app/custom_ensembl_vep:dev" -VEP_CACHE_BUCKET = f"gs://{GCS_BUCKET}/vep/cache" - -RELEASE = "XX.XX" # This needs to be updated to the latest release - -VCF_DST_PATH = f"gs://{GCS_BUCKET}/{RELEASE}/variant_vcf" -VCF_MERGED_DST_PATH = f"{VCF_DST_PATH}/merged" -VEP_OUTPUT_BUCKET = f"gs://{GCS_BUCKET}/{RELEASE}/vep_output" -VARIANT_INDEX_BUCKET = f"gs://{GCS_BUCKET}/{RELEASE}/variant_index" -GNOMAD_ANNOTATION_PATH = f"gs://{GCS_BUCKET}/static_assets/gnomad_variants" -# Internal parameters for the docker image: -MOUNT_DIR = "/mnt/disks/share" - -CLUSTER_NAME = "otg-variant-index" -AUTOSCALING = "eqtl-preprocess" - - -@task(task_id="vcf_creation") -def create_vcf(**kwargs: Any) -> None: - """Task that sends the ConvertToVcfStep job to Google Batch. - - Args: - **kwargs (Any): Keyword arguments - """ - sources = read_yaml_config(CONFIG_FILE_PATH) - task_env = [ - batch_v1.Environment( - variables={ - "SOURCE_NAME": source["name"], - "SOURCE_PATH": source["location"], - "SOURCE_FORMAT": source["format"], - } - ) - for source in sources["sources_inclusion_list"] - ] - - commands = [ - "-c", - rf"poetry run gentropy step=variant_to_vcf step.source_path=$SOURCE_PATH step.source_format=$SOURCE_FORMAT step.vcf_path={VCF_DST_PATH}/$SOURCE_NAME +step.session.extended_spark_conf={{spark.jars:https://storage.googleapis.com/hadoop-lib/gcs/gcs-connector-hadoop3-latest.jar}}", - ] - task = create_task_spec( - GENTROPY_DOCKER_IMAGE, commands, options="-e HYDRA_FULL_ERROR=1" - ) - - batch_task = CloudBatchSubmitJobOperator( - task_id="vep_batch_job", - project_id=PROJECT_ID, - region=REGION, - job_name=f"vcf-job-{time.strftime('%Y%m%d-%H%M%S')}", - job=create_batch_job( - task, - "VEPMACHINE", - task_env, - ), - deferrable=False, - ) - - batch_task.execute(context=kwargs) - - -@task(task_id="merge_vcfs") -def merge_vcfs(chunk_size: int = 2000, **kwargs: Any) -> None: - """Task that merges the information from all the VCF files into a single one so that we only submit one VEP job. - - Args: - chunk_size (int): Partition size of the merged file. Defaults to 2000. - **kwargs (Any): Keyword arguments - """ - ti = kwargs["ti"] - input_vcfs = [ - f"gs://{GCS_BUCKET}/{listed_file}" - for listed_file in ti.xcom_pull( - task_ids="get_vcf_per_source", key="return_value" - ) - ] - merged_df = ( - pd.concat( - pd.read_csv( - file, - sep="\t", - dtype={ - "#CHROM": str, - "POS": int, - "ID": str, - "REF": str, - "ALT": str, - "QUAL": str, - "FILTER": str, - "INFO": str, - }, - ) - for file in input_vcfs - ) - .drop_duplicates(subset=["#CHROM", "POS", "REF", "ALT"]) - .sort_values(by=["#CHROM", "POS"]) - .reset_index(drop=True) - ) - # Partition the merged file into chunks of 2000 variants to run the VEP jobs in parallel - chunks = 0 - for i in range(0, len(merged_df), chunk_size): - merged_df[i : i + chunk_size].to_csv( - f"{VCF_MERGED_DST_PATH}/chunk_{i + 1}-{i + chunk_size}.vcf", - index=False, - header=True, - sep="\t", - ) - chunks += 1 - expected_chunks_count = len(merged_df) // chunk_size + 1 - assert ( - chunks == expected_chunks_count - ), f"Expected {expected_chunks_count} chunks but got {chunks} chunks" - - -@dataclass -class PathManager: - """It is quite complicated to keep track of all the input/output buckets, the corresponding mounting points prefixes etc...""" - - VCF_INPUT_BUCKET: str - VEP_OUTPUT_BUCKET: str - VEP_CACHE_BUCKET: str - MOUNT_DIR_ROOT: str - - # Derived parameters to find the list of files to process: - input_path: str | None = None - input_bucket: str | None = None - - # Derived parameters to initialise the docker image: - path_dictionary: dict[str, dict[str, str]] | None = None - - # Derived parameters to point to the right mouting points: - cache_dir: str | None = None - input_dir: str | None = None - output_dir: str | None = None - - def __post_init__(self: PathManager) -> None: - """Build paths based on the input parameters.""" - self.path_dictionary = { - "input": { - "remote_path": self.VCF_INPUT_BUCKET.replace("gs://", ""), - "mount_point": f"{self.MOUNT_DIR_ROOT}/input", - }, - "output": { - "remote_path": self.VEP_OUTPUT_BUCKET.replace("gs://", ""), - "mount_point": f"{self.MOUNT_DIR_ROOT}/output", - }, - "cache": { - "remote_path": self.VEP_CACHE_BUCKET.replace("gs://", ""), - "mount_point": f"{self.MOUNT_DIR_ROOT}/cache", - }, - } - # Parameters for fetching files: - self.input_path = self.VCF_INPUT_BUCKET.replace("gs://", "") + "/" - self.input_bucket = self.VCF_INPUT_BUCKET.split("/")[2] - - # Parameters for VEP: - self.cache_dir = f"{self.MOUNT_DIR_ROOT}/cache" - self.input_dir = f"{self.MOUNT_DIR_ROOT}/input" - self.output_dir = f"{self.MOUNT_DIR_ROOT}/output" - - def get_mount_config(self) -> list[dict[str, str]]: - """Return the mount configuration. - - Returns: - list[dict[str, str]]: The mount configuration. - """ - assert self.path_dictionary is not None, "Path dictionary not initialized." - return list(self.path_dictionary.values()) - - -@task(task_id="vep_annotation") -def vep_annotation(pm: PathManager, **kwargs: Any) -> None: - """Submit a Batch job to annotate VCFs with a local VEP docker image. - - Args: - pm (PathManager): The path manager with all the required path related information. - **kwargs (Any): Keyword arguments. - """ - # Get the filenames to process: - ti = kwargs["ti"] - filenames = [ - os.path.basename(os.path.splitext(path)[0]) - for path in ti.xcom_pull(task_ids="get_vep_todo_list", key="return_value") - ] - # Stop process if no files was found: - assert filenames, "No files found to process." - - # Based on the filenames, build the environment variables for the batch job: - task_env = [ - batch_v1.Environment( - variables={ - "INPUT_FILE": f"{filename}.vcf", - "OUTPUT_FILE": f"{filename}.json", - } - ) - for filename in filenames - ] - # Build the command to run in the container: - command = [ - "-c", - rf"vep --cache --offline --format vcf --force_overwrite \ - --no_stats \ - --dir_cache {pm.cache_dir} \ - --input_file {pm.input_dir}/$INPUT_FILE \ - --output_file {pm.output_dir}/$OUTPUT_FILE --json \ - --dir_plugins {pm.cache_dir}/VEP_plugins \ - --sift b \ - --polyphen b \ - --fasta {pm.cache_dir}/Homo_sapiens.GRCh38.dna.primary_assembly.fa.gz \ - --mane_select \ - --appris \ - --hgvsg \ - --pick_order mane_select,canonical \ - --per_gene \ - --uniprot \ - --check_existing \ - --exclude_null_alleles \ - --canonical \ - --plugin TSSDistance \ - --distance 500000 \ - --plugin LoF,loftee_path:{pm.cache_dir}/VEP_plugins,gerp_bigwig:{pm.cache_dir}/gerp_conservation_scores.homo_sapiens.GRCh38.bw,human_ancestor_fa:{pm.cache_dir}/human_ancestor.fa.gz,conservation_file:/opt/vep/loftee.sql \ - --plugin AlphaMissense,file={pm.cache_dir}/AlphaMissense_hg38.tsv.gz,transcript_match=1 \ - --plugin CADD,snv={pm.cache_dir}/CADD_GRCh38_whole_genome_SNVs.tsv.gz", - ] - task = create_task_spec(VEP_DOCKER_IMAGE, command) - batch_task = CloudBatchSubmitJobOperator( - task_id="vep_batch_job", - project_id=PROJECT_ID, - region=REGION, - job_name=f"vep-job-{time.strftime('%Y%m%d-%H%M%S')}", - job=create_batch_job(task, "VEPMACHINE", task_env, pm.get_mount_config()), - deferrable=False, - ) - batch_task.execute(context=kwargs) - - -with DAG( - dag_id=Path(__file__).stem, - description="Open Targets Genetics — create VCF file from datasets that contain variant information", - default_args=shared_dag_args, - **shared_dag_kwargs, -) as dag: - pm = PathManager( - VCF_MERGED_DST_PATH, - VEP_OUTPUT_BUCKET, - VEP_CACHE_BUCKET, - MOUNT_DIR, - ) - ( - create_vcf() - >> GCSListObjectsOperator( - task_id="get_vcf_per_source", - bucket=GCS_BUCKET, - prefix=VCF_DST_PATH.replace(f"gs://{GCS_BUCKET}/", ""), - trigger_rule=TriggerRule.ALL_SUCCESS, - match_glob="**.csv", - ) - >> merge_vcfs() - >> GCSListObjectsOperator( - task_id="get_vep_todo_list", - bucket=GCS_BUCKET, - prefix=VCF_MERGED_DST_PATH.replace(f"gs://{GCS_BUCKET}/", ""), - trigger_rule=TriggerRule.ALL_SUCCESS, - match_glob="**.vcf", - ) - >> vep_annotation(pm) - >> create_cluster( - CLUSTER_NAME, - autoscaling_policy=AUTOSCALING, - num_workers=4, - worker_machine_type="n1-highmem-8", - ) - >> install_dependencies(CLUSTER_NAME) - >> submit_step( - cluster_name=CLUSTER_NAME, - step_id="ot_variant_index", - task_id="ot_variant_index", - other_args=[ - f"step.vep_output_json_path={VEP_OUTPUT_BUCKET}", - f"step.variant_index_path={VARIANT_INDEX_BUCKET}", - f"step.gnomad_variant_annotations_path={GNOMAD_ANNOTATION_PATH}", - ], - ) - >> delete_cluster(CLUSTER_NAME) - ) diff --git a/src/airflow/docker-compose.yaml b/src/airflow/docker-compose.yaml deleted file mode 100644 index 8e8523490..000000000 --- a/src/airflow/docker-compose.yaml +++ /dev/null @@ -1,228 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# - -# Basic Airflow cluster configuration for LocalExecutor with PostgreSQL. -# -# WARNING: This configuration is for local development. Do not use it in a production deployment. -# -# This configuration supports basic configuration using environment variables or an .env file -# The following variables are supported: -# -# AIRFLOW_IMAGE_NAME - Docker image name used to run Airflow. -# Default: apache/airflow:slim-2.7.2-python3.10 -# AIRFLOW_UID - User ID in Airflow containers -# Default: 50000 -# AIRFLOW_PROJ_DIR - Base path to which all the files will be volumed. -# Default: . -# Those configurations are useful mostly in case of standalone testing/running Airflow in test/try-out mode -# -# _AIRFLOW_WWW_USER_USERNAME - Username for the administrator account (if requested). -# Default: airflow -# _AIRFLOW_WWW_USER_PASSWORD - Password for the administrator account (if requested). -# Default: airflow -# _PIP_ADDITIONAL_REQUIREMENTS - Additional PIP requirements to add when starting all containers. -# Use this option ONLY for quick checks. Installing requirements at container -# startup is done EVERY TIME the service is started. -# A better way is to build a custom image or extend the official image -# as described in https://airflow.apache.org/docs/docker-stack/build.html. -# Default: '' -# -# Feel free to modify this file to suit your needs. -version: "3.8" -x-airflow-common: &airflow-common - # In order to add custom dependencies or upgrade provider packages you can use your extended image. - # Comment the image line, place your Dockerfile in the directory where you placed the docker-compose.yaml - # and uncomment the "build" line below, Then run `docker-compose build` to build the images. - image: ${AIRFLOW_IMAGE_NAME:-apache/airflow:slim-2.7.2-python3.10} - # build: . - environment: &airflow-common-env - AIRFLOW__CORE__EXECUTOR: LocalExecutor - AIRFLOW__DATABASE__SQL_ALCHEMY_CONN: postgresql+psycopg2://airflow:airflow@postgres/airflow - # For backward compatibility, with Airflow <2.3 - AIRFLOW__CORE__SQL_ALCHEMY_CONN: postgresql+psycopg2://airflow:airflow@postgres/airflow - AIRFLOW__CORE__FERNET_KEY: "" - AIRFLOW__CORE__DAGS_ARE_PAUSED_AT_CREATION: "true" - AIRFLOW__CORE__LOAD_EXAMPLES: "false" - AIRFLOW__API__AUTH_BACKENDS: "airflow.api.auth.backend.basic_auth,airflow.api.auth.backend.session" - # yamllint disable rule:line-length - # Use simple http server on scheduler for health checks - # See https://airflow.apache.org/docs/apache-airflow/stable/administration-and-deployment/logging-monitoring/check-health.html#scheduler-health-check-server - # yamllint enable rule:line-length - AIRFLOW__SCHEDULER__ENABLE_HEALTH_CHECK: "true" - # WARNING: Use _PIP_ADDITIONAL_REQUIREMENTS option ONLY for a quick checks - # for other purpose (development, test and especially production usage) build/extend Airflow image. - _PIP_ADDITIONAL_REQUIREMENTS: ${_PIP_ADDITIONAL_REQUIREMENTS:-} - # GCLOUD Authentication - GOOGLE_APPLICATION_CREDENTIALS: ${GOOGLE_APPLICATION_CREDENTIALS:-} - AIRFLOW_CONN_GOOGLE_CLOUD_DEFAULT: ${AIRFLOW_CONN_GOOGLE_CLOUD_DEFAULT:-} - GCP_PROJECT_ID: ${GCP_PROJECT_ID:-} - GCP_GCS_BUCKET: ${GCP_GCS_BUCKET:-} - - volumes: - - ${AIRFLOW_PROJ_DIR:-.}/dags:/opt/airflow/dags - - ${AIRFLOW_PROJ_DIR:-.}/logs:/opt/airflow/logs - - ${AIRFLOW_PROJ_DIR:-.}/config:/opt/airflow/config - - ${AIRFLOW_PROJ_DIR:-.}/plugins:/opt/airflow/plugins - # GCLOUD Authentication - - ${GOOGLE_LOCAL_CREDENTIALS_PATH}:/${GOOGLE_DOCKER_CREDENTIALS_PATH}:ro - user: "${AIRFLOW_UID:-50000}:0" - depends_on: &airflow-common-depends-on - postgres: - condition: service_healthy - -services: - postgres: - image: postgres:13 - environment: - POSTGRES_USER: airflow - POSTGRES_PASSWORD: airflow - POSTGRES_DB: airflow - volumes: - - postgres-db-volume:/var/lib/postgresql/data - healthcheck: - test: ["CMD", "pg_isready", "-U", "airflow"] - interval: 10s - retries: 5 - start_period: 5s - restart: always - - airflow-webserver: - <<: *airflow-common - command: webserver - ports: - - "8080:8080" - healthcheck: - test: ["CMD", "curl", "--fail", "http://localhost:8080/health"] - interval: 30s - timeout: 10s - retries: 5 - start_period: 30s - restart: always - depends_on: - <<: *airflow-common-depends-on - airflow-init: - condition: service_completed_successfully - - airflow-scheduler: - <<: *airflow-common - command: scheduler - healthcheck: - test: ["CMD", "curl", "--fail", "http://localhost:8974/health"] - interval: 30s - timeout: 10s - retries: 5 - start_period: 30s - restart: always - depends_on: - <<: *airflow-common-depends-on - airflow-init: - condition: service_completed_successfully - - airflow-init: - <<: *airflow-common - entrypoint: /bin/bash - # yamllint disable rule:line-length - command: - - -c - - | - function ver() { - printf "%04d%04d%04d%04d" $${1//./ } - } - airflow_version=$$(AIRFLOW__LOGGING__LOGGING_LEVEL=INFO && gosu airflow airflow version) - airflow_version_comparable=$$(ver $${airflow_version}) - min_airflow_version=2.2.0 - min_airflow_version_comparable=$$(ver $${min_airflow_version}) - if (( airflow_version_comparable < min_airflow_version_comparable )); then - echo - echo -e "\033[1;31mERROR!!!: Too old Airflow version $${airflow_version}!\e[0m" - echo "The minimum Airflow version supported: $${min_airflow_version}. Only use this or higher!" - echo - exit 1 - fi - if [[ -z "${AIRFLOW_UID}" ]]; then - echo - echo -e "\033[1;33mWARNING!!!: AIRFLOW_UID not set!\e[0m" - echo "If you are on Linux, you SHOULD follow the instructions below to set " - echo "AIRFLOW_UID environment variable, otherwise files will be owned by root." - echo "For other operating systems you can get rid of the warning with manually created .env file:" - echo " See: https://airflow.apache.org/docs/apache-airflow/stable/howto/docker-compose/index.html#setting-the-right-airflow-user" - echo - fi - one_meg=1048576 - mem_available=$$(($$(getconf _PHYS_PAGES) * $$(getconf PAGE_SIZE) / one_meg)) - cpus_available=$$(grep -cE 'cpu[0-9]+' /proc/stat) - disk_available=$$(df / | tail -1 | awk '{print $$4}') - warning_resources="false" - if (( mem_available < 4000 )) ; then - echo - echo -e "\033[1;33mWARNING!!!: Not enough memory available for Docker.\e[0m" - echo "At least 4GB of memory required. You have $$(numfmt --to iec $$((mem_available * one_meg)))" - echo - warning_resources="true" - fi - if (( cpus_available < 2 )); then - echo - echo -e "\033[1;33mWARNING!!!: Not enough CPUS available for Docker.\e[0m" - echo "At least 2 CPUs recommended. You have $${cpus_available}" - echo - warning_resources="true" - fi - if (( disk_available < one_meg * 10 )); then - echo - echo -e "\033[1;33mWARNING!!!: Not enough Disk space available for Docker.\e[0m" - echo "At least 10 GBs recommended. You have $$(numfmt --to iec $$((disk_available * 1024 )))" - echo - warning_resources="true" - fi - if [[ $${warning_resources} == "true" ]]; then - echo - echo -e "\033[1;33mWARNING!!!: You have not enough resources to run Airflow (see above)!\e[0m" - echo "Please follow the instructions to increase amount of resources available:" - echo " https://airflow.apache.org/docs/apache-airflow/stable/howto/docker-compose/index.html#before-you-begin" - echo - fi - mkdir -p /sources/logs /sources/dags /sources/plugins - chown -R "${AIRFLOW_UID}:0" /sources/{logs,dags,plugins} - exec /entrypoint airflow version - # yamllint enable rule:line-length - environment: - <<: *airflow-common-env - _AIRFLOW_DB_MIGRATE: "true" - _AIRFLOW_WWW_USER_CREATE: "true" - _AIRFLOW_WWW_USER_USERNAME: ${_AIRFLOW_WWW_USER_USERNAME:-airflow} - _AIRFLOW_WWW_USER_PASSWORD: ${_AIRFLOW_WWW_USER_PASSWORD:-airflow} - _PIP_ADDITIONAL_REQUIREMENTS: "" - user: "0:0" - volumes: - - ${AIRFLOW_PROJ_DIR:-.}:/sources - - airflow-cli: - <<: *airflow-common - profiles: - - debug - environment: - <<: *airflow-common-env - CONNECTION_CHECK_MAX_COUNT: "0" - # Workaround for entrypoint issue. See: https://github.com/apache/airflow/issues/16252 - command: - - bash - - -c - - airflow - -volumes: - postgres-db-volume: diff --git a/src/airflow/logs/.gitkeep b/src/airflow/logs/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/airflow/plugins/.gitkeep b/src/airflow/plugins/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/airflow/requirements.txt b/src/airflow/requirements.txt deleted file mode 100644 index 540c20453..000000000 --- a/src/airflow/requirements.txt +++ /dev/null @@ -1,3 +0,0 @@ -apache-airflow-providers-google==10.17.0 -apache-airflow-providers-apache-beam==5.6.1 -psycopg2-binary==2.9.9 diff --git a/tests/airflow/test_dag.py b/tests/airflow/test_dag.py deleted file mode 100644 index e18f91fb1..000000000 --- a/tests/airflow/test_dag.py +++ /dev/null @@ -1,51 +0,0 @@ -"""Check for airflow import errors. Inspiration from https://garystafford.medium.com/devops-for-dataops-building-a-ci-cd-pipeline-for-apache-airflow-dags-975e4a622f83.""" - -from __future__ import annotations - -import pytest - -from airflow.models import DagBag - - -@pytest.fixture(params=["./src/airflow/dags"]) -def dag_bag(request: pytest.FixtureRequest) -> DagBag: - """Return a DAG bag for testing.""" - return DagBag(dag_folder=request.param, include_examples=False) - - -def test_no_import_errors(dag_bag: DagBag) -> None: - """Test for import errors.""" - assert ( - not dag_bag.import_errors - ), f"DAG import failures. Errors: {dag_bag.import_errors}" - - -def test_requires_tags(dag_bag: DagBag) -> None: - """Tags should be defined for each DAG.""" - for _, dag in dag_bag.dags.items(): - assert dag.tags - - -def test_owner_len_greater_than_five(dag_bag: DagBag) -> None: - """Owner should be defined for each DAG and be longer than 5 characters.""" - for _, dag in dag_bag.dags.items(): - assert len(dag.owner) > 5 - - -def test_desc_len_greater_than_fifteen(dag_bag: DagBag) -> None: - """Description should be defined for each DAG and be longer than 30 characters.""" - for _, dag in dag_bag.dags.items(): - if isinstance(dag.description, str): - assert len(dag.description) > 30 - - -def test_owner_not_airflow(dag_bag: DagBag) -> None: - """Owner should not be 'airflow'.""" - for _, dag in dag_bag.dags.items(): - assert str.lower(dag.owner) != "airflow" - - -def test_three_or_less_retries(dag_bag: DagBag) -> None: - """Retries should be 3 or less.""" - for _, dag in dag_bag.dags.items(): - assert dag.default_args["retries"] <= 3 From d6364f86ee8680e535ba3a6637ffe1a1f8dc9653 Mon Sep 17 00:00:00 2001 From: Kirill Tsukanov Date: Fri, 13 Sep 2024 12:54:36 +0100 Subject: [PATCH 034/188] fix: multiple fixes after debugging and test runs (#760) --- src/gentropy/common/harmonise.py | 19 +++++---- src/gentropy/common/per_chromosome.py | 4 +- src/gentropy/config.py | 1 + .../finngen_ukb_meta/study_index.py | 42 +++++++++++++------ .../finngen_ukb_meta/summary_stats.py | 6 ++- 5 files changed, 50 insertions(+), 22 deletions(-) diff --git a/src/gentropy/common/harmonise.py b/src/gentropy/common/harmonise.py index 9b570eec6..6420245bd 100644 --- a/src/gentropy/common/harmonise.py +++ b/src/gentropy/common/harmonise.py @@ -135,13 +135,6 @@ def harmonise_summary_stats( df .join(va_df, (df["chromosome"] == va_df["vaChromosome"]) & (df["summary_stats_id"] == va_df["summary_stats_id"]), "inner") .drop("vaChromosome", "summary_stats_id") - .withColumn( - "effectAlleleFrequencyFromSource", - f.when( - f.col("direction") == "direct", - f.col(colname_a1freq).cast("float") - ).otherwise(1 - f.col(colname_a1freq).cast("float")) - ) .withColumn( "beta", f.when( @@ -150,6 +143,18 @@ def harmonise_summary_stats( ).otherwise(-f.col(colname_beta).cast("double")) ) ) + if colname_a1freq: + df = ( + df + .withColumn( + "effectAlleleFrequencyFromSource", + f.when( + f.col("direction") == "direct", + f.col(colname_a1freq).cast("float") + ) + .otherwise(1 - f.col(colname_a1freq).cast("float")) + ) + ) df = ( # Harmonise, 7: Drop bad quality variants. df diff --git a/src/gentropy/common/per_chromosome.py b/src/gentropy/common/per_chromosome.py index f2cedd98e..a3016202e 100644 --- a/src/gentropy/common/per_chromosome.py +++ b/src/gentropy/common/per_chromosome.py @@ -36,7 +36,7 @@ def prepare_va(session: SparkSession, variant_annotation_path: str, tmp_variant_ f.col("position"), f.col("referenceAllele"), f.col("alternateAllele") - ).alias("ukb_ppp_id"), + ).alias("summary_stats_id"), f.lit("direct").alias("direction") ) ) @@ -51,7 +51,7 @@ def prepare_va(session: SparkSession, variant_annotation_path: str, tmp_variant_ f.col("position"), f.col("alternateAllele"), f.col("referenceAllele") - ).alias("ukb_ppp_id"), + ).alias("summary_stats_id"), f.lit("flip").alias("direction") ) ) diff --git a/src/gentropy/config.py b/src/gentropy/config.py index 181e9042d..4d1174d6b 100644 --- a/src/gentropy/config.py +++ b/src/gentropy/config.py @@ -598,3 +598,4 @@ def register_config() -> None: name="study_validation", node=StudyValidationStepConfig, ) + cs.store(group="step", name="finngen_ukb_meta_ingestion", node=FinngenUkbMetaConfig) diff --git a/src/gentropy/datasource/finngen_ukb_meta/study_index.py b/src/gentropy/datasource/finngen_ukb_meta/study_index.py index 76e82f0eb..fe6c74beb 100644 --- a/src/gentropy/datasource/finngen_ukb_meta/study_index.py +++ b/src/gentropy/datasource/finngen_ukb_meta/study_index.py @@ -1,10 +1,14 @@ """Study Index for Finngen data source.""" from __future__ import annotations +from urllib.request import urlopen + import pyspark.sql.functions as f from pyspark.sql import SparkSession +from gentropy.config import FinngenStudiesConfig from gentropy.dataset.study_index import StudyIndex +from gentropy.datasource.finngen.study_index import FinnGenStudyIndex class FinngenUkbMetaStudyIndex(StudyIndex): @@ -15,12 +19,14 @@ def from_source( cls: type[FinngenUkbMetaStudyIndex], spark: SparkSession, raw_study_index_path_from_tsv: str, + efo_curation_mapping_url: str = FinngenStudiesConfig().efo_curation_mapping_url, ) -> StudyIndex: """This function ingests study level metadata from FinnGen UKB meta-analysis. Args: spark (SparkSession): Spark session object. raw_study_index_path_from_tsv (str): Raw study index path. + efo_curation_mapping_url (str): URL to the EFO curation mapping file. Returns: StudyIndex: Parsed and annotated FinnGen UKB meta-analysis study table. @@ -35,28 +41,40 @@ def from_source( f.col("name").alias("traitFromSource"), f.lit(True).alias("hasSumstats"), f.col("_gentropy_summary_stats_link").alias("summarystatsLocation"), - (f.col("fg_n_cases") + f.col("ukbb_n_cases") + f.col("fg_n_controls") + f.col("ukbb_n_controls")).alias("nSamples") + (f.col("fg_n_cases") + f.col("ukbb_n_cases") + f.col("fg_n_controls") + f.col("ukbb_n_controls")).cast("integer").alias("nSamples"), + f.array( + f.struct( + (f.col("fg_n_cases") + f.col("fg_n_controls")).cast("integer").alias("sampleSize"), + f.lit("Finnish").alias("ancestry"), + ), + f.struct( + (f.col("ukbb_n_cases") + f.col("ukbb_n_controls")).cast("integer").alias("sampleSize"), + f.lit("European").alias("ancestry"), + ), + ).alias("discoverySamples"), ) ) # Add population structure. study_index_df = ( study_index_df - .withColumn( - "discoverySamples", - f.array( - f.struct( - f.col("nSamples").cast("integer").alias("sampleSize"), - f.lit("European").alias("ancestry"), - ) - ) - ) .withColumn( "ldPopulationStructure", cls.aggregate_and_map_ancestries(f.col("discoverySamples")), ) ) - - return StudyIndex( + # Create study index. + study_index = StudyIndex( _df=study_index_df, _schema=StudyIndex.get_schema(), ) + # Add EFO mappings. + csv_data = urlopen(efo_curation_mapping_url).readlines() + csv_rows = [row.decode("utf8") for row in csv_data] + rdd = spark.sparkContext.parallelize(csv_rows) + efo_curation_mapping = spark.read.csv(rdd, header=True, sep="\t") + study_index = FinnGenStudyIndex.join_efo_mapping( + study_index, + efo_curation_mapping, + finngen_release_prefix="FINNGEN_R11", + ) + return study_index diff --git a/src/gentropy/datasource/finngen_ukb_meta/summary_stats.py b/src/gentropy/datasource/finngen_ukb_meta/summary_stats.py index 6e45736c3..b77d57966 100644 --- a/src/gentropy/datasource/finngen_ukb_meta/summary_stats.py +++ b/src/gentropy/datasource/finngen_ukb_meta/summary_stats.py @@ -4,6 +4,7 @@ from dataclasses import dataclass +import pyspark.sql.functions as f from pyspark.sql import SparkSession from gentropy.common.harmonise import harmonise_summary_stats @@ -53,7 +54,10 @@ def from_source( ) # Populate the sample size column from the study index. - study_index = spark.read.parquet(study_index_path).select("studyId", "nSamples") + study_index = spark.read.parquet(study_index_path).select( + "studyId", + f.col("nSamples").cast("integer").alias("sampleSize") + ) df = df.join(study_index, on=["studyId"], how="inner") # Create the summary statistics object. From 34aaaf5901cff29c6e1971f0b746793c048b20e9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 13 Sep 2024 23:38:24 +0200 Subject: [PATCH 035/188] build(deps-dev): bump mkdocstrings-python from 1.10.5 to 1.11.1 (#749) --- poetry.lock | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/poetry.lock b/poetry.lock index 0df0da543..760522884 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1590,13 +1590,13 @@ grpc = ["grpcio (>=1.44.0,<2.0.0.dev0)"] [[package]] name = "griffe" -version = "0.47.0" +version = "1.2.0" description = "Signatures for entire Python programs. Extract the structure, the frame, the skeleton of your project, to generate API documentation or find breaking changes in your API." optional = false python-versions = ">=3.8" files = [ - {file = "griffe-0.47.0-py3-none-any.whl", hash = "sha256:07a2fd6a8c3d21d0bbb0decf701d62042ccc8a576645c7f8799fe1f10de2b2de"}, - {file = "griffe-0.47.0.tar.gz", hash = "sha256:95119a440a3c932b13293538bdbc405bee4c36428547553dc6b327e7e7d35e5a"}, + {file = "griffe-1.2.0-py3-none-any.whl", hash = "sha256:a8b2fcb1ecdc5a412e646b0b4375eb20a5d2eac3a11dd8c10c56967a4097663c"}, + {file = "griffe-1.2.0.tar.gz", hash = "sha256:1c9f6ef7455930f3f9b0c4145a961c90385d1e2cbc496f7796fbff560ec60d31"}, ] [package.dependencies] @@ -2411,13 +2411,13 @@ mkdocs = ">=1.2.3" [[package]] name = "mkdocs-autorefs" -version = "1.0.1" +version = "1.2.0" description = "Automatically link across pages in MkDocs." optional = false python-versions = ">=3.8" files = [ - {file = "mkdocs_autorefs-1.0.1-py3-none-any.whl", hash = "sha256:aacdfae1ab197780fb7a2dac92ad8a3d8f7ca8049a9cbe56a4218cd52e8da570"}, - {file = "mkdocs_autorefs-1.0.1.tar.gz", hash = "sha256:f684edf847eced40b570b57846b15f0bf57fb93ac2c510450775dcf16accb971"}, + {file = "mkdocs_autorefs-1.2.0-py3-none-any.whl", hash = "sha256:d588754ae89bd0ced0c70c06f58566a4ee43471eeeee5202427da7de9ef85a2f"}, + {file = "mkdocs_autorefs-1.2.0.tar.gz", hash = "sha256:a86b93abff653521bda71cf3fc5596342b7a23982093915cb74273f67522190f"}, ] [package.dependencies] @@ -2559,23 +2559,23 @@ mkdocs = ">=1.2" [[package]] name = "mkdocstrings" -version = "0.25.1" +version = "0.26.1" description = "Automatic documentation from sources, for MkDocs." optional = false python-versions = ">=3.8" files = [ - {file = "mkdocstrings-0.25.1-py3-none-any.whl", hash = "sha256:da01fcc2670ad61888e8fe5b60afe9fee5781017d67431996832d63e887c2e51"}, - {file = "mkdocstrings-0.25.1.tar.gz", hash = "sha256:c3a2515f31577f311a9ee58d089e4c51fc6046dbd9e9b4c3de4c3194667fe9bf"}, + {file = "mkdocstrings-0.26.1-py3-none-any.whl", hash = "sha256:29738bfb72b4608e8e55cc50fb8a54f325dc7ebd2014e4e3881a49892d5983cf"}, + {file = "mkdocstrings-0.26.1.tar.gz", hash = "sha256:bb8b8854d6713d5348ad05b069a09f3b79edbc6a0f33a34c6821141adb03fe33"}, ] [package.dependencies] click = ">=7.0" Jinja2 = ">=2.11.1" -Markdown = ">=3.3" +Markdown = ">=3.6" MarkupSafe = ">=1.1" mkdocs = ">=1.4" -mkdocs-autorefs = ">=0.3.1" -platformdirs = ">=2.2.0" +mkdocs-autorefs = ">=1.2" +platformdirs = ">=2.2" pymdown-extensions = ">=6.3" [package.extras] @@ -2585,18 +2585,19 @@ python-legacy = ["mkdocstrings-python-legacy (>=0.2.1)"] [[package]] name = "mkdocstrings-python" -version = "1.10.5" +version = "1.11.1" description = "A Python handler for mkdocstrings." optional = false python-versions = ">=3.8" files = [ - {file = "mkdocstrings_python-1.10.5-py3-none-any.whl", hash = "sha256:92e3c588ef1b41151f55281d075de7558dd8092e422cb07a65b18ee2b0863ebb"}, - {file = "mkdocstrings_python-1.10.5.tar.gz", hash = "sha256:acdc2a98cd9d46c7ece508193a16ca03ccabcb67520352b7449f84b57c162bdf"}, + {file = "mkdocstrings_python-1.11.1-py3-none-any.whl", hash = "sha256:a21a1c05acef129a618517bb5aae3e33114f569b11588b1e7af3e9d4061a71af"}, + {file = "mkdocstrings_python-1.11.1.tar.gz", hash = "sha256:8824b115c5359304ab0b5378a91f6202324a849e1da907a3485b59208b797322"}, ] [package.dependencies] -griffe = ">=0.47" -mkdocstrings = ">=0.25" +griffe = ">=0.49" +mkdocs-autorefs = ">=1.2" +mkdocstrings = ">=0.26" [[package]] name = "msal" From 2e0e326333336fcd40b3f30f4435e7675bf9c7fa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Sep 2024 10:04:28 +0100 Subject: [PATCH 036/188] build(deps): bump wandb from 0.17.2 to 0.18.0 (#763) Bumps [wandb](https://github.com/wandb/wandb) from 0.17.2 to 0.18.0. - [Release notes](https://github.com/wandb/wandb/releases) - [Changelog](https://github.com/wandb/wandb/blob/main/CHANGELOG.md) - [Commits](https://github.com/wandb/wandb/compare/v0.17.2...v0.18.0) --- updated-dependencies: - dependency-name: wandb dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- poetry.lock | 25 +++++++++++++------------ pyproject.toml | 2 +- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/poetry.lock b/poetry.lock index 760522884..933477f7c 100644 --- a/poetry.lock +++ b/poetry.lock @@ -4895,18 +4895,19 @@ test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess [[package]] name = "wandb" -version = "0.17.2" +version = "0.18.0" description = "A CLI and library for interacting with the Weights & Biases API." optional = false python-versions = ">=3.7" files = [ - {file = "wandb-0.17.2-py3-none-any.whl", hash = "sha256:4bd351be28cea87730365856cfaa72f72ceb787accc21bad359dde5aa9c4356d"}, - {file = "wandb-0.17.2-py3-none-macosx_10_9_x86_64.whl", hash = "sha256:638353a2d702caedd304a5f1e526ef93a291c984c109fcb444262a57aeaacec9"}, - {file = "wandb-0.17.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:824e33ca77af87f87a9cf1122acba164da5bf713adc9d67332bc686028921ec9"}, - {file = "wandb-0.17.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:032ca5939008643349af178a8b66b8047a1eefcb870c4c4a86e22acafde6470f"}, - {file = "wandb-0.17.2-py3-none-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9558bab47a0c8ac4f22cfa2d43f91d1bc1f75d4255629286db674fe49fcd30e5"}, - {file = "wandb-0.17.2-py3-none-win32.whl", hash = "sha256:4bc176e3c81be216dc889fcd098341eb17a14b04e080d4343ce3f0b1740abfc1"}, - {file = "wandb-0.17.2-py3-none-win_amd64.whl", hash = "sha256:62cd707f38b5711971729dae80343b8c35f6003901e690166cc6d526187a9785"}, + {file = "wandb-0.18.0-py3-none-any.whl", hash = "sha256:a176af0d51b55a363dac3c54a8b7aa1cfd5a89cad6fc6574237232f37c779965"}, + {file = "wandb-0.18.0-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:2bc7f18becda9a566a63723666390f941e8b115b9e7746e0e5d73dc9ea9714c6"}, + {file = "wandb-0.18.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:e14a385c95e61e77b0b5c4cbc6c5a0b47ac0d9e66730ca8c17b84eba374e35d1"}, + {file = "wandb-0.18.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0764ad8911a70cdb7cb339567c4170b860e8f5f523447b2f748d7e0e6224e29"}, + {file = "wandb-0.18.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d2ffea43710e3482168a2d89b2770aa9a14007ba16e717b176428f2a50765f2"}, + {file = "wandb-0.18.0-py3-none-win32.whl", hash = "sha256:b209840a9499bf687e8b5b20117341e7722f86a85f986c422501eb1a709dc721"}, + {file = "wandb-0.18.0-py3-none-win_amd64.whl", hash = "sha256:25aa8ee1808eae0c0e4818b81bc43fd6461e4f3603d7918e5eab2f9afca00715"}, + {file = "wandb-0.18.0.tar.gz", hash = "sha256:872dfd7298c053ca861352196bc422452caff105d3bc66b90e7bc86f17ad8bdd"}, ] [package.dependencies] @@ -4914,7 +4915,7 @@ click = ">=7.1,<8.0.0 || >8.0.0" docker-pycreds = ">=0.4.0" gitpython = ">=1.0.0,<3.1.29 || >3.1.29" platformdirs = "*" -protobuf = {version = ">=3.19.0,<4.21.0 || >4.21.0,<6", markers = "python_version > \"3.9\" or sys_platform != \"linux\""} +protobuf = {version = ">=3.19.0,<4.21.0 || >4.21.0,<5.28.0 || >5.28.0,<6", markers = "python_version > \"3.9\" or sys_platform != \"linux\""} psutil = ">=5.0.0" pyyaml = "*" requests = ">=2.0.0,<3" @@ -4926,9 +4927,9 @@ setuptools = "*" aws = ["boto3"] azure = ["azure-identity", "azure-storage-blob"] gcp = ["google-cloud-storage"] -importers = ["filelock", "mlflow", "polars", "rich", "tenacity"] +importers = ["filelock", "mlflow", "polars (<=1.2.1)", "rich", "tenacity"] kubeflow = ["google-cloud-storage", "kubernetes", "minio", "sh"] -launch = ["awscli", "azure-containerregistry", "azure-identity", "azure-storage-blob", "boto3", "botocore", "chardet", "google-auth", "google-cloud-aiplatform", "google-cloud-artifact-registry", "google-cloud-compute", "google-cloud-storage", "iso8601", "kubernetes", "kubernetes-asyncio", "nbconvert", "nbformat", "optuna", "pydantic", "pyyaml (>=6.0.0)", "tomli", "typing-extensions"] +launch = ["awscli", "azure-containerregistry", "azure-identity", "azure-storage-blob", "boto3", "botocore", "chardet", "google-auth", "google-cloud-aiplatform", "google-cloud-artifact-registry", "google-cloud-compute", "google-cloud-storage", "iso8601", "jsonschema", "kubernetes", "kubernetes-asyncio", "nbconvert", "nbformat", "optuna", "pydantic", "pyyaml (>=6.0.0)", "tomli", "typing-extensions"] media = ["bokeh", "moviepy", "numpy", "pillow", "plotly (>=5.18.0)", "rdkit-pypi", "soundfile"] models = ["cloudpickle"] perf = ["orjson"] @@ -5218,4 +5219,4 @@ multidict = ">=4.0" [metadata] lock-version = "2.0" python-versions = "^3.10, <3.11" -content-hash = "5b7e79eb2ca58918d786e61b6331115376a24705da5478c6feef85d37f24685e" +content-hash = "50a797b217805183c5967246c1ca4b339037ce60e44a6c43b5c3fc6a9fb2832a" diff --git a/pyproject.toml b/pyproject.toml index 094ca1f6e..1343c7b50 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,7 +26,7 @@ hydra-core = "^1.3.2" pyliftover = "^0.4" numpy = "^1.26.2" hail = "0.2.127" -wandb = ">=0.16.2,<0.18.0" +wandb = ">=0.16.2,<0.19.0" google = "^3.0.0" omegaconf = "^2.3.0" typing-extensions = "^4.9.0" From 6ede7363c683d0955edafc647c9d13b2baf17fc7 Mon Sep 17 00:00:00 2001 From: David Ochoa Date: Tue, 17 Sep 2024 17:45:44 +0100 Subject: [PATCH 037/188] fix: prevent multiple credible filters to override spark plan (#766) * fix: prevent multiple filters to override spark plan * feat: mhc quality control flag * fix: prevent multiple filters to override spark plan * Revert "fix: prevent multiple filters to override spark plan" This reverts commit a358781017dee62ba7a0466783bf24af108d6d42. * revert: wrong commit * fix: missing changes due to git chaos * chore: merge dev toml, update lock * chore: update lock after upgrading poetry to 1.8.3 v 2 --------- Co-authored-by: Szymon Szyszkowski <69353402+project-defiant@users.noreply.github.com> --- poetry.lock | 1 - src/gentropy/dataset/study_locus.py | 14 ++++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/poetry.lock b/poetry.lock index 933477f7c..226311a8b 100644 --- a/poetry.lock +++ b/poetry.lock @@ -3952,7 +3952,6 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, diff --git a/src/gentropy/dataset/study_locus.py b/src/gentropy/dataset/study_locus.py index b59d57650..38d1e14a2 100644 --- a/src/gentropy/dataset/study_locus.py +++ b/src/gentropy/dataset/study_locus.py @@ -534,14 +534,16 @@ def filter_credible_set( Returns: StudyLocus: Filtered study-locus dataset. """ - self.df = self._df.withColumn( - "locus", - f.filter( - f.col("locus"), - lambda tag: (tag[credible_interval.value]), + return StudyLocus( + _df=self._df.withColumn( + "locus", + f.filter( + f.col("locus"), + lambda tag: (tag[credible_interval.value]), + ), ), + _schema=self._schema, ) - return self @staticmethod def filter_ld_set(ld_set: Column, r2_threshold: float) -> Column: From 8c4421aa221d69be76765375d9525222c7c89572 Mon Sep 17 00:00:00 2001 From: David Ochoa Date: Wed, 18 Sep 2024 12:35:28 +0100 Subject: [PATCH 038/188] feat: flag MHC credible sets based on lead (#767) * fix: prevent multiple filters to override spark plan * feat: mhc quality control flag * fix: typo * docs: genomic region added to docs * docs: info added to common index (and title) * docs: fix paths * Update src/gentropy/study_locus_validation.py * fix: remove unnecessary comment --------- Closes https://github.com/opentargets/issues/issues/3469 Co-authored-by: Szymon Szyszkowski <69353402+project-defiant@users.noreply.github.com> --- docs/python_api/common/_common.md | 1 + docs/python_api/common/genomic_region.md | 6 + src/gentropy/common/genomic_region.py | 103 ++++++++++++++++++ src/gentropy/common/utils.py | 42 +------ src/gentropy/dataset/study_locus.py | 45 ++++++-- src/gentropy/dataset/summary_statistics.py | 17 +-- src/gentropy/locus_breaker_clumping.py | 4 +- src/gentropy/study_locus_validation.py | 7 +- tests/gentropy/dataset/test_study_locus.py | 5 + .../dataset/test_summary_statistics.py | 8 +- 10 files changed, 173 insertions(+), 65 deletions(-) create mode 100644 docs/python_api/common/genomic_region.md create mode 100644 src/gentropy/common/genomic_region.py diff --git a/docs/python_api/common/_common.md b/docs/python_api/common/_common.md index a8abe0f84..5957ec3bd 100644 --- a/docs/python_api/common/_common.md +++ b/docs/python_api/common/_common.md @@ -4,5 +4,6 @@ title: Common Common utilities used in gentropy package. +- [**Genomic Region**](genomic_region.md): class to represent genomic regions - [**Version Engine**](version_engine.md): class to extract version from datasource input paths - [**Types**](types.md): Literal types used in the gentropy diff --git a/docs/python_api/common/genomic_region.md b/docs/python_api/common/genomic_region.md new file mode 100644 index 000000000..c0841d299 --- /dev/null +++ b/docs/python_api/common/genomic_region.md @@ -0,0 +1,6 @@ +--- +title: Genomic Region +--- + +:::gentropy.common.genomic_region.KnownGenomicRegions +:::gentropy.common.genomic_region.GenomicRegion diff --git a/src/gentropy/common/genomic_region.py b/src/gentropy/common/genomic_region.py new file mode 100644 index 000000000..ffa298f86 --- /dev/null +++ b/src/gentropy/common/genomic_region.py @@ -0,0 +1,103 @@ +"""Genomic Region class.""" + +from enum import Enum + + +class KnownGenomicRegions(Enum): + """Known genomic regions in the human genome in string format.""" + + MHC = "chr6:25726063-33400556" + + +class GenomicRegion: + """Genomic regions of interest. + + Attributes: + chromosome (str): Chromosome. + start (int): Start position. + end (int): + """ + + def __init__(self, chromosome: str, start: int, end: int) -> None: + """Class constructor. + + Args: + chromosome (str): Chromosome. + start (int): Start position. + end (int): End position. + """ + self.chromosome = chromosome + self.start = start + self.end = end + + def __str__(self) -> str: + """String representation of the genomic region. + + Returns: + str: Genomic region in chr:start-end format. + """ + return f"{self.chromosome}:{self.start}-{self.end}" + + @classmethod + def from_string(cls: type["GenomicRegion"], region: str) -> "GenomicRegion": + """Parse region string to chr:start-end. + + Args: + region (str): Genomic region expected to follow chr##:#,###-#,### format or ##:####-#####. + + Returns: + GenomicRegion: Genomic region object. + + Raises: + ValueError: If the end and start positions cannot be casted to integer or not all three values value error is raised. + + Examples: + >>> print(GenomicRegion.from_string('chr6:28,510,120-33,480,577')) + 6:28510120-33480577 + >>> print(GenomicRegion.from_string('6:28510120-33480577')) + 6:28510120-33480577 + >>> print(GenomicRegion.from_string('6:28510120')) + Traceback (most recent call last): + ... + ValueError: Genomic region should follow a ##:####-#### format. + >>> print(GenomicRegion.from_string('6:28510120-foo')) + Traceback (most recent call last): + ... + ValueError: Start and the end position of the region has to be integer. + """ + region = region.replace(":", "-").replace(",", "") + try: + chromosome, start_position, end_position = region.split("-") + except ValueError as err: + raise ValueError( + "Genomic region should follow a ##:####-#### format." + ) from err + + try: + return cls( + chromosome=chromosome.replace("chr", ""), + start=int(start_position), + end=int(end_position), + ) + except ValueError as err: + raise ValueError( + "Start and the end position of the region has to be integer." + ) from err + + @classmethod + def from_known_genomic_region( + cls: type["GenomicRegion"], region: KnownGenomicRegions + ) -> "GenomicRegion": + """Get known genomic region. + + Args: + region (KnownGenomicRegions): Known genomic region. + + Returns: + GenomicRegion: Genomic region object. + + Examples: + >>> print(GenomicRegion.from_known_genomic_region(KnownGenomicRegions.MHC)) + 6:25726063-33400556 + """ + return GenomicRegion.from_string(region.value) diff --git a/src/gentropy/common/utils.py b/src/gentropy/common/utils.py index 81a2b4bfd..ca6e8e7f2 100644 --- a/src/gentropy/common/utils.py +++ b/src/gentropy/common/utils.py @@ -4,7 +4,7 @@ import sys from math import floor, log10 -from typing import TYPE_CHECKING, Tuple +from typing import TYPE_CHECKING import hail as hl import numpy as np @@ -19,46 +19,6 @@ from pyspark.sql import Column -def parse_region(region: str) -> Tuple[str, int, int]: - """Parse region string to chr:start-end. - - Args: - region (str): Genomic region expected to follow chr##:#,###-#,### format or ##:####-#####. - - Returns: - Tuple[str, int, int]: Chromosome, start position, end position - - Raises: - ValueError: If the end and start positions cannot be casted to integer or not all three values value error is raised. - - Examples: - >>> parse_region('chr6:28,510,120-33,480,577') - ('6', 28510120, 33480577) - >>> parse_region('6:28510120-33480577') - ('6', 28510120, 33480577) - >>> parse_region('6:28510120') - Traceback (most recent call last): - ... - ValueError: Genomic region should follow a ##:####-#### format. - >>> parse_region('6:28510120-foo') - Traceback (most recent call last): - ... - ValueError: Start and the end position of the region has to be integer. - """ - region = region.replace(":", "-").replace(",", "") - try: - (chromosome, start_position, end_position) = region.split("-") - except ValueError as err: - raise ValueError("Genomic region should follow a ##:####-#### format.") from err - - try: - return (chromosome.replace("chr", ""), int(start_position), int(end_position)) - except ValueError as err: - raise ValueError( - "Start and the end position of the region has to be integer." - ) from err - - def calculate_confidence_interval( pvalue_mantissa: Column, pvalue_exponent: Column, diff --git a/src/gentropy/dataset/study_locus.py b/src/gentropy/dataset/study_locus.py index 38d1e14a2..48f6ee8be 100644 --- a/src/gentropy/dataset/study_locus.py +++ b/src/gentropy/dataset/study_locus.py @@ -10,12 +10,13 @@ import pyspark.sql.functions as f from pyspark.sql.types import ArrayType, FloatType, StringType +from gentropy.common.genomic_region import GenomicRegion, KnownGenomicRegions from gentropy.common.schemas import parse_spark_schema from gentropy.common.spark_helpers import ( calculate_neglog_pvalue, order_array_of_structs_by_field, ) -from gentropy.common.utils import get_logsum, parse_region +from gentropy.common.utils import get_logsum from gentropy.dataset.dataset import Dataset from gentropy.dataset.study_locus_overlap import StudyLocusOverlap from gentropy.dataset.variant_index import VariantIndex @@ -49,6 +50,7 @@ class StudyLocusQualityCheck(Enum): MISSING_STUDY (str): Flagging study loci if the study is not found in the study index as a reference DUPLICATED_STUDYLOCUS_ID (str): Study-locus identifier is not unique. INVALID_VARIANT_IDENTIFIER (str): Flagging study loci where identifier of any tagging variant was not found in the variant index + IN_MHC (str): Flagging study loci in the MHC region """ SUBSIGNIFICANT_FLAG = "Subsignificant p-value" @@ -70,6 +72,7 @@ class StudyLocusQualityCheck(Enum): INVALID_VARIANT_IDENTIFIER = ( "Some variant identifiers of this locus were not found in variant index" ) + IN_MHC = "MHC region" class CredibleInterval(Enum): @@ -817,32 +820,31 @@ def clump(self: StudyLocus) -> StudyLocus: return self def exclude_region( - self: StudyLocus, region: str, exclude_overlap: bool = False + self: StudyLocus, region: GenomicRegion, exclude_overlap: bool = False ) -> StudyLocus: """Exclude a region from the StudyLocus dataset. Args: - region (str): region given in "chr##:#####-####" format + region (GenomicRegion): genomic region object. exclude_overlap (bool): If True, excludes StudyLocus windows with any overlap with the region. Returns: StudyLocus: filtered StudyLocus object. """ - (chromosome, start_position, end_position) = parse_region(region) if exclude_overlap: filter_condition = ~( - (f.col("chromosome") == chromosome) + (f.col("chromosome") == region.chromosome) & ( - (f.col("locusStart") <= end_position) - & (f.col("locusEnd") >= start_position) + (f.col("locusStart") <= region.end) + & (f.col("locusEnd") >= region.start) ) ) else: filter_condition = ~( - (f.col("chromosome") == chromosome) + (f.col("chromosome") == region.chromosome) & ( - (f.col("position") >= start_position) - & (f.col("position") <= end_position) + (f.col("position") >= region.start) + & (f.col("position") <= region.end) ) ) @@ -851,6 +853,29 @@ def exclude_region( _schema=StudyLocus.get_schema(), ) + def qc_MHC_region(self: StudyLocus) -> StudyLocus: + """Adds qualityControl flag when lead overlaps with MHC region. + + Returns: + StudyLocus: including qualityControl flag if in MHC region. + """ + region = GenomicRegion.from_known_genomic_region(KnownGenomicRegions.MHC) + self.df = self.df.withColumn( + "qualityControls", + self.update_quality_flag( + f.col("qualityControls"), + ~( + (f.col("chromosome") == region.chromosome) + & ( + (f.col("position") <= region.end) + & (f.col("position") >= region.start) + ) + ), + StudyLocusQualityCheck.IN_MHC, + ), + ) + return self + def _qc_no_population(self: StudyLocus) -> StudyLocus: """Flag associations where the study doesn't have population information to resolve LD. diff --git a/src/gentropy/dataset/summary_statistics.py b/src/gentropy/dataset/summary_statistics.py index 9aaa9b956..b9a44ff34 100644 --- a/src/gentropy/dataset/summary_statistics.py +++ b/src/gentropy/dataset/summary_statistics.py @@ -7,8 +7,9 @@ import pyspark.sql.functions as f +from gentropy.common.genomic_region import GenomicRegion from gentropy.common.schemas import parse_spark_schema -from gentropy.common.utils import parse_region, split_pvalue +from gentropy.common.utils import split_pvalue from gentropy.config import LocusBreakerClumpingConfig, WindowBasedClumpingStepConfig from gentropy.dataset.dataset import Dataset @@ -112,25 +113,25 @@ def locus_breaker_clumping( flanking_distance, ) - def exclude_region(self: SummaryStatistics, region: str) -> SummaryStatistics: + def exclude_region( + self: SummaryStatistics, region: GenomicRegion + ) -> SummaryStatistics: """Exclude a region from the summary stats dataset. Args: - region (str): region given in "chr##:#####-####" format + region (GenomicRegion): Genomic region to be excluded. Returns: SummaryStatistics: filtered summary statistics. """ - (chromosome, start_position, end_position) = parse_region(region) - return SummaryStatistics( _df=( self.df.filter( ~( - (f.col("chromosome") == chromosome) + (f.col("chromosome") == region.chromosome) & ( - (f.col("position") >= start_position) - & (f.col("position") <= end_position) + (f.col("position") >= region.start) + & (f.col("position") <= region.end) ) ) ) diff --git a/src/gentropy/locus_breaker_clumping.py b/src/gentropy/locus_breaker_clumping.py index 8eb83816e..7f3649097 100644 --- a/src/gentropy/locus_breaker_clumping.py +++ b/src/gentropy/locus_breaker_clumping.py @@ -2,6 +2,7 @@ from __future__ import annotations +from gentropy.common.genomic_region import GenomicRegion, KnownGenomicRegions from gentropy.common.session import Session from gentropy.dataset.summary_statistics import SummaryStatistics from gentropy.method.locus_breaker_clumping import LocusBreakerClumping @@ -63,7 +64,8 @@ def __init__( ) if remove_mhc: clumped_result = clumped_result.exclude_region( - "chr6:25726063-33400556", exclude_overlap=True + GenomicRegion.from_known_genomic_region(KnownGenomicRegions.MHC), + exclude_overlap=True, ) if collect_locus: diff --git a/src/gentropy/study_locus_validation.py b/src/gentropy/study_locus_validation.py index 41a572e79..da660ca57 100644 --- a/src/gentropy/study_locus_validation.py +++ b/src/gentropy/study_locus_validation.py @@ -41,9 +41,10 @@ def __init__( # Running validation then writing output: study_locus_with_qc = ( StudyLocus.from_parquet(session, list(study_locus_path)) - .validate_lead_pvalue( - pvalue_cutoff=gwas_significance - ) # Flagging study locus with subsignificant p-values + # Flagging study locus with subsignificant p-values + .validate_lead_pvalue(pvalue_cutoff=gwas_significance) + # Add flag for MHC region + .qc_MHC_region() .validate_study(study_index) # Flagging studies not in study index .validate_unique_study_locus_id() # Flagging duplicated study locus ids ).persist() # we will need this for 2 types of outputs diff --git a/tests/gentropy/dataset/test_study_locus.py b/tests/gentropy/dataset/test_study_locus.py index c7538b28b..1daf9bb89 100644 --- a/tests/gentropy/dataset/test_study_locus.py +++ b/tests/gentropy/dataset/test_study_locus.py @@ -526,6 +526,11 @@ def test__qc_no_population(mock_study_locus: StudyLocus) -> None: assert isinstance(mock_study_locus._qc_no_population(), StudyLocus) +def test_qc_MHC_region(mock_study_locus: StudyLocus) -> None: + """Test qc_MHC_region.""" + assert isinstance(mock_study_locus.qc_MHC_region(), StudyLocus) + + def test_ldannotate( mock_study_locus: StudyLocus, mock_study_index: StudyIndex, mock_ld_index: LDIndex ) -> None: diff --git a/tests/gentropy/dataset/test_summary_statistics.py b/tests/gentropy/dataset/test_summary_statistics.py index cf3cfdae7..b1b06442b 100644 --- a/tests/gentropy/dataset/test_summary_statistics.py +++ b/tests/gentropy/dataset/test_summary_statistics.py @@ -6,6 +6,7 @@ from pyspark.sql import types as t +from gentropy.common.genomic_region import GenomicRegion from gentropy.dataset.study_locus import StudyLocus from gentropy.dataset.summary_statistics import SummaryStatistics @@ -44,7 +45,10 @@ def test_summary_statistics__exclude_region__return_type( ) -> None: """Testing if the exclude region method returns the right datatype.""" assert isinstance( - mock_summary_statistics.exclude_region("chr12:124-1245"), SummaryStatistics + mock_summary_statistics.exclude_region( + GenomicRegion.from_string("chr12:124-1245") + ), + SummaryStatistics, ) @@ -85,7 +89,7 @@ def test_summary_statistics__exclude_region__correctness( df = spark.createDataFrame(data, schema=schema) filtered_sumstas = SummaryStatistics( _df=df, _schema=SummaryStatistics.get_schema() - ).exclude_region("c1:9-16") + ).exclude_region(GenomicRegion.from_string("c1:9-16")) # Test for the correct number of rows returned: assert filtered_sumstas.df.count() == 8 From d84d43bdc0e75f4b69018b529bccd6d0821098c8 Mon Sep 17 00:00:00 2001 From: Vivien Ho <56025826+vivienho@users.noreply.github.com> Date: Wed, 18 Sep 2024 17:46:19 +0100 Subject: [PATCH 039/188] fix: add condition to eQTL study index and schema (#770) --- src/gentropy/assets/schemas/study_index.json | 6 ++++++ src/gentropy/datasource/eqtl_catalogue/finemapping.py | 1 + 2 files changed, 7 insertions(+) diff --git a/src/gentropy/assets/schemas/study_index.json b/src/gentropy/assets/schemas/study_index.json index b4a2257d7..e18401917 100644 --- a/src/gentropy/assets/schemas/study_index.json +++ b/src/gentropy/assets/schemas/study_index.json @@ -250,6 +250,12 @@ "type": "boolean", "nullable": true, "metadata": {} + }, + { + "name": "condition", + "type": "string", + "nullable": true, + "metadata": {} } ] } diff --git a/src/gentropy/datasource/eqtl_catalogue/finemapping.py b/src/gentropy/datasource/eqtl_catalogue/finemapping.py index a5c02dd3e..11ec5bef1 100644 --- a/src/gentropy/datasource/eqtl_catalogue/finemapping.py +++ b/src/gentropy/datasource/eqtl_catalogue/finemapping.py @@ -206,6 +206,7 @@ def parse_susie_results( f.lit(True).alias("hasSumstats"), f.col("molecular_trait_id"), f.col("pmid").alias("pubmedId"), + f.col("condition_label").alias("condition"), ) ) From c3651b7e8ecad3631fce0d4e9fa79fea1b59d40a Mon Sep 17 00:00:00 2001 From: Daniel Suveges Date: Wed, 18 Sep 2024 22:42:51 +0100 Subject: [PATCH 040/188] fix(effect harmonisation): addressing beta harmonisation bug (#762) * fix: turning OR to beta harmonisation on for GWAS Catalog * fix(ingestion): addressing beta harmonisation bug * fix(ingestion): addressing beta harmonisation bug * test: adding test for effect harmonisation * test: adding doctests for beta harmonisation * fix: fixing value checking bug: effect value needs to be cast to double type * fix: typos in gwas ingestion script --- src/gentropy/common/spark_helpers.py | 32 ++ .../datasource/gwas_catalog/associations.py | 430 +++++++++++------- .../test_gwas_catalog_associations.py | 2 +- 3 files changed, 294 insertions(+), 170 deletions(-) diff --git a/src/gentropy/common/spark_helpers.py b/src/gentropy/common/spark_helpers.py index 65d3ae17b..791fb913d 100644 --- a/src/gentropy/common/spark_helpers.py +++ b/src/gentropy/common/spark_helpers.py @@ -429,6 +429,7 @@ def order_array_of_structs_by_two_fields( """ ) + def map_column_by_dictionary(col: Column, mapping_dict: Dict[str, str]) -> Column: """Map column values to dictionary values by key. @@ -655,3 +656,34 @@ def create_empty_column_if_not_exists( """ return f.lit(None).cast(col_schema).alias(col_name) + + +def get_standard_error_from_confidence_interval(lower: Column, upper: Column) -> Column: + """Compute the standard error from the confidence interval. + + Args: + lower (Column): The lower bound of the confidence interval. + upper (Column): The upper bound of the confidence interval. + + Returns: + Column: The standard error. + + Examples: + >>> data = [(0.5, 1.5), (None, 2.5), (None, None)] + >>> ( + ... spark.createDataFrame(data, ['lower', 'upper']) + ... .select( + ... get_standard_error_from_confidence_interval(f.col('lower'), f.col('upper')).alias('standard_error') + ... ) + ... .show() + ... ) + +-------------------+ + | standard_error| + +-------------------+ + |0.25510204081632654| + | null| + | null| + +-------------------+ + + """ + return (upper - lower) / (2 * 1.96) diff --git a/src/gentropy/datasource/gwas_catalog/associations.py b/src/gentropy/datasource/gwas_catalog/associations.py index 7a6a3c394..6781d045a 100644 --- a/src/gentropy/datasource/gwas_catalog/associations.py +++ b/src/gentropy/datasource/gwas_catalog/associations.py @@ -9,15 +9,15 @@ from typing import TYPE_CHECKING import pyspark.sql.functions as f -from pyspark.sql.types import DoubleType, IntegerType, LongType +from pyspark.sql.types import DoubleType, FloatType, IntegerType, LongType from pyspark.sql.window import Window from gentropy.assets import data from gentropy.common.spark_helpers import ( get_record_with_maximum_value, - pvalue_to_zscore, + get_standard_error_from_confidence_interval, ) -from gentropy.common.utils import parse_efos +from gentropy.common.utils import convert_odds_ratio_to_beta, parse_efos from gentropy.config import WindowBasedClumpingStepConfig from gentropy.dataset.study_locus import StudyLocus, StudyLocusQualityCheck @@ -140,8 +140,8 @@ def _normalise_pvaluetext(p_value_text: Column) -> Column: ) @staticmethod - def _normalise_risk_allele(risk_allele: Column) -> Column: - """Normalised risk allele column to a standardised format. + def _extract_risk_allele(risk_allele: Column) -> Column: + """Extract risk allele from provided "STRONGEST SNP-RISK ALLELE" input column. If multiple risk alleles are present, the first one is returned. @@ -155,7 +155,7 @@ def _normalise_risk_allele(risk_allele: Column) -> Column: >>> import pyspark.sql.types as t >>> d = [("rs1234-A-G"), ("rs1234-A"), ("rs1234-A; rs1235-G")] >>> df = spark.createDataFrame(d, t.StringType()) - >>> df.withColumn('normalised', GWASCatalogCuratedAssociationsParser._normalise_risk_allele(f.col('value'))).show() + >>> df.withColumn('normalised', GWASCatalogCuratedAssociationsParser._extract_risk_allele(f.col('value'))).show() +------------------+----------+ | value|normalised| +------------------+----------+ @@ -164,7 +164,6 @@ def _normalise_risk_allele(risk_allele: Column) -> Column: |rs1234-A; rs1235-G| A| +------------------+----------+ - """ # GWAS Catalog to risk allele mapping return f.split(f.split(risk_allele, "; ").getItem(0), "-").getItem(1) @@ -195,7 +194,7 @@ def _collect_rsids( return f.array_distinct(f.array(snp_id, snp_id_current, risk_allele)) @staticmethod - def _map_variants_to_variant_index( + def _map_variants_to_gnomad_variants( gwas_associations: DataFrame, variant_index: VariantIndex ) -> DataFrame: """Add variant metadata in associations. @@ -220,7 +219,7 @@ def _map_variants_to_variant_index( f.col("SNP_ID_CURRENT"), f.split(f.col("STRONGEST SNP-RISK ALLELE"), "; ").getItem(0), ).alias("rsIdsGwasCatalog"), - GWASCatalogCuratedAssociationsParser._normalise_risk_allele( + GWASCatalogCuratedAssociationsParser._extract_risk_allele( f.col("STRONGEST SNP-RISK ALLELE") ).alias("riskAllele"), ) @@ -570,175 +569,107 @@ def _are_alleles_palindromic( @staticmethod def _harmonise_beta( - risk_allele: Column, - reference_allele: Column, - alternate_allele: Column, effect_size: Column, confidence_interval: Column, + flipping_needed: Column, ) -> Column: - """A function to extract the beta value from the effect size and confidence interval. + """A function to extract the beta value from the effect size and confidence interval and harmonises for the alternate allele. If the confidence interval contains the word "increase" or "decrease" it indicates, we are dealing with betas. - If it's "increase" and the effect size needs to be harmonized, then multiply the effect size by -1 + If it's "increase" and the effect size needs to be harmonized, then multiply the effect size by -1. + The sign of the effect size is flipped if the confidence interval contains "decrease". + + eg. if the reported value is 0.5, and the confidence interval tells "decrease"? -> beta is -0.5 Args: - risk_allele (Column): Risk allele column - reference_allele (Column): Reference allele column - alternate_allele (Column): Alternate allele column - effect_size (Column): GWAS Catalog effect size column - confidence_interval (Column): GWAS Catalog confidence interval column + effect_size (Column): GWAS Catalog effect size column. + confidence_interval (Column): GWAS Catalog confidence interval column to know the direction of the effect. + flipping_needed (Column): Boolean flag indicating if effect needs to be flipped based on the alleles. Returns: Column: A column containing the beta value. + + Examples: + >>> d = [ + ... # positive effect -no flipping: + ... (0.5, 'increase', False), + ... # Positive effect - flip: + ... (0.5, 'decrease', False), + ... # Positive effect - flip: + ... (0.5, 'decrease', True), + ... # Negative effect - no flip: + ... (0.5, 'increase', True), + ... # Negative effect - flip: + ... (0.5, 'decrease', False), + ... ] + >>> ( + ... spark.createDataFrame(d, ['effect', 'ci_text', 'flip']) + ... .select("effect", "ci_text", 'flip', GWASCatalogCuratedAssociationsParser._harmonise_beta(f.col("effect"), f.col("ci_text"), f.lit(False)).alias("beta")) + ... .show() + ... ) + +------+--------+-----+----+ + |effect| ci_text| flip|beta| + +------+--------+-----+----+ + | 0.5|increase|false| 0.5| + | 0.5|decrease|false|-0.5| + | 0.5|decrease| true|-0.5| + | 0.5|increase| true| 0.5| + | 0.5|decrease|false|-0.5| + +------+--------+-----+----+ + """ return ( f.when( - GWASCatalogCuratedAssociationsParser._are_alleles_palindromic( - reference_allele, alternate_allele - ), - None, - ) - .when( - ( - GWASCatalogCuratedAssociationsParser._effect_needs_harmonisation( - risk_allele, reference_allele - ) - & confidence_interval.contains("increase") - ) - | ( - ~GWASCatalogCuratedAssociationsParser._effect_needs_harmonisation( - risk_allele, reference_allele - ) - & confidence_interval.contains("decrease") - ), + (flipping_needed & confidence_interval.contains("increase")) + | (~flipping_needed & confidence_interval.contains("decrease")), -effect_size, ) .otherwise(effect_size) .cast(DoubleType()) ) - @staticmethod - def _harmonise_beta_ci( - risk_allele: Column, - reference_allele: Column, - alternate_allele: Column, - effect_size: Column, - confidence_interval: Column, - p_value: Column, - direction: str, - ) -> Column: - """Calculating confidence intervals for beta values. - - Args: - risk_allele (Column): Risk allele column - reference_allele (Column): Reference allele column - alternate_allele (Column): Alternate allele column - effect_size (Column): GWAS Catalog effect size column - confidence_interval (Column): GWAS Catalog confidence interval column - p_value (Column): GWAS Catalog p-value column - direction (str): This is the direction of the confidence interval. It can be either "upper" or "lower". - - Returns: - Column: The upper and lower bounds of the confidence interval for the beta coefficient. - """ - zscore_95 = f.lit(1.96) - beta = GWASCatalogCuratedAssociationsParser._harmonise_beta( - risk_allele, - reference_allele, - alternate_allele, - effect_size, - confidence_interval, - ) - zscore = pvalue_to_zscore(p_value) - return ( - f.when(f.lit(direction) == "upper", beta + f.abs(zscore_95 * beta) / zscore) - .when(f.lit(direction) == "lower", beta - f.abs(zscore_95 * beta) / zscore) - .otherwise(None) - ) - @staticmethod def _harmonise_odds_ratio( - risk_allele: Column, - reference_allele: Column, - alternate_allele: Column, effect_size: Column, - confidence_interval: Column, + flipping_needed: Column, ) -> Column: - """Harmonizing odds ratio. + """Odds ratio is either propagated as is, or flipped if indicated, meaning returning a reciprocal value. Args: - risk_allele (Column): Risk allele column - reference_allele (Column): Reference allele column - alternate_allele (Column): Alternate allele column - effect_size (Column): GWAS Catalog effect size column - confidence_interval (Column): GWAS Catalog confidence interval column + effect_size (Column): containing effect size, + flipping_needed (Column): Boolean flag indicating if effect needs to be flipped Returns: Column: A column with the odds ratio, or 1/odds_ratio if harmonization required. + + Examples: + >>> d = [(0.5, False), (0.5, True), (0.0, False), (0.0, True)] + >>> ( + ... spark.createDataFrame(d, ['effect', 'flip']) + ... .select("effect", "flip", GWASCatalogCuratedAssociationsParser._harmonise_odds_ratio(f.col("effect"), f.col("flip")).alias("odds_ratio")) + ... .show() + ... ) + +------+-----+----------+ + |effect| flip|odds_ratio| + +------+-----+----------+ + | 0.5|false| 0.5| + | 0.5| true| 2.0| + | 0.0|false| 0.0| + | 0.0| true| null| + +------+-----+----------+ + """ return ( - f.when( - GWASCatalogCuratedAssociationsParser._are_alleles_palindromic( - reference_allele, alternate_allele - ), - None, - ) + # We are not flipping zero effect size: + f.when((effect_size.cast(DoubleType()) == 0) & flipping_needed, f.lit(None)) .when( - ( - GWASCatalogCuratedAssociationsParser._effect_needs_harmonisation( - risk_allele, reference_allele - ) - & ~confidence_interval.rlike("|".join(["decrease", "increase"])) - ), + flipping_needed, 1 / effect_size, ) .otherwise(effect_size) .cast(DoubleType()) ) - @staticmethod - def _harmonise_odds_ratio_ci( - risk_allele: Column, - reference_allele: Column, - alternate_allele: Column, - effect_size: Column, - confidence_interval: Column, - p_value: Column, - direction: str, - ) -> Column: - """Calculating confidence intervals for beta values. - - Args: - risk_allele (Column): Risk allele column - reference_allele (Column): Reference allele column - alternate_allele (Column): Alternate allele column - effect_size (Column): GWAS Catalog effect size column - confidence_interval (Column): GWAS Catalog confidence interval column - p_value (Column): GWAS Catalog p-value column - direction (str): This is the direction of the confidence interval. It can be either "upper" or "lower". - - Returns: - Column: The upper and lower bounds of the 95% confidence interval for the odds ratio. - """ - zscore_95 = f.lit(1.96) - odds_ratio = GWASCatalogCuratedAssociationsParser._harmonise_odds_ratio( - risk_allele, - reference_allele, - alternate_allele, - effect_size, - confidence_interval, - ) - odds_ratio_estimate = f.log(odds_ratio) - zscore = pvalue_to_zscore(p_value) - odds_ratio_se = odds_ratio_estimate / zscore - return f.when( - f.lit(direction) == "upper", - f.exp(odds_ratio_estimate + f.abs(zscore_95 * odds_ratio_se)), - ).when( - f.lit(direction) == "lower", - f.exp(odds_ratio_estimate - f.abs(zscore_95 * odds_ratio_se)), - ) - @staticmethod def _concatenate_substudy_description( association_trait: Column, pvalue_text: Column, mapped_trait_uri: Column @@ -988,11 +919,177 @@ def _qc_palindromic_alleles( StudyLocusQualityCheck.PALINDROMIC_ALLELE_FLAG, ) + @staticmethod + def _get_effect_type(ci_text: Column) -> Column: + """Extracts the effect type from the 95% CI text. + + The GWAS Catalog confidence interval column contains text that can be used to infer the effect type. + If the text contains "increase" or "decrease", the effect type is beta, otherwise it is odds ratio. + Null columns return null as the effect type. + + Args: + ci_text (Column): Column containing the 95% CI text. + + Returns: + Column: A column containing the effect type. + + Examples: + >>> data = [{"ci_text": "95% CI: [0.1-0.2]"}, {"ci_text": "95% CI: [0.1-0.2] increase"}, {"ci_text": "95% CI: [0.1-0.2] decrease"}, {"ci_text": None}] + >>> spark.createDataFrame(data).select('ci_text', GWASCatalogCuratedAssociationsParser._get_effect_type(f.col('ci_text')).alias('effect_type')).show(truncate=False) + +--------------------------+-----------+ + |ci_text |effect_type| + +--------------------------+-----------+ + |95% CI: [0.1-0.2] |odds_ratio | + |95% CI: [0.1-0.2] increase|beta | + |95% CI: [0.1-0.2] decrease|beta | + |null |null | + +--------------------------+-----------+ + + + """ + return f.when( + f.lower(ci_text).contains("increase") + | f.lower(ci_text).contains("decrease"), + f.lit("beta"), + ).when(ci_text.isNotNull(), f.lit("odds_ratio")) + + @staticmethod + def harmonise_association_effect_to_beta( + df: DataFrame, + ) -> DataFrame: + """Harmonise effect to beta value. + + The harmonisation process has a number of steps: + - Extracting the reported effect allele. + - Flagging palindromic alleles. + - Flagging associations where the effect direction needs to be flipped. + - Flagging the effect type. + - Getting the standard error from the confidence interval text. + - Harmonising both beta and odds ratio. + - Converting the odds ratio to beta. + + Args: + df (DataFrame): DataFrame with the following columns: + + Returns: + DataFrame: DataFrame with the following columns: + + Raises: + ValueError: If any of the required columns are missing. + + Examples: + >>> data = [ + ... # Flagged as palindromic: + ... ('rs123-T', 'A', 'T', '0.1', '[0.08-0.12] unit increase'), + ... # Not palindromic, beta needs to be flipped: + ... ('rs123-C', 'G', 'T', '0.1', '[0.08-0.12] unit increase'), + ... # Beta is not flipped: + ... ('rs123-T', 'C', 'T', '0.1', '[0.08-0.12] unit increase'), + ... # odds ratio: + ... ('rs123-T', 'C', 'T', '0.1', '[0.08-0.12]'), + ... # odds ratio flipped: + ... ('rs123-C', 'G', 'T', '0.1', '[0.08-0.12]'), + ... ] + >>> schema = ["STRONGEST SNP-RISK ALLELE", "referenceAllele", "alternateAllele", "OR or BETA", "95% CI (TEXT)"] + >>> df = spark.createDataFrame(data, schema) + >>> GWASCatalogCuratedAssociationsParser.harmonise_association_effect_to_beta(df).show() + +-------------------------+---------------+---------------+----------+--------------------+-------------------+--------------------+ + |STRONGEST SNP-RISK ALLELE|referenceAllele|alternateAllele|OR or BETA| 95% CI (TEXT)| beta| standardError| + +-------------------------+---------------+---------------+----------+--------------------+-------------------+--------------------+ + | rs123-T| A| T| 0.1|[0.08-0.12] unit ...| null| null| + | rs123-C| G| T| 0.1|[0.08-0.12] unit ...| -0.1|0.010204081404574064| + | rs123-T| C| T| 0.1|[0.08-0.12] unit ...| 0.1|0.010204081404574064| + | rs123-T| C| T| 0.1| [0.08-0.12]|-2.3025850929940455| null| + | rs123-C| G| T| 0.1| [0.08-0.12]| 2.302585092994046| null| + +-------------------------+---------------+---------------+----------+--------------------+-------------------+--------------------+ + + """ + # Testing if all columns are in the dataframe: + required_columns = [ + "STRONGEST SNP-RISK ALLELE", + "referenceAllele", + "alternateAllele", + "OR or BETA", + "95% CI (TEXT)", + ] + + for column in required_columns: + if column not in df.columns: + raise ValueError( + f"Column {column} is required for harmonising effect to beta value." + ) + + return ( + df.withColumn( + "reportedRiskAllele", + GWASCatalogCuratedAssociationsParser._extract_risk_allele( + f.col("STRONGEST SNP-RISK ALLELE") + ), + ) + .withColumns( + { + # Flag palindromic alleles: + "isAllelePalindromic": GWASCatalogCuratedAssociationsParser._are_alleles_palindromic( + f.col("referenceAllele"), f.col("alternateAllele") + ), + # Flag associations, where the effect direction needs to be flipped: + "needsFlipping": GWASCatalogCuratedAssociationsParser._effect_needs_harmonisation( + f.col("reportedRiskAllele"), f.col("referenceAllele") + ), + # Flag effect type: + "effectType": GWASCatalogCuratedAssociationsParser._get_effect_type( + f.col("95% CI (TEXT)") + ), + # Get standard error from confidence interval text: + "standardError": get_standard_error_from_confidence_interval( + f.regexp_extract( + "95% CI (TEXT)", r"\[(\d+\.*\d*)-\d+\.*\d*\]", 1 + ).cast(FloatType()), + f.regexp_extract( + "95% CI (TEXT)", r"\[\d+\.*\d*-(\d+\.*\d*)\]", 1 + ).cast(FloatType()), + ), + } + ) + # Harmonise both beta and odds ratio: + .withColumns( + { # Normalise beta value of the association: + "effect_beta": f.when( + (f.col("effectType") == "beta") + & (~f.col("isAllelePalindromic")), + GWASCatalogCuratedAssociationsParser._harmonise_beta( + f.col("OR or BETA"), + f.col("95% CI (TEXT)"), + f.col("needsFlipping"), + ), + ), + # Normalise odds ratio of the association: + "effect_odds_ratio": f.when( + (f.col("effectType") == "odds_ratio") + & (~f.col("isAllelePalindromic")), + GWASCatalogCuratedAssociationsParser._harmonise_odds_ratio( + f.col("OR or BETA"), + f.col("needsFlipping"), + ), + ), + }, + ) + .select( + *df.columns, + # Harmonise OR effect to beta: + *convert_odds_ratio_to_beta( + f.col("effect_beta"), + f.col("effect_odds_ratio"), + f.col("standardError"), + ), + ) + ) + @classmethod def from_source( cls: type[GWASCatalogCuratedAssociationsParser], gwas_associations: DataFrame, - variant_index: VariantIndex, + gnomad_variants: VariantIndex, pvalue_threshold: float = WindowBasedClumpingStepConfig.gwas_significance, ) -> StudyLocusGWASCatalog: """Read GWASCatalog associations. @@ -1002,7 +1099,7 @@ def from_source( Args: gwas_associations (DataFrame): GWAS Catalog raw associations dataset. - variant_index (VariantIndex): Variant index dataset with available allele frequencies. + gnomad_variants (VariantIndex): Variant dataset from GnomAD, with allele frequencies. pvalue_threshold (float): P-value threshold for flagging associations. Returns: @@ -1017,26 +1114,29 @@ def from_source( .transform( # Map/harmonise variants to variant annotation dataset: # This function adds columns: variantId, referenceAllele, alternateAllele, chromosome, position - lambda df: GWASCatalogCuratedAssociationsParser._map_variants_to_variant_index( - df, variant_index + lambda df: GWASCatalogCuratedAssociationsParser._map_variants_to_gnomad_variants( + df, gnomad_variants ) ) - .withColumn( + .withColumns( # Perform all quality control checks: - "qualityControls", - GWASCatalogCuratedAssociationsParser._qc_all( - f.array().alias("qualityControls"), - f.col("CHR_ID"), - f.col("CHR_POS").cast(IntegerType()), - f.col("referenceAllele"), - f.col("alternateAllele"), - f.col("STRONGEST SNP-RISK ALLELE"), - *GWASCatalogCuratedAssociationsParser._parse_pvalue( - f.col("P-VALUE") - ), - pvalue_threshold, - ), + { + "qualityControls": GWASCatalogCuratedAssociationsParser._qc_all( + f.array().alias("qualityControls"), + f.col("CHR_ID"), + f.col("CHR_POS").cast(IntegerType()), + f.col("referenceAllele"), + f.col("alternateAllele"), + f.col("STRONGEST SNP-RISK ALLELE"), + *GWASCatalogCuratedAssociationsParser._parse_pvalue( + f.col("P-VALUE") + ), + pvalue_threshold, + ) + } ) + # Harmonising effect to beta value and flip effect if needed: + .transform(cls.harmonise_association_effect_to_beta) .select( # INSIDE STUDY-LOCUS SCHEMA: "studyLocusId", @@ -1045,16 +1145,6 @@ def from_source( "chromosome", "position", f.col("STUDY ACCESSION").alias("studyId"), - # beta value of the association - GWASCatalogCuratedAssociationsParser._harmonise_beta( - GWASCatalogCuratedAssociationsParser._normalise_risk_allele( - f.col("STRONGEST SNP-RISK ALLELE") - ), - f.col("referenceAllele"), - f.col("alternateAllele"), - f.col("OR or BETA"), - f.col("95% CI (TEXT)"), - ).alias("beta"), # p-value of the association, string: split into exponent and mantissa. *GWASCatalogCuratedAssociationsParser._parse_pvalue(f.col("P-VALUE")), # Capturing phenotype granularity at the association level @@ -1065,6 +1155,8 @@ def from_source( ).alias("subStudyDescription"), # Quality controls (array of strings) "qualityControls", + "beta", + "standardError", ), _schema=StudyLocusGWASCatalog.get_schema(), ) diff --git a/tests/gentropy/datasource/gwas_catalog/test_gwas_catalog_associations.py b/tests/gentropy/datasource/gwas_catalog/test_gwas_catalog_associations.py index 2179150cd..fec181543 100644 --- a/tests/gentropy/datasource/gwas_catalog/test_gwas_catalog_associations.py +++ b/tests/gentropy/datasource/gwas_catalog/test_gwas_catalog_associations.py @@ -69,7 +69,7 @@ def test_map_variants_to_variant_index( ) -> None: """Test mapping to variant annotation variants.""" assert isinstance( - GWASCatalogCuratedAssociationsParser._map_variants_to_variant_index( + GWASCatalogCuratedAssociationsParser._map_variants_to_gnomad_variants( sample_gwas_catalog_associations.withColumn( "studyLocusId", f.monotonically_increasing_id().cast(LongType()) ), From c292e849a2ffd88c62155c511d3c311a6579a54b Mon Sep 17 00:00:00 2001 From: Kirill Tsukanov Date: Thu, 19 Sep 2024 13:24:41 +0100 Subject: [PATCH 041/188] perf: quickly build a Docker image for every branch (#773) * perf: cache Docker image layers * chore: temporary add branch to test * perf: separate AMD and ARM builds for gentropy * perf: temporarily test only VEP image separately * perf: test ARM/AMD gentropy/VEP separately * perf: introduce quick build for all commits * perf: quick build for all tags * fix: use correct syntax for tags * fix: revert accidental changes for the VEP step --- .github/workflows/artifact.yml | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/.github/workflows/artifact.yml b/.github/workflows/artifact.yml index 665dab0d7..61dbab28e 100644 --- a/.github/workflows/artifact.yml +++ b/.github/workflows/artifact.yml @@ -2,8 +2,8 @@ name: Build and Push to Artifact Registry "on": push: - branches: ["dev"] - tags: ["v*"] + branches: ["*"] + tags: ["*"] env: PROJECT_ID: open-targets-genetics-dev @@ -39,7 +39,18 @@ jobs: run: |- gcloud auth configure-docker ${{ env.REGION }}-docker.pkg.dev --quiet + - name: Quick Docker build (gentropy only, AMD64 only, with layer cache) + uses: docker/build-push-action@v6 + with: + platforms: linux/amd64 + push: true + tags: "${{ env.GAR_LOCATION }}/${{ env.REPOSITORY }}/gentropy:${{ github.ref_name }}" + context: . + cache-from: type=gha + cache-to: type=gha,mode=max + - name: Build and push gentropy image + if: github.ref == 'refs/heads/dev' || startsWith(github.ref, 'refs/tags/v') uses: docker/build-push-action@v6 with: platforms: linux/amd64,linux/arm64 @@ -48,6 +59,7 @@ jobs: context: . - name: Build and push VEP image + if: github.ref == 'refs/heads/dev' || startsWith(github.ref, 'refs/tags/v') uses: docker/build-push-action@v6 with: platforms: linux/amd64 From 785dad067c58edb1646af3d89a1580687685b400 Mon Sep 17 00:00:00 2001 From: David Ochoa Date: Fri, 20 Sep 2024 12:23:20 +0100 Subject: [PATCH 042/188] feat: flag all top-hits from GWAS catalog curation (#775) --- src/gentropy/dataset/study_locus.py | 4 +++- .../datasource/gwas_catalog/associations.py | 18 ++++++++++++++++++ .../datasource/gwas_catalog/study_splitter.py | 4 +++- .../test_gwas_catalog_associations.py | 9 +++++++++ 4 files changed, 33 insertions(+), 2 deletions(-) diff --git a/src/gentropy/dataset/study_locus.py b/src/gentropy/dataset/study_locus.py index 48f6ee8be..283280527 100644 --- a/src/gentropy/dataset/study_locus.py +++ b/src/gentropy/dataset/study_locus.py @@ -48,8 +48,9 @@ class StudyLocusQualityCheck(Enum): NOT_QUALIFYING_LD_BLOCK (str): LD block does not contain variants at the required R^2 threshold FAILED_STUDY (str): Flagging study loci if the study has failed QC MISSING_STUDY (str): Flagging study loci if the study is not found in the study index as a reference - DUPLICATED_STUDYLOCUS_ID (str): Study-locus identifier is not unique. + DUPLICATED_STUDYLOCUS_ID (str): Study-locus identifier is not unique INVALID_VARIANT_IDENTIFIER (str): Flagging study loci where identifier of any tagging variant was not found in the variant index + TOP_HIT (str): Study locus from curated top hit IN_MHC (str): Flagging study loci in the MHC region """ @@ -73,6 +74,7 @@ class StudyLocusQualityCheck(Enum): "Some variant identifiers of this locus were not found in variant index" ) IN_MHC = "MHC region" + TOP_HIT = "Study locus from curated top hit" class CredibleInterval(Enum): diff --git a/src/gentropy/datasource/gwas_catalog/associations.py b/src/gentropy/datasource/gwas_catalog/associations.py index 6781d045a..dd9aa3fe2 100644 --- a/src/gentropy/datasource/gwas_catalog/associations.py +++ b/src/gentropy/datasource/gwas_catalog/associations.py @@ -1212,6 +1212,24 @@ def qc_ambiguous_study(self: StudyLocusGWASCatalog) -> StudyLocusGWASCatalog: ) return self + def qc_flag_all_tophits(self: StudyLocusGWASCatalog) -> StudyLocusGWASCatalog: + """Flag all associations as top hits. + + Returns: + StudyLocusGWASCatalog: Updated study locus. + """ + return StudyLocusGWASCatalog( + _df=self._df.withColumn( + "qualityControls", + StudyLocus.update_quality_flag( + f.col("qualityControls"), + f.lit(True), + StudyLocusQualityCheck.TOP_HIT, + ), + ), + _schema=StudyLocusGWASCatalog.get_schema(), + ) + def apply_inclusion_list( self: StudyLocusGWASCatalog, inclusion_list: DataFrame ) -> StudyLocusGWASCatalog: diff --git a/src/gentropy/datasource/gwas_catalog/study_splitter.py b/src/gentropy/datasource/gwas_catalog/study_splitter.py index 882a9893a..0b11e797a 100644 --- a/src/gentropy/datasource/gwas_catalog/study_splitter.py +++ b/src/gentropy/datasource/gwas_catalog/study_splitter.py @@ -132,5 +132,7 @@ def split( st_ass.select( "updatedStudyId", "studyId", "subStudyDescription" ).distinct() - ).qc_ambiguous_study(), + ) + .qc_ambiguous_study() + .qc_flag_all_tophits(), ) diff --git a/tests/gentropy/datasource/gwas_catalog/test_gwas_catalog_associations.py b/tests/gentropy/datasource/gwas_catalog/test_gwas_catalog_associations.py index fec181543..130097f25 100644 --- a/tests/gentropy/datasource/gwas_catalog/test_gwas_catalog_associations.py +++ b/tests/gentropy/datasource/gwas_catalog/test_gwas_catalog_associations.py @@ -77,3 +77,12 @@ def test_map_variants_to_variant_index( ), DataFrame, ) + + +def test_qc_flag_all_tophits( + mock_study_locus_gwas_catalog: StudyLocusGWASCatalog, +) -> None: + """Test qc flag all top hits.""" + assert isinstance( + mock_study_locus_gwas_catalog.qc_flag_all_tophits(), StudyLocusGWASCatalog + ) From 018defa61e8faff3808c02635a5b468726e6c0db Mon Sep 17 00:00:00 2001 From: David Ochoa Date: Fri, 20 Sep 2024 14:06:26 +0100 Subject: [PATCH 043/188] docs: fix broken refs (#768) Co-authored-by: Szymon Szyszkowski <69353402+project-defiant@users.noreply.github.com> --- src/gentropy/dataset/summary_statistics.py | 2 +- src/gentropy/method/sumstat_imputation.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gentropy/dataset/summary_statistics.py b/src/gentropy/dataset/summary_statistics.py index b9a44ff34..d0875fe85 100644 --- a/src/gentropy/dataset/summary_statistics.py +++ b/src/gentropy/dataset/summary_statistics.py @@ -91,7 +91,7 @@ def locus_breaker_clumping( ) -> StudyLocus: """Generate study-locus from summary statistics using locus-breaker clumping method with locus boundaries. - For more info, see [`locus_breaker`][gentropy.method.locus_breaker_clumping.locus_breaker] + For more info, see [`locus_breaker`][gentropy.method.locus_breaker_clumping.LocusBreakerClumping] Args: baseline_pvalue_cutoff (float, optional): Baseline significance we consider for the locus. diff --git a/src/gentropy/method/sumstat_imputation.py b/src/gentropy/method/sumstat_imputation.py index 8375fa84f..b53295560 100644 --- a/src/gentropy/method/sumstat_imputation.py +++ b/src/gentropy/method/sumstat_imputation.py @@ -24,7 +24,7 @@ def raiss_model( Args: z_scores_known (np.ndarray): the vector of known Z scores ld_matrix_known (np.ndarray) : the matrix of known LD correlations - ld_matrix_known_missing (np.ndarray): LD matrix of known SNPs with other unknown SNPs in large matrix (similar to ld[unknowns, :][:,known]) + ld_matrix_known_missing (np.ndarray): LD matrix of known SNPs with other unknown SNPs in large matrix (similar to `ld[unknowns, :][:,known]`) lamb (float): size of the small value added to the diagonal of the covariance matrix before inversion. Defaults to 0.01. rtol (float): threshold to filter eigenvectos by its eigenvalue. It makes an inversion biased but much more numerically robust. Default to 0.01. From ad3f503ae988f7b09fb6723ca2c6a8c7ba0b8d90 Mon Sep 17 00:00:00 2001 From: David Ochoa Date: Fri, 20 Sep 2024 15:29:30 +0100 Subject: [PATCH 044/188] feat: flag PICS top hits in studies with credset sumstats (#777) Co-authored-by: Daniel Suveges --- src/gentropy/dataset/study_locus.py | 42 +++++++++++++ src/gentropy/study_locus_validation.py | 1 + tests/gentropy/dataset/test_study_locus.py | 71 ++++++++++++++++++++++ 3 files changed, 114 insertions(+) diff --git a/src/gentropy/dataset/study_locus.py b/src/gentropy/dataset/study_locus.py index 283280527..e2f9dfece 100644 --- a/src/gentropy/dataset/study_locus.py +++ b/src/gentropy/dataset/study_locus.py @@ -52,6 +52,7 @@ class StudyLocusQualityCheck(Enum): INVALID_VARIANT_IDENTIFIER (str): Flagging study loci where identifier of any tagging variant was not found in the variant index TOP_HIT (str): Study locus from curated top hit IN_MHC (str): Flagging study loci in the MHC region + REDUNDANT_PICS_TOP_HIT (str): Flagging study loci in studies with PICS results from summary statistics """ SUBSIGNIFICANT_FLAG = "Subsignificant p-value" @@ -74,6 +75,9 @@ class StudyLocusQualityCheck(Enum): "Some variant identifiers of this locus were not found in variant index" ) IN_MHC = "MHC region" + REDUNDANT_PICS_TOP_HIT = ( + "PICS results from summary statistics available for this same study" + ) TOP_HIT = "Study locus from curated top hit" @@ -878,6 +882,44 @@ def qc_MHC_region(self: StudyLocus) -> StudyLocus: ) return self + def qc_redundant_top_hits_from_PICS(self: StudyLocus) -> StudyLocus: + """Flag associations from top hits when the study contains other PICS associations from summary statistics. + + This flag can be useful to identify top hits that should be explained by other associations in the study derived from the summary statistics. + + Returns: + StudyLocus: Updated study locus with redundant top hits flagged. + """ + studies_with_pics_sumstats = ( + self.df.filter(f.col("finemappingMethod") == "pics") + # Returns True if the study contains any PICS associations from summary statistics + .withColumn( + "hasPicsSumstats", + ~f.array_contains( + "qualityControls", StudyLocusQualityCheck.TOP_HIT.value + ), + ) + .groupBy("studyId") + .agg(f.max(f.col("hasPicsSumstats")).alias("studiesWithPicsSumstats")) + ) + + return StudyLocus( + _df=self.df.join(studies_with_pics_sumstats, on="studyId", how="left") + .withColumn( + "qualityControls", + self.update_quality_flag( + f.col("qualityControls"), + f.array_contains( + "qualityControls", StudyLocusQualityCheck.TOP_HIT.value + ) + & f.col("studiesWithPicsSumstats"), + StudyLocusQualityCheck.REDUNDANT_PICS_TOP_HIT, + ), + ) + .drop("studiesWithPicsSumstats"), + _schema=StudyLocus.get_schema(), + ) + def _qc_no_population(self: StudyLocus) -> StudyLocus: """Flag associations where the study doesn't have population information to resolve LD. diff --git a/src/gentropy/study_locus_validation.py b/src/gentropy/study_locus_validation.py index da660ca57..e3d10f3db 100644 --- a/src/gentropy/study_locus_validation.py +++ b/src/gentropy/study_locus_validation.py @@ -46,6 +46,7 @@ def __init__( # Add flag for MHC region .qc_MHC_region() .validate_study(study_index) # Flagging studies not in study index + .qc_redundant_top_hits_from_PICS() # Flagging top hits from studies with PICS summary statistics .validate_unique_study_locus_id() # Flagging duplicated study locus ids ).persist() # we will need this for 2 types of outputs diff --git a/tests/gentropy/dataset/test_study_locus.py b/tests/gentropy/dataset/test_study_locus.py index 1daf9bb89..94390d20b 100644 --- a/tests/gentropy/dataset/test_study_locus.py +++ b/tests/gentropy/dataset/test_study_locus.py @@ -778,3 +778,74 @@ def test_study_validation_correctness(self: TestStudyLocusValidation) -> None: ) .count() ) == 1 + + +class TestStudyLocusRedundancyFlagging: + """Collection of tests related to flagging redundant credible sets.""" + + STUDY_LOCUS_DATA = [ + (1, "v1", "s1", "pics", []), + (2, "v2", "s1", "pics", [StudyLocusQualityCheck.TOP_HIT.value]), + (3, "v3", "s1", "pics", []), + (3, "v3", "s1", "pics", []), + (1, "v1", "s1", "pics", [StudyLocusQualityCheck.TOP_HIT.value]), + (1, "v1", "s2", "pics", [StudyLocusQualityCheck.TOP_HIT.value]), + (1, "v1", "s2", "pics", [StudyLocusQualityCheck.TOP_HIT.value]), + (1, "v1", "s3", "SuSie", []), + (1, "v1", "s3", "pics", [StudyLocusQualityCheck.TOP_HIT.value]), + (1, "v1", "s4", "pics", []), + (1, "v1", "s4", "SuSie", []), + (1, "v1", "s4", "pics", [StudyLocusQualityCheck.TOP_HIT.value]), + ] + + STUDY_LOCUS_SCHEMA = t.StructType( + [ + t.StructField("studyLocusId", t.LongType(), False), + t.StructField("variantId", t.StringType(), False), + t.StructField("studyId", t.StringType(), False), + t.StructField("finemappingMethod", t.StringType(), False), + t.StructField("qualityControls", t.ArrayType(t.StringType()), False), + ] + ) + + @pytest.fixture(autouse=True) + def _setup(self: TestStudyLocusRedundancyFlagging, spark: SparkSession) -> None: + """Setup study locus for testing.""" + self.study_locus = StudyLocus( + _df=spark.createDataFrame( + self.STUDY_LOCUS_DATA, schema=self.STUDY_LOCUS_SCHEMA + ), + _schema=StudyLocus.get_schema(), + ) + + def test_qc_redundant_top_hits_from_PICS_returntype( + self: TestStudyLocusRedundancyFlagging, + ) -> None: + """Test qc_redundant_top_hits_from_PICS.""" + assert isinstance( + self.study_locus.qc_redundant_top_hits_from_PICS(), StudyLocus + ) + + def test_qc_redundant_top_hits_from_PICS_no_data_loss( + self: TestStudyLocusRedundancyFlagging, + ) -> None: + """Testing if the redundancy flagging returns the same number of rows.""" + assert ( + self.study_locus.qc_redundant_top_hits_from_PICS().df.count() + == self.study_locus.df.count() + ) + + def test_qc_redundant_top_hits_from_PICS_correctness( + self: TestStudyLocusRedundancyFlagging, + ) -> None: + """Testing if the study validation flags the right number of studies.""" + assert ( + self.study_locus.qc_redundant_top_hits_from_PICS() + .df.filter( + f.array_contains( + f.col("qualityControls"), + StudyLocusQualityCheck.REDUNDANT_PICS_TOP_HIT.value, + ) + ) + .count() + ) == 3 From 58fb726a867d9b25f55f4ca6873b9a08adb3a8f5 Mon Sep 17 00:00:00 2001 From: Daniel Suveges Date: Mon, 23 Sep 2024 13:16:35 +0100 Subject: [PATCH 045/188] fix(ld clumping): a revised logic allows a more accurate clumping (#772) * fix(ld clumping): a revised logic allows a more accurate identification of linked loci * test: adding some test * chore: pre-commit auto fixes [...] * test: adding more test cases * fix: fixing test data --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- src/gentropy/dataset/study_locus.py | 8 +- src/gentropy/method/clump.py | 45 ++--- tests/gentropy/method/test_clump.py | 250 ++++++++++++---------------- 3 files changed, 131 insertions(+), 172 deletions(-) diff --git a/src/gentropy/dataset/study_locus.py b/src/gentropy/dataset/study_locus.py index e2f9dfece..9ab19dab6 100644 --- a/src/gentropy/dataset/study_locus.py +++ b/src/gentropy/dataset/study_locus.py @@ -798,11 +798,12 @@ def clump(self: StudyLocus) -> StudyLocus: Returns: StudyLocus: with empty credible sets for linked variants and QC flag. """ - self.df = ( + clumped_df = ( self.df.withColumn( "is_lead_linked", LDclumping._is_lead_linked( self.df.studyId, + self.df.chromosome, self.df.variantId, self.df.pValueExponent, self.df.pValueMantissa, @@ -823,7 +824,10 @@ def clump(self: StudyLocus) -> StudyLocus: ) .drop("is_lead_linked") ) - return self + return StudyLocus( + _df=clumped_df, + _schema=self.get_schema(), + ) def exclude_region( self: StudyLocus, region: GenomicRegion, exclude_overlap: bool = False diff --git a/src/gentropy/method/clump.py b/src/gentropy/method/clump.py index d239c062c..442d9d611 100644 --- a/src/gentropy/method/clump.py +++ b/src/gentropy/method/clump.py @@ -1,6 +1,5 @@ """Clumps GWAS significant variants to generate a studyLocus dataset of independent variants.""" - from __future__ import annotations from typing import TYPE_CHECKING @@ -20,6 +19,7 @@ class LDclumping: @staticmethod def _is_lead_linked( study_id: Column, + chromosome: Column, variant_id: Column, p_value_exponent: Column, p_value_mantissa: Column, @@ -29,6 +29,7 @@ def _is_lead_linked( Args: study_id (Column): studyId + chromosome (Column): chromosome variant_id (Column): Lead variant id p_value_exponent (Column): p-value exponent p_value_mantissa (Column): p-value mantissa @@ -37,31 +38,31 @@ def _is_lead_linked( Returns: Column: Boolean in which True indicates that the lead is linked to another tag in the same dataset. """ - leads_in_study = f.collect_set(variant_id).over(Window.partitionBy(study_id)) - tags_in_studylocus = f.array_union( - # Get all tag variants from the credible set per studyLocusId - f.transform(ld_set, lambda x: x.tagVariantId), - # And append the lead variant so that the intersection is the same for all studyLocusIds in a study - f.array(variant_id), - ) - intersect_lead_tags = f.array_sort( - f.array_intersect(leads_in_study, tags_in_studylocus) + # Partitoning data by study and chromosome - this is the scope for looking for linked loci. + # Within the partition, we order the data by increasing p-value, and we collect the more significant lead variants in the window. + windowspec = ( + Window.partitionBy(study_id, chromosome) + .orderBy(p_value_exponent.asc(), p_value_mantissa.asc()) + .rowsBetween(Window.unboundedPreceding, Window.currentRow) ) - return ( - # If the lead is in the credible set, we rank the peaks by p-value - f.when( - f.size(intersect_lead_tags) > 0, - f.row_number().over( - Window.partitionBy(study_id, intersect_lead_tags).orderBy( - p_value_exponent, p_value_mantissa - ) - ) - > 1, + more_significant_leads = f.collect_set(variant_id).over(windowspec) + + # Collect all variants from the ld_set + adding the lead variant to the list to make sure that the lead is always in the list. + tags_in_studylocus = f.array_distinct( + f.array_union( + f.array(variant_id), + f.transform(ld_set, lambda x: x.getField("tagVariantId")), ) - # If the intersection is empty (lead is not in the credible set or cred set is empty), the association is not linked - .otherwise(f.lit(False)) ) + # If more than one tags of the ld_set can be found in the list of the more significant leads, the lead is linked. + # Study loci without variantId is considered as not linked. + # Also leads that were not found in the LD index is also considered as not linked. + return f.when( + variant_id.isNotNull(), + f.size(f.array_intersect(more_significant_leads, tags_in_studylocus)) > 1, + ).otherwise(f.lit(False)) + @classmethod def clump(cls: type[LDclumping], associations: StudyLocus) -> StudyLocus: """Perform clumping on studyLocus dataset. diff --git a/tests/gentropy/method/test_clump.py b/tests/gentropy/method/test_clump.py index 4616c5c6f..1e754df3a 100644 --- a/tests/gentropy/method/test_clump.py +++ b/tests/gentropy/method/test_clump.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Any +from typing import TYPE_CHECKING import pyspark.sql.functions as f import pyspark.sql.types as t @@ -20,142 +20,77 @@ def test_clump(mock_study_locus: StudyLocus) -> None: assert isinstance(LDclumping.clump(mock_study_locus), StudyLocus) -@pytest.mark.parametrize( - ("observed_data", "expected_data"), - [ +class TestIsLeadLinked: + """Testing the is_lead_linked method.""" + + DATA = [ + # Linked to V2: ( - [ - ( - # Dependent locus - lead is correlated with a more significant variant - 1, - "L1", - "GCST005650_1", - 1.0, - -17, - [{"tagVariantId": "T1"}, {"tagVariantId": "L2"}], - None, - ), - ( - # Dependent locus - lead shows a stronger association than the row above - 2, - "L2", - "GCST005650_1", - 4.0, - -18, - [ - {"tagVariantId": "T2"}, - {"tagVariantId": "T3"}, - {"tagVariantId": "L1"}, - ], - None, - ), - ( - # Independent locus - 3, - "L2", - "GCST005650_1", - 4.0, - -18, - [ - {"tagVariantId": "L3"}, - {"tagVariantId": "T4"}, - {"tagVariantId": "L5"}, - ], - None, - ), - ( - # Empty credible set - 4, - "L3", - "GCST005650_1", - 4.0, - -18, - [], - None, - ), - ( - # Null credible set - 5, - "L4", - "GCST005650_1", - 4.0, - -18, - None, - None, - ), - ], - [ - ( - # Signal is linked to the next row - 1, - "L1", - "GCST005650_1", - 1.0, - -17, - [{"tagVariantId": "T1"}, {"tagVariantId": "L2"}], - True, - ), - ( - # Signal is the most significant - 2, - "L2", - "GCST005650_1", - 4.0, - -18, - [ - {"tagVariantId": "T2"}, - {"tagVariantId": "T3"}, - {"tagVariantId": "L1"}, - ], - False, - ), - ( - # Signal is not linked - 3, - "L2", - "GCST005650_1", - 4.0, - -18, - [ - {"tagVariantId": "L3"}, - {"tagVariantId": "T4"}, - {"tagVariantId": "L5"}, - ], - False, - ), - ( - # Empty credible set - signal is not linked - 4, - "L3", - "GCST005650_1", - 4.0, - -18, - [], - False, - ), - ( - # Null credible set - signal is not linked - 5, - "L4", - "GCST005650_1", - 4.0, - -18, - None, - False, - ), - ], - ) - ], -) -def test_is_lead_linked( - spark: SparkSession, observed_data: list[Any], expected_data: list[Any] -) -> None: - """Test function that annotates whether a studyLocusId is linked to a more statistically significant studyLocusId.""" - schema = t.StructType( + "s1", + 1, + "c1", + "v3", + 1.0, + -8, + [{"tagVariantId": "v3"}, {"tagVariantId": "v2"}, {"tagVariantId": "v4"}], + True, + ), + # True lead: + ( + "s1", + 2, + "c1", + "v1", + 1.0, + -10, + [{"tagVariantId": "v1"}, {"tagVariantId": "v2"}, {"tagVariantId": "v3"}], + False, + ), + # Linked to V1: + ( + "s1", + 3, + "c1", + "v2", + 1.0, + -9, + [{"tagVariantId": "v2"}, {"tagVariantId": "v1"}], + True, + ), + # Independent - No LD set: + ("s1", 4, "c1", "v10", 1.0, -10, [], False), + # Independent - No variantId: + ("s1", 5, "c1", None, 1.0, -10, [], False), + # An other independent variant on the same chromosome, but lead is not in ldSet: + ( + "s1", + 6, + "c1", + "v6", + 1.0, + -8, + [{"tagVariantId": "v7"}, {"tagVariantId": "v8"}, {"tagVariantId": "v9"}], + False, + ), + # An other independent variant on a different chromosome, but lead is not in ldSet: + ( + "s1", + 7, + "c2", + "v10", + 1.0, + -8, + [{"tagVariantId": "v2"}, {"tagVariantId": "v10"}], + False, + ), + ] + + SCHEMA = t.StructType( [ + t.StructField("studyId", t.StringType(), True), t.StructField("studyLocusId", t.LongType(), True), + t.StructField("chromosome", t.StringType(), True), t.StructField("variantId", t.StringType(), True), - t.StructField("studyId", t.StringType(), True), t.StructField("pValueMantissa", t.FloatType(), True), t.StructField("pValueExponent", t.IntegerType(), True), t.StructField( @@ -169,28 +104,47 @@ def test_is_lead_linked( ), True, ), - t.StructField("is_lead_linked", t.BooleanType(), True), + t.StructField("expected_flag", t.BooleanType(), True), ] ) - study_locus_df = spark.createDataFrame( - observed_data, - schema, - ) - observed_df = ( - study_locus_df.withColumn( + + @pytest.fixture(autouse=True) + def _setup(self: TestIsLeadLinked, spark: SparkSession) -> None: + """Setup study the mock index for testing.""" + # Store input data: + self.df = spark.createDataFrame(self.DATA, self.SCHEMA) + + def test_is_lead_correctness(self: TestIsLeadLinked) -> None: + """Test the correctness of the is_lead_linked method.""" + observed = self.df.withColumn( "is_lead_linked", LDclumping._is_lead_linked( f.col("studyId"), + f.col("chromosome"), f.col("variantId"), f.col("pValueExponent"), f.col("pValueMantissa"), f.col("ldSet"), ), - ) - .orderBy("studyLocusId") - .collect() - ) - expected_df = ( - spark.createDataFrame(expected_data, schema).orderBy("studyLocusId").collect() - ) - assert observed_df == expected_df + ).collect() + + for row in observed: + assert row["is_lead_linked"] == row["expected_flag"] + + def test_flagging(self: TestIsLeadLinked) -> None: + """Test flagging of lead variants.""" + # Create the study locus and clump: + sl_flagged = StudyLocus( + _df=self.df.drop("expected_flag").withColumn("qualityControls", f.array()), + _schema=StudyLocus.get_schema(), + ).clump() + + # Assert that the clumped locus is a StudyLocus: + assert isinstance(sl_flagged, StudyLocus) + + # Assert that the clumped locus has the correct columns: + for row in sl_flagged.df.join(self.df, on="studylocusId").collect(): + if len(row["qualityControls"]) == 0: + assert not row["expected_flag"] + else: + assert row["expected_flag"] From b93842af125b255b83c6e206c30ee1213d2860bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Irene=20L=C3=B3pez=20Santiago?= <45119610+ireneisdoomed@users.noreply.github.com> Date: Mon, 23 Sep 2024 13:30:33 +0100 Subject: [PATCH 046/188] refactor(L2GFeatureMatrix)!: streamline feature matrix management (#745) * refactor(L2GFeatureMatrix): remove schema validation * refactor(FeatureFactory): reshape feature generation WIP * chore: pre-commit auto fixes [...] * chore: set l2gfeature properties with decorator * chore(l2gfeature): make credible_set and input_dependency instance attributes * chore(l2gfeature): make credible_set and input_dependency instance attributes * chore(featurefactory): distanceTssMeanFeature working * refactor(l2g): improve step dependency management * feat: implement * chore: fix mypy issues * feat: l2gfeaturematrix.from_features_list working * chore: comment out obsolete refs * chore(L2GFeatureMatrix): change `mode` attribute to `with_gold_standard` * refactor(l2g): move feature matrix writing to training module * feat(L2GFeatureMatrix): accept L2GGoldStandard or StudyLocus as inputs * feat: implement methods to build a feature matrix based on a studylocus/L2GGoldStandard instance * feat: coloc logic prototype * feat(l2g): filter non gwas credible sets at the start of the step * feat: rewrite colocalisation feature factory * test: add `test_colocalisation_feature_type` * test(colocalisation): add test_extract_maximum_coloc_probability_per_region_and_gene * feat(L2GFeatureInputLoader): support multiple deps by passing loader as kwarg * test: add integration tests `test_build_feature_matrix` * chore: drop config yamls * refactor: move feature classes to datasets module * docs: update feature docs * refactor(colocalisation): cleaner joins in `append_right_study_metadata` * chore: better logging abstract methods * test: add `L2GFeatureMatrix.test_from_features_list` unit tests * fix: add goldStandardSet when a gs instance is passed to `from_features_list` * fix: lowercase colocalisation type and add semantic test * test: add semantic test for `append_right_study_metadata` * feat(colocalisation): make `append_right_study_metadata` extensible to left metadata * fix(colocalisation): append_study_metadata cant take a gold standard * fix(colocalisation): extract_maximum_coloc_probability_per_region_and_gene cant take a gold standard * feat: add `StudyLocus` as a dependency of colocalisation features * fix: add studylocus to input loader in test * fix: add studylocus to input loader in test * fix: add studylocus to input loader in test --- docs/python_api/datasets/l2g_feature.md | 22 +- .../python_api/methods/l2g/feature_factory.md | 4 +- .../assets/schemas/l2g_feature_matrix.json | 155 ------ src/gentropy/config.py | 55 +- src/gentropy/dataset/colocalisation.py | 134 +++++ src/gentropy/dataset/dataset.py | 5 +- src/gentropy/dataset/l2g_feature.py | 487 +++++++++++++++++- src/gentropy/dataset/l2g_feature_matrix.py | 150 +++--- src/gentropy/dataset/l2g_gold_standard.py | 25 + src/gentropy/dataset/l2g_prediction.py | 57 +- src/gentropy/dataset/study_locus.py | 24 + .../datasource/eqtl_catalogue/study_index.py | 20 +- src/gentropy/l2g.py | 302 +++++------ src/gentropy/method/colocalisation.py | 2 +- src/gentropy/method/l2g/feature_factory.py | 422 +++++---------- src/gentropy/method/l2g/model.py | 2 +- src/gentropy/method/l2g/trainer.py | 4 +- tests/gentropy/conftest.py | 38 +- tests/gentropy/dataset/test_colocalisation.py | 122 +++++ tests/gentropy/dataset/test_l2g.py | 55 +- tests/gentropy/dataset/test_l2g_feature.py | 59 +++ .../dataset/test_l2g_feature_matrix.py | 150 ++++++ tests/gentropy/dataset/test_study_locus.py | 21 + .../open_targets/test_l2g_gold_standard.py | 25 + tests/gentropy/method/test_locus_to_gene.py | 156 ------ 25 files changed, 1491 insertions(+), 1005 deletions(-) delete mode 100644 src/gentropy/assets/schemas/l2g_feature_matrix.json create mode 100644 tests/gentropy/dataset/test_l2g_feature.py create mode 100644 tests/gentropy/dataset/test_l2g_feature_matrix.py delete mode 100644 tests/gentropy/method/test_locus_to_gene.py diff --git a/docs/python_api/datasets/l2g_feature.md b/docs/python_api/datasets/l2g_feature.md index cf8c3dcf1..bdab67e7c 100644 --- a/docs/python_api/datasets/l2g_feature.md +++ b/docs/python_api/datasets/l2g_feature.md @@ -2,7 +2,27 @@ title: L2G Feature --- -::: gentropy.method.l2g.feature_factory.L2GFeature +## Abstract Class + +::: gentropy.dataset.l2g_feature.L2GFeature + +## Feature Classes + +### Derived from colocalisation + +::: gentropy.dataset.l2g_feature.EQtlColocClppMaximumFeature +::: gentropy.dataset.l2g_feature.PQtlColocClppMaximumFeature +::: gentropy.dataset.l2g_feature.SQtlColocClppMaximumFeature +::: gentropy.dataset.l2g_feature.TuQtlColocClppMaximumFeature +::: gentropy.dataset.l2g_feature.EQtlColocH4MaximumFeature +::: gentropy.dataset.l2g_feature.PQtlColocH4MaximumFeature +::: gentropy.dataset.l2g_feature.SQtlColocH4MaximumFeature +::: gentropy.dataset.l2g_feature.TuQtlColocH4MaximumFeature + +### Derived from distance + +::: gentropy.dataset.l2g_feature.DistanceTssMinimumFeature +::: gentropy.dataset.l2g_feature.DistanceTssMeanFeature ## Schema diff --git a/docs/python_api/methods/l2g/feature_factory.md b/docs/python_api/methods/l2g/feature_factory.md index 35b4ed710..ec812d2da 100644 --- a/docs/python_api/methods/l2g/feature_factory.md +++ b/docs/python_api/methods/l2g/feature_factory.md @@ -2,6 +2,6 @@ title: L2G Feature Factory --- -::: gentropy.method.l2g.feature_factory.ColocalisationFactory +::: gentropy.method.l2g.feature_factory.FeatureFactory -::: gentropy.method.l2g.feature_factory.StudyLocusFactory +::: gentropy.method.l2g.feature_factory.L2GFeatureInputLoader diff --git a/src/gentropy/assets/schemas/l2g_feature_matrix.json b/src/gentropy/assets/schemas/l2g_feature_matrix.json deleted file mode 100644 index 114936168..000000000 --- a/src/gentropy/assets/schemas/l2g_feature_matrix.json +++ /dev/null @@ -1,155 +0,0 @@ -{ - "fields": [ - { - "metadata": {}, - "name": "studyLocusId", - "nullable": false, - "type": "long" - }, - { - "metadata": {}, - "name": "geneId", - "nullable": false, - "type": "string" - }, - { - "metadata": {}, - "name": "goldStandardSet", - "nullable": true, - "type": "string" - }, - { - "metadata": {}, - "name": "distanceTssMean", - "nullable": true, - "type": "float" - }, - { - "metadata": {}, - "name": "distanceTssMinimum", - "nullable": true, - "type": "float" - }, - { - "metadata": {}, - "name": "vepMaximumNeighborhood", - "nullable": true, - "type": "float" - }, - { - "metadata": {}, - "name": "vepMaximum", - "nullable": true, - "type": "float" - }, - { - "metadata": {}, - "name": "vepMeanNeighborhood", - "nullable": true, - "type": "float" - }, - { - "metadata": {}, - "name": "vepMean", - "nullable": true, - "type": "float" - }, - { - "metadata": {}, - "name": "eqtlColocClppMaximum", - "nullable": true, - "type": "float" - }, - { - "metadata": {}, - "name": "eqtlColocClppMaximumNeighborhood", - "nullable": true, - "type": "float" - }, - { - "metadata": {}, - "name": "eqtlColocLlrMaximum", - "nullable": true, - "type": "float" - }, - { - "metadata": {}, - "name": "eqtlColocLlrMaximumNeighborhood", - "nullable": true, - "type": "float" - }, - { - "metadata": {}, - "name": "pqtlColocClppMaximum", - "nullable": true, - "type": "float" - }, - { - "metadata": {}, - "name": "pqtlColocClppMaximumNeighborhood", - "nullable": true, - "type": "float" - }, - { - "metadata": {}, - "name": "pqtlColocLlrMaximum", - "nullable": true, - "type": "float" - }, - { - "metadata": {}, - "name": "pqtlColocLlrMaximumNeighborhood", - "nullable": true, - "type": "float" - }, - { - "metadata": {}, - "name": "sqtlColocClppMaximum", - "nullable": true, - "type": "float" - }, - { - "metadata": {}, - "name": "sqtlColocClppMaximumNeighborhood", - "nullable": true, - "type": "float" - }, - { - "metadata": {}, - "name": "sqtlColocLlrMaximum", - "nullable": true, - "type": "float" - }, - { - "metadata": {}, - "name": "sqtlColocLlrMaximumNeighborhood", - "nullable": true, - "type": "float" - }, - { - "metadata": {}, - "name": "tuqtlColocClppMaximum", - "nullable": true, - "type": "float" - }, - { - "metadata": {}, - "name": "tuqtlColocClppMaximumNeighborhood", - "nullable": true, - "type": "float" - }, - { - "metadata": {}, - "name": "tuqtlColocLlrMaximum", - "nullable": true, - "type": "float" - }, - { - "metadata": {}, - "name": "tuqtlColocLlrMaximumNeighborhood", - "nullable": true, - "type": "float" - } - ], - "type": "struct" -} diff --git a/src/gentropy/config.py b/src/gentropy/config.py index 4d1174d6b..d5e02924b 100644 --- a/src/gentropy/config.py +++ b/src/gentropy/config.py @@ -227,50 +227,16 @@ class LocusToGeneConfig(StepConfig): gene_interactions_path: str | None = None features_list: list[str] = field( default_factory=lambda: [ - # average distance of all tagging variants to gene TSS - "distanceTssMean", - # minimum distance of all tagging variants to gene TSS - "distanceTssMinimum", - # maximum vep consequence score of the locus 95% credible set among all genes in the vicinity - "vepMaximumNeighborhood", - # maximum vep consequence score of the locus 95% credible set split by gene - "vepMaximum", - # mean vep consequence score of the locus 95% credible set among all genes in the vicinity - "vepMeanNeighborhood", - # mean vep consequence score of the locus 95% credible set split by gene - "vepMean", - # max clpp for each (study, locus, gene) aggregating over all eQTLs - "eqtlColocClppMaximum", - # max clpp for each (study, locus) aggregating over all eQTLs - "eqtlColocClppMaximumNeighborhood", - # max clpp for each (study, locus, gene) aggregating over all pQTLs - "pqtlColocClppMaximum", - # max clpp for each (study, locus) aggregating over all pQTLs - "pqtlColocClppMaximumNeighborhood", - # max clpp for each (study, locus, gene) aggregating over all sQTLs - "sqtlColocClppMaximum", - # max clpp for each (study, locus) aggregating over all sQTLs - "sqtlColocClppMaximumNeighborhood", - # max clpp for each (study, locus) aggregating over all tuQTLs - "tuqtlColocClppMaximum", - # max clpp for each (study, locus, gene) aggregating over all tuQTLs - "tuqtlColocClppMaximumNeighborhood", - # max log-likelihood ratio value for each (study, locus, gene) aggregating over all eQTLs - "eqtlColocLlrMaximum", - # max log-likelihood ratio value for each (study, locus) aggregating over all eQTLs - "eqtlColocLlrMaximumNeighborhood", - # max log-likelihood ratio value for each (study, locus, gene) aggregating over all pQTLs - "pqtlColocLlrMaximum", - # max log-likelihood ratio value for each (study, locus) aggregating over all pQTLs - "pqtlColocLlrMaximumNeighborhood", - # max log-likelihood ratio value for each (study, locus, gene) aggregating over all sQTLs - "sqtlColocLlrMaximum", - # max log-likelihood ratio value for each (study, locus) aggregating over all sQTLs - "sqtlColocLlrMaximumNeighborhood", - # max log-likelihood ratio value for each (study, locus, gene) aggregating over all tuQTLs - "tuqtlColocLlrMaximum", - # max log-likelihood ratio value for each (study, locus) aggregating over all tuQTLs - "tuqtlColocLlrMaximumNeighborhood", + # max CLPP for each (study, locus, gene) aggregating over a specific qtl type + "eQtlColocClppMaximum", + "pQtlColocClppMaximum", + "sQtlColocClppMaximum", + "tuQtlColocClppMaximum", + # max H4 for each (study, locus, gene) aggregating over a specific qtl type + "eQtlColocH4Maximum", + "pQtlColocH4Maximum", + "sQtlColocH4Maximum", + "tuQtlColocH4Maximum", ] ) hyperparameters: dict[str, Any] = field( @@ -283,6 +249,7 @@ class LocusToGeneConfig(StepConfig): wandb_run_name: str | None = None hf_hub_repo_id: str | None = "opentargets/locus_to_gene" download_from_hub: bool = True + write_feature_matrix: bool = True _target_: str = "gentropy.l2g.LocusToGeneStep" diff --git a/src/gentropy/dataset/colocalisation.py b/src/gentropy/dataset/colocalisation.py index e72543cb2..c0d074ae3 100644 --- a/src/gentropy/dataset/colocalisation.py +++ b/src/gentropy/dataset/colocalisation.py @@ -1,15 +1,26 @@ """Colocalisation dataset.""" + from __future__ import annotations from dataclasses import dataclass from typing import TYPE_CHECKING +import pyspark.sql.functions as f + from gentropy.common.schemas import parse_spark_schema +from gentropy.common.spark_helpers import get_record_with_maximum_value from gentropy.dataset.dataset import Dataset +from gentropy.dataset.study_locus import StudyLocus +from gentropy.datasource.eqtl_catalogue.study_index import EqtlCatalogueStudyIndex if TYPE_CHECKING: + from pyspark.sql import DataFrame from pyspark.sql.types import StructType + from gentropy.dataset.study_index import StudyIndex + +from functools import reduce + @dataclass class Colocalisation(Dataset): @@ -23,3 +34,126 @@ def get_schema(cls: type[Colocalisation]) -> StructType: StructType: Schema for the Colocalisation dataset """ return parse_spark_schema("colocalisation.json") + + def extract_maximum_coloc_probability_per_region_and_gene( + self: Colocalisation, + study_locus: StudyLocus, + study_index: StudyIndex, + *, + filter_by_colocalisation_method: str, + filter_by_qtl: str | None = None, + ) -> DataFrame: + """Get maximum colocalisation probability for a (studyLocus, gene) window. + + Args: + study_locus (StudyLocus): Dataset containing study loci to filter the colocalisation dataset on and the geneId linked to the region + study_index (StudyIndex): Study index to use to get study metadata + filter_by_colocalisation_method (str): optional filter to apply on the colocalisation dataset + filter_by_qtl (str | None): optional filter to apply on the colocalisation dataset + + Returns: + DataFrame: table with the maximum colocalisation scores for the provided study loci + + Raises: + ValueError: if filter_by_qtl is not in the list of valid QTL types + ValueError: if filter_by_colocalisation_method is not in the list of valid colocalisation methods + """ + from gentropy.colocalisation import ColocalisationStep + + valid_qtls = list(EqtlCatalogueStudyIndex.method_to_study_type_mapping.values()) + if filter_by_qtl and filter_by_qtl not in valid_qtls: + raise ValueError(f"There are no studies with QTL type {filter_by_qtl}") + + if filter_by_colocalisation_method not in [ + "ECaviar", + "Coloc", + ]: # TODO: Write helper class to retrieve coloc method names + raise ValueError( + f"Colocalisation method {filter_by_colocalisation_method} is not supported." + ) + + method_colocalisation_metric = ColocalisationStep._get_colocalisation_class( + filter_by_colocalisation_method + ).METHOD_METRIC # type: ignore + + coloc_filtering_expr = [ + f.col("rightGeneId").isNotNull(), + f.lower("colocalisationMethod") == filter_by_colocalisation_method.lower(), + ] + if filter_by_qtl: + coloc_filtering_expr.append( + f.lower("rightStudyType") == filter_by_qtl.lower() + ) + + filtered_colocalisation = ( + # Bring rightStudyType and rightGeneId and filter by rows where the gene is null, + # which is equivalent to filtering studyloci from gwas on the right side + self.append_study_metadata( + study_locus, + study_index, + metadata_cols=["studyType", "geneId"], + colocalisation_side="right", + ) + # it also filters based on method and qtl type + .filter(reduce(lambda a, b: a & b, coloc_filtering_expr)) + # and filters colocalisation results to only include the subset of studylocus that contains gwas studylocusid + .join( + study_locus.df.selectExpr("studyLocusId as leftStudyLocusId"), + "leftStudyLocusId", + ) + ) + + return get_record_with_maximum_value( + filtered_colocalisation.withColumnRenamed( + "leftStudyLocusId", "studyLocusId" + ).withColumnRenamed("rightGeneId", "geneId"), + ["studyLocusId", "geneId"], + method_colocalisation_metric, + ) + + def append_study_metadata( + self: Colocalisation, + study_locus: StudyLocus, + study_index: StudyIndex, + *, + metadata_cols: list[str], + colocalisation_side: str = "right", + ) -> DataFrame: + """Appends metadata from the study to the requested side of the colocalisation dataset. + + Args: + study_locus (StudyLocus): Dataset containing study loci that links the colocalisation dataset and the study index via the studyId + study_index (StudyIndex): Dataset containing study index that contains the metadata + metadata_cols (list[str]): List of study columns to append + colocalisation_side (str): Which side of the colocalisation dataset to append metadata to. Must be either 'right' or 'left' + + Returns: + DataFrame: Colocalisation dataset with appended metadata of the study from the requested side + + Raises: + ValueError: if colocalisation_side is not 'right' or 'left' + """ + metadata_cols = ["studyId", *metadata_cols] + if colocalisation_side not in ["right", "left"]: + raise ValueError( + f"colocalisation_side must be either 'right' or 'left', got {colocalisation_side}" + ) + + study_loci_w_metadata = ( + study_locus.df.select("studyLocusId", "studyId") + .join( + f.broadcast(study_index.df.select("studyId", *metadata_cols)), + "studyId", + ) + .distinct() + ) + return ( + # Append that to the respective side of the colocalisation dataset + study_loci_w_metadata.selectExpr( + f"studyLocusId as {colocalisation_side}StudyLocusId", + *[ + f"{col} as {colocalisation_side}{col[0].upper() + col[1:]}" + for col in metadata_cols + ], + ).join(self.df, f"{colocalisation_side}StudyLocusId", "right") + ) diff --git a/src/gentropy/dataset/dataset.py b/src/gentropy/dataset/dataset.py index e019ea379..cbeae7073 100644 --- a/src/gentropy/dataset/dataset.py +++ b/src/gentropy/dataset/dataset.py @@ -73,8 +73,11 @@ def get_schema(cls: type[Self]) -> StructType: Returns: StructType: Schema for the Dataset + + Raises: + NotImplementedError: Must be implemented in the child classes """ - pass + raise NotImplementedError("Must be implemented in the child classes") @classmethod def get_QC_column_name(cls: type[Self]) -> str | None: diff --git a/src/gentropy/dataset/l2g_feature.py b/src/gentropy/dataset/l2g_feature.py index 2e9f19d61..319570cfd 100644 --- a/src/gentropy/dataset/l2g_feature.py +++ b/src/gentropy/dataset/l2g_feature.py @@ -1,20 +1,46 @@ -"""L2G Feature Dataset.""" +"""L2G Feature Dataset with a collection of methods that extract features from the gentropy datasets to be fed in L2G.""" + from __future__ import annotations +from abc import ABC, abstractmethod from dataclasses import dataclass -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Any + +import pyspark.sql.functions as f from gentropy.common.schemas import parse_spark_schema +from gentropy.common.spark_helpers import convert_from_wide_to_long +from gentropy.dataset.colocalisation import Colocalisation from gentropy.dataset.dataset import Dataset +from gentropy.dataset.l2g_gold_standard import L2GGoldStandard +from gentropy.dataset.study_index import StudyIndex +from gentropy.dataset.study_locus import StudyLocus +from gentropy.dataset.v2g import V2G if TYPE_CHECKING: + from pyspark.sql import DataFrame from pyspark.sql.types import StructType @dataclass -class L2GFeature(Dataset): +class L2GFeature(Dataset, ABC): """Locus-to-gene feature dataset.""" + def __post_init__( + self: L2GFeature, + feature_dependency_type: Any = None, + credible_set: StudyLocus | None = None, + ) -> None: + """Initializes a L2GFeature dataset. Any child class of L2GFeature must implement the `compute` method. + + Args: + feature_dependency_type (Any): The dependency that the L2GFeature dataset depends on. Defaults to None. + credible_set (StudyLocus | None): The credible set that the L2GFeature dataset is based on. Defaults to None. + """ + super().__post_init__() + self.feature_dependency_type = feature_dependency_type + self.credible_set = credible_set + @classmethod def get_schema(cls: type[L2GFeature]) -> StructType: """Provides the schema for the L2GFeature dataset. @@ -23,3 +49,458 @@ def get_schema(cls: type[L2GFeature]) -> StructType: StructType: Schema for the L2GFeature dataset """ return parse_spark_schema("l2g_feature.json") + + @classmethod + @abstractmethod + def compute( + cls: type[L2GFeature], + study_loci_to_annotate: StudyLocus | L2GGoldStandard, + feature_dependency: Any, + ) -> L2GFeature: + """Computes the L2GFeature dataset. + + Args: + study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation + feature_dependency (Any): The dependency that the L2GFeature class needs to compute the feature + Returns: + L2GFeature: a L2GFeature dataset + + Raises: + NotImplementedError: This method must be implemented in the child classes + """ + raise NotImplementedError("Must be implemented in the child classes") + + +def _common_colocalisation_feature_logic( + study_loci_to_annotate: StudyLocus | L2GGoldStandard, + colocalisation_method: str, + colocalisation_metric: str, + feature_name: str, + qtl_type: str, + *, + colocalisation: Colocalisation, + study_index: StudyIndex, + study_locus: StudyLocus, +) -> DataFrame: + """Wrapper to call the logic that creates a type of colocalisation features. + + Args: + study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation + colocalisation_method (str): The colocalisation method to filter the data by + colocalisation_metric (str): The colocalisation metric to use + feature_name (str): The name of the feature to create + qtl_type (str): The type of QTL to filter the data by + colocalisation (Colocalisation): Dataset with the colocalisation results + study_index (StudyIndex): Study index to fetch study type and gene + study_locus (StudyLocus): Study locus to traverse between colocalisation and study index + + Returns: + DataFrame: Feature annotation in long format with the columns: studyLocusId, geneId, featureName, featureValue + """ + joining_cols = ( + ["studyLocusId", "geneId"] + if isinstance(study_loci_to_annotate, L2GGoldStandard) + else ["studyLocusId"] + ) + return convert_from_wide_to_long( + study_loci_to_annotate.df.join( + colocalisation.extract_maximum_coloc_probability_per_region_and_gene( + study_locus, + study_index, + filter_by_colocalisation_method=colocalisation_method, + filter_by_qtl=qtl_type, + ), + on=joining_cols, + ) + .selectExpr( + "studyLocusId", + "geneId", + f"{colocalisation_metric} as {feature_name}", + ) + .distinct(), + id_vars=("studyLocusId", "geneId"), + var_name="featureName", + value_name="featureValue", + ) + + +class EQtlColocClppMaximumFeature(L2GFeature): + """Max CLPP for each (study, locus, gene) aggregating over all eQTLs.""" + + feature_dependency_type = [Colocalisation, StudyIndex, StudyLocus] + feature_name = "eQtlColocClppMaximum" + + @classmethod + def compute( + cls: type[EQtlColocClppMaximumFeature], + study_loci_to_annotate: StudyLocus | L2GGoldStandard, + feature_dependency: dict[str, Any], + ) -> EQtlColocClppMaximumFeature: + """Computes the feature. + + Args: + study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation + feature_dependency (dict[str, Any]): Dictionary with the dependencies required. They are passed as keyword arguments. + + Returns: + EQtlColocClppMaximumFeature: Feature dataset + """ + colocalisation_method = "ECaviar" + colocalisation_metric = "clpp" + qtl_type = "eqtl" + + return cls( + _df=_common_colocalisation_feature_logic( + study_loci_to_annotate, + colocalisation_method, + colocalisation_metric, + cls.feature_name, + qtl_type, + **feature_dependency, + ), + _schema=cls.get_schema(), + ) + + +class PQtlColocClppMaximumFeature(L2GFeature): + """Max CLPP for each (study, locus, gene) aggregating over all pQTLs.""" + + feature_dependency_type = [Colocalisation, StudyIndex, StudyLocus] + feature_name = "pQtlColocClppMaximum" + + @classmethod + def compute( + cls: type[PQtlColocClppMaximumFeature], + study_loci_to_annotate: StudyLocus | L2GGoldStandard, + feature_dependency: dict[str, Any], + ) -> PQtlColocClppMaximumFeature: + """Computes the feature. + + Args: + study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation + feature_dependency (dict[str, Any]): Dataset with the colocalisation results + + Returns: + PQtlColocClppMaximumFeature: Feature dataset + """ + colocalisation_method = "ECaviar" + colocalisation_metric = "clpp" + qtl_type = "pqtl" + return cls( + _df=_common_colocalisation_feature_logic( + study_loci_to_annotate, + colocalisation_method, + colocalisation_metric, + cls.feature_name, + qtl_type, + **feature_dependency, + ), + _schema=cls.get_schema(), + ) + + +class SQtlColocClppMaximumFeature(L2GFeature): + """Max CLPP for each (study, locus, gene) aggregating over all sQTLs.""" + + feature_dependency_type = [Colocalisation, StudyIndex, StudyLocus] + feature_name = "sQtlColocClppMaximum" + + @classmethod + def compute( + cls: type[SQtlColocClppMaximumFeature], + study_loci_to_annotate: StudyLocus | L2GGoldStandard, + feature_dependency: dict[str, Any], + ) -> SQtlColocClppMaximumFeature: + """Computes the feature. + + Args: + study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation + feature_dependency (dict[str, Any]): Dataset with the colocalisation results + + Returns: + SQtlColocClppMaximumFeature: Feature dataset + """ + colocalisation_method = "ECaviar" + colocalisation_metric = "clpp" + qtl_type = "sqtl" + return cls( + _df=_common_colocalisation_feature_logic( + study_loci_to_annotate, + colocalisation_method, + colocalisation_metric, + cls.feature_name, + qtl_type, + **feature_dependency, + ), + _schema=cls.get_schema(), + ) + + +class TuQtlColocClppMaximumFeature(L2GFeature): + """Max CLPP for each (study, locus, gene) aggregating over all tuQTLs.""" + + feature_dependency_type = [Colocalisation, StudyIndex, StudyLocus] + feature_name = "tuQtlColocClppMaximum" + + @classmethod + def compute( + cls: type[TuQtlColocClppMaximumFeature], + study_loci_to_annotate: StudyLocus | L2GGoldStandard, + feature_dependency: dict[str, Any], + ) -> TuQtlColocClppMaximumFeature: + """Computes the feature. + + Args: + study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation + feature_dependency (dict[str, Any]): Dataset with the colocalisation results + + Returns: + TuQtlColocClppMaximumFeature: Feature dataset + """ + colocalisation_method = "ECaviar" + colocalisation_metric = "clpp" + qtl_type = "tuqtl" + return cls( + _df=_common_colocalisation_feature_logic( + study_loci_to_annotate, + colocalisation_method, + colocalisation_metric, + cls.feature_name, + qtl_type, + **feature_dependency, + ), + _schema=cls.get_schema(), + ) + + +class EQtlColocH4MaximumFeature(L2GFeature): + """Max CLPP for each (study, locus, gene) aggregating over all eQTLs.""" + + feature_dependency_type = [Colocalisation, StudyIndex, StudyLocus] + feature_name = "eQtlColocH4Maximum" + + @classmethod + def compute( + cls: type[EQtlColocH4MaximumFeature], + study_loci_to_annotate: StudyLocus | L2GGoldStandard, + feature_dependency: dict[str, Any], + ) -> EQtlColocH4MaximumFeature: + """Computes the feature. + + Args: + study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation + feature_dependency (dict[str, Any]): Dataset with the colocalisation results + + Returns: + EQtlColocH4MaximumFeature: Feature dataset + """ + colocalisation_method = "Coloc" + colocalisation_metric = "h4" + qtl_type = "eqtl" + return cls( + _df=_common_colocalisation_feature_logic( + study_loci_to_annotate, + colocalisation_method, + colocalisation_metric, + cls.feature_name, + qtl_type, + **feature_dependency, + ), + _schema=cls.get_schema(), + ) + + +class PQtlColocH4MaximumFeature(L2GFeature): + """Max CLPP for each (study, locus, gene) aggregating over all pQTLs.""" + + feature_dependency_type = [Colocalisation, StudyIndex, StudyLocus] + feature_name = "pQtlColocH4Maximum" + + @classmethod + def compute( + cls: type[PQtlColocH4MaximumFeature], + study_loci_to_annotate: StudyLocus | L2GGoldStandard, + feature_dependency: dict[str, Any], + ) -> PQtlColocH4MaximumFeature: + """Computes the feature. + + Args: + study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation + feature_dependency (dict[str, Any]): Dataset with the colocalisation results + + Returns: + PQtlColocH4MaximumFeature: Feature dataset + """ + colocalisation_method = "Coloc" + colocalisation_metric = "h4" + qtl_type = "pqtl" + return cls( + _df=_common_colocalisation_feature_logic( + study_loci_to_annotate, + colocalisation_method, + colocalisation_metric, + cls.feature_name, + qtl_type, + **feature_dependency, + ), + _schema=cls.get_schema(), + ) + + +class SQtlColocH4MaximumFeature(L2GFeature): + """Max CLPP for each (study, locus, gene) aggregating over all sQTLs.""" + + feature_dependency_type = [Colocalisation, StudyIndex, StudyLocus] + feature_name = "sQtlColocH4Maximum" + + @classmethod + def compute( + cls: type[SQtlColocH4MaximumFeature], + study_loci_to_annotate: StudyLocus | L2GGoldStandard, + feature_dependency: dict[str, Any], + ) -> SQtlColocH4MaximumFeature: + """Computes the feature. + + Args: + study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation + feature_dependency (dict[str, Any]): Dataset with the colocalisation results + + Returns: + SQtlColocH4MaximumFeature: Feature dataset + """ + colocalisation_method = "Coloc" + colocalisation_metric = "h4" + qtl_type = "sqtl" + return cls( + _df=_common_colocalisation_feature_logic( + study_loci_to_annotate, + colocalisation_method, + colocalisation_metric, + cls.feature_name, + qtl_type, + **feature_dependency, + ), + _schema=cls.get_schema(), + ) + + +class TuQtlColocH4MaximumFeature(L2GFeature): + """Max H4 for each (study, locus, gene) aggregating over all tuQTLs.""" + + feature_dependency_type = [Colocalisation, StudyIndex, StudyLocus] + feature_name = "tuQtlColocH4Maximum" + + @classmethod + def compute( + cls: type[TuQtlColocH4MaximumFeature], + study_loci_to_annotate: StudyLocus | L2GGoldStandard, + feature_dependency: dict[str, Any], + ) -> TuQtlColocH4MaximumFeature: + """Computes the feature. + + Args: + study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation + feature_dependency (dict[str, Any]): Dataset with the colocalisation results + + Returns: + TuQtlColocH4MaximumFeature: Feature dataset + """ + colocalisation_method = "Coloc" + colocalisation_metric = "h4" + qtl_type = "tuqtl" + return cls( + _df=_common_colocalisation_feature_logic( + study_loci_to_annotate, + colocalisation_method, + colocalisation_metric, + cls.feature_name, + qtl_type, + **feature_dependency, + ), + _schema=cls.get_schema(), + ) + + +class DistanceTssMinimumFeature(L2GFeature): + """Minimum distance of all tagging variants to gene TSS.""" + + @classmethod + def compute( + cls: type[DistanceTssMinimumFeature], + study_loci_to_annotate: StudyLocus | L2GGoldStandard, + feature_dependency: V2G, + ) -> L2GFeature: + """Computes the feature. + + Args: + study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation + feature_dependency (V2G): Dataset that contains the distance information + + Returns: + L2GFeature: Feature dataset + + Raises: + NotImplementedError: Not implemented + """ + raise NotImplementedError + + +class DistanceTssMeanFeature(L2GFeature): + """Average distance of all tagging variants to gene TSS. + + NOTE: to be rewritten taking variant index as input + """ + + fill_na_value = 500_000 + feature_dependency_type = V2G + + @classmethod + def compute( + cls: type[DistanceTssMeanFeature], + study_loci_to_annotate: StudyLocus | L2GGoldStandard, + feature_dependency: V2G, + ) -> DistanceTssMeanFeature: + """Computes the feature. + + Args: + study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation + feature_dependency (V2G): Dataset that contains the distance information + + Returns: + DistanceTssMeanFeature: Feature dataset + """ + agg_expr = f.mean("weightedScore").alias("distanceTssMean") + # Everything but expresion is common logic + v2g = feature_dependency.df.filter(f.col("datasourceId") == "canonical_tss") + wide_df = ( + study_loci_to_annotate.df.withColumn( + "variantInLocus", f.explode_outer("locus") + ) + .select( + "studyLocusId", + f.col("variantInLocus.variantId").alias("variantInLocusId"), + f.col("variantInLocus.posteriorProbability").alias( + "variantInLocusPosteriorProbability" + ), + ) + .join( + v2g.selectExpr("variantId as variantInLocusId", "geneId", "score"), + on="variantInLocusId", + how="inner", + ) + .withColumn( + "weightedScore", + f.col("score") * f.col("variantInLocusPosteriorProbability"), + ) + .groupBy("studyLocusId", "geneId") + .agg(agg_expr) + ) + return cls( + _df=convert_from_wide_to_long( + wide_df, + id_vars=("studyLocusId", "geneId"), + var_name="featureName", + value_name="featureValue", + ), + _schema=cls.get_schema(), + ) diff --git a/src/gentropy/dataset/l2g_feature_matrix.py b/src/gentropy/dataset/l2g_feature_matrix.py index 4c611e3da..b4893a785 100644 --- a/src/gentropy/dataset/l2g_feature_matrix.py +++ b/src/gentropy/dataset/l2g_feature_matrix.py @@ -2,112 +2,103 @@ from __future__ import annotations -from dataclasses import dataclass, field from functools import reduce from typing import TYPE_CHECKING, Type -from gentropy.common.schemas import parse_spark_schema from gentropy.common.spark_helpers import convert_from_long_to_wide -from gentropy.dataset.dataset import Dataset -from gentropy.method.l2g.feature_factory import ColocalisationFactory, StudyLocusFactory +from gentropy.dataset.l2g_gold_standard import L2GGoldStandard +from gentropy.method.l2g.feature_factory import FeatureFactory, L2GFeatureInputLoader if TYPE_CHECKING: - from pyspark.sql.types import StructType + from pyspark.sql import DataFrame - from gentropy.dataset.colocalisation import Colocalisation - from gentropy.dataset.study_index import StudyIndex from gentropy.dataset.study_locus import StudyLocus - from gentropy.dataset.v2g import V2G -@dataclass -class L2GFeatureMatrix(Dataset): - """Dataset with features for Locus to Gene prediction. +class L2GFeatureMatrix: + """Dataset with features for Locus to Gene prediction.""" - Attributes: - features_list (list[str] | None): List of features to use. If None, all possible features are used. - fixed_cols (list[str]): Columns that should be kept fixed in the feature matrix, although not considered as features. - mode (str): Mode of the feature matrix. Defaults to "train". Can be either "train" or "predict". - """ - - features_list: list[str] | None = None - fixed_cols: list[str] = field(default_factory=lambda: ["studyLocusId", "geneId"]) - mode: str = "train" - - def __post_init__(self: L2GFeatureMatrix) -> None: + def __init__( + self, + _df: DataFrame, + features_list: list[str] | None = None, + with_gold_standard: bool = False, + ) -> None: """Post-initialisation to set the features list. If not provided, all columns except the fixed ones are used. - Raises: - ValueError: If the mode is neither 'train' nor 'predict'. + Args: + _df (DataFrame): Feature matrix dataset + features_list (list[str] | None): List of features to use. If None, all possible features are used. + with_gold_standard (bool): Whether to include the gold standard set in the feature matrix. """ - if self.mode not in ["train", "predict"]: - raise ValueError("Mode should be either 'train' or 'predict'") - if self.mode == "train": - self.fixed_cols = self.fixed_cols + ["goldStandardSet"] - self.features_list = self.features_list or [ - col for col in self._df.columns if col not in self.fixed_cols + self.fixed_cols = ["studyLocusId", "geneId"] + if with_gold_standard: + self.fixed_cols.append("goldStandardSet") + + self.features_list = features_list or [ + col for col in _df.columns if col not in self.fixed_cols ] - self.validate_schema() + self._df = _df.selectExpr( + self.fixed_cols + + [ + f"CAST({feature} AS FLOAT) AS {feature}" + for feature in self.features_list + ] + ) @classmethod - def generate_features( + def from_features_list( cls: Type[L2GFeatureMatrix], + study_loci_to_annotate: StudyLocus | L2GGoldStandard, features_list: list[str], - credible_set: StudyLocus, - study_index: StudyIndex, - variant_gene: V2G, - colocalisation: Colocalisation, + features_input_loader: L2GFeatureInputLoader, ) -> L2GFeatureMatrix: - """Generate features from the gentropy datasets. + """Generate features from the gentropy datasets by calling the feature factory that will instantiate the corresponding features. Args: - features_list (list[str]): List of features to generate - credible_set (StudyLocus): Credible set dataset - study_index (StudyIndex): Study index dataset - variant_gene (V2G): Variant to gene dataset - colocalisation (Colocalisation): Colocalisation dataset + study_loci_to_annotate (StudyLocus | L2GGoldStandard): Study locus pairs to annotate + features_list (list[str]): List of feature names to be computed. + features_input_loader (L2GFeatureInputLoader): Object that contais features input. Returns: L2GFeatureMatrix: L2G feature matrix dataset - - Raises: - ValueError: If the feature matrix is empty """ - if features_dfs := [ - # Extract features - ColocalisationFactory._get_max_coloc_per_credible_set( - colocalisation, - credible_set, - study_index, - ).df, - StudyLocusFactory._get_tss_distance_features(credible_set, variant_gene).df, - StudyLocusFactory._get_vep_features(credible_set, variant_gene).df, - ]: - fm = reduce( - lambda x, y: x.unionByName(y), - features_dfs, + features_long_df = reduce( + lambda x, y: x.unionByName(y, allowMissingColumns=True), + [ + # Compute all features and merge them into a single dataframe + feature.df + for feature in FeatureFactory( + study_loci_to_annotate, features_list + ).generate_features(features_input_loader) + ], + ) + if isinstance(study_loci_to_annotate, L2GGoldStandard): + return cls( + _df=convert_from_long_to_wide( + # Add gold standard set to the feature matrix + features_long_df.join( + study_loci_to_annotate.df.select( + "studyLocusId", "geneId", "goldStandardSet" + ), + ["studyLocusId", "geneId"], + ), + ["studyLocusId", "geneId", "goldStandardSet"], + "featureName", + "featureValue", + ), + with_gold_standard=True, ) - else: - raise ValueError("No features found") - - # raise error if the feature matrix is empty return cls( _df=convert_from_long_to_wide( - fm, ["studyLocusId", "geneId"], "featureName", "featureValue" + features_long_df, + ["studyLocusId", "geneId"], + "featureName", + "featureValue", ), - _schema=cls.get_schema(), - features_list=features_list, + with_gold_standard=False, ) - @classmethod - def get_schema(cls: type[L2GFeatureMatrix]) -> StructType: - """Provides the schema for the L2gFeatureMatrix dataset. - - Returns: - StructType: Schema for the L2gFeatureMatrix dataset - """ - return parse_spark_schema("l2g_feature_matrix.json") - def calculate_feature_missingness_rate( self: L2GFeatureMatrix, ) -> dict[str, float]: @@ -145,7 +136,7 @@ def fill_na( Returns: L2GFeatureMatrix: L2G feature matrix dataset """ - self.df = self._df.fillna(value, subset=subset) + self._df = self._df.fillna(value, subset=subset) return self def select_features( @@ -164,6 +155,13 @@ def select_features( ValueError: If no features have been selected. """ if features_list := features_list or self.features_list: - self.df = self._df.select(self.fixed_cols + features_list) + # cast to float every feature in the features_list + self._df = self._df.selectExpr( + self.fixed_cols + + [ + f"CAST({feature} AS FLOAT) AS {feature}" + for feature in features_list + ] + ) return self raise ValueError("features_list cannot be None") diff --git a/src/gentropy/dataset/l2g_gold_standard.py b/src/gentropy/dataset/l2g_gold_standard.py index 5bc48413c..89f4c5f5d 100644 --- a/src/gentropy/dataset/l2g_gold_standard.py +++ b/src/gentropy/dataset/l2g_gold_standard.py @@ -1,4 +1,5 @@ """L2G gold standard dataset.""" + from __future__ import annotations from dataclasses import dataclass @@ -15,6 +16,7 @@ from pyspark.sql import DataFrame from pyspark.sql.types import StructType + from gentropy.dataset.l2g_feature_matrix import L2GFeatureMatrix from gentropy.dataset.study_locus_overlap import StudyLocusOverlap from gentropy.dataset.v2g import V2G @@ -100,6 +102,29 @@ def process_gene_interactions( "scoring as score", ) + def build_feature_matrix( + self: L2GGoldStandard, + full_feature_matrix: L2GFeatureMatrix, + ) -> L2GFeatureMatrix: + """Return a feature matrix for study loci in the gold standard. + + Args: + full_feature_matrix (L2GFeatureMatrix): Feature matrix for all study loci to join on + + Returns: + L2GFeatureMatrix: Feature matrix for study loci in the gold standard + """ + from gentropy.dataset.l2g_feature_matrix import L2GFeatureMatrix + + return L2GFeatureMatrix( + _df=full_feature_matrix._df.join( + f.broadcast(self.df.drop("variantId", "studyId", "sources")), + on=["studyLocusId", "geneId"], + how="inner", + ), + with_gold_standard=True, + ) + def filter_unique_associations( self: L2GGoldStandard, study_locus_overlap: StudyLocusOverlap, diff --git a/src/gentropy/dataset/l2g_prediction.py b/src/gentropy/dataset/l2g_prediction.py index 9895f55b7..97e58f526 100644 --- a/src/gentropy/dataset/l2g_prediction.py +++ b/src/gentropy/dataset/l2g_prediction.py @@ -7,12 +7,10 @@ from gentropy.common.schemas import parse_spark_schema from gentropy.common.session import Session -from gentropy.dataset.colocalisation import Colocalisation from gentropy.dataset.dataset import Dataset from gentropy.dataset.l2g_feature_matrix import L2GFeatureMatrix -from gentropy.dataset.study_index import StudyIndex from gentropy.dataset.study_locus import StudyLocus -from gentropy.dataset.v2g import V2G +from gentropy.method.l2g.feature_factory import L2GFeatureInputLoader from gentropy.method.l2g.model import LocusToGeneModel if TYPE_CHECKING: @@ -40,31 +38,27 @@ def get_schema(cls: type[L2GPrediction]) -> StructType: @classmethod def from_credible_set( cls: Type[L2GPrediction], - features_list: list[str], - credible_set: StudyLocus, - study_index: StudyIndex, - v2g: V2G, - coloc: Colocalisation, session: Session, + credible_set: StudyLocus, + features_list: list[str], + features_input_loader: L2GFeatureInputLoader, model_path: str | None, hf_token: str | None = None, download_from_hub: bool = True, - ) -> tuple[L2GPrediction, L2GFeatureMatrix]: + ) -> L2GPrediction: """Extract L2G predictions for a set of credible sets derived from GWAS. Args: - features_list (list[str]): List of features to use for the model - credible_set (StudyLocus): Credible set dataset - study_index (StudyIndex): Study index dataset - v2g (V2G): Variant to gene dataset - coloc (Colocalisation): Colocalisation dataset session (Session): Session object that contains the Spark session + credible_set (StudyLocus): Dataset containing credible sets from GWAS only + features_list (list[str]): List of features to use for the model + features_input_loader (L2GFeatureInputLoader): Loader with all feature dependencies model_path (str | None): Path to the model file. It can be either in the filesystem or the name on the Hugging Face Hub (in the form of username/repo_name). hf_token (str | None): Hugging Face token to download the model from the Hub. Only required if the model is private. download_from_hub (bool): Whether to download the model from the Hugging Face Hub. Defaults to True. Returns: - tuple[L2GPrediction, L2GFeatureMatrix]: L2G dataset and feature matrix limited to GWAS study only. + L2GPrediction: L2G scores for a set of credible sets. """ # Load the model if download_from_hub: @@ -75,31 +69,14 @@ def from_credible_set( l2g_model = LocusToGeneModel.load_from_disk(model_path) # Prepare data - fm = L2GFeatureMatrix.generate_features( - features_list=features_list, - credible_set=credible_set, - study_index=study_index, - variant_gene=v2g, - colocalisation=coloc, - ).fill_na() - - gwas_fm = ( - L2GFeatureMatrix( - _df=( - fm.df.join( - credible_set.filter_by_study_type( - "gwas", study_index - ).df.select("studyLocusId"), - on="studyLocusId", - ) - ), - _schema=L2GFeatureMatrix.get_schema(), - mode="predict", + fm = ( + L2GFeatureMatrix.from_features_list( + study_loci_to_annotate=credible_set, + features_list=features_list, + features_input_loader=features_input_loader, ) + .fill_na() .select_features(features_list) - .persist() - ) - return ( - l2g_model.predict(gwas_fm, session), - gwas_fm, ) + + return l2g_model.predict(fm, session) diff --git a/src/gentropy/dataset/study_locus.py b/src/gentropy/dataset/study_locus.py index 9ab19dab6..e8363aa4e 100644 --- a/src/gentropy/dataset/study_locus.py +++ b/src/gentropy/dataset/study_locus.py @@ -26,9 +26,11 @@ from pyspark.sql import Column, DataFrame from pyspark.sql.types import StructType + from gentropy.dataset.l2g_feature_matrix import L2GFeatureMatrix from gentropy.dataset.ld_index import LDIndex from gentropy.dataset.study_index import StudyIndex from gentropy.dataset.summary_statistics import SummaryStatistics + from gentropy.method.l2g.feature_factory import L2GFeatureInputLoader class StudyLocusQualityCheck(Enum): @@ -647,6 +649,28 @@ def neglog_pvalue(self: StudyLocus) -> Column: self.df.pValueExponent, ) + def build_feature_matrix( + self: StudyLocus, + features_list: list[str], + features_input_loader: L2GFeatureInputLoader, + ) -> L2GFeatureMatrix: + """Returns the feature matrix for a StudyLocus. + + Args: + features_list (list[str]): List of features to include in the feature matrix. + features_input_loader (L2GFeatureInputLoader): Feature input loader to use. + + Returns: + L2GFeatureMatrix: Feature matrix for this study-locus. + """ + from gentropy.dataset.l2g_feature_matrix import L2GFeatureMatrix + + return L2GFeatureMatrix.from_features_list( + self, + features_list, + features_input_loader, + ) + def annotate_credible_sets(self: StudyLocus) -> StudyLocus: """Annotate study-locus dataset with credible set flags. diff --git a/src/gentropy/datasource/eqtl_catalogue/study_index.py b/src/gentropy/datasource/eqtl_catalogue/study_index.py index 6add70ffb..d284eb781 100644 --- a/src/gentropy/datasource/eqtl_catalogue/study_index.py +++ b/src/gentropy/datasource/eqtl_catalogue/study_index.py @@ -45,6 +45,15 @@ class EqtlCatalogueStudyIndex: ] ) raw_studies_metadata_path = "https://raw.githubusercontent.com/eQTL-Catalogue/eQTL-Catalogue-resources/092e01a9601feb404f1c88f86311b43b907a88f6/data_tables/dataset_metadata_upcoming.tsv" + method_to_study_type_mapping = { + "ge": "eqtl", + "exon": "eqtl", + "tx": "eqtl", + "microarray": "eqtl", + "leafcutter": "sqtl", + "aptamer": "pqtl", + "txrev": "tuqtl", + } @classmethod def _identify_study_type( @@ -76,17 +85,8 @@ def _identify_study_type( +------------+---------+----------+ """ - method_to_study_type_mapping = { - "ge": "eqtl", - "exon": "eqtl", - "tx": "eqtl", - "microarray": "eqtl", - "leafcutter": "sqtl", - "aptamer": "pqtl", - "txrev": "tuqtl", - } qtl_type_mapping = f.create_map( - *[f.lit(x) for x in chain(*method_to_study_type_mapping.items())] + *[f.lit(x) for x in chain(*cls.method_to_study_type_mapping.items())] )[quantification_method_col] return f.when( biosample_col.startswith("CL"), f.concat(f.lit("sc"), qtl_type_mapping) diff --git a/src/gentropy/l2g.py b/src/gentropy/l2g.py index cb13d3640..832023cd8 100644 --- a/src/gentropy/l2g.py +++ b/src/gentropy/l2g.py @@ -18,6 +18,7 @@ from gentropy.dataset.study_index import StudyIndex from gentropy.dataset.study_locus import StudyLocus from gentropy.dataset.v2g import V2G +from gentropy.method.l2g.feature_factory import L2GFeatureInputLoader from gentropy.method.l2g.model import LocusToGeneModel from gentropy.method.l2g.trainer import LocusToGeneTrainer @@ -28,41 +29,44 @@ class LocusToGeneStep: def __init__( self, session: Session, + hyperparameters: dict[str, Any], + *, run_mode: str, - predictions_path: str, - credible_set_path: str, - variant_gene_path: str, - colocalisation_path: str, - study_index_path: str, - gold_standard_curation_path: str, - gene_interactions_path: str, features_list: list[str], - hyperparameters: dict[str, Any], download_from_hub: bool, - model_path: str | None, + wandb_run_name: str, + model_path: str | None = None, + credible_set_path: str, + gold_standard_curation_path: str | None = None, + variant_gene_path: str | None = None, + colocalisation_path: str | None = None, + study_index_path: str | None = None, + gene_interactions_path: str | None = None, + predictions_path: str | None = None, feature_matrix_path: str | None = None, - wandb_run_name: str | None = None, + write_feature_matrix: bool, hf_hub_repo_id: str | None = LocusToGeneConfig().hf_hub_repo_id, ) -> None: """Initialise the step and run the logic based on mode. Args: session (Session): Session object that contains the Spark session + hyperparameters (dict[str, Any]): Hyperparameters for the model run_mode (str): Run mode, either 'train' or 'predict' - predictions_path (str): Path to save the predictions - credible_set_path (str): Path to the credible set dataset - variant_gene_path (str): Path to the variant to gene dataset - colocalisation_path (str): Path to the colocalisation dataset - study_index_path (str): Path to the study index dataset - gold_standard_curation_path (str): Path to the gold standard curation dataset - gene_interactions_path (str): Path to the gene interactions dataset features_list (list[str]): List of features to use for the model - hyperparameters (dict[str, Any]): Hyperparameters for the model - download_from_hub (bool): Whether to download the model from the Hugging Face Hub - model_path (str | None): Path to the fitted model - feature_matrix_path (str | None): Path to save the feature matrix. Defaults to None. - wandb_run_name (str | None): Name of the wandb run. Defaults to None. - hf_hub_repo_id (str | None): Hugging Face Hub repo id. Defaults to the one set in the step configuration. + download_from_hub (bool): Whether to download the model from Hugging Face Hub + wandb_run_name (str): Name of the run to track model training in Weights and Biases + model_path (str | None): Path to the model. It can be either in the filesystem or the name on the Hugging Face Hub (in the form of username/repo_name). + credible_set_path (str): Path to the credible set dataset necessary to build the feature matrix + gold_standard_curation_path (str | None): Path to the gold standard curation file + variant_gene_path (str | None): Path to the variant-gene dataset + colocalisation_path (str | None): Path to the colocalisation dataset + study_index_path (str | None): Path to the study index dataset + gene_interactions_path (str | None): Path to the gene interactions dataset + predictions_path (str | None): Path to the L2G predictions output dataset + feature_matrix_path (str | None): Path to the L2G feature matrix output dataset + write_feature_matrix (bool): Whether to write the full feature matrix to the filesystem + hf_hub_repo_id (str | None): Hugging Face Hub repository ID. If provided, the model will be uploaded to Hugging Face. Raises: ValueError: If run_mode is not 'train' or 'predict' @@ -76,12 +80,6 @@ def __init__( self.run_mode = run_mode self.model_path = model_path self.predictions_path = predictions_path - self.credible_set_path = credible_set_path - self.variant_gene_path = variant_gene_path - self.colocalisation_path = colocalisation_path - self.study_index_path = study_index_path - self.gold_standard_curation_path = gold_standard_curation_path - self.gene_interactions_path = gene_interactions_path self.features_list = list(features_list) self.hyperparameters = dict(hyperparameters) self.feature_matrix_path = feature_matrix_path @@ -92,151 +90,163 @@ def __init__( # Load common inputs self.credible_set = StudyLocus.from_parquet( session, credible_set_path, recursiveFileLookup=True + ).filter(f.col("studyType") == "gwas") + self.studies = ( + StudyIndex.from_parquet(session, study_index_path, recursiveFileLookup=True) + if study_index_path + else None ) - self.studies = StudyIndex.from_parquet( - session, study_index_path, recursiveFileLookup=True + self.v2g = ( + V2G.from_parquet(session, variant_gene_path) if variant_gene_path else None ) - self.v2g = V2G.from_parquet(session, variant_gene_path) - self.coloc = Colocalisation.from_parquet( - session, colocalisation_path, recursiveFileLookup=True + self.coloc = ( + Colocalisation.from_parquet( + session, colocalisation_path, recursiveFileLookup=True + ) + if colocalisation_path + else None + ) + self.features_input_loader = L2GFeatureInputLoader( + v2g=self.v2g, + coloc=self.coloc, + studies=self.studies, + study_locus=self.credible_set, ) if run_mode == "predict": self.run_predict() elif run_mode == "train": + self.gs_curation = ( + self.session.spark.read.json(gold_standard_curation_path) + if gold_standard_curation_path + else None + ) + self.interactions = ( + self.session.spark.read.parquet(gene_interactions_path) + if gene_interactions_path + else None + ) self.run_train() def run_predict(self) -> None: """Run the prediction step. Raises: - ValueError: If predictions_path is not set. + ValueError: If not all dependencies in prediction mode are set """ - if not self.predictions_path: - raise ValueError("predictions_path must be set for predict mode.") - predictions, feature_matrix = L2GPrediction.from_credible_set( - self.features_list, - self.credible_set, - self.studies, - self.v2g, - self.coloc, - self.session, - model_path=self.model_path, - hf_token=access_gcp_secret("hfhub-key", "open-targets-genetics-dev"), - download_from_hub=self.download_from_hub, - ) - if self.feature_matrix_path: - feature_matrix.df.write.mode(self.session.write_mode).parquet( - self.feature_matrix_path + if self.studies and self.v2g and self.coloc: + predictions = L2GPrediction.from_credible_set( + self.session, + self.credible_set, + self.features_list, + self.features_input_loader, + model_path=self.model_path, + hf_token=access_gcp_secret("hfhub-key", "open-targets-genetics-dev"), + download_from_hub=self.download_from_hub, ) - predictions.df.write.mode(self.session.write_mode).parquet( - self.predictions_path - ) - self.session.logger.info(self.predictions_path) + if self.predictions_path: + predictions.df.write.mode(self.session.write_mode).parquet( + self.predictions_path + ) + self.session.logger.info(self.predictions_path) + else: + raise ValueError("Dependencies for predict mode not set.") def run_train(self) -> None: - """Run the training step. - - Raises: - ValueError: If gold_standard_curation_path, gene_interactions_path, or wandb_run_name are not set. - """ - if not ( - self.gold_standard_curation_path - and self.gene_interactions_path + """Run the training step.""" + if ( + self.gs_curation + and self.interactions + and self.v2g and self.wandb_run_name and self.model_path ): - raise ValueError( - "gold_standard_curation_path, gene_interactions_path, and wandb_run_name, and a path to save the model must be set for train mode." + wandb_key = access_gcp_secret("wandb-key", "open-targets-genetics-dev") + # Process gold standard and L2G features + data = self._generate_feature_matrix(write_feature_matrix=True) + + # Instantiate classifier and train model + l2g_model = LocusToGeneModel( + model=GradientBoostingClassifier(random_state=42), + hyperparameters=self.hyperparameters, ) + wandb_login(key=wandb_key) + trained_model = LocusToGeneTrainer( + model=l2g_model, feature_matrix=data + ).train(self.wandb_run_name) + if trained_model.training_data and trained_model.model and self.model_path: + trained_model.save(self.model_path) + if self.hf_hub_repo_id: + hf_hub_token = access_gcp_secret( + "hfhub-key", "open-targets-genetics-dev" + ) + trained_model.export_to_hugging_face_hub( + # we upload the model in the filesystem + self.model_path.split("/")[-1], + hf_hub_token, + data=trained_model.training_data._df.drop( + "goldStandardSet", "geneId" + ).toPandas(), + repo_id=self.hf_hub_repo_id, + commit_message="chore: update model", + ) - wandb_key = access_gcp_secret("wandb-key", "open-targets-genetics-dev") - # Process gold standard and L2G features - data = self._generate_feature_matrix().persist() + def _generate_feature_matrix(self, write_feature_matrix: bool) -> L2GFeatureMatrix: + """Generate the feature matrix of annotated gold standards. - # Instantiate classifier and train model - l2g_model = LocusToGeneModel( - model=GradientBoostingClassifier(random_state=42), - hyperparameters=self.hyperparameters, - ) - wandb_login(key=wandb_key) - trained_model = LocusToGeneTrainer(model=l2g_model, feature_matrix=data).train( - self.wandb_run_name - ) - if trained_model.training_data and trained_model.model: - trained_model.save(self.model_path) - if self.hf_hub_repo_id: - hf_hub_token = access_gcp_secret( - "hfhub-key", "open-targets-genetics-dev" - ) - trained_model.export_to_hugging_face_hub( - # we upload the model in the filesystem - self.model_path.split("/")[-1], - hf_hub_token, - data=trained_model.training_data.df.drop( - "goldStandardSet", "geneId" - ).toPandas(), - repo_id=self.hf_hub_repo_id, - commit_message="chore: update model", - ) - - def _generate_feature_matrix(self) -> L2GFeatureMatrix: - """Generate the feature matrix for training. + Args: + write_feature_matrix (bool): Whether to write the feature matrix for all credible sets to disk Returns: L2GFeatureMatrix: Feature matrix with gold standards annotated with features. - """ - gs_curation = self.session.spark.read.json(self.gold_standard_curation_path) - interactions = self.session.spark.read.parquet(self.gene_interactions_path) - study_locus_overlap = StudyLocus( - _df=self.credible_set.df.join( - f.broadcast( - gs_curation.select( - StudyLocus.assign_study_locus_id( - f.col("association_info.otg_id"), # studyId - f.concat_ws( # variantId - "_", - f.col("sentinel_variant.locus_GRCh38.chromosome"), - f.col("sentinel_variant.locus_GRCh38.position"), - f.col("sentinel_variant.alleles.reference"), - f.col("sentinel_variant.alleles.alternative"), - ), - f.col("finemappingMethod"), - ).alias("studyLocusId"), - ) - ), - "studyLocusId", - "inner", - ), - _schema=StudyLocus.get_schema(), - ).find_overlaps(self.studies) - - gold_standards = L2GGoldStandard.from_otg_curation( - gold_standard_curation=gs_curation, - v2g=self.v2g, - study_locus_overlap=study_locus_overlap, - interactions=interactions, - ) - fm = L2GFeatureMatrix.generate_features( - features_list=self.features_list, - credible_set=self.credible_set, - study_index=self.studies, - variant_gene=self.v2g, - colocalisation=self.coloc, - ) - - return ( - L2GFeatureMatrix( - _df=fm.df.join( + Raises: + ValueError: If write_feature_matrix is set to True but a path is not provided. + ValueError: If dependencies to build features are not set. + """ + if self.gs_curation and self.interactions and self.v2g and self.studies: + study_locus_overlap = StudyLocus( + _df=self.credible_set.df.join( f.broadcast( - gold_standards.df.drop("variantId", "studyId", "sources") + self.gs_curation.select( + StudyLocus.assign_study_locus_id( + f.col("association_info.otg_id"), # studyId + f.concat_ws( # variantId + "_", + f.col("sentinel_variant.locus_GRCh38.chromosome"), + f.col("sentinel_variant.locus_GRCh38.position"), + f.col("sentinel_variant.alleles.reference"), + f.col("sentinel_variant.alleles.alternative"), + ), + ).alias("studyLocusId"), + ) ), - on=["studyLocusId", "geneId"], - how="inner", + "studyLocusId", + "inner", ), - _schema=L2GFeatureMatrix.get_schema(), + _schema=StudyLocus.get_schema(), + ).find_overlaps(self.studies) + + gold_standards = L2GGoldStandard.from_otg_curation( + gold_standard_curation=self.gs_curation, + v2g=self.v2g, + study_locus_overlap=study_locus_overlap, + interactions=self.interactions, ) - .fill_na() - .select_features(self.features_list) - ) + + fm = self.credible_set.build_feature_matrix( + self.features_list, self.features_input_loader + ) + if write_feature_matrix: + if not self.feature_matrix_path: + raise ValueError("feature_matrix_path must be set.") + fm._df.write.mode(self.session.write_mode).parquet( + self.feature_matrix_path + ) + + return ( + gold_standards.build_feature_matrix(fm) + .fill_na() + .select_features(self.features_list) + ) + raise ValueError("Dependencies for train mode not set.") diff --git a/src/gentropy/method/colocalisation.py b/src/gentropy/method/colocalisation.py index 18d97fdf8..c3320f931 100644 --- a/src/gentropy/method/colocalisation.py +++ b/src/gentropy/method/colocalisation.py @@ -112,7 +112,7 @@ class Coloc: """ METHOD_NAME: str = "COLOC" - METHOD_METRIC: str = "llr" + METHOD_METRIC: str = "h4" PSEUDOCOUNT: float = 1e-10 @staticmethod diff --git a/src/gentropy/method/l2g/feature_factory.py b/src/gentropy/method/l2g/feature_factory.py index 1158c6067..c0f0ef9b4 100644 --- a/src/gentropy/method/l2g/feature_factory.py +++ b/src/gentropy/method/l2g/feature_factory.py @@ -1,341 +1,151 @@ -"""Collection of methods that extract features from the gentropy datasets to be fed in L2G.""" +"""Factory that computes features based on an input list.""" from __future__ import annotations -from functools import reduce -from itertools import chain -from typing import TYPE_CHECKING - -import pyspark.sql.functions as f - -from gentropy.common.spark_helpers import ( - convert_from_wide_to_long, - get_record_with_maximum_value, +from typing import Any, Iterator, Mapping + +from gentropy.dataset.l2g_feature import ( + EQtlColocClppMaximumFeature, + EQtlColocH4MaximumFeature, + L2GFeature, + PQtlColocClppMaximumFeature, + PQtlColocH4MaximumFeature, + SQtlColocClppMaximumFeature, + SQtlColocH4MaximumFeature, + TuQtlColocClppMaximumFeature, + TuQtlColocH4MaximumFeature, ) -from gentropy.dataset.l2g_feature import L2GFeature -from gentropy.dataset.study_locus import CredibleInterval, StudyLocus -from gentropy.method.colocalisation import Coloc, ECaviar - -if TYPE_CHECKING: - from pyspark.sql import Column, DataFrame +from gentropy.dataset.l2g_gold_standard import L2GGoldStandard +from gentropy.dataset.study_locus import StudyLocus - from gentropy.dataset.colocalisation import Colocalisation - from gentropy.dataset.study_index import StudyIndex - from gentropy.dataset.v2g import V2G +class L2GFeatureInputLoader: + """Loads all input datasets required for the L2GFeature dataset.""" -class ColocalisationFactory: - """Feature extraction in colocalisation.""" + def __init__( + self, + **kwargs: Any, + ) -> None: + """Initializes L2GFeatureInputLoader with the provided inputs and returns loaded dependencies as a dictionary. - @classmethod - def _add_colocalisation_metric(cls: type[ColocalisationFactory]) -> Column: - """Expression that adds a `colocalisationMetric` column to the colocalisation dataframe in preparation for feature extraction. - - Returns: - Column: The expression that adds a `colocalisationMetric` column with the derived metric + Args: + **kwargs (Any): keyword arguments with the name of the dependency and the dependency itself. """ - method_metric_map = { - ECaviar.METHOD_NAME: ECaviar.METHOD_METRIC, - Coloc.METHOD_NAME: Coloc.METHOD_METRIC, - } - map_expr = f.create_map(*[f.lit(x) for x in chain(*method_metric_map.items())]) - return map_expr[f.col("colocalisationMethod")].alias("colocalisationMetric") + self.input_dependencies = {k: v for k, v in kwargs.items() if v is not None} - @staticmethod - def _get_max_coloc_per_credible_set( - colocalisation: Colocalisation, - credible_set: StudyLocus, - studies: StudyIndex, - ) -> L2GFeature: - """Get the maximum colocalisation posterior probability for each pair of overlapping study-locus per type of colocalisation method and QTL type. + def get_dependency_by_type( + self, dependency_type: list[Any] | Any + ) -> dict[str, Any]: + """Returns the dependency that matches the provided type. Args: - colocalisation (Colocalisation): Colocalisation dataset - credible_set (StudyLocus): Study locus dataset - studies (StudyIndex): Study index dataset + dependency_type (list[Any] | Any): type(s) of the dependency to return. Returns: - L2GFeature: Stores the features with the max coloc probabilities for each pair of study-locus + dict[str, Any]: dictionary of dependenci(es) that match the provided type(s). """ - colocalisation_df = colocalisation.df.select( - f.col("leftStudyLocusId").alias("studyLocusId"), - "rightStudyLocusId", - f.coalesce("h4", "clpp").alias("score"), - ColocalisationFactory._add_colocalisation_metric(), - ) + if not isinstance(dependency_type, list): + dependency_type = [dependency_type] + return { + k: v + for k, v in self.input_dependencies.items() + if isinstance(v, tuple(dependency_type)) + } - colocalising_credible_sets = ( - credible_set.df.select("studyLocusId", "studyId") - # annotate studyLoci with overlapping IDs on the left - to just keep GWAS associations - .join( - colocalisation_df, - on="studyLocusId", - how="inner", - ) - # bring study metadata to just keep QTL studies on the right - .join( - credible_set.df.join( - studies.df.select("studyId", "studyType", "geneId"), "studyId" - ).selectExpr( - "studyLocusId as rightStudyLocusId", - "studyType as right_studyType", - "geneId", - ), - on="rightStudyLocusId", - how="inner", - ) - .filter(f.col("right_studyType") != "gwas") - .select( - "studyLocusId", - "right_studyType", - "geneId", - "score", - "colocalisationMetric", - ) - ) + def __iter__(self) -> Iterator[tuple[str, Any]]: + """Make the class iterable, returning an iterator over key-value pairs. - # Max PP calculation per credible set AND type of QTL AND colocalisation method - local_max = ( - get_record_with_maximum_value( - colocalising_credible_sets, - ["studyLocusId", "right_studyType", "geneId", "colocalisationMetric"], - "score", - ) - .select( - "*", - f.col("score").alias("max_score"), - f.lit("Local").alias("score_type"), - ) - .drop("score") - ) + Returns: + Iterator[tuple[str, Any]]: iterator over the dictionary's key-value pairs. + """ + return iter(self.input_dependencies.items()) - neighbourhood_max = ( - local_max.selectExpr( - "studyLocusId", "max_score as local_max_score", "geneId" - ) - .join( - # Add maximum in the neighborhood - get_record_with_maximum_value( - colocalising_credible_sets.withColumnRenamed( - "score", "tmp_nbh_max_score" - ), - ["studyLocusId", "right_studyType", "colocalisationMetric"], - "tmp_nbh_max_score", - ).drop("geneId"), - on="studyLocusId", - ) - .withColumn("score_type", f.lit("Neighborhood")) - .withColumn( - "max_score", - f.log10( - f.abs( - f.col("local_max_score") - - f.col("tmp_nbh_max_score") - + f.lit(0.0001) # intercept - ) - ), - ) - ).drop("tmp_nbh_max_score", "local_max_score") + def __repr__(self) -> str: + """Return a string representation of the input dependencies. - return L2GFeature( - _df=( - # Combine local and neighborhood metrics - local_max.unionByName( - neighbourhood_max, allowMissingColumns=True - ).select( - "studyLocusId", - "geneId", - # Feature name is a concatenation of the QTL type, colocalisation metric and if it's local or in the vicinity - f.concat_ws( - "", - f.col("right_studyType"), - f.lit("Coloc"), - f.initcap(f.col("colocalisationMetric")), - f.lit("Maximum"), - f.regexp_replace(f.col("score_type"), "Local", ""), - ).alias("featureName"), - f.col("max_score").cast("float").alias("featureValue"), - ) - ), - _schema=L2GFeature.get_schema(), - ) + Useful for understanding the loader content without having to print the object attribute. + Returns: + str: string representation of the input dependencies. + """ + return repr(self.input_dependencies) + + +class FeatureFactory: + """Factory class for creating features.""" + + feature_mapper: Mapping[str, type[L2GFeature]] = { + # "distanceTssMinimum": DistanceTssMinimumFeature, + # "distanceTssMean": DistanceTssMeanFeature, + "eQtlColocClppMaximum": EQtlColocClppMaximumFeature, + "pQtlColocClppMaximum": PQtlColocClppMaximumFeature, + "sQtlColocClppMaximum": SQtlColocClppMaximumFeature, + "tuQtlColocClppMaximum": TuQtlColocClppMaximumFeature, + "eQtlColocH4Maximum": EQtlColocH4MaximumFeature, + "pQtlColocH4Maximum": PQtlColocH4MaximumFeature, + "sQtlColocH4Maximum": SQtlColocH4MaximumFeature, + "tuQtlColocH4Maximum": TuQtlColocH4MaximumFeature, + } + + def __init__( + self: FeatureFactory, + study_loci_to_annotate: StudyLocus | L2GGoldStandard, + features_list: list[str], + ) -> None: + """Initializes the factory. -class StudyLocusFactory(StudyLocus): - """Feature extraction in study locus.""" + Args: + study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation + features_list (list[str]): list of features to compute. + """ + self.study_loci_to_annotate = study_loci_to_annotate + self.features_list = features_list - @staticmethod - def _get_tss_distance_features(credible_set: StudyLocus, v2g: V2G) -> L2GFeature: - """Joins StudyLocus with the V2G to extract a score that is based on the distance to a gene TSS of any variant weighted by its posterior probability in a credible set. + def generate_features( + self: FeatureFactory, + features_input_loader: L2GFeatureInputLoader, + ) -> list[L2GFeature]: + """Generates a feature matrix by reading an object with instructions on how to create the features. Args: - credible_set (StudyLocus): Credible set dataset - v2g (V2G): Dataframe containing the distances of all variants to all genes TSS within a region + features_input_loader (L2GFeatureInputLoader): object with required features dependencies. Returns: - L2GFeature: Stores the features with the score of weighting the distance to the TSS by the posterior probability of the variant + list[L2GFeature]: list of computed features. + Raises: + ValueError: If feature not found. """ - wide_df = ( - credible_set.filter_credible_set(CredibleInterval.IS95) - .df.withColumn("variantInLocus", f.explode_outer("locus")) - .select( - "studyLocusId", - "variantId", - f.col("variantInLocus.variantId").alias("variantInLocusId"), - f.col("variantInLocus.posteriorProbability").alias( - "variantInLocusPosteriorProbability" - ), - ) - .join( - v2g.df.filter(f.col("datasourceId") == "canonical_tss").selectExpr( - "variantId as variantInLocusId", "geneId", "score" - ), - on="variantInLocusId", - how="inner", - ) - .withColumn( - "weightedScore", - f.col("score") * f.col("variantInLocusPosteriorProbability"), - ) - .groupBy("studyLocusId", "geneId") - .agg( - f.min("weightedScore").alias("distanceTssMinimum"), - f.mean("weightedScore").alias("distanceTssMean"), - ) - ) - - return L2GFeature( - _df=convert_from_wide_to_long( - wide_df, - id_vars=("studyLocusId", "geneId"), - var_name="featureName", - value_name="featureValue", - ), - _schema=L2GFeature.get_schema(), - ) - - @staticmethod - def _get_vep_features( - credible_set: StudyLocus, - v2g: V2G, + computed_features = [] + for feature in self.features_list: + if feature in self.feature_mapper: + computed_features.append( + self.compute_feature(feature, features_input_loader) + ) + else: + raise ValueError(f"Feature {feature} not found.") + return computed_features + + def compute_feature( + self: FeatureFactory, + feature_name: str, + features_input_loader: L2GFeatureInputLoader, ) -> L2GFeature: - """Get the maximum VEP score for all variants in a locus's 95% credible set. - - This informs about functional impact of the variants in the locus. For more information on variant consequences, see: https://www.ensembl.org/info/genome/variation/prediction/predicted_data.html - Two metrics: max VEP score per study locus and gene, and max VEP score per study locus. - + """Instantiates feature class. Args: - credible_set (StudyLocus): Study locus dataset with the associations to be annotated - v2g (V2G): V2G dataset with the variant/gene relationships and their consequences + feature_name (str): name of the feature + features_input_loader (L2GFeatureInputLoader): Object that contais features input. Returns: - L2GFeature: Stores the features with the max VEP score. + L2GFeature: instantiated feature object """ - - def _aggregate_vep_feature( - df: DataFrame, - aggregation_expr: Column, - aggregation_cols: list[str], - feature_name: str, - ) -> DataFrame: - """Extracts the maximum or average VEP score after grouping by the given columns. Different aggregations return different predictive annotations. - - If the group_cols include "geneId", the maximum/mean VEP score per gene is returned. - Otherwise, the maximum/mean VEP score for all genes in the neighborhood of the locus is returned. - - Args: - df (DataFrame): DataFrame with the VEP scores for each variant in a studyLocus - aggregation_expr (Column): Aggregation expression to apply - aggregation_cols (list[str]): Columns to group by - feature_name (str): Name of the feature to be returned - - Returns: - DataFrame: DataFrame with the maximum VEP score per locus or per locus/gene - """ - if "geneId" in aggregation_cols: - return df.groupBy(aggregation_cols).agg( - aggregation_expr.alias(feature_name) - ) - return ( - df.groupBy(aggregation_cols) - .agg( - aggregation_expr.alias(feature_name), - f.collect_set("geneId").alias("geneId"), - ) - .withColumn("geneId", f.explode("geneId")) - ) - - credible_set_w_variant_consequences = ( - credible_set.filter_credible_set(CredibleInterval.IS95) - .df.withColumn("variantInLocus", f.explode_outer("locus")) - .select( - f.col("studyLocusId"), - f.col("variantId"), - f.col("studyId"), - f.col("variantInLocus.variantId").alias("variantInLocusId"), - f.col("variantInLocus.posteriorProbability").alias( - "variantInLocusPosteriorProbability" - ), - ) - .join( - # Join with V2G to get variant consequences - v2g.df.filter(f.col("datasourceId") == "variantConsequence").selectExpr( - "variantId as variantInLocusId", "geneId", "score" - ), - on="variantInLocusId", - ) - .select( - "studyLocusId", - "variantId", - "studyId", - "geneId", - (f.col("score") * f.col("variantInLocusPosteriorProbability")).alias( - "weightedScore" - ), - ) - .distinct() - ) - - return L2GFeature( - _df=convert_from_wide_to_long( - reduce( - lambda x, y: x.unionByName(y, allowMissingColumns=True), - [ - # Calculate overall max VEP score for all genes in the vicinity - credible_set_w_variant_consequences.transform( - _aggregate_vep_feature, - f.max("weightedScore"), - ["studyLocusId"], - "vepMaximumNeighborhood", - ), - # Calculate overall max VEP score per gene - credible_set_w_variant_consequences.transform( - _aggregate_vep_feature, - f.max("weightedScore"), - ["studyLocusId", "geneId"], - "vepMaximum", - ), - # Calculate mean VEP score for all genes in the vicinity - credible_set_w_variant_consequences.transform( - _aggregate_vep_feature, - f.mean("weightedScore"), - ["studyLocusId"], - "vepMeanNeighborhood", - ), - # Calculate mean VEP score per gene - credible_set_w_variant_consequences.transform( - _aggregate_vep_feature, - f.mean("weightedScore"), - ["studyLocusId", "geneId"], - "vepMean", - ), - ], - ), - id_vars=("studyLocusId", "geneId"), - var_name="featureName", - value_name="featureValue", - ).filter(f.col("featureValue").isNotNull()), - _schema=L2GFeature.get_schema(), + # Extract feature class and dependency type + feature_cls = self.feature_mapper[feature_name] + feature_dependency_type = feature_cls.feature_dependency_type + return feature_cls.compute( + study_loci_to_annotate=self.study_loci_to_annotate, + feature_dependency=features_input_loader.get_dependency_by_type( + feature_dependency_type + ), ) diff --git a/src/gentropy/method/l2g/model.py b/src/gentropy/method/l2g/model.py index e0d9e42fb..6e0b0fda1 100644 --- a/src/gentropy/method/l2g/model.py +++ b/src/gentropy/method/l2g/model.py @@ -114,7 +114,7 @@ def predict( pd_dataframe.iteritems = pd_dataframe.items - feature_matrix_pdf = feature_matrix.df.toPandas() + feature_matrix_pdf = feature_matrix._df.toPandas() # L2G score is the probability the classifier assigns to the positive class (the second element in the probability array) feature_matrix_pdf["score"] = self.model.predict_proba( # We drop the fixed columns to only pass the feature values to the classifier diff --git a/src/gentropy/method/l2g/trainer.py b/src/gentropy/method/l2g/trainer.py index 85fedc45b..69dfb24ff 100644 --- a/src/gentropy/method/l2g/trainer.py +++ b/src/gentropy/method/l2g/trainer.py @@ -134,7 +134,7 @@ def log_to_wandb( run.log({"f1": f1_score(self.y_test, y_predicted, average="weighted")}) # Track gold standards and their features run.log( - {"featureMatrix": Table(dataframe=self.feature_matrix.df.toPandas())} + {"featureMatrix": Table(dataframe=self.feature_matrix._df.toPandas())} ) # Log feature missingness run.log( @@ -155,7 +155,7 @@ def train( Returns: LocusToGeneModel: Fitted model """ - data_df = self.feature_matrix.df.drop("geneId").toPandas() + data_df = self.feature_matrix._df.drop("geneId").toPandas() # Encode labels in `goldStandardSet` to a numeric value data_df["goldStandardSet"] = data_df["goldStandardSet"].map( diff --git a/tests/gentropy/conftest.py b/tests/gentropy/conftest.py index 629f3a505..93ee38471 100644 --- a/tests/gentropy/conftest.py +++ b/tests/gentropy/conftest.py @@ -584,37 +584,17 @@ def sample_otp_interactions(spark: SparkSession) -> DataFrame: @pytest.fixture() def mock_l2g_feature_matrix(spark: SparkSession) -> L2GFeatureMatrix: """Mock l2g feature matrix dataset.""" - schema = L2GFeatureMatrix.get_schema() - - data_spec = ( - dg.DataGenerator( - spark, - rows=50, - partitions=4, - randomSeedMethod="hash_fieldname", - ) - .withSchema(schema) - .withColumnSpec("distanceTssMean", percentNulls=0.1) - .withColumnSpec("distanceTssMinimum", percentNulls=0.1) - .withColumnSpec("eqtlColocClppMaximum", percentNulls=0.1) - .withColumnSpec("eqtlColocClppMaximumNeighborhood", percentNulls=0.1) - .withColumnSpec("eqtlColocLlrMaximum", percentNulls=0.1) - .withColumnSpec("eqtlColocLlrMaximumNeighborhood", percentNulls=0.1) - .withColumnSpec("pqtlColocClppMaximum", percentNulls=0.1) - .withColumnSpec("pqtlColocClppMaximumNeighborhood", percentNulls=0.1) - .withColumnSpec("pqtlColocLlrMaximum", percentNulls=0.1) - .withColumnSpec("pqtlColocLlrMaximumNeighborhood", percentNulls=0.1) - .withColumnSpec("sqtlColocClppMaximum", percentNulls=0.1) - .withColumnSpec("sqtlColocClppMaximumNeighborhood", percentNulls=0.1) - .withColumnSpec("sqtlColocLlrMaximum", percentNulls=0.1) - .withColumnSpec("sqtlColocLlrMaximumNeighborhood", percentNulls=0.1) - .withColumnSpec( - "goldStandardSet", percentNulls=0.0, values=["positive", "negative"] - ) + return L2GFeatureMatrix( + _df=spark.createDataFrame( + [ + (1, "gene1", 100.0, None), + (2, "gene2", 1000.0, 0.0), + ], + "studyLocusId LONG, geneId STRING, distanceTssMean FLOAT, distanceTssMinimum FLOAT", + ), + with_gold_standard=False, ) - return L2GFeatureMatrix(_df=data_spec.build(), _schema=schema) - @pytest.fixture() def mock_l2g_gold_standard(spark: SparkSession) -> L2GGoldStandard: diff --git a/tests/gentropy/dataset/test_colocalisation.py b/tests/gentropy/dataset/test_colocalisation.py index 1651aa2d4..5371cf42c 100644 --- a/tests/gentropy/dataset/test_colocalisation.py +++ b/tests/gentropy/dataset/test_colocalisation.py @@ -2,9 +2,131 @@ from __future__ import annotations +from typing import TYPE_CHECKING + +import pytest + from gentropy.dataset.colocalisation import Colocalisation +from gentropy.dataset.study_index import StudyIndex +from gentropy.dataset.study_locus import StudyLocus + +if TYPE_CHECKING: + from pyspark.sql import SparkSession def test_colocalisation_creation(mock_colocalisation: Colocalisation) -> None: """Test colocalisation creation with mock data.""" assert isinstance(mock_colocalisation, Colocalisation) + + +def test_append_study_metadata_study_locus( + mock_colocalisation: Colocalisation, + mock_study_locus: StudyLocus, + mock_study_index: StudyIndex, + metadata_cols: list[str] | None = None, +) -> None: + """Test appending right study metadata.""" + if metadata_cols is None: + metadata_cols = ["studyType"] + expected_extra_col = ["rightStudyType", "rightStudyId"] + res_df = mock_colocalisation.append_study_metadata( + mock_study_locus, + mock_study_index, + metadata_cols=metadata_cols, + colocalisation_side="right", + ) + for col in expected_extra_col: + assert col in res_df.columns, f"Column {col} not found in result DataFrame." + + +class TestAppendStudyMetadata: + """Test Colocalisation.append_study_metadata method.""" + + @pytest.mark.parametrize( + ("colocalisation_side", "expected_geneId"), [("right", "g1"), ("left", None)] + ) + def test_append_study_metadata_right( + self: TestAppendStudyMetadata, + colocalisation_side: str, + expected_geneId: str | None, + metadata_cols: list[str] | None = None, + ) -> None: + """Test appending right study metadata.""" + if metadata_cols is None: + metadata_cols = ["geneId"] + observed_df = self.sample_colocalisation.append_study_metadata( + self.sample_study_locus, + self.sample_study_index, + metadata_cols=metadata_cols, + colocalisation_side=colocalisation_side, + ) + assert ( + observed_df.select(f"{colocalisation_side}GeneId").collect()[0][0] + == expected_geneId + ), f"Expected {colocalisation_side}GeneId {expected_geneId}, but got {observed_df.select(f'{colocalisation_side}GeneId').collect()[0][0]}" + + @pytest.fixture(autouse=True) + def _setup(self: TestAppendStudyMetadata, spark: SparkSession) -> None: + """Setup fixture.""" + self.sample_study_locus = StudyLocus( + _df=spark.createDataFrame( + [ + ( + 1, + "var1", + "gwas1", + ), + ( + 2, + "var2", + "eqtl1", + ), + ], + ["studyLocusId", "variantId", "studyId"], + ), + _schema=StudyLocus.get_schema(), + ) + self.sample_study_index = StudyIndex( + _df=spark.createDataFrame( + [("gwas1", "gwas", None, "p1"), ("eqtl1", "eqtl", "g1", "p2")], + [ + "studyId", + "studyType", + "geneId", + "projectId", + ], + ), + _schema=StudyIndex.get_schema(), + ) + self.sample_colocalisation = Colocalisation( + _df=spark.createDataFrame( + [(1, 2, "X", "COLOC", 1, 0.9)], + [ + "leftStudyLocusId", + "rightStudyLocusId", + "chromosome", + "colocalisationMethod", + "numberColocalisingVariants", + "h4", + ], + ), + _schema=Colocalisation.get_schema(), + ) + + +def test_extract_maximum_coloc_probability_per_region_and_gene( + mock_colocalisation: Colocalisation, + mock_study_locus: StudyLocus, + mock_study_index: StudyIndex, + filter_by_colocalisation_method: str | None = None, +) -> None: + """Test extracting maximum coloc probability per region and gene returns a dataframe with the correct columns: studyLocusId, geneId, h4.""" + filter_by_colocalisation_method = filter_by_colocalisation_method or "Coloc" + res_df = mock_colocalisation.extract_maximum_coloc_probability_per_region_and_gene( + mock_study_locus, + mock_study_index, + filter_by_colocalisation_method=filter_by_colocalisation_method, + ) + expected_cols = ["studyLocusId", "geneId", "h4"] + for col in expected_cols: + assert col in res_df.columns, f"Column {col} not found in result DataFrame." diff --git a/tests/gentropy/dataset/test_l2g.py b/tests/gentropy/dataset/test_l2g.py index d0f1c3672..d37ce5a4a 100644 --- a/tests/gentropy/dataset/test_l2g.py +++ b/tests/gentropy/dataset/test_l2g.py @@ -4,7 +4,7 @@ from typing import TYPE_CHECKING -import pytest +from pyspark.sql.types import FloatType from gentropy.dataset.l2g_feature_matrix import L2GFeatureMatrix from gentropy.dataset.l2g_gold_standard import L2GGoldStandard @@ -34,7 +34,7 @@ def test_process_gene_interactions(sample_otp_interactions: DataFrame) -> None: ), "Gene interactions has a different schema." -def test_predictions(mock_l2g_predictions: L2GFeatureMatrix) -> None: +def test_predictions(mock_l2g_predictions: L2GPrediction) -> None: """Test L2G predictions creation with mock data.""" assert isinstance(mock_l2g_predictions, L2GPrediction) @@ -154,45 +154,36 @@ def test_remove_false_negatives(spark: SparkSession) -> None: assert observed_df.collect() == expected_df.collect() -def test_l2g_feature_constructor_with_schema_mismatch(spark: SparkSession) -> None: - """Test if provided shema mismatch results in error in L2GFeatureMatrix constructor. - - distanceTssMean is expected to be FLOAT by schema in src.gentropy.assets.schemas and is actualy DOUBLE. - """ - with pytest.raises(ValueError) as e: - L2GFeatureMatrix( - _df=spark.createDataFrame( - [ - (1, "gene1", 100.0), - (2, "gene2", 1000.0), - ], - "studyLocusId LONG, geneId STRING, distanceTssMean DOUBLE", - ), - _schema=L2GFeatureMatrix.get_schema(), - ) - assert e.value.args[0] == ( - "The following fields present differences in their datatypes: ['distanceTssMean']." - ) - - -def test_calculate_feature_missingness_rate(spark: SparkSession) -> None: - """Test L2GFeatureMatrix.calculate_feature_missingness_rate.""" +def test_l2g_feature_constructor_with_schema_mismatch( + spark: SparkSession, +) -> None: + """Test if provided schema mismatch is converted to right type in the L2GFeatureMatrix constructor.""" fm = L2GFeatureMatrix( _df=spark.createDataFrame( [ - (1, "gene1", 100.0, None), - (2, "gene2", 1000.0, 0.0), + (1, "gene1", 100.0), + (2, "gene2", 1000.0), ], - "studyLocusId LONG, geneId STRING, distanceTssMean FLOAT, distanceTssMinimum FLOAT", + "studyLocusId LONG, geneId STRING, distanceTssMean DOUBLE", ), - _schema=L2GFeatureMatrix.get_schema(), + with_gold_standard=False, ) + assert ( + fm._df.schema["distanceTssMean"].dataType == FloatType() + ), "Feature `distanceTssMean` is not being casted to FloatType. Check L2GFeatureMatrix constructor." + +def test_calculate_feature_missingness_rate( + spark: SparkSession, mock_l2g_feature_matrix: L2GFeatureMatrix +) -> None: + """Test L2GFeatureMatrix.calculate_feature_missingness_rate.""" expected_missingness = {"distanceTssMean": 0.0, "distanceTssMinimum": 1.0} - observed_missingness = fm.calculate_feature_missingness_rate() + observed_missingness = mock_l2g_feature_matrix.calculate_feature_missingness_rate() assert isinstance(observed_missingness, dict) - assert fm.features_list is not None and len(observed_missingness) == len( - fm.features_list + assert mock_l2g_feature_matrix.features_list is not None and len( + observed_missingness + ) == len( + mock_l2g_feature_matrix.features_list ), "Missing features in the missingness rate dictionary." assert ( observed_missingness == expected_missingness diff --git a/tests/gentropy/dataset/test_l2g_feature.py b/tests/gentropy/dataset/test_l2g_feature.py new file mode 100644 index 000000000..82df2dd4f --- /dev/null +++ b/tests/gentropy/dataset/test_l2g_feature.py @@ -0,0 +1,59 @@ +"""Test L2G feature generation.""" + +from __future__ import annotations + +from typing import TYPE_CHECKING, Any + +import pytest + +from gentropy.dataset.l2g_feature import ( + EQtlColocClppMaximumFeature, + EQtlColocH4MaximumFeature, + L2GFeature, + PQtlColocClppMaximumFeature, + PQtlColocH4MaximumFeature, + SQtlColocClppMaximumFeature, + SQtlColocH4MaximumFeature, + TuQtlColocClppMaximumFeature, + TuQtlColocH4MaximumFeature, +) +from gentropy.method.l2g.feature_factory import L2GFeatureInputLoader + +if TYPE_CHECKING: + from gentropy.dataset.colocalisation import Colocalisation + from gentropy.dataset.study_index import StudyIndex + from gentropy.dataset.study_locus import StudyLocus + + +@pytest.mark.parametrize( + "feature_class", + [ + EQtlColocH4MaximumFeature, + PQtlColocH4MaximumFeature, + SQtlColocH4MaximumFeature, + TuQtlColocH4MaximumFeature, + EQtlColocClppMaximumFeature, + PQtlColocClppMaximumFeature, + SQtlColocClppMaximumFeature, + TuQtlColocClppMaximumFeature, + ], +) +def test_feature_factory_return_type( + feature_class: Any, + mock_study_locus: StudyLocus, + mock_colocalisation: Colocalisation, + mock_study_index: StudyIndex, +) -> None: + """Test that every feature factory returns a L2GFeature dataset.""" + loader = L2GFeatureInputLoader( + colocalisation=mock_colocalisation, + study_index=mock_study_index, + study_locus=mock_study_locus, + ) + feature_dataset = feature_class.compute( + study_loci_to_annotate=mock_study_locus, + feature_dependency=loader.get_dependency_by_type( + feature_class.feature_dependency_type + ), + ) + assert isinstance(feature_dataset, L2GFeature) diff --git a/tests/gentropy/dataset/test_l2g_feature_matrix.py b/tests/gentropy/dataset/test_l2g_feature_matrix.py new file mode 100644 index 000000000..46384239c --- /dev/null +++ b/tests/gentropy/dataset/test_l2g_feature_matrix.py @@ -0,0 +1,150 @@ +"""Test L2G feature matrix methods.""" + +from __future__ import annotations + +from typing import TYPE_CHECKING + +import pytest +from pyspark.sql.types import ( + ArrayType, + DoubleType, + LongType, + StringType, + StructField, + StructType, +) + +from gentropy.dataset.colocalisation import Colocalisation +from gentropy.dataset.l2g_feature_matrix import L2GFeatureMatrix +from gentropy.dataset.l2g_gold_standard import L2GGoldStandard +from gentropy.dataset.study_index import StudyIndex +from gentropy.dataset.study_locus import StudyLocus +from gentropy.method.l2g.feature_factory import L2GFeatureInputLoader + +if TYPE_CHECKING: + from pyspark.sql import SparkSession + + +class TestFromFeaturesList: + """Test L2GFeatureMatrix.from_features_list method. + + If the columns from the features list are there, it means that the business logic is working (the dataframe is not empty when converting from long to wide). + """ + + def test_study_locus( + self: TestFromFeaturesList, + ) -> None: + """Test building feature matrix for a SL with the eQtlColocH4Maximum feature.""" + features_list = ["eQtlColocH4Maximum"] + loader = L2GFeatureInputLoader( + colocalisation=self.sample_colocalisation, + study_index=self.sample_study_index, + study_locus=self.sample_study_locus, + ) + fm = L2GFeatureMatrix.from_features_list( + self.sample_study_locus, features_list, loader + ) + for feature in features_list: + assert ( + feature in fm._df.columns + ), f"Feature {feature} not found in feature matrix." + + def test_gold_standard( + self: TestFromFeaturesList, + ) -> None: + """Test building feature matrix for a gold standard with the eQtlColocH4Maximum feature.""" + features_list = ["eQtlColocH4Maximum"] + loader = L2GFeatureInputLoader( + colocalisation=self.sample_colocalisation, + study_index=self.sample_study_index, + study_locus=self.sample_study_locus, + ) + fm = L2GFeatureMatrix.from_features_list( + self.sample_gold_standard, features_list, loader + ) + for feature in features_list: + assert ( + feature in fm._df.columns + ), f"Feature {feature} not found in feature matrix." + + @pytest.fixture(autouse=True) + def _setup(self: TestFromFeaturesList, spark: SparkSession) -> None: + """Setup fixture.""" + self.sample_gold_standard = L2GGoldStandard( + _df=spark.createDataFrame( + [(1, "var1", "gwas1", "g1", "positive", ["a_source"])], + L2GGoldStandard.get_schema(), + ), + _schema=L2GGoldStandard.get_schema(), + ) + self.sample_study_locus = StudyLocus( + _df=spark.createDataFrame( + [ + ( + 1, + "var1", + "gwas1", + [ + {"variantId": "var1", "posteriorProbability": 0.8}, + {"variantId": "var12", "posteriorProbability": 0.2}, + ], + ), + ( + 2, + "var2", + "eqtl1", + [ + {"variantId": "var2", "posteriorProbability": 1.0}, + ], + ), + ], + schema=StructType( + [ + StructField("studyLocusId", LongType(), True), + StructField("variantId", StringType(), True), + StructField("studyId", StringType(), True), + StructField( + "locus", + ArrayType( + StructType( + [ + StructField("variantId", StringType(), True), + StructField( + "posteriorProbability", DoubleType(), True + ), + ] + ) + ), + True, + ), + ] + ), + ), + _schema=StudyLocus.get_schema(), + ) + self.sample_study_index = StudyIndex( + _df=spark.createDataFrame( + [("gwas1", "gwas", None, "p1"), ("eqtl1", "eqtl", "g1", "p2")], + [ + "studyId", + "studyType", + "geneId", + "projectId", + ], + ), + _schema=StudyIndex.get_schema(), + ) + self.sample_colocalisation = Colocalisation( + _df=spark.createDataFrame( + [(1, 2, "X", "COLOC", 1, 0.9)], + [ + "leftStudyLocusId", + "rightStudyLocusId", + "chromosome", + "colocalisationMethod", + "numberColocalisingVariants", + "h4", + ], + ), + _schema=Colocalisation.get_schema(), + ) diff --git a/tests/gentropy/dataset/test_study_locus.py b/tests/gentropy/dataset/test_study_locus.py index 94390d20b..c89521b3c 100644 --- a/tests/gentropy/dataset/test_study_locus.py +++ b/tests/gentropy/dataset/test_study_locus.py @@ -18,6 +18,8 @@ StructType, ) +from gentropy.dataset.colocalisation import Colocalisation +from gentropy.dataset.l2g_feature_matrix import L2GFeatureMatrix from gentropy.dataset.ld_index import LDIndex from gentropy.dataset.study_index import StudyIndex from gentropy.dataset.study_locus import ( @@ -28,6 +30,7 @@ from gentropy.dataset.study_locus_overlap import StudyLocusOverlap from gentropy.dataset.summary_statistics import SummaryStatistics from gentropy.dataset.variant_index import VariantIndex +from gentropy.method.l2g.feature_factory import L2GFeatureInputLoader @pytest.mark.parametrize( @@ -780,6 +783,24 @@ def test_study_validation_correctness(self: TestStudyLocusValidation) -> None: ) == 1 +def test_build_feature_matrix( + mock_study_locus: StudyLocus, + mock_colocalisation: Colocalisation, + mock_study_index: StudyIndex, +) -> None: + """Test building feature matrix with the eQtlColocH4Maximum feature.""" + features_list = ["eQtlColocH4Maximum"] + loader = L2GFeatureInputLoader( + colocalisation=mock_colocalisation, + study_index=mock_study_index, + study_locus=mock_study_locus, + ) + fm = mock_study_locus.build_feature_matrix(features_list, loader) + assert isinstance( + fm, L2GFeatureMatrix + ), "Feature matrix should be of type L2GFeatureMatrix" + + class TestStudyLocusRedundancyFlagging: """Collection of tests related to flagging redundant credible sets.""" diff --git a/tests/gentropy/datasource/open_targets/test_l2g_gold_standard.py b/tests/gentropy/datasource/open_targets/test_l2g_gold_standard.py index 6f91d32a9..78f97d48f 100644 --- a/tests/gentropy/datasource/open_targets/test_l2g_gold_standard.py +++ b/tests/gentropy/datasource/open_targets/test_l2g_gold_standard.py @@ -7,15 +7,21 @@ import pytest from pyspark.sql import DataFrame +from gentropy.dataset.l2g_feature_matrix import L2GFeatureMatrix from gentropy.dataset.l2g_gold_standard import L2GGoldStandard +from gentropy.dataset.study_index import StudyIndex from gentropy.dataset.v2g import V2G from gentropy.datasource.open_targets.l2g_gold_standard import ( OpenTargetsL2GGoldStandard, ) +from gentropy.method.l2g.feature_factory import L2GFeatureInputLoader if TYPE_CHECKING: from pyspark.sql.session import SparkSession + from gentropy.dataset.colocalisation import Colocalisation + from gentropy.dataset.study_locus import StudyLocus + def test_open_targets_as_l2g_gold_standard( sample_l2g_gold_standard: DataFrame, @@ -104,3 +110,22 @@ def _setup(self: TestExpandGoldStandardWithNegatives, spark: SparkSession) -> No V2G(_df=sample_v2g_df, _schema=V2G.get_schema()), ) ) + + +def test_build_feature_matrix( + mock_l2g_gold_standard: L2GGoldStandard, + mock_study_locus: StudyLocus, + mock_colocalisation: Colocalisation, + mock_study_index: StudyIndex, +) -> None: + """Test building feature matrix with the eQtlColocH4Maximum feature.""" + features_list = ["eQtlColocH4Maximum"] + loader = L2GFeatureInputLoader( + colocalisation=mock_colocalisation, + study_index=mock_study_index, + study_locus=mock_study_locus, + ) + fm = mock_study_locus.build_feature_matrix(features_list, loader) + assert isinstance( + mock_l2g_gold_standard.build_feature_matrix(fm), L2GFeatureMatrix + ), "Feature matrix should be of type L2GFeatureMatrix" diff --git a/tests/gentropy/method/test_locus_to_gene.py b/tests/gentropy/method/test_locus_to_gene.py deleted file mode 100644 index 460d65062..000000000 --- a/tests/gentropy/method/test_locus_to_gene.py +++ /dev/null @@ -1,156 +0,0 @@ -"""Test locus-to-gene model training.""" - -from __future__ import annotations - -from typing import TYPE_CHECKING - -import pytest -from sklearn.ensemble import RandomForestClassifier - -from gentropy.dataset.colocalisation import Colocalisation -from gentropy.dataset.l2g_feature import L2GFeature -from gentropy.dataset.study_index import StudyIndex -from gentropy.dataset.study_locus import StudyLocus -from gentropy.method.l2g.feature_factory import ColocalisationFactory, StudyLocusFactory -from gentropy.method.l2g.model import LocusToGeneModel - -if TYPE_CHECKING: - from pyspark.sql import SparkSession - - from gentropy.dataset.v2g import V2G - - -@pytest.fixture(scope="module") -def model() -> LocusToGeneModel: - """Creates an instance of the LocusToGene class.""" - return LocusToGeneModel(model=RandomForestClassifier()) - - -class TestColocalisationFactory: - """Test the ColocalisationFactory methods.""" - - def test_get_max_coloc_per_credible_set( - self: TestColocalisationFactory, - mock_study_locus: StudyLocus, - mock_study_index: StudyIndex, - mock_colocalisation: Colocalisation, - ) -> None: - """Test the function that extracts the maximum log likelihood ratio for each pair of overlapping study-locus returns the right data type.""" - coloc_features = ColocalisationFactory._get_max_coloc_per_credible_set( - mock_colocalisation, - mock_study_locus, - mock_study_index, - ) - assert isinstance( - coloc_features, L2GFeature - ), "Unexpected type returned from _get_max_coloc_per_credible_set" - - def test_get_max_coloc_per_credible_set_semantic( - self: TestColocalisationFactory, - spark: SparkSession, - ) -> None: - """Test logic of the function that extracts the maximum log likelihood ratio for each pair of overlapping study-locus.""" - # Prepare mock datasets based on 2 associations - credset = StudyLocus( - _df=spark.createDataFrame( - # 2 associations with a common variant in the locus - [ - { - "studyLocusId": 1, - "variantId": "lead1", - "studyId": "study1", # this is a GWAS - "locus": [ - {"variantId": "commonTag", "posteriorProbability": 0.9}, - ], - "chromosome": "1", - }, - { - "studyLocusId": 2, - "variantId": "lead2", - "studyId": "study2", # this is a eQTL study - "locus": [ - {"variantId": "commonTag", "posteriorProbability": 0.9}, - ], - "chromosome": "1", - }, - ], - StudyLocus.get_schema(), - ), - _schema=StudyLocus.get_schema(), - ) - - studies = StudyIndex( - _df=spark.createDataFrame( - [ - { - "studyId": "study1", - "studyType": "gwas", - "traitFromSource": "trait1", - "projectId": "project1", - }, - { - "studyId": "study2", - "studyType": "eqtl", - "geneId": "gene1", - "traitFromSource": "trait2", - "projectId": "project2", - }, - ] - ), - _schema=StudyIndex.get_schema(), - ) - coloc = Colocalisation( - _df=spark.createDataFrame( - [ - { - "leftStudyLocusId": 1, - "rightStudyLocusId": 2, - "chromosome": "1", - "colocalisationMethod": "eCAVIAR", - "numberColocalisingVariants": 1, - "clpp": 0.81, # 0.9*0.9 - "log2h4h3": None, - } - ], - schema=Colocalisation.get_schema(), - ), - _schema=Colocalisation.get_schema(), - ) - expected_coloc_features_df = spark.createDataFrame( - [ - (1, "gene1", "eqtlColocClppMaximum", 0.81), - (1, "gene1", "eqtlColocClppMaximumNeighborhood", -4.0), - ], - L2GFeature.get_schema(), - ) - # Test - coloc_features = ColocalisationFactory._get_max_coloc_per_credible_set( - coloc, - credset, - studies, - ) - assert coloc_features.df.collect() == expected_coloc_features_df.collect() - - -class TestStudyLocusFactory: - """Test the StudyLocusFactory methods.""" - - def test_get_tss_distance_features( - self: TestStudyLocusFactory, mock_study_locus: StudyLocus, mock_v2g: V2G - ) -> None: - """Test the function that extracts the distance to the TSS.""" - tss_distance = StudyLocusFactory._get_tss_distance_features( - mock_study_locus, mock_v2g - ) - assert isinstance( - tss_distance, L2GFeature - ), "Unexpected model type returned from _get_tss_distance_features" - - def test_get_vep_features( - self: TestStudyLocusFactory, mock_study_locus: StudyLocus, mock_v2g: V2G - ) -> None: - """Test the function that extracts the VEP features.""" - vep_features = StudyLocusFactory._get_vep_features(mock_study_locus, mock_v2g) - assert isinstance( - vep_features, L2GFeature - ), "Unexpected model type returned from _get_vep_features" From a29222ed8d9bb8d023981626917eca6e659d2335 Mon Sep 17 00:00:00 2001 From: Szymon Szyszkowski <69353402+project-defiant@users.noreply.github.com> Date: Mon, 23 Sep 2024 19:42:51 +0200 Subject: [PATCH 047/188] feat(dataproc): ability to version gentropy for dataproc cluster (#774) --- .github/workflows/artifact.yml | 16 ++++++++++++ Makefile | 32 +++++++++++------------- docs/development/troubleshooting.md | 16 ++++++++++++ pyproject.toml | 2 +- utils/install_dependencies_on_cluster.sh | 4 --- 5 files changed, 48 insertions(+), 22 deletions(-) diff --git a/.github/workflows/artifact.yml b/.github/workflows/artifact.yml index 61dbab28e..2aa634a7e 100644 --- a/.github/workflows/artifact.yml +++ b/.github/workflows/artifact.yml @@ -10,6 +10,7 @@ env: REGION: europe-west1 GAR_LOCATION: europe-west1-docker.pkg.dev/open-targets-genetics-dev REPOSITORY: gentropy-app + PYTHON_VERSION_DEFAULT: "3.10.8" jobs: build-push-artifact: @@ -67,3 +68,18 @@ jobs: tags: "${{ env.GAR_LOCATION }}/${{ env.REPOSITORY }}/custom_ensembl_vep:${{ github.ref_name }}" context: . file: "src/vep/Dockerfile" + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: ${{ env.PYTHON_VERSION_DEFAULT }} + - name: Install and configure Poetry + uses: snok/install-poetry@v1 + with: + virtualenvs-create: true + virtualenvs-in-project: true + installer-parallel: true + + - name: Build and push spark cluster dependencies + run: | + make build diff --git a/Makefile b/Makefile index b83075558..1d79d35fd 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,10 @@ PROJECT_ID ?= open-targets-genetics-dev REGION ?= europe-west1 -APP_NAME ?= $$(cat pyproject.toml| grep -m 1 "name" | cut -d" " -f3 | sed 's/"//g') -VERSION_NO ?= $$(poetry version --short) -CLEAN_VERSION_NO := $(shell echo "$(VERSION_NO)" | tr -cd '[:alnum:]') -BUCKET_NAME=gs://genetics_etl_python_playground/initialisation/${VERSION_NO}/ -BUCKET_COMPOSER_DAGS=gs://europe-west1-ot-workflows-fe147745-bucket/dags/ +APP_NAME ?= $$(cat pyproject.toml | grep -m 1 "name" | cut -d" " -f3 | sed 's/"//g') +REF ?= $$(git rev-parse --abbrev-ref HEAD) +PACKAGE_VERSION ?= $$(poetry version --short) +CLEAN_PACKAGE_VERSION := $(shell echo "$(PACKAGE_VERSION)" | tr -cd '[:alnum:]') +BUCKET_NAME=gs://genetics_etl_python_playground/initialisation/${APP_NAME}/${REF} .PHONY: $(shell sed -n -e '/^$$/ { n ; /^[^ .\#][^ ]*:/ { s/:.*$$// ; p ; } ; }' $(MAKEFILE_LIST)) @@ -38,35 +38,33 @@ build-documentation: ## Create local server with documentation create-dev-cluster: build ## Spin up a simple dataproc cluster with all dependencies for development purposes @echo "Creating Dataproc Dev Cluster" @gcloud config set project ${PROJECT_ID} - @gcloud dataproc clusters create "ot-genetics-dev-${CLEAN_VERSION_NO}-$(USER)" \ + @gcloud dataproc clusters create "ot-genetics-dev-${CLEAN_PACKAGE_VERSION}-$(USER)" \ --image-version 2.1 \ --region ${REGION} \ --master-machine-type n1-standard-16 \ - --initialization-actions=gs://genetics_etl_python_playground/initialisation/${VERSION_NO}/install_dependencies_on_cluster.sh \ - --metadata="PACKAGE=gs://genetics_etl_python_playground/initialisation/${VERSION_NO}/gentropy-${VERSION_NO}-py3-none-any.whl,CONFIGTAR=gs://genetics_etl_python_playground/initialisation/${VERSION_NO}/config.tar.gz" \ + --initialization-actions=$(BUCKET_NAME)/install_dependencies_on_cluster.sh \ + --metadata="PACKAGE=$(BUCKET_NAME)/${APP_NAME}-${PACKAGE_VERSION}-py3-none-any.whl" \ --secondary-worker-type spot \ --worker-machine-type n1-standard-4 \ --worker-boot-disk-size 500 \ --autoscaling-policy="projects/${PROJECT_ID}/regions/${REGION}/autoscalingPolicies/otg-etl" \ --optional-components=JUPYTER \ --enable-component-gateway \ - --max-idle=30m + --max-idle=60m make update-dev-cluster: build ## Reinstalls the package on the dev-cluster @echo "Updating Dataproc Dev Cluster" @gcloud config set project ${PROJECT_ID} - gcloud dataproc jobs submit pig --cluster="ot-genetics-dev-${CLEAN_VERSION_NO}" \ + gcloud dataproc jobs submit pig --cluster="ot-genetics-dev-${CLEAN_PACKAGE_VERSION}" \ --region ${REGION} \ --jars=${BUCKET_NAME}/install_dependencies_on_cluster.sh \ -e='sh chmod 750 $${PWD}/install_dependencies_on_cluster.sh; sh $${PWD}/install_dependencies_on_cluster.sh' build: clean ## Build Python package with dependencies @gcloud config set project ${PROJECT_ID} - @echo "Packaging Code and Dependencies for ${APP_NAME}-${VERSION_NO}" + @echo "Packaging Code and Dependencies for ${APP_NAME}-${PACKAGE_VERSION}" @poetry build - @tar -czf dist/config.tar.gz config/ - @echo "Uploading to Dataproc" - @gsutil cp src/gentropy/cli.py ${BUCKET_NAME} - @gsutil cp ./dist/${APP_NAME}-${VERSION_NO}-py3-none-any.whl ${BUCKET_NAME} - @gsutil cp ./dist/config.tar.gz ${BUCKET_NAME} - @gsutil cp ./utils/install_dependencies_on_cluster.sh ${BUCKET_NAME} + @echo "Uploading to ${BUCKET_NAME}" + @gsutil cp src/${APP_NAME}/cli.py ${BUCKET_NAME}/ + @gsutil cp ./dist/${APP_NAME}-${PACKAGE_VERSION}-py3-none-any.whl ${BUCKET_NAME}/ + @gsutil cp ./utils/install_dependencies_on_cluster.sh ${BUCKET_NAME}/ diff --git a/docs/development/troubleshooting.md b/docs/development/troubleshooting.md index a30f72be0..498ee3b86 100644 --- a/docs/development/troubleshooting.md +++ b/docs/development/troubleshooting.md @@ -49,3 +49,19 @@ Some functions on MacOS may throw a java error: This can be resolved by adding the follow line to your `~/.zshrc`: `export OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES` + +## Creating development dataproc cluster (OT users only) + +To start dataproc cluster in the development mode run + +``` +make create-dev-cluster +``` + +The command above will prepare 3 different resources: + +- gentropy package +- cli script +- cluster setup script + +and based on the branch ref (for example `dev`) will create a namespaced folder under GCS (`gs://genetics_etl_python_playground/initialisation/gentropy/dev`) with the three files described above. These files will be then used to create the cluster environment. diff --git a/pyproject.toml b/pyproject.toml index 1343c7b50..8e5469c6a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -31,7 +31,7 @@ google = "^3.0.0" omegaconf = "^2.3.0" typing-extensions = "^4.9.0" scikit-learn = "^1.3.2" -pandas = {extras = ["gcp", "parquet"], version = "^2.2.2"} +pandas = { extras = ["gcp", "parquet"], version = "^2.2.2" } skops = ">=0.9,<0.11" google-cloud-secret-manager = "^2.20.0" diff --git a/utils/install_dependencies_on_cluster.sh b/utils/install_dependencies_on_cluster.sh index 9f26b9f17..6b76a7d60 100644 --- a/utils/install_dependencies_on_cluster.sh +++ b/utils/install_dependencies_on_cluster.sh @@ -3,7 +3,6 @@ set -exo pipefail readonly PACKAGE=$(/usr/share/google/get_metadata_value attributes/PACKAGE || true) -readonly CONFIGTAR=$(/usr/share/google/get_metadata_value attributes/CONFIGTAR || true) function err() { echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $*" >&2 @@ -63,9 +62,6 @@ function main() { echo "Install package..." run_with_retry pip install --upgrade ${PACKAGENAME} - echo "Downloading and uncompressing config..." - gsutil cp ${CONFIGTAR} . || err "Failed to download CONFIGTAR" - tar -xvf $(basename ${CONFIGTAR}) || err "Failed to extract CONFIGTAR" } main From dcacaf7d2694818c4d60545944ba6d40f27e45a8 Mon Sep 17 00:00:00 2001 From: Vivien Ho <56025826+vivienho@users.noreply.github.com> Date: Tue, 24 Sep 2024 14:37:11 +0100 Subject: [PATCH 048/188] feat: add `studyType` to `StudyLocus` and `Colocalisation` (and `StudyLocusOverlap`) (#782) * feat: add studyType to StudyLocus schema * feat: add annotate_study_type function to add studyType to StudyLocus * fix: remove lines for retrieving studyType as StudyLocus now contains studyType * fix: add studyType to test input data as StudyLocus now contains studyType * feat: add leftStudyType and rightStudyType to Colocalisation and StudyLocusOverlap schemas * feat: update _convert_to_square_matrix and its test with leftStudyType and rightStudyType * feat: update test_find_overlaps_semantic inputs with leftStudyType and rightStudyType * feat: update tests in test_colocalisation_method.py with leftStudyType and rightStudyType * feat: add leftStudyType and rightStudyType when creating StudyLocusOverlap * feat: add leftStudyType and rightStudyType to Colocalisation results * fix: remove redundant study_index parameter from filter_by_study_type function def and calls * fix: remove redundant study_index parameter from find_overlaps function def and calls * fix: remove leftStudyType from Colocalisation (not needed as always gwas) * fix: remove leftStudyType from StudyLocusOverlap (not needed as always gwas) * fix: missing comma * feat: update tests in test_locus_to_gene.py with studyType and rightStudyType * feat: update tests (colocalisation, l2g, l2g feature matrix) with rightStudyType * fix: remove studyType from metadata_cols in append_study_metadata function call --- .../assets/schemas/colocalisation.json | 6 ++ src/gentropy/assets/schemas/study_locus.json | 6 ++ .../assets/schemas/study_locus_overlap.json | 6 ++ src/gentropy/colocalisation.py | 8 +-- src/gentropy/dataset/colocalisation.py | 2 +- src/gentropy/dataset/study_locus.py | 31 ++++++++-- src/gentropy/dataset/study_locus_overlap.py | 7 +-- src/gentropy/l2g.py | 4 +- src/gentropy/method/colocalisation.py | 4 +- src/gentropy/study_locus_validation.py | 1 + tests/gentropy/dataset/test_colocalisation.py | 3 +- tests/gentropy/dataset/test_l2g.py | 4 +- .../dataset/test_l2g_feature_matrix.py | 3 +- tests/gentropy/dataset/test_study_locus.py | 58 ++++--------------- .../dataset/test_study_locus_overlap.py | 10 ++-- .../dataset/test_study_locus_overlaps.py | 8 +-- .../method/test_colocalisation_method.py | 5 ++ 17 files changed, 83 insertions(+), 83 deletions(-) diff --git a/src/gentropy/assets/schemas/colocalisation.json b/src/gentropy/assets/schemas/colocalisation.json index 7ff7453b9..6e1163cfe 100644 --- a/src/gentropy/assets/schemas/colocalisation.json +++ b/src/gentropy/assets/schemas/colocalisation.json @@ -13,6 +13,12 @@ "type": "long", "metadata": {} }, + { + "name": "rightStudyType", + "nullable": false, + "type": "string", + "metadata": {} + }, { "name": "chromosome", "nullable": false, diff --git a/src/gentropy/assets/schemas/study_locus.json b/src/gentropy/assets/schemas/study_locus.json index 11908f687..a8d15aba6 100644 --- a/src/gentropy/assets/schemas/study_locus.json +++ b/src/gentropy/assets/schemas/study_locus.json @@ -6,6 +6,12 @@ "nullable": false, "type": "long" }, + { + "metadata": {}, + "name": "studyType", + "nullable": true, + "type": "string" + }, { "metadata": {}, "name": "variantId", diff --git a/src/gentropy/assets/schemas/study_locus_overlap.json b/src/gentropy/assets/schemas/study_locus_overlap.json index 9a8e123cd..22ba7705e 100644 --- a/src/gentropy/assets/schemas/study_locus_overlap.json +++ b/src/gentropy/assets/schemas/study_locus_overlap.json @@ -12,6 +12,12 @@ "nullable": false, "type": "long" }, + { + "metadata": {}, + "name": "rightStudyType", + "nullable": false, + "type": "string" + }, { "metadata": {}, "name": "chromosome", diff --git a/src/gentropy/colocalisation.py b/src/gentropy/colocalisation.py index 6b370d426..4f8431b98 100644 --- a/src/gentropy/colocalisation.py +++ b/src/gentropy/colocalisation.py @@ -8,7 +8,6 @@ from pyspark.sql.functions import col from gentropy.common.session import Session -from gentropy.dataset.study_index import StudyIndex from gentropy.dataset.study_locus import CredibleInterval, StudyLocus from gentropy.method.colocalisation import Coloc @@ -23,7 +22,6 @@ def __init__( self, session: Session, credible_set_path: str, - study_index_path: str, coloc_path: str, colocalisation_method: str, ) -> None: @@ -32,7 +30,6 @@ def __init__( Args: session (Session): Session object. credible_set_path (str): Input credible sets path. - study_index_path (str): Input study index path. coloc_path (str): Output Colocalisation path. colocalisation_method (str): Colocalisation method. """ @@ -47,14 +44,11 @@ def __init__( session, credible_set_path, recursiveFileLookup=True ) ) - si = StudyIndex.from_parquet( - session, study_index_path, recursiveFileLookup=True - ) # Transform overlaps = credible_set.filter_credible_set( CredibleInterval.IS95 - ).find_overlaps(si) + ).find_overlaps() colocalisation_results = colocalisation_class.colocalise(overlaps) # type: ignore # Load diff --git a/src/gentropy/dataset/colocalisation.py b/src/gentropy/dataset/colocalisation.py index c0d074ae3..94a4f09dc 100644 --- a/src/gentropy/dataset/colocalisation.py +++ b/src/gentropy/dataset/colocalisation.py @@ -91,7 +91,7 @@ def extract_maximum_coloc_probability_per_region_and_gene( self.append_study_metadata( study_locus, study_index, - metadata_cols=["studyType", "geneId"], + metadata_cols=["geneId"], colocalisation_side="right", ) # it also filters based on method and qtl type diff --git a/src/gentropy/dataset/study_locus.py b/src/gentropy/dataset/study_locus.py index e8363aa4e..57482fda8 100644 --- a/src/gentropy/dataset/study_locus.py +++ b/src/gentropy/dataset/study_locus.py @@ -157,6 +157,24 @@ def validate_study(self: StudyLocus, study_index: StudyIndex) -> StudyLocus: _schema=self.get_schema(), ) + def annotate_study_type(self: StudyLocus, study_index: StudyIndex) -> StudyLocus: + """Gets study type from study index and adds it to study locus. + + Args: + study_index (StudyIndex): Study index to get study type. + + Returns: + StudyLocus: Updated study locus with study type. + """ + return StudyLocus( + _df=( + self.df + .drop("studyType") + .join(study_index.study_type_lut(), on="studyId", how="left") + ), + _schema=self.get_schema(), + ) + def validate_variant_identifiers( self: StudyLocus, variant_index: VariantIndex ) -> StudyLocus: @@ -394,6 +412,7 @@ def _align_overlapping_tags( f.col("chromosome"), f.col("tagVariantId"), f.col("studyLocusId").alias("rightStudyLocusId"), + f.col("studyType").alias("rightStudyType"), *[f.col(col).alias(f"right_{col}") for col in stats_cols], ).join(peak_overlaps, on=["chromosome", "rightStudyLocusId"], how="inner") @@ -410,6 +429,7 @@ def _align_overlapping_tags( ).select( "leftStudyLocusId", "rightStudyLocusId", + "rightStudyType", "chromosome", "tagVariantId", f.struct( @@ -505,13 +525,12 @@ def get_QC_mappings(cls: type[StudyLocus]) -> dict[str, str]: return {member.name: member.value for member in StudyLocusQualityCheck} def filter_by_study_type( - self: StudyLocus, study_type: str, study_index: StudyIndex + self: StudyLocus, study_type: str ) -> StudyLocus: """Creates a new StudyLocus dataset filtered by study type. Args: study_type (str): Study type to filter for. Can be one of `gwas`, `eqtl`, `pqtl`, `eqtl`. - study_index (StudyIndex): Study index to resolve study types. Returns: StudyLocus: Filtered study-locus dataset. @@ -524,7 +543,7 @@ def filter_by_study_type( f"Study type {study_type} not supported. Supported types are: gwas, eqtl, pqtl, sqtl." ) new_df = ( - self.df.join(study_index.study_type_lut(), on="studyId", how="inner") + self.df .filter(f.col("studyType") == study_type) .drop("studyType") ) @@ -576,7 +595,7 @@ def filter_ld_set(ld_set: Column, r2_threshold: float) -> Column: ) def find_overlaps( - self: StudyLocus, study_index: StudyIndex, intra_study_overlap: bool = False + self: StudyLocus, intra_study_overlap: bool = False ) -> StudyLocusOverlap: """Calculate overlapping study-locus. @@ -584,14 +603,14 @@ def find_overlaps( appearing on the right side. Args: - study_index (StudyIndex): Study index to resolve study types. intra_study_overlap (bool): If True, finds intra-study overlaps for credible set deduplication. Default is False. Returns: StudyLocusOverlap: Pairs of overlapping study-locus with aligned tags. """ loci_to_overlap = ( - self.df.join(study_index.study_type_lut(), on="studyId", how="inner") + self.df + .filter(f.col("studyType").isNotNull()) .withColumn("locus", f.explode("locus")) .select( "studyLocusId", diff --git a/src/gentropy/dataset/study_locus_overlap.py b/src/gentropy/dataset/study_locus_overlap.py index 5f839bd9c..d14a2da96 100644 --- a/src/gentropy/dataset/study_locus_overlap.py +++ b/src/gentropy/dataset/study_locus_overlap.py @@ -10,7 +10,6 @@ if TYPE_CHECKING: from pyspark.sql.types import StructType - from gentropy.dataset.study_index import StudyIndex from gentropy.dataset.study_locus import StudyLocus @@ -36,18 +35,17 @@ def get_schema(cls: type[StudyLocusOverlap]) -> StructType: @classmethod def from_associations( - cls: type[StudyLocusOverlap], study_locus: StudyLocus, study_index: StudyIndex + cls: type[StudyLocusOverlap], study_locus: StudyLocus ) -> StudyLocusOverlap: """Find the overlapping signals in a particular set of associations (StudyLocus dataset). Args: study_locus (StudyLocus): Study-locus associations to find the overlapping signals - study_index (StudyIndex): Study index to find the overlapping signals Returns: StudyLocusOverlap: Study-locus overlap dataset """ - return study_locus.find_overlaps(study_index) + return study_locus.find_overlaps() def _convert_to_square_matrix(self: StudyLocusOverlap) -> StudyLocusOverlap: """Convert the dataset to a square matrix. @@ -60,6 +58,7 @@ def _convert_to_square_matrix(self: StudyLocusOverlap) -> StudyLocusOverlap: self.df.selectExpr( "leftStudyLocusId as rightStudyLocusId", "rightStudyLocusId as leftStudyLocusId", + "rightStudyType", "tagVariantId", ) ).distinct(), diff --git a/src/gentropy/l2g.py b/src/gentropy/l2g.py index 832023cd8..13dbb881b 100644 --- a/src/gentropy/l2g.py +++ b/src/gentropy/l2g.py @@ -204,7 +204,7 @@ def _generate_feature_matrix(self, write_feature_matrix: bool) -> L2GFeatureMatr ValueError: If write_feature_matrix is set to True but a path is not provided. ValueError: If dependencies to build features are not set. """ - if self.gs_curation and self.interactions and self.v2g and self.studies: + if self.gs_curation and self.interactions and self.v2g: study_locus_overlap = StudyLocus( _df=self.credible_set.df.join( f.broadcast( @@ -225,7 +225,7 @@ def _generate_feature_matrix(self, write_feature_matrix: bool) -> L2GFeatureMatr "inner", ), _schema=StudyLocus.get_schema(), - ).find_overlaps(self.studies) + ).find_overlaps() gold_standards = L2GGoldStandard.from_otg_curation( gold_standard_curation=self.gs_curation, diff --git a/src/gentropy/method/colocalisation.py b/src/gentropy/method/colocalisation.py index c3320f931..7a3a0d9c5 100644 --- a/src/gentropy/method/colocalisation.py +++ b/src/gentropy/method/colocalisation.py @@ -79,7 +79,7 @@ def colocalise( f.col("statistics.right_posteriorProbability"), ), ) - .groupBy("leftStudyLocusId", "rightStudyLocusId", "chromosome") + .groupBy("leftStudyLocusId", "rightStudyLocusId", "rightStudyType", "chromosome") .agg( f.count("*").alias("numberColocalisingVariants"), f.sum(f.col("clpp")).alias("clpp"), @@ -168,7 +168,7 @@ def colocalise( f.col("left_logBF") + f.col("right_logBF"), ) # Group by overlapping peak and generating dense vectors of log_BF: - .groupBy("chromosome", "leftStudyLocusId", "rightStudyLocusId") + .groupBy("chromosome", "leftStudyLocusId", "rightStudyLocusId", "rightStudyType") .agg( f.count("*").alias("numberColocalisingVariants"), fml.array_to_vector(f.collect_list(f.col("left_logBF"))).alias( diff --git a/src/gentropy/study_locus_validation.py b/src/gentropy/study_locus_validation.py index e3d10f3db..4d1c234dc 100644 --- a/src/gentropy/study_locus_validation.py +++ b/src/gentropy/study_locus_validation.py @@ -46,6 +46,7 @@ def __init__( # Add flag for MHC region .qc_MHC_region() .validate_study(study_index) # Flagging studies not in study index + .annotate_study_type(study_index) # Add study type to study locus .qc_redundant_top_hits_from_PICS() # Flagging top hits from studies with PICS summary statistics .validate_unique_study_locus_id() # Flagging duplicated study locus ids ).persist() # we will need this for 2 types of outputs diff --git a/tests/gentropy/dataset/test_colocalisation.py b/tests/gentropy/dataset/test_colocalisation.py index 5371cf42c..8f2766fb4 100644 --- a/tests/gentropy/dataset/test_colocalisation.py +++ b/tests/gentropy/dataset/test_colocalisation.py @@ -100,10 +100,11 @@ def _setup(self: TestAppendStudyMetadata, spark: SparkSession) -> None: ) self.sample_colocalisation = Colocalisation( _df=spark.createDataFrame( - [(1, 2, "X", "COLOC", 1, 0.9)], + [(1, 2, "eqtl", "X", "COLOC", 1, 0.9)], [ "leftStudyLocusId", "rightStudyLocusId", + "rightStudyType", "chromosome", "colocalisationMethod", "numberColocalisingVariants", diff --git a/tests/gentropy/dataset/test_l2g.py b/tests/gentropy/dataset/test_l2g.py index d37ce5a4a..2523b97dd 100644 --- a/tests/gentropy/dataset/test_l2g.py +++ b/tests/gentropy/dataset/test_l2g.py @@ -70,8 +70,8 @@ def test_filter_unique_associations(spark: SparkSession) -> None: ) mock_sl_overlap_df = spark.createDataFrame( - [(1, 2, "variant2"), (1, 4, "variant4")], - "leftStudyLocusId LONG, rightStudyLocusId LONG, tagVariantId STRING", + [(1, 2, "eqtl", "variant2"), (1, 4, "eqtl", "variant4")], + "leftStudyLocusId LONG, rightStudyLocusId LONG, rightStudyType STRING, tagVariantId STRING", ) expected_df = spark.createDataFrame( diff --git a/tests/gentropy/dataset/test_l2g_feature_matrix.py b/tests/gentropy/dataset/test_l2g_feature_matrix.py index 46384239c..09460ee85 100644 --- a/tests/gentropy/dataset/test_l2g_feature_matrix.py +++ b/tests/gentropy/dataset/test_l2g_feature_matrix.py @@ -136,10 +136,11 @@ def _setup(self: TestFromFeaturesList, spark: SparkSession) -> None: ) self.sample_colocalisation = Colocalisation( _df=spark.createDataFrame( - [(1, 2, "X", "COLOC", 1, 0.9)], + [(1, 2, "eqtl", "X", "COLOC", 1, 0.9)], [ "leftStudyLocusId", "rightStudyLocusId", + "rightStudyType", "chromosome", "colocalisationMethod", "numberColocalisingVariants", diff --git a/tests/gentropy/dataset/test_study_locus.py b/tests/gentropy/dataset/test_study_locus.py index c89521b3c..ffb210d09 100644 --- a/tests/gentropy/dataset/test_study_locus.py +++ b/tests/gentropy/dataset/test_study_locus.py @@ -43,6 +43,7 @@ { "leftStudyLocusId": 1, "rightStudyLocusId": 2, + "rightStudyType": "eqtl", "chromosome": "1", "tagVariantId": "commonTag", "statistics": { @@ -53,6 +54,7 @@ { "leftStudyLocusId": 1, "rightStudyLocusId": 2, + "rightStudyType": "eqtl", "chromosome": "1", "tagVariantId": "nonCommonTag", "statistics": { @@ -79,6 +81,7 @@ def test_find_overlaps_semantic( "studyLocusId": 1, "variantId": "lead1", "studyId": "study1", + "studyType": "gwas", "locus": [ {"variantId": "commonTag", "posteriorProbability": 0.9}, ], @@ -88,6 +91,7 @@ def test_find_overlaps_semantic( "studyLocusId": 2, "variantId": "lead2", "studyId": "study2", + "studyType": "eqtl", "locus": [ {"variantId": "commonTag", "posteriorProbability": 0.6}, {"variantId": "nonCommonTag", "posteriorProbability": 0.6}, @@ -108,6 +112,7 @@ def test_find_overlaps_semantic( "studyLocusId": 1, "variantId": "lead1", "studyId": "study1", + "studyType": "gwas", "locus": [ {"variantId": "var1", "posteriorProbability": 0.9}, ], @@ -117,6 +122,7 @@ def test_find_overlaps_semantic( "studyLocusId": 2, "variantId": "lead2", "studyId": "study2", + "studyType": "eqtl", "locus": None, "chromosome": "1", }, @@ -126,25 +132,6 @@ def test_find_overlaps_semantic( _schema=StudyLocus.get_schema(), ) - studies = StudyIndex( - _df=spark.createDataFrame( - [ - { - "studyId": "study1", - "studyType": "gwas", - "traitFromSource": "trait1", - "projectId": "project1", - }, - { - "studyId": "study2", - "studyType": "eqtl", - "traitFromSource": "trait2", - "projectId": "project2", - }, - ] - ), - _schema=StudyIndex.get_schema(), - ) expected_overlaps_df = spark.createDataFrame( expected, StudyLocusOverlap.get_schema() ) @@ -154,18 +141,14 @@ def test_find_overlaps_semantic( "statistics.right_posteriorProbability", ] assert ( - credset.find_overlaps(studies).df.select(*cols_to_compare).collect() + credset.find_overlaps().df.select(*cols_to_compare).collect() == expected_overlaps_df.select(*cols_to_compare).collect() ), "Overlaps differ from expected." -def test_find_overlaps( - mock_study_locus: StudyLocus, mock_study_index: StudyIndex -) -> None: +def test_find_overlaps(mock_study_locus: StudyLocus) -> None: """Test study locus overlaps.""" - assert isinstance( - mock_study_locus.find_overlaps(mock_study_index), StudyLocusOverlap - ) + assert isinstance(mock_study_locus.find_overlaps(), StudyLocusOverlap) @pytest.mark.parametrize( @@ -184,39 +167,22 @@ def test_filter_by_study_type( "studyLocusId": 1, "variantId": "lead1", "studyId": "study1", + "studyType": "gwas", }, { # from eqtl "studyLocusId": 2, "variantId": "lead2", "studyId": "study2", + "studyType": "eqtl", }, ], StudyLocus.get_schema(), ), _schema=StudyLocus.get_schema(), ) - studies = StudyIndex( - _df=spark.createDataFrame( - [ - { - "studyId": "study1", - "studyType": "gwas", - "traitFromSource": "trait1", - "projectId": "project1", - }, - { - "studyId": "study2", - "studyType": "eqtl", - "traitFromSource": "trait2", - "projectId": "project2", - }, - ] - ), - _schema=StudyIndex.get_schema(), - ) - observed = sl.filter_by_study_type(study_type, studies) + observed = sl.filter_by_study_type(study_type) assert observed.df.count() == expected_sl_count diff --git a/tests/gentropy/dataset/test_study_locus_overlap.py b/tests/gentropy/dataset/test_study_locus_overlap.py index e26b59c30..7e591df30 100644 --- a/tests/gentropy/dataset/test_study_locus_overlap.py +++ b/tests/gentropy/dataset/test_study_locus_overlap.py @@ -19,19 +19,19 @@ def test_convert_to_square_matrix(spark: SparkSession) -> None: mock_sl_overlap = StudyLocusOverlap( _df=spark.createDataFrame( [ - (1, 2, "variant2"), + (1, 2, "eqtl", "variant2"), ], - "leftStudyLocusId LONG, rightStudyLocusId LONG, tagVariantId STRING", + "leftStudyLocusId LONG, rightStudyLocusId LONG, rightStudyType STRING, tagVariantId STRING", ), _schema=StudyLocusOverlap.get_schema(), ) expected_df = spark.createDataFrame( [ - (1, 2, "variant2"), - (2, 1, "variant2"), + (1, 2, "eqtl", "variant2"), + (2, 1, "eqtl", "variant2"), ], - "leftStudyLocusId LONG, rightStudyLocusId LONG, tagVariantId STRING", + "leftStudyLocusId LONG, rightStudyLocusId LONG, rightStudyType STRING, tagVariantId STRING", ) observed_df = mock_sl_overlap._convert_to_square_matrix().df diff --git a/tests/gentropy/dataset/test_study_locus_overlaps.py b/tests/gentropy/dataset/test_study_locus_overlaps.py index bd3415959..745f07ed2 100644 --- a/tests/gentropy/dataset/test_study_locus_overlaps.py +++ b/tests/gentropy/dataset/test_study_locus_overlaps.py @@ -13,8 +13,6 @@ if TYPE_CHECKING: from pyspark.sql import SparkSession - from gentropy.dataset.study_index import StudyIndex - def test_study_locus_overlap_creation( mock_study_locus_overlap: StudyLocusOverlap, @@ -23,11 +21,9 @@ def test_study_locus_overlap_creation( assert isinstance(mock_study_locus_overlap, StudyLocusOverlap) -def test_study_locus_overlap_from_associations( - mock_study_locus: StudyLocus, mock_study_index: StudyIndex -) -> None: +def test_study_locus_overlap_from_associations(mock_study_locus: StudyLocus) -> None: """Test colocalisation creation from mock associations.""" - overlaps = StudyLocusOverlap.from_associations(mock_study_locus, mock_study_index) + overlaps = StudyLocusOverlap.from_associations(mock_study_locus) assert isinstance(overlaps, StudyLocusOverlap) diff --git a/tests/gentropy/method/test_colocalisation_method.py b/tests/gentropy/method/test_colocalisation_method.py index d6798d831..e292784c1 100644 --- a/tests/gentropy/method/test_colocalisation_method.py +++ b/tests/gentropy/method/test_colocalisation_method.py @@ -29,6 +29,7 @@ def test_coloc(mock_study_locus_overlap: StudyLocusOverlap) -> None: { "leftStudyLocusId": 1, "rightStudyLocusId": 2, + "rightStudyType": "eqtl", "chromosome": "1", "tagVariantId": "snp", "statistics": {"left_logBF": 10.3, "right_logBF": 10.5}, @@ -52,6 +53,7 @@ def test_coloc(mock_study_locus_overlap: StudyLocusOverlap) -> None: { "leftStudyLocusId": 1, "rightStudyLocusId": 2, + "rightStudyType": "eqtl", "chromosome": "1", "tagVariantId": "snp1", "statistics": {"left_logBF": 10.3, "right_logBF": 10.5}, @@ -59,6 +61,7 @@ def test_coloc(mock_study_locus_overlap: StudyLocusOverlap) -> None: { "leftStudyLocusId": 1, "rightStudyLocusId": 2, + "rightStudyType": "eqtl", "chromosome": "1", "tagVariantId": "snp2", "statistics": {"left_logBF": 10.3, "right_logBF": 10.5}, @@ -119,6 +122,7 @@ def test_coloc_no_logbf( { "leftStudyLocusId": 1, "rightStudyLocusId": 2, + "rightStudyType": "eqtl", "chromosome": "1", "tagVariantId": "snp", "statistics": { @@ -131,6 +135,7 @@ def test_coloc_no_logbf( [ StructField("leftStudyLocusId", LongType(), False), StructField("rightStudyLocusId", LongType(), False), + StructField("rightStudyType", StringType(), False), StructField("chromosome", StringType(), False), StructField("tagVariantId", StringType(), False), StructField( From df45a6c9a7b925745f919a42f03f11a4c6eaaab5 Mon Sep 17 00:00:00 2001 From: Daniel Suveges Date: Tue, 24 Sep 2024 15:58:42 +0100 Subject: [PATCH 049/188] feat: adding window based clumping to StudyLocus (#779) * feat: adding window based clumping to locus * fix: reverting some changes * chore: pre-commit auto fixes [...] * fix: fixing probem introduced by merge conflict * fix: addressing review comment --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- src/gentropy/dataset/study_locus.py | 42 +++++++----- src/gentropy/dataset/summary_statistics.py | 7 +- src/gentropy/gwas_catalog_ingestion.py | 10 ++- src/gentropy/method/window_based_clumping.py | 51 +++++++++------ tests/gentropy/dataset/test_study_locus.py | 68 ++++++++++++++++++++ 5 files changed, 138 insertions(+), 40 deletions(-) diff --git a/src/gentropy/dataset/study_locus.py b/src/gentropy/dataset/study_locus.py index 57482fda8..2385df984 100644 --- a/src/gentropy/dataset/study_locus.py +++ b/src/gentropy/dataset/study_locus.py @@ -17,6 +17,7 @@ order_array_of_structs_by_field, ) from gentropy.common.utils import get_logsum +from gentropy.config import WindowBasedClumpingStepConfig from gentropy.dataset.dataset import Dataset from gentropy.dataset.study_locus_overlap import StudyLocusOverlap from gentropy.dataset.variant_index import VariantIndex @@ -45,7 +46,8 @@ class StudyLocusQualityCheck(Enum): PALINDROMIC_ALLELE_FLAG (str): Alleles are palindromic - cannot harmonize AMBIGUOUS_STUDY (str): Association with ambiguous study UNRESOLVED_LD (str): Variant not found in LD reference - LD_CLUMPED (str): Explained by a more significant variant in high LD (clumped) + LD_CLUMPED (str): Explained by a more significant variant in high LD + WINDOW_CLUMPED (str): Explained by a more significant variant in the same window NO_POPULATION (str): Study does not have population annotation to resolve LD NOT_QUALIFYING_LD_BLOCK (str): LD block does not contain variants at the required R^2 threshold FAILED_STUDY (str): Flagging study loci if the study has failed QC @@ -65,7 +67,8 @@ class StudyLocusQualityCheck(Enum): PALINDROMIC_ALLELE_FLAG = "Palindrome alleles - cannot harmonize" AMBIGUOUS_STUDY = "Association with ambiguous study" UNRESOLVED_LD = "Variant not found in LD reference" - LD_CLUMPED = "Explained by a more significant variant in high LD (clumped)" + LD_CLUMPED = "Explained by a more significant variant in high LD" + WINDOW_CLUMPED = "Explained by a more significant variant in the same window" NO_POPULATION = "Study does not have population annotation to resolve LD" NOT_QUALIFYING_LD_BLOCK = ( "LD block does not contain variants at the required R^2 threshold" @@ -168,9 +171,9 @@ def annotate_study_type(self: StudyLocus, study_index: StudyIndex) -> StudyLocus """ return StudyLocus( _df=( - self.df - .drop("studyType") - .join(study_index.study_type_lut(), on="studyId", how="left") + self.df.drop("studyType").join( + study_index.study_type_lut(), on="studyId", how="left" + ) ), _schema=self.get_schema(), ) @@ -524,9 +527,7 @@ def get_QC_mappings(cls: type[StudyLocus]) -> dict[str, str]: """ return {member.name: member.value for member in StudyLocusQualityCheck} - def filter_by_study_type( - self: StudyLocus, study_type: str - ) -> StudyLocus: + def filter_by_study_type(self: StudyLocus, study_type: str) -> StudyLocus: """Creates a new StudyLocus dataset filtered by study type. Args: @@ -542,11 +543,7 @@ def filter_by_study_type( raise ValueError( f"Study type {study_type} not supported. Supported types are: gwas, eqtl, pqtl, sqtl." ) - new_df = ( - self.df - .filter(f.col("studyType") == study_type) - .drop("studyType") - ) + new_df = self.df.filter(f.col("studyType") == study_type).drop("studyType") return StudyLocus( _df=new_df, _schema=self._schema, @@ -609,8 +606,7 @@ def find_overlaps( StudyLocusOverlap: Pairs of overlapping study-locus with aligned tags. """ loci_to_overlap = ( - self.df - .filter(f.col("studyType").isNotNull()) + self.df.filter(f.col("studyType").isNotNull()) .withColumn("locus", f.explode("locus")) .select( "studyLocusId", @@ -1051,3 +1047,19 @@ def annotate_locus_statistics_boundaries( ) return self + + def window_based_clumping( + self: StudyLocus, + window_size: int = WindowBasedClumpingStepConfig().distance, + ) -> StudyLocus: + """Clump study locus by window size. + + Args: + window_size (int): Window size for clumping. + + Returns: + StudyLocus: Clumped study locus, where clumped associations are flagged. + """ + from gentropy.method.window_based_clumping import WindowBasedClumping + + return WindowBasedClumping.clump(self, window_size) diff --git a/src/gentropy/dataset/summary_statistics.py b/src/gentropy/dataset/summary_statistics.py index d0875fe85..25edbeca7 100644 --- a/src/gentropy/dataset/summary_statistics.py +++ b/src/gentropy/dataset/summary_statistics.py @@ -77,10 +77,11 @@ def window_based_clumping( from gentropy.method.window_based_clumping import WindowBasedClumping return WindowBasedClumping.clump( - self, + # Before clumping, we filter the summary statistics by p-value: + self.pvalue_filter(gwas_significance), distance=distance, - gwas_significance=gwas_significance, - ) + # After applying the clumping, we filter the clumped loci by the flag: + ).valid_rows(["WINDOW_CLUMPED"]) def locus_breaker_clumping( self: SummaryStatistics, diff --git a/src/gentropy/gwas_catalog_ingestion.py b/src/gentropy/gwas_catalog_ingestion.py index 725f1ca4d..5dab5bf16 100644 --- a/src/gentropy/gwas_catalog_ingestion.py +++ b/src/gentropy/gwas_catalog_ingestion.py @@ -3,6 +3,7 @@ from __future__ import annotations from gentropy.common.session import Session +from gentropy.config import WindowBasedClumpingStepConfig from gentropy.dataset.variant_index import VariantIndex from gentropy.datasource.gwas_catalog.associations import ( GWASCatalogCuratedAssociationsParser, @@ -30,6 +31,7 @@ def __init__( gnomad_variant_path: str, catalog_studies_out: str, catalog_associations_out: str, + distance: int = WindowBasedClumpingStepConfig().distance, gwas_catalog_study_curation_file: str | None = None, inclusion_list_path: str | None = None, ) -> None: @@ -44,6 +46,7 @@ def __init__( gnomad_variant_path (str): Path to GnomAD variants. catalog_studies_out (str): Output GWAS catalog studies path. catalog_associations_out (str): Output GWAS catalog associations path. + distance (int): Distance, within which tagging variants are collected around the semi-index. gwas_catalog_study_curation_file (str | None): file of the curation table. Optional. inclusion_list_path (str | None): optional inclusion list (parquet) """ @@ -86,4 +89,9 @@ def __init__( # Load study_index.df.write.mode(session.write_mode).parquet(catalog_studies_out) - study_locus.df.write.mode(session.write_mode).parquet(catalog_associations_out) + + ( + study_locus.window_based_clumping(distance) + .df.write.mode(session.write_mode) + .parquet(catalog_associations_out) + ) diff --git a/src/gentropy/method/window_based_clumping.py b/src/gentropy/method/window_based_clumping.py index 629fe627e..9ef747abf 100644 --- a/src/gentropy/method/window_based_clumping.py +++ b/src/gentropy/method/window_based_clumping.py @@ -12,7 +12,7 @@ from pyspark.sql.window import Window from gentropy.config import WindowBasedClumpingStepConfig -from gentropy.dataset.study_locus import StudyLocus +from gentropy.dataset.study_locus import StudyLocus, StudyLocusQualityCheck if TYPE_CHECKING: from numpy.typing import NDArray @@ -154,22 +154,38 @@ def _prune_peak(position: NDArray[np.float64], window_size: int) -> DenseVector: @staticmethod def clump( - summary_statistics: SummaryStatistics, + unclumped_associations: SummaryStatistics | StudyLocus, distance: int = WindowBasedClumpingStepConfig().distance, - gwas_significance: float = WindowBasedClumpingStepConfig().gwas_significance, ) -> StudyLocus: - """Clump significant signals from summary statistics based on window. + """Clump single point associations from summary statistics or study locus dataset based on window. Args: - summary_statistics (SummaryStatistics): Summary statistics to be used for clumping. + unclumped_associations (SummaryStatistics | StudyLocus): Input dataset to be used for clumping. Assumes that the input dataset is already filtered for significant variants. distance (int): Distance in base pairs to be used for clumping. Defaults to 500_000. - gwas_significance (float): GWAS significance threshold. Defaults to 5e-8. Returns: - StudyLocus: clumped summary statistics (without locus collection) - - Check WindowBasedClumpingStepConfig object for default values + StudyLocus: clumped associations, where the clumped variants are flagged. """ + # Quality check expression that flags variants that are not considered lead variant: + qc_check = f.col("semiIndices")[f.col("pvRank") - 1] <= 0 + + # The quality control expression will depend on the input dataset, as the column might be already present: + qc_expression = ( + # When the column is already present and the condition is met, the value is appended to the array, otherwise keep as is: + f.when( + qc_check, + f.array_union( + f.col("qualityControls"), + f.array(f.lit(StudyLocusQualityCheck.WINDOW_CLUMPED.value)), + ), + ).otherwise(f.col("qualityControls")) + if "qualityControls" in unclumped_associations.df.columns + # If column is not there yet, initialize it with the flag value, or an empty array: + else f.when( + qc_check, f.array(f.lit(StudyLocusQualityCheck.WINDOW_CLUMPED.value)) + ).otherwise(f.array().cast(t.ArrayType(t.StringType()))) + ) + # Create window for locus clusters # - variants where the distance between subsequent variants is below the defined threshold. # - Variants are sorted by descending significance @@ -179,11 +195,8 @@ def clump( return StudyLocus( _df=( - summary_statistics - # Dropping snps below significance - all subsequent steps are done on significant variants: - .pvalue_filter(gwas_significance) - .df - # Clustering summary variants for efficient windowing (complexity reduction): + unclumped_associations.df + # Clustering variants for efficient windowing (complexity reduction): .withColumn( "cluster_id", WindowBasedClumping._cluster_peaks( @@ -207,7 +220,7 @@ def clump( ), ).otherwise(f.array()), ) - # Get semi indices only ONCE per cluster: + # Collect top loci per cluster: .withColumn( "semiIndices", f.when( @@ -230,9 +243,6 @@ def clump( ), ).otherwise(f.col("semiIndices")), ) - # Keeping semi indices only: - .filter(f.col("semiIndices")[f.col("pvRank") - 1] > 0) - .drop("pvRank", "collectedPositions", "semiIndices", "cluster_id") # Adding study-locus id: .withColumn( "studyLocusId", @@ -241,9 +251,8 @@ def clump( ), ) # Initialize QC column as array of strings: - .withColumn( - "qualityControls", f.array().cast(t.ArrayType(t.StringType())) - ) + .withColumn("qualityControls", qc_expression) + .drop("pvRank", "collectedPositions", "semiIndices", "cluster_id") ), _schema=StudyLocus.get_schema(), ) diff --git a/tests/gentropy/dataset/test_study_locus.py b/tests/gentropy/dataset/test_study_locus.py index ffb210d09..51fc2ed92 100644 --- a/tests/gentropy/dataset/test_study_locus.py +++ b/tests/gentropy/dataset/test_study_locus.py @@ -749,6 +749,74 @@ def test_study_validation_correctness(self: TestStudyLocusValidation) -> None: ) == 1 +class TestStudyLocusWindowClumping: + """Testing window-based clumping on study locus.""" + + TEST_DATASET = [ + ("s1", "c1", 1, -1), + ("s1", "c1", 2, -2), + ("s1", "c1", 3, -3), + ("s2", "c2", 2, -2), + ("s3", "c2", 2, -2), + ] + + TEST_SCHEMA = t.StructType( + [ + t.StructField("studyId", t.StringType(), False), + t.StructField("chromosome", t.StringType(), False), + t.StructField("position", t.IntegerType(), False), + t.StructField("pValueExponent", t.IntegerType(), False), + ] + ) + + @pytest.fixture(autouse=True) + def _setup(self: TestStudyLocusWindowClumping, spark: SparkSession) -> None: + """Setup study locus for testing.""" + self.study_locus = StudyLocus( + _df=( + spark.createDataFrame( + self.TEST_DATASET, schema=self.TEST_SCHEMA + ).withColumns( + { + "studyLocusId": f.monotonically_increasing_id().cast( + t.LongType() + ), + "pValueMantissa": f.lit(1).cast(t.FloatType()), + "variantId": f.concat( + f.lit("v"), + f.monotonically_increasing_id().cast(t.StringType()), + ), + } + ) + ), + _schema=StudyLocus.get_schema(), + ) + + def test_clump_return_type(self: TestStudyLocusWindowClumping) -> None: + """Testing if the clumping returns the right type.""" + assert isinstance(self.study_locus.window_based_clumping(3), StudyLocus) + + def test_clump_no_data_loss(self: TestStudyLocusWindowClumping) -> None: + """Testing if the clumping returns same number of rows.""" + assert ( + self.study_locus.window_based_clumping(3).df.count() + == self.study_locus.df.count() + ) + + def test_correct_flag(self: TestStudyLocusWindowClumping) -> None: + """Testing if the clumping flags are for variants.""" + assert ( + self.study_locus.window_based_clumping(3) + .df.filter( + f.array_contains( + f.col("qualityControls"), + StudyLocusQualityCheck.WINDOW_CLUMPED.value, + ) + ) + .count() + ) == 2 + + def test_build_feature_matrix( mock_study_locus: StudyLocus, mock_colocalisation: Colocalisation, From 148e26e7013ebd400f4ada63a4d0a8b2480c490b Mon Sep 17 00:00:00 2001 From: Yakov Date: Tue, 24 Sep 2024 16:36:44 +0100 Subject: [PATCH 050/188] fix: small qc flag fixes (#784) --- src/gentropy/dataset/study_index.py | 2 -- src/gentropy/study_locus_validation.py | 5 +---- src/gentropy/study_validation.py | 3 +-- 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/gentropy/dataset/study_index.py b/src/gentropy/dataset/study_index.py index ac637f137..3c3debba9 100644 --- a/src/gentropy/dataset/study_index.py +++ b/src/gentropy/dataset/study_index.py @@ -30,14 +30,12 @@ class StudyQualityCheck(Enum): UNRESOLVED_DISEASE (str): Disease identifier could not match to referece or retired identifier - labelling failing disease UNKNOWN_STUDY_TYPE (str): Indicating the provided type of study is not supported. DUPLICATED_STUDY (str): Flagging if a study identifier is not unique. - NO_GENE_PROVIDED (str): Flagging QTL studies if the measured """ UNRESOLVED_TARGET = "Target/gene identifier could not match to reference." UNRESOLVED_DISEASE = "No valid disease identifier found." UNKNOWN_STUDY_TYPE = "This type of study is not supported." DUPLICATED_STUDY = "The identifier of this study is not unique." - NO_GENE_PROVIDED = "QTL study doesn't have gene assigned." @dataclass diff --git a/src/gentropy/study_locus_validation.py b/src/gentropy/study_locus_validation.py index 4d1c234dc..7c853bbcb 100644 --- a/src/gentropy/study_locus_validation.py +++ b/src/gentropy/study_locus_validation.py @@ -41,14 +41,11 @@ def __init__( # Running validation then writing output: study_locus_with_qc = ( StudyLocus.from_parquet(session, list(study_locus_path)) - # Flagging study locus with subsignificant p-values - .validate_lead_pvalue(pvalue_cutoff=gwas_significance) # Add flag for MHC region .qc_MHC_region() .validate_study(study_index) # Flagging studies not in study index - .annotate_study_type(study_index) # Add study type to study locus + .annotate_study_type(study_index) # Add study type to study locus .qc_redundant_top_hits_from_PICS() # Flagging top hits from studies with PICS summary statistics - .validate_unique_study_locus_id() # Flagging duplicated study locus ids ).persist() # we will need this for 2 types of outputs study_locus_with_qc.valid_rows( diff --git a/src/gentropy/study_validation.py b/src/gentropy/study_validation.py index 5bfb83fe0..565aa410d 100644 --- a/src/gentropy/study_validation.py +++ b/src/gentropy/study_validation.py @@ -58,8 +58,7 @@ def __init__( # Running validation: study_index_with_qc = ( - study_index.validate_disease(disease_index) - .validate_unique_study_id() # Flagging duplicated study ids + study_index.validate_unique_study_id() # Flagging duplicated study ids .validate_study_type() # Flagging non-supported study types. .validate_target(target_index) # Flagging QTL studies with invalid targets .validate_disease(disease_index) # Flagging invalid EFOs From ccdb1f25de6dba9e3c4ebdaa9b432f9e300a8bb8 Mon Sep 17 00:00:00 2001 From: Tobi Alegbe Date: Tue, 24 Sep 2024 16:49:10 +0100 Subject: [PATCH 051/188] feat: add biosample index (#769) * Initial commit of biosample index * Make minimal class * Tidy up first draft of adding biosample index * Add beginning of logic for checking if biosample from a studyindex is in biosample index * Make early file for merging multiple biosample indices into one * Finish adding basic iteration of biosample index, needs debugging * Tweak slightly * Modified the parser to accept JSON files * Update biosample index * Tests and docs * Updating tests * Revert GWAS catalog file * fix(biosample index): update to match pre-commit standards * fix(biosample index): merging indices fix * fix(biosample index): update study index qc logic * fix(biosample index): fix missing mock_biosample_index * chore(biosample index): change datasource name from ontologies * fix(biosample index): add dataset doc * fix(biosample index): change dbXrefs to xrefs * chore (biosample index): better commenting Co-authored-by: Daniel Suveges * fix(biosample index): various minor tweaks to biosample index * fix(biosample index): minor bug * fix(biosample index): fix merge shift to method * feat(biosample index): make biosampleName not nullable --------- Co-authored-by: Daniel Suveges --- docs/python_api/datasets/biosample_index.md | 9 + docs/python_api/datasources/_datasources.md | 7 +- .../biosample_ontologies/_cell_ontology.md | 5 + .../biosample_ontologies/_uberon.md | 5 + docs/python_api/steps/biosample_index_step.md | 5 + poetry.lock | 3 +- .../assets/schemas/biosample_index.json | 83 ++ src/gentropy/biosample_index.py | 34 + src/gentropy/config.py | 12 + src/gentropy/dataset/biosample_index.py | 72 ++ src/gentropy/dataset/study_index.py | 36 + .../biosample_ontologies/__init__.py | 3 + .../datasource/biosample_ontologies/utils.py | 130 +++ src/gentropy/study_validation.py | 5 + tests/gentropy/conftest.py | 30 + .../data_samples/cell_ontology_sample.json | 351 +++++++ .../gentropy/data_samples/uberon_sample.json | 889 ++++++++++++++++++ .../gentropy/dataset/test_biosample_index.py | 8 + .../test_biosample_ontology.py | 50 + 19 files changed, 1735 insertions(+), 2 deletions(-) create mode 100644 docs/python_api/datasets/biosample_index.md create mode 100644 docs/python_api/datasources/biosample_ontologies/_cell_ontology.md create mode 100644 docs/python_api/datasources/biosample_ontologies/_uberon.md create mode 100644 docs/python_api/steps/biosample_index_step.md create mode 100644 src/gentropy/assets/schemas/biosample_index.json create mode 100644 src/gentropy/biosample_index.py create mode 100644 src/gentropy/dataset/biosample_index.py create mode 100644 src/gentropy/datasource/biosample_ontologies/__init__.py create mode 100644 src/gentropy/datasource/biosample_ontologies/utils.py create mode 100644 tests/gentropy/data_samples/cell_ontology_sample.json create mode 100644 tests/gentropy/data_samples/uberon_sample.json create mode 100644 tests/gentropy/dataset/test_biosample_index.py create mode 100644 tests/gentropy/datasource/biosample_ontologies/test_biosample_ontology.py diff --git a/docs/python_api/datasets/biosample_index.md b/docs/python_api/datasets/biosample_index.md new file mode 100644 index 000000000..d3e4ee2c8 --- /dev/null +++ b/docs/python_api/datasets/biosample_index.md @@ -0,0 +1,9 @@ +--- +title: Biosample index +--- + +::: gentropy.dataset.biosample_index.BiosampleIndex + +## Schema + +--8<-- "assets/schemas/biosample_index.md" diff --git a/docs/python_api/datasources/_datasources.md b/docs/python_api/datasources/_datasources.md index e6e081b21..43b212e50 100644 --- a/docs/python_api/datasources/_datasources.md +++ b/docs/python_api/datasources/_datasources.md @@ -26,7 +26,7 @@ This section contains information about the data source harmonisation tools avai 2. GWAS catalog's [harmonisation pipeline](https://www.ebi.ac.uk/gwas/docs/methods/summary-statistics#_harmonised_summary_statistics_data) 3. Ensembl's [Variant Effect Predictor](https://www.ensembl.org/info/docs/tools/vep/index.html) -## Linkage desiquilibrium +## Linkage disequilibrium 1. [GnomAD](gnomad/_gnomad.md) v2.1.1 LD matrixes (7 ancestries) @@ -37,3 +37,8 @@ This section contains information about the data source harmonisation tools avai ## Gene annotation 1. [Open Targets Platform Target Dataset](open_targets/target.md) (derived from Ensembl) + +## Biological samples + +1. [Uberon](biosample_ontologies/_uberon.md) +2. [Cell Ontology](biosample_ontologies/_cell_ontology.md) diff --git a/docs/python_api/datasources/biosample_ontologies/_cell_ontology.md b/docs/python_api/datasources/biosample_ontologies/_cell_ontology.md new file mode 100644 index 000000000..5798e032b --- /dev/null +++ b/docs/python_api/datasources/biosample_ontologies/_cell_ontology.md @@ -0,0 +1,5 @@ +--- +title: Cell Ontology +--- + +The [Cell Ontology](http://www.obofoundry.org/ontology/cl.html) is a structured controlled vocabulary for cell types. It is used to annotate cell types in single-cell RNA-seq data and other omics data. diff --git a/docs/python_api/datasources/biosample_ontologies/_uberon.md b/docs/python_api/datasources/biosample_ontologies/_uberon.md new file mode 100644 index 000000000..4bb47305a --- /dev/null +++ b/docs/python_api/datasources/biosample_ontologies/_uberon.md @@ -0,0 +1,5 @@ +--- +title: Uberon +--- + +The [Uberon](http://uberon.github.io/) ontology is a multi-species anatomy ontology that integrates cross-species ontologies into a single ontology. diff --git a/docs/python_api/steps/biosample_index_step.md b/docs/python_api/steps/biosample_index_step.md new file mode 100644 index 000000000..d8f7abbb4 --- /dev/null +++ b/docs/python_api/steps/biosample_index_step.md @@ -0,0 +1,5 @@ +--- +title: biosample_index +--- + +::: gentropy.biosample_index.BiosampleIndexStep diff --git a/poetry.lock b/poetry.lock index 226311a8b..296f07145 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.0 and should not be changed by hand. [[package]] name = "aiodns" @@ -3952,6 +3952,7 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, diff --git a/src/gentropy/assets/schemas/biosample_index.json b/src/gentropy/assets/schemas/biosample_index.json new file mode 100644 index 000000000..6309ca2c7 --- /dev/null +++ b/src/gentropy/assets/schemas/biosample_index.json @@ -0,0 +1,83 @@ +{ + "type": "struct", + "fields": [ + { + "name": "biosampleId", + "type": "string", + "nullable": false, + "metadata": {} + }, + { + "name": "biosampleName", + "type": "string", + "nullable": false, + "metadata": {} + }, + { + "name": "description", + "type": "string", + "nullable": true, + "metadata": {} + }, + { + "name": "xrefs", + "type": { + "type": "array", + "elementType": "string", + "containsNull": true + }, + "nullable": true, + "metadata": {} + }, + { + "name": "synonyms", + "type": { + "type": "array", + "elementType": "string", + "containsNull": true + }, + "nullable": true, + "metadata": {} + }, + { + "name": "parents", + "type": { + "type": "array", + "elementType": "string", + "containsNull": true + }, + "nullable": true, + "metadata": {} + }, + { + "name": "ancestors", + "type": { + "type": "array", + "elementType": "string", + "containsNull": true + }, + "nullable": true, + "metadata": {} + }, + { + "name": "descendants", + "type": { + "type": "array", + "elementType": "string", + "containsNull": true + }, + "nullable": true, + "metadata": {} + }, + { + "name": "children", + "type": { + "type": "array", + "elementType": "string", + "containsNull": true + }, + "nullable": true, + "metadata": {} + } + ] +} diff --git a/src/gentropy/biosample_index.py b/src/gentropy/biosample_index.py new file mode 100644 index 000000000..e85c2e135 --- /dev/null +++ b/src/gentropy/biosample_index.py @@ -0,0 +1,34 @@ +"""Step to generate biosample index dataset.""" +from __future__ import annotations + +from gentropy.common.session import Session +from gentropy.datasource.biosample_ontologies.utils import extract_ontology_from_json + + +class BiosampleIndexStep: + """Biosample index step. + + This step generates a Biosample index dataset from the various ontology sources. Currently Cell Ontology and Uberon are supported. + """ + + def __init__( + self, + session: Session, + cell_ontology_input_path: str, + uberon_input_path: str, + biosample_index_path: str, + ) -> None: + """Run Biosample index generation step. + + Args: + session (Session): Session object. + cell_ontology_input_path (str): Input cell ontology dataset path. + uberon_input_path (str): Input uberon dataset path. + biosample_index_path (str): Output gene index dataset path. + """ + cell_ontology_index = extract_ontology_from_json(cell_ontology_input_path, session.spark) + uberon_index = extract_ontology_from_json(uberon_input_path, session.spark) + + biosample_index = cell_ontology_index.merge_indices([uberon_index]) + + biosample_index.df.write.mode(session.write_mode).parquet(biosample_index_path) diff --git a/src/gentropy/config.py b/src/gentropy/config.py index d5e02924b..32edc9a4a 100644 --- a/src/gentropy/config.py +++ b/src/gentropy/config.py @@ -51,6 +51,16 @@ class GeneIndexConfig(StepConfig): _target_: str = "gentropy.gene_index.GeneIndexStep" +@dataclass +class BiosampleIndexConfig(StepConfig): + """Biosample index step configuration.""" + + cell_ontology_input_path: str = MISSING + uberon_input_path: str = MISSING + biosample_index_path: str = MISSING + _target_: str = "gentropy.biosample_index.BiosampleIndexStep" + + @dataclass class GWASCatalogStudyCurationConfig(StepConfig): """GWAS Catalog study curation step configuration.""" @@ -472,6 +482,7 @@ class StudyValidationStepConfig(StepConfig): study_index_path: list[str] = MISSING target_index_path: str = MISSING disease_index_path: str = MISSING + biosample_index_path: str = MISSING valid_study_index_path: str = MISSING invalid_study_index_path: str = MISSING invalid_qc_reasons: list[str] = MISSING @@ -512,6 +523,7 @@ def register_config() -> None: cs.store(group="step", name="colocalisation", node=ColocalisationConfig) cs.store(group="step", name="eqtl_catalogue", node=EqtlCatalogueConfig) cs.store(group="step", name="gene_index", node=GeneIndexConfig) + cs.store(group="step", name="biosample_index", node=BiosampleIndexConfig) cs.store( group="step", name="gwas_catalog_study_curation", diff --git a/src/gentropy/dataset/biosample_index.py b/src/gentropy/dataset/biosample_index.py new file mode 100644 index 000000000..39c597142 --- /dev/null +++ b/src/gentropy/dataset/biosample_index.py @@ -0,0 +1,72 @@ +"""Biosample index dataset.""" + +from __future__ import annotations + +from dataclasses import dataclass +from functools import reduce +from typing import TYPE_CHECKING + +import pyspark.sql.functions as f +from pyspark.sql import DataFrame +from pyspark.sql.types import ArrayType, StringType + +from gentropy.common.schemas import parse_spark_schema +from gentropy.dataset.dataset import Dataset + +if TYPE_CHECKING: + from pyspark.sql.types import StructType + + +@dataclass +class BiosampleIndex(Dataset): + """Biosample index dataset. + + A Biosample index dataset captures the metadata of the biosamples (e.g. tissues, cell types, cell lines, etc) such as alternate names and relationships with other biosamples. + """ + + @classmethod + def get_schema(cls: type[BiosampleIndex]) -> StructType: + """Provide the schema for the BiosampleIndex dataset. + + Returns: + StructType: The schema of the BiosampleIndex dataset. + """ + return parse_spark_schema("biosample_index.json") + + def merge_indices( + self: BiosampleIndex, + biosample_indices : list[BiosampleIndex] + ) -> BiosampleIndex: + """Merge a list of biosample indices into a single biosample index. + + Where there are conflicts, in single values - the first value is taken. In list values, the union of all values is taken. + + Args: + biosample_indices (list[BiosampleIndex]): Biosample indices to merge. + + Returns: + BiosampleIndex: Merged biosample index. + """ + # Extract the DataFrames from the BiosampleIndex objects + biosample_dfs = [biosample_index.df for biosample_index in biosample_indices] + [self.df] + + # Merge the DataFrames + merged_df = reduce(DataFrame.unionAll, biosample_dfs) + + # Determine aggregation functions for each column + # Currently this will take the first value for single values and merge lists for list values + agg_funcs = [] + for field in merged_df.schema.fields: + if field.name != "biosampleId": # Skip the grouping column + if field.dataType == ArrayType(StringType()): + agg_funcs.append(f.array_distinct(f.flatten(f.collect_list(field.name))).alias(field.name)) + else: + agg_funcs.append(f.first(f.col(field.name), ignorenulls=True).alias(field.name)) + + # Perform aggregation + aggregated_df = merged_df.groupBy("biosampleId").agg(*agg_funcs) + + return BiosampleIndex( + _df=aggregated_df, + _schema=BiosampleIndex.get_schema() + ) diff --git a/src/gentropy/dataset/study_index.py b/src/gentropy/dataset/study_index.py index 3c3debba9..3f9b65097 100644 --- a/src/gentropy/dataset/study_index.py +++ b/src/gentropy/dataset/study_index.py @@ -19,6 +19,7 @@ from pyspark.sql import Column, DataFrame from pyspark.sql.types import StructType + from gentropy.dataset.biosample_index import BiosampleIndex from gentropy.dataset.gene_index import GeneIndex @@ -29,12 +30,14 @@ class StudyQualityCheck(Enum): UNRESOLVED_TARGET (str): Target/gene identifier could not match to reference - Labelling failing target. UNRESOLVED_DISEASE (str): Disease identifier could not match to referece or retired identifier - labelling failing disease UNKNOWN_STUDY_TYPE (str): Indicating the provided type of study is not supported. + UNKNOWN_BIOSAMPLE (str): Flagging if a biosample identifier is not found in the reference. DUPLICATED_STUDY (str): Flagging if a study identifier is not unique. """ UNRESOLVED_TARGET = "Target/gene identifier could not match to reference." UNRESOLVED_DISEASE = "No valid disease identifier found." UNKNOWN_STUDY_TYPE = "This type of study is not supported." + UNKNOWN_BIOSAMPLE = "Biosample identifier was not found in the reference." DUPLICATED_STUDY = "The identifier of this study is not unique." @@ -406,3 +409,36 @@ def validate_target(self: StudyIndex, target_index: GeneIndex) -> StudyIndex: ) return StudyIndex(_df=validated_df, _schema=StudyIndex.get_schema()) + + def validate_biosample(self: StudyIndex, biosample_index: BiosampleIndex) -> StudyIndex: + """Validating biosample identifiers in the study index against the provided biosample index. + + Args: + biosample_index (BiosampleIndex): Biosample index containing a reference of biosample identifiers e.g. cell types, tissues, cell lines, etc. + + Returns: + StudyIndex: with flagged studies if biosampleIndex could not be validated. + """ + biosample_set = biosample_index.df.select("biosampleId", f.lit(True).alias("isIdFound")) + + validated_df = ( + self.df.join(biosample_set, self.df.biosampleFromSourceId == biosample_set.biosampleId, how="left") + .withColumn( + "isIdFound", + f.when( + f.col("isIdFound").isNull(), + f.lit(False), + ).otherwise(f.lit(True)), + ) + .withColumn( + "qualityControls", + StudyIndex.update_quality_flag( + f.col("qualityControls"), + ~f.col("isIdFound"), + StudyQualityCheck.UNKNOWN_BIOSAMPLE, + ), + ) + .drop("isIdFound").drop("biosampleId") + ) + + return StudyIndex(_df=validated_df, _schema=StudyIndex.get_schema()) diff --git a/src/gentropy/datasource/biosample_ontologies/__init__.py b/src/gentropy/datasource/biosample_ontologies/__init__.py new file mode 100644 index 000000000..d3fa6b416 --- /dev/null +++ b/src/gentropy/datasource/biosample_ontologies/__init__.py @@ -0,0 +1,3 @@ +"""Biosample index data source.""" + +from __future__ import annotations diff --git a/src/gentropy/datasource/biosample_ontologies/utils.py b/src/gentropy/datasource/biosample_ontologies/utils.py new file mode 100644 index 000000000..3ef1747ee --- /dev/null +++ b/src/gentropy/datasource/biosample_ontologies/utils.py @@ -0,0 +1,130 @@ +"""Utility functions for Biosample ontology processing.""" +from pyspark.sql import DataFrame, SparkSession +from pyspark.sql import functions as f +from pyspark.sql.types import ArrayType, StringType +from pyspark.sql.window import Window + +from gentropy.dataset.biosample_index import BiosampleIndex + + +def extract_ontology_from_json( + ontology_json : str, + spark : SparkSession +) -> BiosampleIndex: + """Extracts the ontology information from a JSON file. Currently only supports Uberon and Cell Ontology. + + Args: + ontology_json (str): Path to the JSON file containing the ontology information. + spark (SparkSession): Spark session. + + Returns: + BiosampleIndex: Parsed and annotated biosample index table. + """ + + def json_graph_traversal( + df : DataFrame, + node_col : str, + link_col: str, + traversal_type: str + ) -> DataFrame: + """Traverse a graph represented in a DataFrame to find all ancestors or descendants. + + Args: + df (DataFrame): DataFrame containing the graph data. + node_col (str): Column name for the node. + link_col (str): Column name for the link. + traversal_type (str): Type of traversal - "ancestors" or "descendants". + + Returns: + DataFrame: DataFrame with the result column added. + """ + # Collect graph data as a map + graph_map = df.select(node_col, link_col).rdd.collectAsMap() + broadcasted_graph = spark.sparkContext.broadcast(graph_map) + + def get_relationships( + node : str + ) -> list[str]: + """Get all relationships for a given node. + + Args: + node (str): Node ID. + + Returns: + list[str]: List of relationships. + """ + relationships = set() + stack = [node] + while stack: + current = stack.pop() + if current in broadcasted_graph.value: + current_links = broadcasted_graph.value[current] + stack.extend(current_links) + relationships.update(current_links) + return list(relationships) + + # Choose column name based on traversal type + result_col = "ancestors" if traversal_type == "ancestors" else "descendants" + + # Register the UDF based on traversal type + relationship_udf = f.udf(get_relationships, ArrayType(StringType())) + + # Apply the UDF to create the result column + return df.withColumn(result_col, relationship_udf(f.col(node_col))) + + # Load the JSON file + df = spark.read.json(ontology_json, multiLine=True) + + # Exploding the 'graphs' array to make individual records easier to access + df_graphs = df.select(f.explode_outer("graphs").alias("graph")) + + # Exploding the 'nodes' array within each graph + df_nodes = df_graphs.select( + f.col("graph.id").alias("graph_id"), + f.explode_outer("graph.nodes").alias("node")) + + # Exploding the 'edges' array within each graph for relationship data + df_edges = df_graphs.select( + f.col("graph.id").alias("graph_id"), + f.explode_outer("graph.edges").alias("edge") + ).select( + f.col("edge.sub").alias("subject"), + f.col("edge.pred").alias("predicate"), + f.col("edge.obj").alias("object") + ) + df_edges = df_edges.withColumn("subject", f.regexp_replace(f.col("subject"), "http://purl.obolibrary.org/obo/", "")) + df_edges = df_edges.withColumn("object", f.regexp_replace(f.col("object"), "http://purl.obolibrary.org/obo/", "")) + + # Extract the relevant information from the nodes + transformed_df = df_nodes.select( + f.regexp_replace(f.col("node.id"), "http://purl.obolibrary.org/obo/", "").alias("biosampleId"), + f.coalesce(f.col("node.lbl"), f.col("node.id")).alias("biosampleName"), + f.col("node.meta.definition.val").alias("description"), + f.collect_set(f.col("node.meta.xrefs.val")).over(Window.partitionBy("node.id")).getItem(0).alias("xrefs"), + f.collect_set(f.col("node.meta.synonyms.val")).over(Window.partitionBy("node.id")).getItem(0).alias("synonyms")) + + + # Extract the relationships from the edges + # Prepare relationship-specific DataFrames + df_parents = df_edges.filter(f.col("predicate") == "is_a").select("subject", "object").withColumnRenamed("object", "parent") + df_children = df_edges.filter(f.col("predicate") == "is_a").select("object", "subject").withColumnRenamed("subject", "child") + + # Aggregate relationships back to nodes + df_parents_grouped = df_parents.groupBy("subject").agg(f.array_distinct(f.collect_list("parent")).alias("parents")) + df_children_grouped = df_children.groupBy("object").agg(f.array_distinct(f.collect_list("child")).alias("children")) + + # Get all ancestors + df_with_ancestors = json_graph_traversal(df_parents_grouped, "subject", "parents", "ancestors") + # Get all descendants + df_with_descendants = json_graph_traversal(df_children_grouped, "object", "children", "descendants") + + # Join the ancestor and descendant DataFrames + df_with_relationships = df_with_ancestors.join(df_with_descendants, df_with_ancestors.subject == df_with_descendants.object, "full_outer").withColumn("biosampleId", f.coalesce(df_with_ancestors.subject, df_with_descendants.object)).drop("subject", "object") + + # Join the original DataFrame with the relationship DataFrame + final_df = transformed_df.join(df_with_relationships, ["biosampleId"], "left") + + return BiosampleIndex( + _df=final_df, + _schema=BiosampleIndex.get_schema() + ) diff --git a/src/gentropy/study_validation.py b/src/gentropy/study_validation.py index 565aa410d..e1337dd00 100644 --- a/src/gentropy/study_validation.py +++ b/src/gentropy/study_validation.py @@ -5,6 +5,7 @@ from pyspark.sql import functions as f from gentropy.common.session import Session +from gentropy.dataset.biosample_index import BiosampleIndex from gentropy.dataset.gene_index import GeneIndex from gentropy.dataset.study_index import StudyIndex @@ -22,6 +23,7 @@ def __init__( study_index_path: list[str], target_index_path: str, disease_index_path: str, + biosample_index_path: str, valid_study_index_path: str, invalid_study_index_path: str, invalid_qc_reasons: list[str] = [], @@ -33,12 +35,14 @@ def __init__( study_index_path (list[str]): Path to study index file. target_index_path (str): Path to target index file. disease_index_path (str): Path to disease index file. + biosample_index_path (str): Path to biosample index file. valid_study_index_path (str): Path to write the valid records. invalid_study_index_path (str): Path to write the output file. invalid_qc_reasons (list[str]): List of invalid quality check reason names from `StudyQualityCheck` (e.g. ['DUPLICATED_STUDY']). """ # Reading datasets: target_index = GeneIndex.from_parquet(session, target_index_path) + biosample_index = BiosampleIndex.from_parquet(session, biosample_index_path) # Reading disease index and pre-process. # This logic does not belong anywhere, but gentorpy has no disease dataset yet. disease_index = ( @@ -62,6 +66,7 @@ def __init__( .validate_study_type() # Flagging non-supported study types. .validate_target(target_index) # Flagging QTL studies with invalid targets .validate_disease(disease_index) # Flagging invalid EFOs + .validate_biosample(biosample_index) # Flagging studies with invalid biosamples ).persist() # we will need this for 2 types of outputs study_index_with_qc.valid_rows( diff --git a/tests/gentropy/conftest.py b/tests/gentropy/conftest.py index 93ee38471..4045833f9 100644 --- a/tests/gentropy/conftest.py +++ b/tests/gentropy/conftest.py @@ -13,6 +13,7 @@ from gentropy.common.Liftover import LiftOverSpark from gentropy.common.session import Session +from gentropy.dataset.biosample_index import BiosampleIndex from gentropy.dataset.colocalisation import Colocalisation from gentropy.dataset.gene_index import GeneIndex from gentropy.dataset.intervals import Intervals @@ -559,6 +560,35 @@ def mock_gene_index(spark: SparkSession) -> GeneIndex: return GeneIndex(_df=data_spec.build(), _schema=gi_schema) +@pytest.fixture() +def mock_biosample_index(spark: SparkSession) -> BiosampleIndex: + """Mock biosample index dataset.""" + bi_schema = BiosampleIndex.get_schema() + + # Makes arrays of varying length with random integers between 1 and 100 + array_expression = "transform(sequence(1, 1 + floor(rand() * 9)), x -> cast((rand() * 100) as int))" + + data_spec = ( + dg.DataGenerator( + spark, + rows=400, + partitions=4, + randomSeedMethod="hash_fieldname", + ) + .withSchema(bi_schema) + .withColumnSpec("biosampleName", percentNulls=0.1) + .withColumnSpec("description", percentNulls=0.1) + .withColumnSpec("xrefs", expr=array_expression, percentNulls=0.1) + .withColumnSpec("synonyms", expr=array_expression, percentNulls=0.1) + .withColumnSpec("parents", expr=array_expression, percentNulls=0.1) + .withColumnSpec("ancestors", expr=array_expression, percentNulls=0.1) + .withColumnSpec("descendants", expr=array_expression, percentNulls=0.1) + .withColumnSpec("children", expr=array_expression, percentNulls=0.1) + ) + + return BiosampleIndex(_df=data_spec.build(), _schema=bi_schema) + + @pytest.fixture() def liftover_chain_37_to_38(spark: SparkSession) -> LiftOverSpark: """Sample liftover chain file.""" diff --git a/tests/gentropy/data_samples/cell_ontology_sample.json b/tests/gentropy/data_samples/cell_ontology_sample.json new file mode 100644 index 000000000..5e73bfdee --- /dev/null +++ b/tests/gentropy/data_samples/cell_ontology_sample.json @@ -0,0 +1,351 @@ +{ + "graphs": [ + { + "id": "http://purl.obolibrary.org/obo/cl.json", + "meta": { + "basicPropertyValues": [ + { + "pred": "http://purl.obolibrary.org/obo/IAO_0000700", + "val": "http://purl.obolibrary.org/obo/CL_0000000" + }, + { + "pred": "http://purl.org/dc/elements/1.1/description", + "val": "An ontology of cell types." + }, + { + "pred": "http://purl.org/dc/elements/1.1/title", + "val": "Cell Ontology" + }, + { + "pred": "http://purl.org/dc/terms/contributor", + "val": "https://orcid.org/0000-0001-5208-3432" + }, + { + "pred": "http://purl.org/dc/terms/contributor", + "val": "https://orcid.org/0000-0001-9114-8737" + }, + { + "pred": "http://purl.org/dc/terms/contributor", + "val": "https://orcid.org/0000-0001-9990-8331" + }, + { + "pred": "http://purl.org/dc/terms/contributor", + "val": "https://orcid.org/0000-0002-2244-7917" + }, + { + "pred": "http://purl.org/dc/terms/contributor", + "val": "https://orcid.org/0000-0002-6601-2165" + }, + { + "pred": "http://purl.org/dc/terms/contributor", + "val": "https://orcid.org/0000-0002-7073-9172" + }, + { + "pred": "http://purl.org/dc/terms/contributor", + "val": "https://orcid.org/0000-0002-8688-6599" + }, + { + "pred": "http://purl.org/dc/terms/contributor", + "val": "https://orcid.org/0000-0002-9900-7880" + }, + { + "pred": "http://purl.org/dc/terms/contributor", + "val": "https://orcid.org/0000-0003-1980-3228" + }, + { + "pred": "http://purl.org/dc/terms/license", + "val": "http://creativecommons.org/licenses/by/4.0/" + }, + { + "pred": "http://www.w3.org/2000/01/rdf-schema#comment", + "val": "See PMID:15693950, PMID:12799354, PMID:20123131, PMID:21208450; Contact Alexander Diehl, addiehl@buffalo.edu, university at buffalo." + }, + { + "pred": "http://www.w3.org/2002/07/owl#versionInfo", + "val": "2024-08-16" + } + ], + "version": "http://purl.obolibrary.org/obo/cl/releases/2024-08-16/cl.json" + }, + "nodes": [ + { + "id": "http://purl.obolibrary.org/obo/CL_0000653", + "lbl": "podocyte", + "type": "CLASS", + "meta": { + "definition": { + "val": "A specialized kidney epithelial cell, contained within a glomerulus, that contains \"feet\" that interdigitate with the \"feet\" of other podocytes.", + "xrefs": ["GOC:tfm", "https://doi.org/10.1101/2021.10.10.463829"] + }, + "subsets": [ + "http://purl.obolibrary.org/obo/cl#cellxgene_subset", + "http://purl.obolibrary.org/obo/uberon/core#human_reference_atlas" + ], + "synonyms": [ + { + "pred": "hasBroadSynonym", + "val": "epithelial cell of visceral layer of glomerular capsule", + "xrefs": ["FMA:70967"] + }, + { + "pred": "hasExactSynonym", + "val": "glomerular podocyte", + "xrefs": ["FMA:70967"] + }, + { + "pred": "hasExactSynonym", + "val": "glomerular visceral epithelial cell" + }, + { + "pred": "hasExactSynonym", + "val": "kidney podocyte" + }, + { + "pred": "hasExactSynonym", + "val": "renal podocyte" + } + ], + "xrefs": [ + { + "val": "BTO:0002295" + }, + { + "val": "FMA:70967" + }, + { + "val": "ZFA:0009285" + } + ], + "basicPropertyValues": [ + { + "pred": "http://purl.obolibrary.org/obo/RO_0002175", + "val": "http://purl.obolibrary.org/obo/NCBITaxon_9606" + }, + { + "pred": "http://www.w3.org/2000/01/rdf-schema#seeAlso", + "val": "https://github.com/obophenotype/cell-ontology/issues/1460" + } + ] + } + }, + { + "id": "http://purl.obolibrary.org/obo/CL_0000654", + "lbl": "primary oocyte", + "type": "CLASS", + "meta": { + "definition": { + "val": "A primary oocyte is an oocyte that has not completed female meosis I.", + "xrefs": ["GOC:tfm", "ISBN:0721662544"] + }, + "subsets": [ + "http://purl.obolibrary.org/obo/uberon/core#human_reference_atlas" + ], + "synonyms": [ + { + "pred": "hasRelatedSynonym", + "val": "primary oogonium" + } + ], + "xrefs": [ + { + "val": "BTO:0000512" + }, + { + "val": "FMA:18645" + } + ], + "basicPropertyValues": [ + { + "pred": "http://purl.obolibrary.org/obo/RO_0002175", + "val": "http://purl.obolibrary.org/obo/NCBITaxon_9606" + } + ] + } + }, + { + "id": "http://purl.obolibrary.org/obo/CL_0000655", + "lbl": "secondary oocyte", + "type": "CLASS", + "meta": { + "definition": { + "val": "A secondary oocyte is an oocyte that has not completed meiosis II.", + "xrefs": ["GOC:tfm", "ISBN:0721662544"] + }, + "synonyms": [ + { + "pred": "hasRelatedSynonym", + "val": "primary oogonium" + } + ], + "xrefs": [ + { + "val": "BTO:0003094" + }, + { + "val": "FMA:18646" + } + ] + } + }, + { + "id": "http://purl.obolibrary.org/obo/CL_0000656", + "lbl": "primary spermatocyte", + "type": "CLASS", + "meta": { + "definition": { + "val": "A diploid cell that has derived from a spermatogonium and can subsequently begin meiosis and divide into two haploid secondary spermatocytes.", + "xrefs": ["GOC:tfm", "ISBN:0721662544"] + }, + "xrefs": [ + { + "val": "BTO:0001115" + }, + { + "val": "CALOHA:TS-2194" + }, + { + "val": "FMA:72292" + } + ] + } + }, + { + "id": "http://purl.obolibrary.org/obo/CL_0000657", + "lbl": "secondary spermatocyte", + "type": "CLASS", + "meta": { + "definition": { + "val": "One of the two haploid cells into which a primary spermatocyte divides, and which in turn gives origin to spermatids.", + "xrefs": ["GOC:tfm", "ISBN:0721662544"] + }, + "xrefs": [ + { + "val": "BTO:0000709" + }, + { + "val": "CALOHA:TS-2195" + }, + { + "val": "FBbt:00004941" + }, + { + "val": "FMA:72293" + } + ] + } + }, + { + "id": "http://purl.obolibrary.org/obo/CL_0000658", + "lbl": "cuticle secreting cell", + "type": "CLASS", + "meta": { + "definition": { + "val": "An epithelial cell that secretes cuticle.", + "xrefs": ["GOC:tfm"] + } + } + }, + { + "id": "http://purl.obolibrary.org/obo/CL_0000659", + "lbl": "eggshell secreting cell", + "type": "CLASS", + "meta": { + "definition": { + "val": "An extracellular matrix secreting cell that secretes eggshell.", + "xrefs": ["GOC:tfm"] + } + } + }, + { + "id": "http://purl.obolibrary.org/obo/CL_1000451", + "lbl": "obsolete epithelial cell of visceral layer of glomerular capsule", + "type": "CLASS", + "meta": { + "basicPropertyValues": [ + { + "pred": "http://purl.obolibrary.org/obo/IAO_0100001", + "val": "http://purl.obolibrary.org/obo/CL_0000653" + } + ], + "deprecated": true + } + } + ], + "edges": [ + { + "sub": "http://purl.obolibrary.org/obo/UBERON_0005751", + "pred": "http://purl.obolibrary.org/obo/BFO_0000051", + "obj": "http://purl.obolibrary.org/obo/CL_0000653" + }, + { + "sub": "http://purl.obolibrary.org/obo/GO_1903210", + "pred": "http://purl.obolibrary.org/obo/BFO_0000066", + "obj": "http://purl.obolibrary.org/obo/CL_0000653" + }, + { + "sub": "http://purl.obolibrary.org/obo/GO_0090521", + "pred": "http://purl.obolibrary.org/obo/RO_0002565", + "obj": "http://purl.obolibrary.org/obo/CL_0000653" + }, + { + "sub": "http://purl.obolibrary.org/obo/GO_0072015", + "pred": "http://purl.obolibrary.org/obo/RO_0002296", + "obj": "http://purl.obolibrary.org/obo/CL_0000653" + }, + { + "sub": "http://purl.obolibrary.org/obo/CL_4030008", + "pred": "is_a", + "obj": "http://purl.obolibrary.org/obo/CL_0000653" + }, + { + "sub": "http://purl.obolibrary.org/obo/CL_0002525", + "pred": "is_a", + "obj": "http://purl.obolibrary.org/obo/CL_0000653" + }, + { + "sub": "http://purl.obolibrary.org/obo/CL_0002523", + "pred": "is_a", + "obj": "http://purl.obolibrary.org/obo/CL_0000653" + }, + { + "sub": "http://purl.obolibrary.org/obo/CL_0000653", + "pred": "is_a", + "obj": "http://purl.obolibrary.org/obo/CL_0002522" + }, + { + "sub": "http://purl.obolibrary.org/obo/CL_0000653", + "pred": "is_a", + "obj": "http://purl.obolibrary.org/obo/CL_1000450" + }, + { + "sub": "http://purl.obolibrary.org/obo/CL_0000653", + "pred": "http://purl.obolibrary.org/obo/BFO_0000050", + "obj": "http://purl.obolibrary.org/obo/UBERON_0005751" + }, + { + "sub": "http://purl.obolibrary.org/obo/CL_0000655", + "pred": "is_a", + "obj": "http://purl.obolibrary.org/obo/CL_0000023", + "meta": { + "basicPropertyValues": [ + { + "pred": "http://www.geneontology.org/formats/oboInOwl#is_inferred", + "val": "true" + } + ] + } + }, + { + "sub": "http://purl.obolibrary.org/obo/CL_0000655", + "pred": "http://purl.obolibrary.org/obo/CL_4030044", + "obj": "http://purl.obolibrary.org/obo/GO_0007147" + }, + { + "sub": "http://purl.obolibrary.org/obo/CL_0000655", + "pred": "http://purl.obolibrary.org/obo/RO_0002202", + "obj": "http://purl.obolibrary.org/obo/CL_0000654" + } + ] + } + ] +} diff --git a/tests/gentropy/data_samples/uberon_sample.json b/tests/gentropy/data_samples/uberon_sample.json new file mode 100644 index 000000000..7dedfa23c --- /dev/null +++ b/tests/gentropy/data_samples/uberon_sample.json @@ -0,0 +1,889 @@ +{ + "graphs": [ + { + "id": "http://purl.obolibrary.org/obo/uberon.json", + "meta": { + "basicPropertyValues": [ + { + "pred": "http://purl.obolibrary.org/obo/IAO_0000700", + "val": "http://purl.obolibrary.org/obo/UBERON_0000104" + }, + { + "pred": "http://purl.obolibrary.org/obo/IAO_0000700", + "val": "http://purl.obolibrary.org/obo/UBERON_0001062" + }, + { + "pred": "http://purl.org/dc/elements/1.1/creator", + "val": "https://orcid.org/0000-0001-5839-6798" + }, + { + "pred": "http://purl.org/dc/elements/1.1/creator", + "val": "https://orcid.org/0000-0001-7972-3866" + }, + { + "pred": "http://purl.org/dc/elements/1.1/creator", + "val": "https://orcid.org/0000-0001-9114-8737" + }, + { + "pred": "http://purl.org/dc/elements/1.1/creator", + "val": "https://orcid.org/0000-0002-1810-9886" + }, + { + "pred": "http://purl.org/dc/elements/1.1/creator", + "val": "https://orcid.org/0000-0002-6601-2165" + }, + { + "pred": "http://purl.org/dc/elements/1.1/creator", + "val": "https://orcid.org/0000-0002-7356-1779" + }, + { + "pred": "http://purl.org/dc/elements/1.1/creator", + "val": "https://orcid.org/0000-0002-9611-1279" + }, + { + "pred": "http://purl.org/dc/elements/1.1/creator", + "val": "https://orcid.org/0000-0003-3162-7490" + }, + { + "pred": "http://purl.org/dc/elements/1.1/creator", + "val": "https://orcid.org/0000-0003-3308-6245" + }, + { + "pred": "http://purl.org/dc/elements/1.1/description", + "val": "Uberon is an integrated cross-species anatomy ontology representing a variety of entities classified according to traditional anatomical criteria such as structure, function and developmental lineage. The ontology includes comprehensive relationships to taxon-specific anatomical ontologies, allowing integration of functional, phenotype and expression data." + }, + { + "pred": "http://purl.org/dc/elements/1.1/publisher", + "val": "http://uberon.org" + }, + { + "pred": "http://purl.org/dc/elements/1.1/source", + "val": "http://dbpedia.org" + }, + { + "pred": "http://purl.org/dc/elements/1.1/source", + "val": "http://palaeos.com" + }, + { + "pred": "http://purl.org/dc/elements/1.1/source", + "val": "http://www.brain-map.org" + }, + { + "pred": "http://purl.org/dc/elements/1.1/source", + "val": "http://braininfo.rprc.washington.edu/" + }, + { + "pred": "http://purl.org/dc/elements/1.1/source", + "val": "http://en.wikipedia.org/wiki/" + }, + { + "pred": "http://purl.org/dc/elements/1.1/source", + "val": "http://ontology.neuinfo.org/NIF/BiomaterialEntities/NIF-GrossAnatomy.owl" + }, + { + "pred": "http://purl.org/dc/elements/1.1/source", + "val": "http://pons.incf.org/wiki/Common_Upper_Mammalian_Brain_Ontology_%28Cumbo%29" + }, + { + "pred": "http://purl.org/dc/elements/1.1/source", + "val": "http://purl.obolibrary.org/obo/aao.owl" + }, + { + "pred": "http://purl.org/dc/elements/1.1/source", + "val": "http://purl.obolibrary.org/obo/aba.owl" + }, + { + "pred": "http://purl.org/dc/elements/1.1/source", + "val": "http://purl.obolibrary.org/obo/aeo.owl" + }, + { + "pred": "http://purl.org/dc/elements/1.1/source", + "val": "http://purl.obolibrary.org/obo/bila.owl" + }, + { + "pred": "http://purl.org/dc/elements/1.1/source", + "val": "http://purl.obolibrary.org/obo/bto.owl" + }, + { + "pred": "http://purl.org/dc/elements/1.1/source", + "val": "http://purl.obolibrary.org/obo/caro.owl" + }, + { + "pred": "http://purl.org/dc/elements/1.1/source", + "val": "http://purl.obolibrary.org/obo/cl.owl" + }, + { + "pred": "http://purl.org/dc/elements/1.1/source", + "val": "http://purl.obolibrary.org/obo/ehdaa2.owl" + }, + { + "pred": "http://purl.org/dc/elements/1.1/source", + "val": "http://purl.obolibrary.org/obo/emapa.owl" + }, + { + "pred": "http://purl.org/dc/elements/1.1/source", + "val": "http://purl.obolibrary.org/obo/fbbt.owl" + }, + { + "pred": "http://purl.org/dc/elements/1.1/source", + "val": "http://purl.obolibrary.org/obo/fma.owl" + }, + { + "pred": "http://purl.org/dc/elements/1.1/source", + "val": "http://purl.obolibrary.org/obo/go.owl" + }, + { + "pred": "http://purl.org/dc/elements/1.1/source", + "val": "http://purl.obolibrary.org/obo/hp.owl" + }, + { + "pred": "http://purl.org/dc/elements/1.1/source", + "val": "http://purl.obolibrary.org/obo/ma.owl" + }, + { + "pred": "http://purl.org/dc/elements/1.1/source", + "val": "http://purl.obolibrary.org/obo/mp.owl" + }, + { + "pred": "http://purl.org/dc/elements/1.1/source", + "val": "http://purl.obolibrary.org/obo/tao.owl" + }, + { + "pred": "http://purl.org/dc/elements/1.1/source", + "val": "http://purl.obolibrary.org/obo/vhog.owl" + }, + { + "pred": "http://purl.org/dc/elements/1.1/source", + "val": "http://purl.obolibrary.org/obo/vsao.owl" + }, + { + "pred": "http://purl.org/dc/elements/1.1/source", + "val": "http://purl.obolibrary.org/obo/wbbt.owl" + }, + { + "pred": "http://purl.org/dc/elements/1.1/source", + "val": "http://purl.obolibrary.org/obo/xao.owl" + }, + { + "pred": "http://purl.org/dc/elements/1.1/source", + "val": "http://purl.obolibrary.org/obo/zfa.owl" + }, + { + "pred": "http://purl.org/dc/elements/1.1/source", + "val": "http://uri.neuinfo.org/nif/nifstd" + }, + { + "pred": "http://purl.org/dc/elements/1.1/source", + "val": "http://www.e-lico.eu/public/kupo/kupo.owl" + }, + { + "pred": "http://purl.org/dc/elements/1.1/source", + "val": "http://www.ebi.ac.uk/efo/efo.owl" + }, + { + "pred": "http://purl.org/dc/elements/1.1/source", + "val": "ISBN:0030229073 Invertebrate Zoology, Barnes" + }, + { + "pred": "http://purl.org/dc/elements/1.1/source", + "val": "ISBN:0073040584 Vertebrates, Kardong" + }, + { + "pred": "http://purl.org/dc/elements/1.1/source", + "val": "ISBN:0123813611 Comparative Anatomy and Histology: A Mouse and Human Atlas, Treuting and Dintzis" + }, + { + "pred": "http://purl.org/dc/elements/1.1/source", + "val": "ISBN:0226313379 Fins into Limbs: Evolution, Development, and Transformation, Hall" + }, + { + "pred": "http://purl.org/dc/elements/1.1/source", + "val": "ISBN:0443065837 Human embryology, Larsen" + }, + { + "pred": "http://purl.org/dc/elements/1.1/source", + "val": "ISBN:0471888893 Comparative Vertebrate Neuroanatomy: Evolution and Adaptation by Butler and Hodos" + }, + { + "pred": "http://purl.org/dc/elements/1.1/source", + "val": "ISBN:0683400088 Stedman's Medical Dictionary" + }, + { + "pred": "http://purl.org/dc/elements/1.1/source", + "val": "ISBN:1588900649 Color Atlas and Textbook of Human Anatomy: Nervous system and sensory organs By Werner Kahle, Michael Frotscher" + }, + { + "pred": "http://purl.org/dc/elements/1.1/source", + "val": "ISBN:1588903958 Principles and practice of pediatric neurosurgery By A. Leland Albright, P. David Adelson, Ian F. Pollack" + }, + { + "pred": "http://purl.org/dc/elements/1.1/source", + "val": "ISBN:1607950324 Craniofacial Embryogenetics & Development, 2nd edition, Sperber" + }, + { + "pred": "http://purl.org/dc/elements/1.1/source", + "val": "ISBN:978-0-12-369548-2 Principles of Developmental Genetics, Sally A Moody" + }, + { + "pred": "http://purl.org/dc/elements/1.1/source", + "val": "ISBN:9780120749034 The laboratory rat" + }, + { + "pred": "http://purl.org/dc/elements/1.1/source", + "val": "ISBN:9780397517251 Surgical anatomy of the hand and upper extremity. By James R. Doyle and Michael J. Botte" + }, + { + "pred": "http://purl.org/dc/elements/1.1/source", + "val": "ISBN:9780674021839 The Tree of Life - Guillaume Lecointre, Herve Le Guyader" + }, + { + "pred": "http://purl.org/dc/elements/1.1/source", + "val": "ISBN:9780878932504 Developmental Biology" + }, + { + "pred": "http://purl.org/dc/elements/1.1/source", + "val": "MESH" + }, + { + "pred": "http://purl.org/dc/elements/1.1/source", + "val": "PMID:11433360 Placental development: lessons from mouse mutants" + }, + { + "pred": "http://purl.org/dc/elements/1.1/source", + "val": "PMID:16417468 Forgotten and novel aspects in pancreas development, Pieler and Chen" + }, + { + "pred": "http://purl.org/dc/elements/1.1/source", + "val": "aggregates AAO from 13:04:2012" + }, + { + "pred": "http://purl.org/dc/elements/1.1/source", + "val": "aggregates TAO from 09:08:2012" + }, + { + "pred": "http://purl.org/dc/elements/1.1/source", + "val": "aggregates VSAO from 16:07:2012" + }, + { + "pred": "http://purl.org/dc/elements/1.1/source", + "val": "http://wiki.phenotypercn.org/wg/phenotypercn/index.php?title=Neural_Crest_Workshop" + }, + { + "pred": "http://purl.org/dc/elements/1.1/source", + "val": "http://wiki.phenotypercn.org/wiki/August_2012_Notes" + }, + { + "pred": "http://purl.org/dc/elements/1.1/source", + "val": "https://docs.google.com/document/d/16JZOuH9sh_a8uIXA4cqg0Q1H6MV5yCj3-rhuKsZoV_U/edit" + }, + { + "pred": "http://purl.org/dc/elements/1.1/source", + "val": "https://docs.google.com/document/d/1MnUgispgGfNQoezYzWzzGTnkAnI0gzRnJIwdip6MMtw/edit" + }, + { + "pred": "http://purl.org/dc/elements/1.1/source", + "val": "https://docs.google.com/document/d/1cPWBqrl_Qy7XHEWFqtR_PgQX61yRkgGuLaiDpnEXxkE/edit" + }, + { + "pred": "http://purl.org/dc/elements/1.1/source", + "val": "https://docs.google.com/document/d/1r9kNPpFYGdu0SpJDLyFAVQczBlG0wAZCBMd18gG3Ot8/edit#" + }, + { + "pred": "http://purl.org/dc/elements/1.1/source", + "val": "https://docs.google.com/spreadsheet/ccc?key=0Aj8NJdyb-leqdDM0R3hTVTRHRExDVjRCSkZEbDc5N1E#gid=0" + }, + { + "pred": "http://purl.org/dc/elements/1.1/title", + "val": "Uber-anatomy ontology" + }, + { + "pred": "http://purl.org/dc/terms/contributor", + "val": "https://github.com/orgs/pato-ontology/teams/pato-community" + }, + { + "pred": "http://purl.org/dc/terms/contributor", + "val": "https://orcid.org/0000-0001-5889-4463" + }, + { + "pred": "http://purl.org/dc/terms/contributor", + "val": "https://orcid.org/0000-0001-7433-0086" + }, + { + "pred": "http://purl.org/dc/terms/contributor", + "val": "https://orcid.org/0000-0001-7476-6306" + }, + { + "pred": "http://purl.org/dc/terms/contributor", + "val": "https://orcid.org/0000-0001-7920-5321" + }, + { + "pred": "http://purl.org/dc/terms/contributor", + "val": "https://orcid.org/0000-0001-7958-3701" + }, + { + "pred": "http://purl.org/dc/terms/contributor", + "val": "https://orcid.org/0000-0001-8682-8754" + }, + { + "pred": "http://purl.org/dc/terms/contributor", + "val": "https://orcid.org/0000-0001-9107-0714" + }, + { + "pred": "http://purl.org/dc/terms/contributor", + "val": "https://orcid.org/0000-0001-9990-8331" + }, + { + "pred": "http://purl.org/dc/terms/contributor", + "val": "https://orcid.org/0000-0002-0819-0473" + }, + { + "pred": "http://purl.org/dc/terms/contributor", + "val": "https://orcid.org/0000-0002-0956-8634" + }, + { + "pred": "http://purl.org/dc/terms/contributor", + "val": "https://orcid.org/0000-0002-1112-5832" + }, + { + "pred": "http://purl.org/dc/terms/contributor", + "val": "https://orcid.org/0000-0002-1572-1316" + }, + { + "pred": "http://purl.org/dc/terms/contributor", + "val": "https://orcid.org/0000-0002-1604-3078" + }, + { + "pred": "http://purl.org/dc/terms/contributor", + "val": "https://orcid.org/0000-0002-1615-2899" + }, + { + "pred": "http://purl.org/dc/terms/contributor", + "val": "https://orcid.org/0000-0002-2061-091X" + }, + { + "pred": "http://purl.org/dc/terms/contributor", + "val": "https://orcid.org/0000-0002-2244-7917" + }, + { + "pred": "http://purl.org/dc/terms/contributor", + "val": "https://orcid.org/0000-0002-3437-3329" + }, + { + "pred": "http://purl.org/dc/terms/contributor", + "val": "https://orcid.org/0000-0002-3467-2636" + }, + { + "pred": "http://purl.org/dc/terms/contributor", + "val": "https://orcid.org/0000-0002-3734-1859" + }, + { + "pred": "http://purl.org/dc/terms/contributor", + "val": "https://orcid.org/0000-0002-5111-7263" + }, + { + "pred": "http://purl.org/dc/terms/contributor", + "val": "https://orcid.org/0000-0002-6490-7723" + }, + { + "pred": "http://purl.org/dc/terms/contributor", + "val": "https://orcid.org/0000-0002-7073-9172" + }, + { + "pred": "http://purl.org/dc/terms/contributor", + "val": "https://orcid.org/0000-0002-8406-3871" + }, + { + "pred": "http://purl.org/dc/terms/contributor", + "val": "https://orcid.org/0000-0002-8455-3213" + }, + { + "pred": "http://purl.org/dc/terms/contributor", + "val": "https://orcid.org/0000-0002-8688-6599" + }, + { + "pred": "http://purl.org/dc/terms/contributor", + "val": "https://orcid.org/0000-0002-9415-5104" + }, + { + "pred": "http://purl.org/dc/terms/contributor", + "val": "https://orcid.org/0000-0002-9818-3030" + }, + { + "pred": "http://purl.org/dc/terms/contributor", + "val": "https://orcid.org/0000-0002-9900-7880" + }, + { + "pred": "http://purl.org/dc/terms/contributor", + "val": "https://orcid.org/0000-0003-1980-3228" + }, + { + "pred": "http://purl.org/dc/terms/contributor", + "val": "https://orcid.org/0000-0003-2105-2283" + }, + { + "pred": "http://purl.org/dc/terms/contributor", + "val": "https://orcid.org/0000-0003-2338-2550" + }, + { + "pred": "http://purl.org/dc/terms/contributor", + "val": "https://orcid.org/0000-0003-3691-0324" + }, + { + "pred": "http://purl.org/dc/terms/contributor", + "val": "https://orcid.org/0000-0003-4423-4370" + }, + { + "pred": "http://purl.org/dc/terms/contributor", + "val": "https://www.wikidata.org/wiki/Q11695472" + }, + { + "pred": "http://purl.org/dc/terms/contributor", + "val": "https://www.wikidata.org/wiki/Q23809253" + }, + { + "pred": "http://purl.org/dc/terms/contributor", + "val": "https://www.wikidata.org/wiki/Q4964264" + }, + { + "pred": "http://purl.org/dc/terms/contributor", + "val": "https://www.wikidata.org/wiki/Q54985720" + }, + { + "pred": "http://purl.org/dc/terms/contributor", + "val": "https://www.wikidata.org/wiki/Q6983890" + }, + { + "pred": "http://purl.org/dc/terms/contributor", + "val": "https://www.wikidata.org/wiki/Q7650732" + }, + { + "pred": "http://purl.org/dc/terms/contributor", + "val": "https://www.wikidata.org/wiki/Q85793053" + }, + { + "pred": "http://purl.org/dc/terms/isReferencedBy", + "val": "http://genomebiology.com/2012/13/1/R5" + }, + { + "pred": "http://purl.org/dc/terms/isReferencedBy", + "val": "http://www.ncbi.nlm.nih.gov/pubmed/22293552" + }, + { + "pred": "http://purl.org/dc/terms/license", + "val": "http://creativecommons.org/licenses/by/3.0/" + }, + { + "pred": "http://usefulinc.com/ns/doap#GitRepository", + "val": "https://github.com/cmungall/uberon/" + }, + { + "pred": "http://usefulinc.com/ns/doap#SVNRepository", + "val": "https://obo.svn.sourceforge.net/svnroot/obo/uberon/" + }, + { + "pred": "http://usefulinc.com/ns/doap#bug-database", + "val": "https://github.com/obophenotype/uberon/issues/" + }, + { + "pred": "http://usefulinc.com/ns/doap#mailing-list", + "val": "https://lists.sourceforge.net/lists/listinfo/obo-anatomy" + }, + { + "pred": "http://www.geneontology.org/formats/oboInOwl#default-namespace", + "val": "uberon" + }, + { + "pred": "http://www.geneontology.org/formats/oboInOwl#hasOBOFormatVersion", + "val": "1.2" + }, + { + "pred": "http://www.geneontology.org/formats/oboInOwl#treat-xrefs-as-equivalent", + "val": "AEO" + }, + { + "pred": "http://www.geneontology.org/formats/oboInOwl#treat-xrefs-as-equivalent", + "val": "BILA" + }, + { + "pred": "http://www.geneontology.org/formats/oboInOwl#treat-xrefs-as-equivalent", + "val": "BSPO" + }, + { + "pred": "http://www.geneontology.org/formats/oboInOwl#treat-xrefs-as-equivalent", + "val": "CARO" + }, + { + "pred": "http://www.geneontology.org/formats/oboInOwl#treat-xrefs-as-equivalent", + "val": "GO" + }, + { + "pred": "http://www.geneontology.org/formats/oboInOwl#treat-xrefs-as-equivalent", + "val": "OG" + }, + { + "pred": "http://www.geneontology.org/formats/oboInOwl#treat-xrefs-as-equivalent", + "val": "VSAO" + }, + { + "pred": "http://www.geneontology.org/formats/oboInOwl#treat-xrefs-as-has-subclass", + "val": "EHDAA" + }, + { + "pred": "http://www.geneontology.org/formats/oboInOwl#treat-xrefs-as-has-subclass", + "val": "EV" + }, + { + "pred": "http://www.geneontology.org/formats/oboInOwl#treat-xrefs-as-has-subclass", + "val": "NCIT" + }, + { + "pred": "http://www.geneontology.org/formats/oboInOwl#treat-xrefs-as-has-subclass", + "val": "OGES" + }, + { + "pred": "http://www.geneontology.org/formats/oboInOwl#treat-xrefs-as-has-subclass", + "val": "SCTID" + }, + { + "pred": "http://www.geneontology.org/formats/oboInOwl#treat-xrefs-as-is_a", + "val": "BFO" + }, + { + "pred": "http://www.geneontology.org/formats/oboInOwl#treat-xrefs-as-is_a", + "val": "VHOG" + }, + { + "pred": "http://www.geneontology.org/formats/oboInOwl#treat-xrefs-as-reverse-genus-differentia", + "val": "AAO part_of NCBITaxon:8292" + }, + { + "pred": "http://www.geneontology.org/formats/oboInOwl#treat-xrefs-as-reverse-genus-differentia", + "val": "DHBA part_of NCBITaxon:9606" + }, + { + "pred": "http://www.geneontology.org/formats/oboInOwl#treat-xrefs-as-reverse-genus-differentia", + "val": "EHDAA2 part_of NCBITaxon:9606" + }, + { + "pred": "http://www.geneontology.org/formats/oboInOwl#treat-xrefs-as-reverse-genus-differentia", + "val": "EMAPA part_of NCBITaxon:10090" + }, + { + "pred": "http://www.geneontology.org/formats/oboInOwl#treat-xrefs-as-reverse-genus-differentia", + "val": "FBdv part_of NCBITaxon:7227" + }, + { + "pred": "http://www.geneontology.org/formats/oboInOwl#treat-xrefs-as-reverse-genus-differentia", + "val": "FMA part_of NCBITaxon:9606" + }, + { + "pred": "http://www.geneontology.org/formats/oboInOwl#treat-xrefs-as-reverse-genus-differentia", + "val": "HAO part_of NCBITaxon:7399" + }, + { + "pred": "http://www.geneontology.org/formats/oboInOwl#treat-xrefs-as-reverse-genus-differentia", + "val": "HBA part_of NCBITaxon:9606" + }, + { + "pred": "http://www.geneontology.org/formats/oboInOwl#treat-xrefs-as-reverse-genus-differentia", + "val": "HsapDv part_of NCBITaxon:9606" + }, + { + "pred": "http://www.geneontology.org/formats/oboInOwl#treat-xrefs-as-reverse-genus-differentia", + "val": "KUPO part_of NCBITaxon:9606" + }, + { + "pred": "http://www.geneontology.org/formats/oboInOwl#treat-xrefs-as-reverse-genus-differentia", + "val": "MA part_of NCBITaxon:10090" + }, + { + "pred": "http://www.geneontology.org/formats/oboInOwl#treat-xrefs-as-reverse-genus-differentia", + "val": "MFO part_of NCBITaxon:8089" + }, + { + "pred": "http://www.geneontology.org/formats/oboInOwl#treat-xrefs-as-reverse-genus-differentia", + "val": "MmusDv part_of NCBITaxon:10090" + }, + { + "pred": "http://www.geneontology.org/formats/oboInOwl#treat-xrefs-as-reverse-genus-differentia", + "val": "OlatDv part_of NCBITaxon:8089" + }, + { + "pred": "http://www.geneontology.org/formats/oboInOwl#treat-xrefs-as-reverse-genus-differentia", + "val": "PBA part_of NCBITaxon:9443" + }, + { + "pred": "http://www.geneontology.org/formats/oboInOwl#treat-xrefs-as-reverse-genus-differentia", + "val": "SPD part_of NCBITaxon:6893" + }, + { + "pred": "http://www.geneontology.org/formats/oboInOwl#treat-xrefs-as-reverse-genus-differentia", + "val": "TADS part_of NCBITaxon:6939" + }, + { + "pred": "http://www.geneontology.org/formats/oboInOwl#treat-xrefs-as-reverse-genus-differentia", + "val": "TAO part_of NCBITaxon:32443" + }, + { + "pred": "http://www.geneontology.org/formats/oboInOwl#treat-xrefs-as-reverse-genus-differentia", + "val": "TGMA part_of NCBITaxon:44484" + }, + { + "pred": "http://www.geneontology.org/formats/oboInOwl#treat-xrefs-as-reverse-genus-differentia", + "val": "WBbt part_of NCBITaxon:6237" + }, + { + "pred": "http://www.geneontology.org/formats/oboInOwl#treat-xrefs-as-reverse-genus-differentia", + "val": "WBls part_of NCBITaxon:6237" + }, + { + "pred": "http://www.geneontology.org/formats/oboInOwl#treat-xrefs-as-reverse-genus-differentia", + "val": "XAO part_of NCBITaxon:8353" + }, + { + "pred": "http://www.geneontology.org/formats/oboInOwl#treat-xrefs-as-reverse-genus-differentia", + "val": "ZFA part_of NCBITaxon:7954" + }, + { + "pred": "http://www.geneontology.org/formats/oboInOwl#treat-xrefs-as-reverse-genus-differentia", + "val": "ZFS part_of NCBITaxon:7954" + }, + { + "pred": "http://www.w3.org/2000/01/rdf-schema#comment", + "val": "Aurelie Comte, Bill Bug, Catherine Leroy, Duncan Davidson and Trish Whetzel are also contributors. However their ORCIDs were not found." + }, + { + "pred": "http://www.w3.org/2002/07/owl#versionInfo", + "val": "2024-09-03" + }, + { + "pred": "http://xmlns.com/foaf/0.1/homepage", + "val": "http://uberon.org" + } + ], + "version": "http://purl.obolibrary.org/obo/uberon/releases/2024-09-03/uberon.json" + }, + "nodes": [ + { + "id": "http://purl.obolibrary.org/obo/CL_1001593", + "lbl": "parathyroid glandular cell", + "type": "CLASS", + "meta": { + "definition": { + "val": "Glandular cell of parathyroid epithelium. Example: Parathyroid chief cell and parathyroid oxyphil cells.", + "xrefs": ["HPA:HPA", "NPX:PDR"] + }, + "synonyms": [ + { + "pred": "hasRelatedSynonym", + "val": "parathyroid gland glandular cell", + "xrefs": ["CALOHA:TS-1279"] + }, + { + "pred": "hasRelatedSynonym", + "val": "parathyroid gland glandular cells", + "xrefs": ["CALOHA:TS-1279"] + } + ], + "xrefs": [ + { + "val": "CALOHA:TS-1279" + } + ] + } + }, + { + "id": "http://purl.obolibrary.org/obo/CL_1001595", + "lbl": "rectum glandular cell", + "type": "CLASS", + "meta": { + "definition": { + "val": "Glandular cell of rectal epithelium. Example: Goblet cell; enterocytes or absorptive cells; enteroendocrine and M cells.", + "xrefs": ["NPX:PDR"] + }, + "synonyms": [ + { + "pred": "hasRelatedSynonym", + "val": "rectal glandular cell", + "xrefs": ["CALOHA:TS-1281"] + }, + { + "pred": "hasRelatedSynonym", + "val": "rectum glandular cells", + "xrefs": ["CALOHA:TS-1281"] + } + ], + "xrefs": [ + { + "val": "CALOHA:TS-1281" + } + ] + } + }, + { + "id": "http://purl.obolibrary.org/obo/CL_1001596", + "lbl": "salivary gland glandular cell", + "type": "CLASS", + "meta": { + "definition": { + "val": "Glandular cell of salivary gland. Example: Serous cells, mucous cells, cuboidal epithelial cells of the intercalated ducts, simple cuboidal epithelium of the striated ducts, epithelial cells of excretory ducts.", + "xrefs": ["HPA:HPA", "NPX:PDR"] + }, + "synonyms": [ + { + "pred": "hasRelatedSynonym", + "val": "salivary gland glandular cells", + "xrefs": ["CALOHA:TS-1282"] + } + ], + "xrefs": [ + { + "val": "CALOHA:TS-1282" + } + ] + } + }, + { + "id": "http://purl.obolibrary.org/obo/CL_0000653", + "lbl": "podocyte", + "type": "CLASS", + "meta": { + "definition": { + "val": "A specialized kidney epithelial cell, contained within a glomerulus, that contains \"feet\" that interdigitate with the \"feet\" of other podocytes.", + "xrefs": ["GOC:tfm", "https://doi.org/10.1101/2021.10.10.463829"] + }, + "subsets": [ + "http://purl.obolibrary.org/obo/cl#cellxgene_subset", + "http://purl.obolibrary.org/obo/uberon/core#human_reference_atlas" + ], + "synonyms": [ + { + "pred": "hasBroadSynonym", + "val": "epithelial cell of visceral layer of glomerular capsule", + "xrefs": ["FMA:70967"] + }, + { + "pred": "hasExactSynonym", + "val": "glomerular podocyte", + "xrefs": ["FMA:70967"] + }, + { + "pred": "hasExactSynonym", + "val": "glomerular visceral epithelial cell" + }, + { + "pred": "hasExactSynonym", + "val": "kidney podocyte" + }, + { + "pred": "hasExactSynonym", + "val": "renal podocyte" + } + ], + "xrefs": [ + { + "val": "BTO:0002295" + }, + { + "val": "FMA:70967" + } + ], + "basicPropertyValues": [ + { + "pred": "http://purl.obolibrary.org/obo/RO_0002175", + "val": "http://purl.obolibrary.org/obo/NCBITaxon_9606" + }, + { + "pred": "http://www.w3.org/2000/01/rdf-schema#seeAlso", + "val": "https://github.com/obophenotype/cell-ontology/issues/1460" + } + ] + } + } + ], + "edges": [ + { + "sub": "http://purl.obolibrary.org/obo/CL_1001596", + "pred": "is_a", + "obj": "http://purl.obolibrary.org/obo/CL_0000150" + }, + { + "sub": "http://purl.obolibrary.org/obo/CL_1001596", + "pred": "is_a", + "obj": "http://purl.obolibrary.org/obo/CL_0000152" + }, + { + "sub": "http://purl.obolibrary.org/obo/CL_1001596", + "pred": "is_a", + "obj": "http://purl.obolibrary.org/obo/CL_0002251" + }, + { + "sub": "http://purl.obolibrary.org/obo/CL_1001596", + "pred": "http://purl.obolibrary.org/obo/BFO_0000050", + "obj": "http://purl.obolibrary.org/obo/UBERON_0001044" + }, + { + "sub": "http://purl.obolibrary.org/obo/CL_1001596", + "pred": "http://purl.obolibrary.org/obo/BFO_0000050", + "obj": "http://purl.obolibrary.org/obo/UBERON_0004809" + }, + { + "sub": "http://purl.obolibrary.org/obo/CL_0002623", + "pred": "is_a", + "obj": "http://purl.obolibrary.org/obo/CL_0000622", + "meta": { + "basicPropertyValues": [ + { + "pred": "http://www.geneontology.org/formats/oboInOwl#is_inferred", + "val": "true" + } + ] + } + }, + { + "sub": "http://purl.obolibrary.org/obo/CL_0002623", + "pred": "is_a", + "obj": "http://purl.obolibrary.org/obo/CL_1001596" + }, + { + "sub": "http://purl.obolibrary.org/obo/CL_0002623", + "pred": "http://purl.obolibrary.org/obo/BFO_0000050", + "obj": "http://purl.obolibrary.org/obo/UBERON_0001044" + }, + { + "sub": "http://purl.obolibrary.org/obo/CL_0002623", + "pred": "is_a", + "obj": "http://purl.obolibrary.org/obo/CL_0000622", + "meta": { + "basicPropertyValues": [ + { + "pred": "http://www.geneontology.org/formats/oboInOwl#is_inferred", + "val": "true" + } + ] + } + }, + { + "sub": "http://purl.obolibrary.org/obo/CL_0002623", + "pred": "is_a", + "obj": "http://purl.obolibrary.org/obo/CL_1001596" + }, + { + "sub": "http://purl.obolibrary.org/obo/CL_0002623", + "pred": "http://purl.obolibrary.org/obo/BFO_0000050", + "obj": "http://purl.obolibrary.org/obo/UBERON_0001044" + }, + { + "sub": "http://purl.obolibrary.org/obo/CL_0000653", + "pred": "is_a", + "obj": "http://purl.obolibrary.org/obo/CL_1000450" + }, + { + "sub": "http://purl.obolibrary.org/obo/CL_0000653", + "pred": "http://purl.obolibrary.org/obo/BFO_0000050", + "obj": "http://purl.obolibrary.org/obo/UBERON_0005751" + } + ] + } + ] +} diff --git a/tests/gentropy/dataset/test_biosample_index.py b/tests/gentropy/dataset/test_biosample_index.py new file mode 100644 index 000000000..c647710d1 --- /dev/null +++ b/tests/gentropy/dataset/test_biosample_index.py @@ -0,0 +1,8 @@ +"""Tests on Biosample index.""" + +from gentropy.dataset.biosample_index import BiosampleIndex + + +def test_biosample_index_creation(mock_biosample_index: BiosampleIndex) -> None: + """Test biosample index creation with mock biosample index.""" + assert isinstance(mock_biosample_index, BiosampleIndex) diff --git a/tests/gentropy/datasource/biosample_ontologies/test_biosample_ontology.py b/tests/gentropy/datasource/biosample_ontologies/test_biosample_ontology.py new file mode 100644 index 000000000..b88623b0d --- /dev/null +++ b/tests/gentropy/datasource/biosample_ontologies/test_biosample_ontology.py @@ -0,0 +1,50 @@ +"""Tests for biosample index dataset.""" + +from __future__ import annotations + +from typing import TYPE_CHECKING + +from gentropy.dataset.biosample_index import BiosampleIndex +from gentropy.datasource.biosample_ontologies.utils import extract_ontology_from_json + +if TYPE_CHECKING: + from pyspark.sql import SparkSession + + +class TestOntologyParger: + """Testing ontology parser.""" + + SAMPLE_CELL_ONTOLOGY_PATH = "tests/gentropy/data_samples/cell_ontology_sample.json" + SAMPLE_UBERON_PATH = "tests/gentropy/data_samples/uberon_sample.json" + + def test_cell_ontology_parser( + self: TestOntologyParger, spark: SparkSession + ) -> None: + """Test cell ontology parser.""" + cell_ontology = extract_ontology_from_json( + self.SAMPLE_CELL_ONTOLOGY_PATH, spark + ) + assert isinstance( + cell_ontology, BiosampleIndex + ), "Cell ontology subset is not parsed correctly to BiosampleIndex." + + def test_uberon_parser(self: TestOntologyParger, spark: SparkSession) -> None: + """Test uberon parser.""" + uberon = extract_ontology_from_json(self.SAMPLE_UBERON_PATH, spark) + assert isinstance( + uberon, BiosampleIndex + ), "Uberon subset is not parsed correctly to BiosampleIndex." + + def test_merge_biosample_indices( + self: TestOntologyParger, spark: SparkSession + ) -> None: + """Test merging of biosample indices.""" + cell_ontology = extract_ontology_from_json( + self.SAMPLE_CELL_ONTOLOGY_PATH, spark + ) + uberon = extract_ontology_from_json(self.SAMPLE_UBERON_PATH, spark) + + merged = cell_ontology.merge_indices([uberon]) + assert isinstance( + merged, BiosampleIndex + ), "Merging of biosample indices is not correct." From 84d663849716a61fa40642959d80300dd99842fc Mon Sep 17 00:00:00 2001 From: David Ochoa Date: Tue, 24 Sep 2024 16:57:29 +0100 Subject: [PATCH 052/188] feat: 99% credible set validation during `study_locus_validation` (#765) * feat: study locus validation filters for 95% credible sets * revert: no longer needed to filter for credible set interval * feat: annotate credible sets before filter them * docs: adding more context here --- src/gentropy/colocalisation.py | 6 ++---- src/gentropy/dataset/study_locus.py | 4 ++-- src/gentropy/pics.py | 6 ++---- src/gentropy/study_locus_validation.py | 4 +++- 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/gentropy/colocalisation.py b/src/gentropy/colocalisation.py index 4f8431b98..0dcdff206 100644 --- a/src/gentropy/colocalisation.py +++ b/src/gentropy/colocalisation.py @@ -8,7 +8,7 @@ from pyspark.sql.functions import col from gentropy.common.session import Session -from gentropy.dataset.study_locus import CredibleInterval, StudyLocus +from gentropy.dataset.study_locus import StudyLocus from gentropy.method.colocalisation import Coloc @@ -46,9 +46,7 @@ def __init__( ) # Transform - overlaps = credible_set.filter_credible_set( - CredibleInterval.IS95 - ).find_overlaps() + overlaps = credible_set.find_overlaps() colocalisation_results = colocalisation_class.colocalise(overlaps) # type: ignore # Load diff --git a/src/gentropy/dataset/study_locus.py b/src/gentropy/dataset/study_locus.py index 2385df984..c7f9ffc3d 100644 --- a/src/gentropy/dataset/study_locus.py +++ b/src/gentropy/dataset/study_locus.py @@ -553,7 +553,7 @@ def filter_credible_set( self: StudyLocus, credible_interval: CredibleInterval, ) -> StudyLocus: - """Filter study-locus tag variants based on given credible interval. + """Annotate and filter study-locus tag variants based on given credible interval. Args: credible_interval (CredibleInterval): Credible interval to filter for. @@ -562,7 +562,7 @@ def filter_credible_set( StudyLocus: Filtered study-locus dataset. """ return StudyLocus( - _df=self._df.withColumn( + _df=self.annotate_credible_sets().df.withColumn( "locus", f.filter( f.col("locus"), diff --git a/src/gentropy/pics.py b/src/gentropy/pics.py index 80421b9ae..e80a37eb6 100644 --- a/src/gentropy/pics.py +++ b/src/gentropy/pics.py @@ -28,10 +28,8 @@ def __init__( session, study_locus_ld_annotated_in ) # PICS - picsed_sl = ( - PICS.finemap(study_locus_ld_annotated) - .annotate_credible_sets() - .filter_credible_set(credible_interval=CredibleInterval.IS99) + picsed_sl = PICS.finemap(study_locus_ld_annotated).filter_credible_set( + credible_interval=CredibleInterval.IS99 ) # Write picsed_sl.df.write.mode(session.write_mode).parquet(picsed_study_locus_out) diff --git a/src/gentropy/study_locus_validation.py b/src/gentropy/study_locus_validation.py index 7c853bbcb..114eb01f7 100644 --- a/src/gentropy/study_locus_validation.py +++ b/src/gentropy/study_locus_validation.py @@ -4,7 +4,7 @@ from gentropy.common.session import Session from gentropy.dataset.study_index import StudyIndex -from gentropy.dataset.study_locus import StudyLocus +from gentropy.dataset.study_locus import CredibleInterval, StudyLocus class StudyLocusValidationStep: @@ -46,6 +46,8 @@ def __init__( .validate_study(study_index) # Flagging studies not in study index .annotate_study_type(study_index) # Add study type to study locus .qc_redundant_top_hits_from_PICS() # Flagging top hits from studies with PICS summary statistics + # Annotates credible intervals and filter to only keep 99% credible sets + .filter_credible_set(credible_interval=CredibleInterval.IS99) ).persist() # we will need this for 2 types of outputs study_locus_with_qc.valid_rows( From 2199ece29182cbfb3911c1a8b6d261f9a76bf1f0 Mon Sep 17 00:00:00 2001 From: David Ochoa Date: Tue, 24 Sep 2024 17:04:42 +0100 Subject: [PATCH 053/188] feat: flag credible sets explained by SuSiE regions (#780) * feat: flag PICS top hits in studies with credset sumstats * feat: flag credible sets explained by SuSiE region * feat: consider unresolved LD cases * refactor: improve readability of code * refactor: improve code readability --------- Co-authored-by: Daniel Suveges --- src/gentropy/dataset/study_locus.py | 72 ++++++++++ src/gentropy/study_locus_validation.py | 1 + tests/gentropy/dataset/test_study_locus.py | 160 +++++++++++++++++++++ 3 files changed, 233 insertions(+) diff --git a/src/gentropy/dataset/study_locus.py b/src/gentropy/dataset/study_locus.py index c7f9ffc3d..e3706eaf0 100644 --- a/src/gentropy/dataset/study_locus.py +++ b/src/gentropy/dataset/study_locus.py @@ -57,6 +57,7 @@ class StudyLocusQualityCheck(Enum): TOP_HIT (str): Study locus from curated top hit IN_MHC (str): Flagging study loci in the MHC region REDUNDANT_PICS_TOP_HIT (str): Flagging study loci in studies with PICS results from summary statistics + EXPLAINED_BY_SUSIE (str): Study locus in region explained by a SuSiE credible set """ SUBSIGNIFICANT_FLAG = "Subsignificant p-value" @@ -84,6 +85,7 @@ class StudyLocusQualityCheck(Enum): "PICS results from summary statistics available for this same study" ) TOP_HIT = "Study locus from curated top hit" + EXPLAINED_BY_SUSIE = "Study locus in region explained by a SuSiE credible set" class CredibleInterval(Enum): @@ -963,6 +965,76 @@ def qc_redundant_top_hits_from_PICS(self: StudyLocus) -> StudyLocus: _schema=StudyLocus.get_schema(), ) + def qc_explained_by_SuSiE(self: StudyLocus) -> StudyLocus: + """Flag associations that are explained by SuSiE associations. + + Credible sets overlapping in the same region as a SuSiE credible set are flagged as explained by SuSiE. + + Returns: + StudyLocus: Updated study locus with SuSiE explained flags. + """ + # unique study-regions covered by SuSie credible sets + susie_study_regions = ( + self.filter(f.col("finemappingMethod") == "SuSiE-inf") + .df.select( + "studyId", + "chromosome", + "locusStart", + "locusEnd", + f.lit(True).alias("inSuSiE"), + ) + .distinct() + ) + + # non SuSiE credible sets (studyLocusId) overlapping in any variant with SuSiE locus + redundant_study_locus = ( + self.filter(f.col("finemappingMethod") != "SuSiE-inf") + .df.withColumn("l", f.explode("locus")) + .select( + "studyLocusId", + "studyId", + "chromosome", + f.split(f.col("l.variantId"), "_")[1].alias("tag_position"), + ) + .alias("study_locus") + .join( + susie_study_regions.alias("regions"), + how="inner", + on=[ + (f.col("study_locus.chromosome") == f.col("regions.chromosome")) + & (f.col("study_locus.studyId") == f.col("regions.studyId")) + & (f.col("study_locus.tag_position") >= f.col("regions.locusStart")) + & (f.col("study_locus.tag_position") <= f.col("regions.locusEnd")) + ], + ) + .select("studyLocusId", "inSuSiE") + .distinct() + ) + + return StudyLocus( + _df=( + self.df.join(redundant_study_locus, on="studyLocusId", how="left") + .withColumn( + "qualityControls", + self.update_quality_flag( + f.col("qualityControls"), + # credible set in SuSiE overlapping region + f.col("inSuSiE") + # credible set not based on SuSiE + & (f.col("finemappingMethod") != "SuSiE-inf") + # credible set not already flagged as unresolved LD + & ~f.array_contains( + f.col("qualityControls"), + StudyLocusQualityCheck.UNRESOLVED_LD.value, + ), + StudyLocusQualityCheck.EXPLAINED_BY_SUSIE, + ), + ) + .drop("inSuSiE") + ), + _schema=StudyLocus.get_schema(), + ) + def _qc_no_population(self: StudyLocus) -> StudyLocus: """Flag associations where the study doesn't have population information to resolve LD. diff --git a/src/gentropy/study_locus_validation.py b/src/gentropy/study_locus_validation.py index 114eb01f7..287cd5645 100644 --- a/src/gentropy/study_locus_validation.py +++ b/src/gentropy/study_locus_validation.py @@ -46,6 +46,7 @@ def __init__( .validate_study(study_index) # Flagging studies not in study index .annotate_study_type(study_index) # Add study type to study locus .qc_redundant_top_hits_from_PICS() # Flagging top hits from studies with PICS summary statistics + .qc_explained_by_SuSiE() # Flagging credible sets in regions explained by SuSiE # Annotates credible intervals and filter to only keep 99% credible sets .filter_credible_set(credible_interval=CredibleInterval.IS99) ).persist() # we will need this for 2 types of outputs diff --git a/tests/gentropy/dataset/test_study_locus.py b/tests/gentropy/dataset/test_study_locus.py index 51fc2ed92..29cbffad2 100644 --- a/tests/gentropy/dataset/test_study_locus.py +++ b/tests/gentropy/dataset/test_study_locus.py @@ -904,3 +904,163 @@ def test_qc_redundant_top_hits_from_PICS_correctness( ) .count() ) == 3 + + +class TestStudyLocusSuSiERedundancyFlagging: + """Collection of tests related to flagging redundant credible sets.""" + + STUDY_LOCUS_DATA: Any = [ + # to be flagged due to v4 + ( + 1, + "v1", + "s1", + "X", + "pics", + 1, + 3, + [ + {"variantId": "X_1_A_A"}, + {"variantId": "X_2_A_A"}, + {"variantId": "X_3_A_A"}, + ], + [], + ), + # to be flagged due to v4 + ( + 2, + "v2", + "s1", + "X", + "pics", + 4, + 5, + [ + {"variantId": "X_4_A_A"}, + {"variantId": "X_5_A_A"}, + ], + [], + ), + # NOT to be flagged (outside regions) + ( + 3, + "v3", + "s1", + "X", + "pics", + 6, + 7, + [ + {"variantId": "X_6_A_A"}, + {"variantId": "X_7_A_A"}, + ], + [], + ), + # NOT to be flagged (SuSie-Inf credible set) + ( + 4, + "v4", + "s1", + "X", + "SuSiE-inf", + 3, + 5, + [{"variantId": "X_3_A_A"}, {"variantId": "X_5_A_A"}], + [], + ), + # NOT to be flagged (Unresolved LD) + ( + 5, + "v5", + "s1", + "X", + "pics", + 5, + 5, + [ + {"variantId": "X_5_A_A"}, + ], + [StudyLocusQualityCheck.UNRESOLVED_LD.value], + ), + # NOT to be flagged (different study) + ( + 6, + "v6", + "s2", + "X", + "pics", + 3, + 5, + [ + {"variantId": "X_3_A_A"}, + {"variantId": "X_5_A_A"}, + ], + [], + ), + ] + + STUDY_LOCUS_SCHEMA = t.StructType( + [ + t.StructField("studyLocusId", t.LongType(), False), + t.StructField("variantId", t.StringType(), False), + t.StructField("studyId", t.StringType(), False), + t.StructField("chromosome", t.StringType(), False), + t.StructField("finemappingMethod", t.StringType(), False), + t.StructField("locusStart", t.IntegerType(), False), + t.StructField("locusEnd", t.IntegerType(), False), + StructField( + "locus", + ArrayType( + StructType( + [ + StructField("variantId", StringType(), True), + ] + ) + ), + True, + ), + t.StructField("qualityControls", t.ArrayType(t.StringType()), False), + ] + ) + + @pytest.fixture(autouse=True) + def _setup( + self: TestStudyLocusSuSiERedundancyFlagging, spark: SparkSession + ) -> None: + """Setup study locus for testing.""" + self.study_locus = StudyLocus( + _df=spark.createDataFrame( + self.STUDY_LOCUS_DATA, schema=self.STUDY_LOCUS_SCHEMA + ), + _schema=StudyLocus.get_schema(), + ) + + def test_qc_qc_explained_by_SuSiE_returntype( + self: TestStudyLocusSuSiERedundancyFlagging, + ) -> None: + """Test qc_explained_by_SuSiE.""" + assert isinstance(self.study_locus.qc_explained_by_SuSiE(), StudyLocus) + + def test_qc_explained_by_SuSiE_no_data_loss( + self: TestStudyLocusSuSiERedundancyFlagging, + ) -> None: + """Test qc_explained_by_SuSiE no data loss.""" + assert ( + self.study_locus.qc_explained_by_SuSiE().df.count() + == self.study_locus.df.count() + ) + + def test_qc_explained_by_SuSiE_correctness( + self: TestStudyLocusSuSiERedundancyFlagging, + ) -> None: + """Testing if the study validation flags the right number of studies.""" + assert ( + self.study_locus.qc_explained_by_SuSiE() + .df.filter( + f.array_contains( + f.col("qualityControls"), + StudyLocusQualityCheck.EXPLAINED_BY_SUSIE.value, + ) + ) + .count() + ) == 2 From 2010fb654e5cae241028e9614b79865e871034e1 Mon Sep 17 00:00:00 2001 From: Yakov Date: Tue, 24 Sep 2024 17:10:23 +0100 Subject: [PATCH 054/188] fix: remove n_eff check from qc_step (#785) --- src/gentropy/config.py | 1 + .../method/sumstat_quality_controls.py | 21 ++++++++----------- src/gentropy/sumstat_qc_step.py | 4 +++- tests/gentropy/method/test_qc_of_sumstats.py | 16 +++++--------- 4 files changed, 18 insertions(+), 24 deletions(-) diff --git a/src/gentropy/config.py b/src/gentropy/config.py index 32edc9a4a..86bfc7afe 100644 --- a/src/gentropy/config.py +++ b/src/gentropy/config.py @@ -455,6 +455,7 @@ class GWASQCStep(StepConfig): gwas_path: str = MISSING output_path: str = MISSING studyid: str = MISSING + pval_threshold: float = MISSING _target_: str = "gentropy.sumstat_qc_step.SummaryStatisticsQCStep" diff --git a/src/gentropy/method/sumstat_quality_controls.py b/src/gentropy/method/sumstat_quality_controls.py index 2858f4813..1647851de 100644 --- a/src/gentropy/method/sumstat_quality_controls.py +++ b/src/gentropy/method/sumstat_quality_controls.py @@ -1,4 +1,5 @@ """Summary statistics qulity control methods.""" + from __future__ import annotations import numpy as np @@ -225,13 +226,13 @@ def gc_lambda_check( @staticmethod def number_of_snps( - gwas_for_qc: SummaryStatistics, pval_threhod: float = 5e-8 + gwas_for_qc: SummaryStatistics, pval_threshold: float = 5e-8 ) -> DataFrame: """The function caluates number of SNPs and number of SNPs with p-value less than 5e-8. Args: gwas_for_qc (SummaryStatistics): The instance of the SummaryStatistics class. - pval_threhod (float): The threshold for the p-value. + pval_threshold (float): The threshold for the p-value. Returns: DataFrame: PySpark DataFrame with the number of SNPs and number of SNPs with p-value less than threshold. @@ -243,7 +244,7 @@ def number_of_snps( f.sum( ( f.log10(f.col("pValueMantissa")) + f.col("pValueExponent") - <= np.log10(pval_threhod) + <= np.log10(pval_threshold) ).cast("int") ).alias("n_variants_sig"), ) @@ -254,30 +255,26 @@ def number_of_snps( def get_quality_control_metrics( gwas: SummaryStatistics, limit: int = 100_000_000, - min_count: int = 100_000, - n_total: int = 100_000, + pval_threshold: float = 5e-8, ) -> DataFrame: """The function calculates the quality control metrics for the summary statistics. Args: gwas (SummaryStatistics): The instance of the SummaryStatistics class. limit (int): The limit for the number of variants to be used for the estimation. - min_count (int): The minimum number of variants to be used for the estimation. - n_total (int): The total sample size. + pval_threshold (float): The threshold for the p-value. Returns: DataFrame: PySpark DataFrame with the quality control metrics for the summary statistics. """ qc1 = SummaryStatisticsQC.sumstat_qc_beta_check(gwas_for_qc=gwas) qc2 = SummaryStatisticsQC.sumstat_qc_pz_check(gwas_for_qc=gwas, limit=limit) - qc3 = SummaryStatisticsQC.sumstat_n_eff_check( - gwas_for_qc=gwas, n_total=n_total, limit=limit, min_count=min_count - ) qc4 = SummaryStatisticsQC.gc_lambda_check(gwas_for_qc=gwas, limit=limit) - qc5 = SummaryStatisticsQC.number_of_snps(gwas_for_qc=gwas) + qc5 = SummaryStatisticsQC.number_of_snps( + gwas_for_qc=gwas, pval_threshold=pval_threshold + ) df = ( qc1.join(qc2, on="studyId", how="outer") - .join(qc3, on="studyId", how="outer") .join(qc4, on="studyId", how="outer") .join(qc5, on="studyId", how="outer") ) diff --git a/src/gentropy/sumstat_qc_step.py b/src/gentropy/sumstat_qc_step.py index 0c3b7bb14..b5aed905e 100644 --- a/src/gentropy/sumstat_qc_step.py +++ b/src/gentropy/sumstat_qc_step.py @@ -16,6 +16,7 @@ def __init__( gwas_path: str, output_path: str, studyid: str, + pval_threshold: float = 1e-8, ) -> None: """Calculating quality control metrics on the provided GWAS study. @@ -24,13 +25,14 @@ def __init__( gwas_path (str): Path to the GWAS summary statistics. output_path (str): Output path for the QC results. studyid (str): Study ID for the QC. + pval_threshold (float): P-value threshold for the QC. Default is 1e-8. """ gwas = SummaryStatistics.from_parquet(session, path=gwas_path) ( SummaryStatisticsQC.get_quality_control_metrics( - gwas=gwas, limit=100_000_000, min_count=100, n_total=100000 + gwas=gwas, limit=100_000_000, pval_threshold=pval_threshold ) .write.mode(session.write_mode) .parquet(output_path + "/qc_results_" + studyid) diff --git a/tests/gentropy/method/test_qc_of_sumstats.py b/tests/gentropy/method/test_qc_of_sumstats.py index d734fcaef..8f63e6ba2 100644 --- a/tests/gentropy/method/test_qc_of_sumstats.py +++ b/tests/gentropy/method/test_qc_of_sumstats.py @@ -3,7 +3,6 @@ from __future__ import annotations import numpy as np -import pandas as pd import pyspark.sql.functions as f import pytest from pyspark.sql.functions import rand, when @@ -18,9 +17,7 @@ def test_qc_functions( ) -> None: """Test all sumstat qc functions.""" gwas = sample_summary_statistics.sanity_filter() - QC = SummaryStatisticsQC.get_quality_control_metrics( - gwas=gwas, limit=100000, min_count=100, n_total=100000 - ) + QC = SummaryStatisticsQC.get_quality_control_metrics(gwas=gwas, limit=100000) QC = QC.toPandas() assert QC["n_variants"].iloc[0] == 1663 @@ -29,7 +26,6 @@ def test_qc_functions( assert np.round(QC["mean_beta"].iloc[0], 4) == 0.0013 assert np.round(QC["mean_diff_pz"].iloc[0], 6) == 0 assert np.round(QC["se_diff_pz"].iloc[0], 6) == 0 - assert pd.isna(QC["se_N"].iloc[0]) def test_neff_check_eaf( @@ -41,8 +37,8 @@ def test_neff_check_eaf( gwas_df = gwas_df.withColumn("effectAlleleFrequencyFromSource", f.lit(0.5)) gwas._df = gwas_df - QC = SummaryStatisticsQC.get_quality_control_metrics( - gwas=gwas, limit=100000, min_count=100, n_total=100000 + QC = SummaryStatisticsQC.sumstat_n_eff_check( + gwas_for_qc=gwas, limit=100000, min_count=100, n_total=100000 ) QC = QC.toPandas() assert np.round(QC["se_N"].iloc[0], 4) == 0.5586 @@ -59,11 +55,9 @@ def test_several_studyid( ) gwas._df = gwas_df - QC = SummaryStatisticsQC.get_quality_control_metrics( - gwas=gwas, limit=100000, min_count=100, n_total=100000 - ) + QC = SummaryStatisticsQC.get_quality_control_metrics(gwas=gwas, limit=100000) QC = QC.toPandas() - assert QC.shape == (2, 8) + assert QC.shape == (2, 7) def test_sanity_filter_remove_inf_values( From d2a68d934462a9706455bac0d67a065bb43f9f0b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Sep 2024 17:41:27 +0100 Subject: [PATCH 055/188] build(deps-dev): bump pymdown-extensions from 10.9 to 10.10.1 (#781) Bumps [pymdown-extensions](https://github.com/facelessuser/pymdown-extensions) from 10.9 to 10.10.1. - [Release notes](https://github.com/facelessuser/pymdown-extensions/releases) - [Commits](https://github.com/facelessuser/pymdown-extensions/compare/10.9...10.10.1) --- updated-dependencies: - dependency-name: pymdown-extensions dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: David Ochoa --- poetry.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/poetry.lock b/poetry.lock index 296f07145..4cc0e3bba 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.0 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. [[package]] name = "aiodns" @@ -3740,13 +3740,13 @@ files = [ [[package]] name = "pymdown-extensions" -version = "10.9" +version = "10.10.1" description = "Extension pack for Python Markdown." optional = false python-versions = ">=3.8" files = [ - {file = "pymdown_extensions-10.9-py3-none-any.whl", hash = "sha256:d323f7e90d83c86113ee78f3fe62fc9dee5f56b54d912660703ea1816fed5626"}, - {file = "pymdown_extensions-10.9.tar.gz", hash = "sha256:6ff740bcd99ec4172a938970d42b96128bdc9d4b9bcad72494f29921dc69b753"}, + {file = "pymdown_extensions-10.10.1-py3-none-any.whl", hash = "sha256:6c74ea6c2e2285186a241417480fc2d3cc52941b3ec2dced4014c84dc78c5493"}, + {file = "pymdown_extensions-10.10.1.tar.gz", hash = "sha256:ad277ee4739ced051c3b6328d22ce782358a3bec39bc6ca52815ccbf44f7acdc"}, ] [package.dependencies] From 95be9f6d0694dff95764197bdd1247675b688551 Mon Sep 17 00:00:00 2001 From: David Ochoa Date: Tue, 24 Sep 2024 21:33:13 +0100 Subject: [PATCH 056/188] build: updated precommits including adjustments to docstrings (#787) --- .pre-commit-config.yaml | 8 ++++---- poetry.lock | 1 - src/gentropy/common/version_engine.py | 8 ++++++-- src/gentropy/dataset/colocalisation.py | 3 +-- src/gentropy/dataset/dataset.py | 3 +-- src/gentropy/datasource/ensembl/vep_parser.py | 3 +-- src/gentropy/l2g.py | 3 +-- src/gentropy/method/l2g/model.py | 7 +++---- src/gentropy/method/susie_inf.py | 7 +++++-- 9 files changed, 22 insertions(+), 21 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 17b7a4f6e..a938f03a3 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -6,7 +6,7 @@ ci: skip: [poetry-lock] repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.6.1 + rev: v0.6.7 hooks: - id: ruff args: @@ -58,14 +58,14 @@ repos: exclude: "CHANGELOG.md" - repo: https://github.com/alessandrojcm/commitlint-pre-commit-hook - rev: v9.16.0 + rev: v9.18.0 hooks: - id: commitlint additional_dependencies: ["@commitlint/config-conventional@18.6.3"] stages: [commit-msg] - repo: https://github.com/pre-commit/mirrors-mypy - rev: "v1.11.1" + rev: "v1.11.2" hooks: - id: mypy args: @@ -98,7 +98,7 @@ repos: - id: beautysh - repo: https://github.com/jsh9/pydoclint - rev: 0.5.6 + rev: 0.5.8 hooks: - id: pydoclint diff --git a/poetry.lock b/poetry.lock index 4cc0e3bba..bf854b313 100644 --- a/poetry.lock +++ b/poetry.lock @@ -3952,7 +3952,6 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, diff --git a/src/gentropy/common/version_engine.py b/src/gentropy/common/version_engine.py index 1cf34bbec..d852d8f5d 100644 --- a/src/gentropy/common/version_engine.py +++ b/src/gentropy/common/version_engine.py @@ -101,7 +101,11 @@ def amend_version( class DatasourceVersionSeeker(ABC): - """Interface for datasource version seeker.""" + """Interface for datasource version seeker. + + Raises: + NotImplementedError: if method is not implemented in the subclass + """ @staticmethod @abstractmethod @@ -115,7 +119,7 @@ def seek_version(text: str) -> str: str: seeked version Raises: - ValueError: if version can not be seeked + NotImplementedError: if method is not implemented in the subclass """ raise NotImplementedError diff --git a/src/gentropy/dataset/colocalisation.py b/src/gentropy/dataset/colocalisation.py index 94a4f09dc..9e9035488 100644 --- a/src/gentropy/dataset/colocalisation.py +++ b/src/gentropy/dataset/colocalisation.py @@ -55,8 +55,7 @@ def extract_maximum_coloc_probability_per_region_and_gene( DataFrame: table with the maximum colocalisation scores for the provided study loci Raises: - ValueError: if filter_by_qtl is not in the list of valid QTL types - ValueError: if filter_by_colocalisation_method is not in the list of valid colocalisation methods + ValueError: if filter_by_qtl is not in the list of valid QTL types or is not in the list of valid colocalisation methods """ from gentropy.colocalisation import ColocalisationStep diff --git a/src/gentropy/dataset/dataset.py b/src/gentropy/dataset/dataset.py index cbeae7073..e56ef2ecc 100644 --- a/src/gentropy/dataset/dataset.py +++ b/src/gentropy/dataset/dataset.py @@ -211,8 +211,7 @@ def valid_rows(self: Self, invalid_flags: list[str], invalid: bool = False) -> S Self: filtered dataset. Raises: - ValueError: If the Dataset does not contain a QC column. - ValueError: If the invalid_flags elements do not exist in QC mappings flags. + ValueError: If the Dataset does not contain a QC column or if the invalid_flags elements do not exist in QC mappings flags. """ # If the invalid flags are not valid quality checks (enum) for this Dataset we raise an error: invalid_reasons = [] diff --git a/src/gentropy/datasource/ensembl/vep_parser.py b/src/gentropy/datasource/ensembl/vep_parser.py index c7ee05d13..4b70a36e6 100644 --- a/src/gentropy/datasource/ensembl/vep_parser.py +++ b/src/gentropy/datasource/ensembl/vep_parser.py @@ -71,8 +71,7 @@ def extract_variant_index_from_vep( VariantIndex: Variant index dataset. Raises: - ValueError: Failed reading file. - ValueError: The dataset is empty. + ValueError: Failed reading file or if the dataset is empty. """ # To speed things up and simplify the json structure, read data following an expected schema: vep_schema = cls.get_schema() diff --git a/src/gentropy/l2g.py b/src/gentropy/l2g.py index 13dbb881b..6f80d826e 100644 --- a/src/gentropy/l2g.py +++ b/src/gentropy/l2g.py @@ -201,8 +201,7 @@ def _generate_feature_matrix(self, write_feature_matrix: bool) -> L2GFeatureMatr L2GFeatureMatrix: Feature matrix with gold standards annotated with features. Raises: - ValueError: If write_feature_matrix is set to True but a path is not provided. - ValueError: If dependencies to build features are not set. + ValueError: If write_feature_matrix is set to True but a path is not provided or if dependencies to build features are not set. """ if self.gs_curation and self.interactions and self.v2g: study_locus_overlap = StudyLocus( diff --git a/src/gentropy/method/l2g/model.py b/src/gentropy/method/l2g/model.py index 6e0b0fda1..45d90f90d 100644 --- a/src/gentropy/method/l2g/model.py +++ b/src/gentropy/method/l2g/model.py @@ -135,8 +135,7 @@ def save(self: LocusToGeneModel, path: str) -> None: path (str): Path to save the persisted model. Should end with .skops Raises: - ValueError: If the model has not been fitted yet - ValueError: If the path does not end with .skops + ValueError: If the model has not been fitted yet or if the path does not end with .skops """ if self.model is None: raise ValueError("Model has not been fitted yet.") @@ -215,7 +214,7 @@ def export_to_hugging_face_hub( local_repo (str): Path to the folder where the contents of the model repo + the documentation are located. This is used to push the model to the Hugging Face Hub. Raises: - Exception: If the push to the Hugging Face Hub fails + RuntimeError: If the push to the Hugging Face Hub fails """ from sklearn import __version__ as sklearn_version @@ -241,4 +240,4 @@ def export_to_hugging_face_hub( for p in Path(local_repo).glob("*"): p.unlink() Path(local_repo).rmdir() - raise e + raise RuntimeError from e diff --git a/src/gentropy/method/susie_inf.py b/src/gentropy/method/susie_inf.py index 482818b71..4f75faad8 100644 --- a/src/gentropy/method/susie_inf.py +++ b/src/gentropy/method/susie_inf.py @@ -23,6 +23,9 @@ class SUSIE_inf: Note: code copied from fine-mapping-inf package as a placeholder https://github.com/FinucaneLab/fine-mapping-inf + + Raises: + RuntimeError: if missing LD or if unsupported variance estimation """ @staticmethod @@ -89,8 +92,7 @@ def susie_inf( # noqa: C901 lbf -- length-p array of log-Bayes-factors for each CS Raises: - RuntimeError: if missing LD - RuntimeError: if unsupported variance estimation method + RuntimeError: if missing LD or if unsupported variance estimation method """ p = len(z) # Precompute V,D^2 in the SVD X=UDV', and V'X'y and y'y @@ -428,6 +430,7 @@ def cred_inf( Raises: RuntimeError: if missing inputs for purity filtering + ValueError: if either LD or V, Dsq are None """ if (V is None or Dsq is None or n is None) and LD is None: raise RuntimeError("Missing inputs for purity filtering") From 6c4bdf50430201e870dd810a2a4c325f653456cf Mon Sep 17 00:00:00 2001 From: Szymon Szyszkowski <69353402+project-defiant@users.noreply.github.com> Date: Wed, 25 Sep 2024 00:16:27 +0200 Subject: [PATCH 057/188] fix(finngen_study_index): improved tests for finngen study index (#776) * fix(finngen_study_index): improved tests for finngen study index * chore(tests): added pytest mark to be able to isolate step tests * chore: pr comments * feat: revert mock.patch --------- Co-authored-by: Szymon Szyszkowski --- pyproject.toml | 1 + src/gentropy/config.py | 1 + .../datasource/finngen/study_index.py | 19 +- src/gentropy/finngen_studies.py | 4 + .../finngen/test_finngen_study_index.py | 359 +++++++++++++++--- 5 files changed, 322 insertions(+), 62 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 8e5469c6a..f61d82116 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -126,6 +126,7 @@ exclude = ["dist"] addopts = "-n auto --doctest-modules --cov=src/ --cov-report=xml" pythonpath = ["."] testpaths = ["tests/gentropy", "src/gentropy"] +marks = ["step_test"] # Semi-strict mode for mypy [tool.mypy] diff --git a/src/gentropy/config.py b/src/gentropy/config.py index 86bfc7afe..3293a882a 100644 --- a/src/gentropy/config.py +++ b/src/gentropy/config.py @@ -146,6 +146,7 @@ class FinngenStudiesConfig(StepConfig): ) finngen_summary_stats_url_suffix: str = ".gz" efo_curation_mapping_url: str = "https://raw.githubusercontent.com/opentargets/curation/24.09.1/mappings/disease/manual_string.tsv" + sample_size: int = 453733 # https://www.finngen.fi/en/access_results#:~:text=Total%20sample%20size%3A%C2%A0453%2C733%C2%A0(254%2C618%C2%A0females%20and%C2%A0199%2C115%20males) _target_: str = "gentropy.finngen_studies.FinnGenStudiesStep" diff --git a/src/gentropy/datasource/finngen/study_index.py b/src/gentropy/datasource/finngen/study_index.py index 1e2e71f72..3946323f4 100644 --- a/src/gentropy/datasource/finngen/study_index.py +++ b/src/gentropy/datasource/finngen/study_index.py @@ -1,4 +1,4 @@ -"""Study Index for Finngen data source.""" +"""Study Index for FinnGen data source.""" from __future__ import annotations @@ -8,7 +8,6 @@ import pyspark.sql.functions as f from pyspark.sql import DataFrame, SparkSession -from gentropy.config import FinngenStudiesConfig from gentropy.dataset.study_index import StudyIndex @@ -30,7 +29,7 @@ class FinnGenStudyIndex: def join_efo_mapping( study_index: StudyIndex, efo_curation_mapping: DataFrame, - finngen_release_prefix: str = FinngenStudiesConfig().finngen_release_prefix, + finngen_release_prefix: str, ) -> StudyIndex: """Add EFO mapping to the Finngen study index table. @@ -88,10 +87,11 @@ def join_efo_mapping( def from_source( cls: type[FinnGenStudyIndex], spark: SparkSession, - finngen_phenotype_table_url: str = FinngenStudiesConfig().finngen_phenotype_table_url, - finngen_release_prefix: str = FinngenStudiesConfig().finngen_release_prefix, - finngen_summary_stats_url_prefix: str = FinngenStudiesConfig().finngen_summary_stats_url_prefix, - finngen_summary_stats_url_suffix: str = FinngenStudiesConfig().finngen_summary_stats_url_suffix, + finngen_phenotype_table_url: str, + finngen_release_prefix: str, + finngen_summary_stats_url_prefix: str, + finngen_summary_stats_url_suffix: str, + sample_size: int, ) -> StudyIndex: """This function ingests study level metadata from FinnGen. @@ -101,6 +101,7 @@ def from_source( finngen_release_prefix (str): FinnGen release prefix. finngen_summary_stats_url_prefix (str): FinnGen summary stats URL prefix. finngen_summary_stats_url_suffix (str): FinnGen summary stats URL suffix. + sample_size (int): Number of individuals participated in sample collection. Returns: StudyIndex: Parsed and annotated FinnGen study table. @@ -120,12 +121,12 @@ def from_source( f.lit(finngen_release_prefix).alias("projectId"), f.lit("gwas").alias("studyType"), f.lit(True).alias("hasSumstats"), - f.lit("377,277 (210,870 females and 166,407 males)").alias( + f.lit("453,733 (254,618 females and 199,115 males)").alias( "initialSampleSize" ), f.array( f.struct( - f.lit(377277).cast("integer").alias("sampleSize"), + f.lit(sample_size).cast("integer").alias("sampleSize"), f.lit("Finnish").alias("ancestry"), ) ).alias("discoverySamples"), diff --git a/src/gentropy/finngen_studies.py b/src/gentropy/finngen_studies.py index 706fa3d39..80866ac99 100644 --- a/src/gentropy/finngen_studies.py +++ b/src/gentropy/finngen_studies.py @@ -21,6 +21,7 @@ def __init__( finngen_summary_stats_url_prefix: str = FinngenStudiesConfig().finngen_summary_stats_url_prefix, finngen_summary_stats_url_suffix: str = FinngenStudiesConfig().finngen_summary_stats_url_suffix, efo_curation_mapping_url: str = FinngenStudiesConfig().efo_curation_mapping_url, + sample_size: int = FinngenStudiesConfig().sample_size, ) -> None: """Run FinnGen study index generation step. @@ -32,6 +33,7 @@ def __init__( finngen_summary_stats_url_prefix (str): FinnGen summary stats URL prefix. finngen_summary_stats_url_suffix (str): FinnGen summary stats URL suffix. efo_curation_mapping_url (str): URL to the EFO curation mapping file + sample_size (int): Number of individuals that participated in sample collection, derived from finngen release metadata. """ study_index = FinnGenStudyIndex.from_source( session.spark, @@ -39,12 +41,14 @@ def __init__( finngen_release_prefix, finngen_summary_stats_url_prefix, finngen_summary_stats_url_suffix, + sample_size, ) # NOTE: hack to allow spark to read directly from the URL. csv_data = urlopen(efo_curation_mapping_url).readlines() csv_rows = [row.decode("utf8") for row in csv_data] rdd = session.spark.sparkContext.parallelize(csv_rows) + # NOTE: type annotations for spark.read.csv miss the fact that the first param can be [RDD[str]] efo_curation_mapping = session.spark.read.csv(rdd, header=True, sep="\t") study_index_with_efo = FinnGenStudyIndex.join_efo_mapping( diff --git a/tests/gentropy/datasource/finngen/test_finngen_study_index.py b/tests/gentropy/datasource/finngen/test_finngen_study_index.py index 5b2be30c4..07d014d13 100644 --- a/tests/gentropy/datasource/finngen/test_finngen_study_index.py +++ b/tests/gentropy/datasource/finngen/test_finngen_study_index.py @@ -2,85 +2,338 @@ from __future__ import annotations -from pyspark.sql import SparkSession -from pyspark.sql import types as t +import json +from typing import TYPE_CHECKING +from unittest.mock import MagicMock + +import pytest +from pyspark.sql import types as T from gentropy.dataset.study_index import StudyIndex from gentropy.datasource.finngen.study_index import FinnGenStudyIndex +from gentropy.finngen_studies import FinnGenStudiesStep +if TYPE_CHECKING: + from pathlib import Path + from typing import Callable -def test_finngen_study_index_from_source(spark: SparkSession) -> None: - """Test study index from source.""" - assert isinstance(FinnGenStudyIndex.from_source(spark), StudyIndex) + from pyspark.sql import DataFrame, SparkSession + from gentropy.common.session import Session -def test_finngen_study_index_add_efos(spark: SparkSession) -> None: - """Test finngen study index add efo ids.""" - study_index_table_data = [ + +@pytest.fixture() +def finngen_study_index_mock(spark: SparkSession) -> StudyIndex: + """Finngen minimal example for mocking join to the efo mappings.""" + data = [ + # NOTE: Study maps to a single EFO trait ( - "AB1_1", + "STUDY_1", "Actinomycosis", "FINNGEN_R11", "gwas", ), + # NOTE: Study does not map to EFO traits ( - "AB1_2", - "Some unknown trait", - "FINNGEN_R11", - "gwas", - ), - ( - "AB1_1", - "Some unknown trait", + "STUDY_2", + "Some other trait", "FINNGEN_R11", "gwas", ), + # NOTE: Study maps to two EFO traits ( - "AB1_1", - "Bleeding", + "STUDY_3", + "Glucose", "FINNGEN_R11", "gwas", ), ] - study_index_df = spark.createDataFrame( - data=study_index_table_data, - schema=t.StructType( - [ - t.StructField("studyId", t.StringType(), nullable=False), - t.StructField("traitFromSource", t.StringType(), nullable=False), - t.StructField("projectId", t.StringType(), nullable=False), - t.StructField("studyType", t.StringType(), nullable=False), - ] - ), + schema = T.StructType( + [ + T.StructField("studyId", T.StringType(), nullable=False), + T.StructField("traitFromSource", T.StringType(), nullable=False), + T.StructField("projectId", T.StringType(), nullable=False), + T.StructField("studyType", T.StringType(), nullable=False), + ] ) + df = spark.createDataFrame(data=data, schema=schema) + return StudyIndex(_df=df, _schema=StudyIndex.get_schema()) - curation_table_data = [ - ("FinnGen r11", "Actinomycosis", "http://www.ebi.ac.uk/efo/EFO_0007128"), - ("FinnGen r11", "bleeding", "http://purl.obolibrary.org/obo/MP_0001914"), - ("FinnGen r11", "Bruxism", "http://purl.obolibrary.org/obo/MONDO_0002443"), + +@pytest.fixture() +def finngen_phenotype_table_mock() -> str: + """This is the data extracted from https://r11.finngen.fi/api/phenos.""" + data = json.dumps( + [ + # NOTE: Study maps to single EFO trait. + { + "assoc_files": [ + "/cromwell_root/pheweb/generated-by-pheweb/pheno_gz/AB1_ACTINOMYCOSIS.gz" + ], + "category": "I Certain infectious and parasitic diseases (AB1_)", + "category_index": 1, + "gc_lambda": { + "0.001": 0.93878, + "0.01": 0.96727, + "0.1": 0.85429, + "0.5": 0.52544, + }, + "num_cases": 113, + "num_cases_prev": 101, + "num_controls": 399149, + "num_controls_prev": 363227, + "num_gw_significant": 0, + "num_gw_significant_prev": 0, + "phenocode": "AB1_ACTINOMYCOSIS", + "phenostring": "Actinomycosis", + }, + # NOTE: Study maps to multiple EFO traits. + { + "assoc_files": [ + "/cromwell_root/pheweb/generated-by-pheweb/pheno_gz/GLUCOSE.gz" + ], + "category": "Glucose", + "category_index": 28, + "gc_lambda": { + "0.001": 1.1251, + "0.01": 1.062, + "0.1": 1.0531, + "0.5": 1.0599, + }, + "num_cases": 43764, + "num_cases_prev": 39231, + "num_controls": 409969, + "num_controls_prev": 372950, + "num_gw_significant": 3, + "num_gw_significant_prev": 3, + "phenocode": "GLUCOSE", + "phenostring": "Glucose", + }, + # NOTE: Study does not map to EFO traits + { + "assoc_files": [ + "/cromwell_root/pheweb/generated-by-pheweb/pheno_gz/SOME_OTHER_TRAIT.gz" + ], + "category": "SomeOtherTrait", + "category_index": 28, + "gc_lambda": { + "0.001": 1.1251, + "0.01": 1.062, + "0.1": 1.0531, + "0.5": 1.0599, + }, + "num_cases": 43764, + "num_cases_prev": 39231, + "num_controls": 409969, + "num_controls_prev": 372950, + "num_gw_significant": 3, + "num_gw_significant_prev": 3, + "phenocode": "SOME_OTHER_TRAIT", + "phenostring": "Some other trait", + }, + ] + ) + return data + + +@pytest.fixture() +def efo_mappings_mock() -> list[tuple[str, str, str]]: + """EFO mappings mock based on https://raw.githubusercontent.com/opentargets/curation/24.09.1/mappings/disease/manual_string.tsv. + + Only required fields are extracted. + """ + data = [ ( - "PheWAS 2024", - "20161#Pack years of smoking", - "http://www.ebi.ac.uk/efo/EFO_0005671", + "STUDY", + "PROPERTY_VALUE", + "SEMANTIC_TAG", ), + ("FinnGen r11", "Actinomycosis", "http://www.ebi.ac.uk/efo/EFO_0007128"), + # NOTE: EFO does not map, as it's missing from the StudyIndex - hypothetical example. + ("FinnGen r11", "Bleeding", "http://purl.obolibrary.org/obo/MP_0001914"), + # NOTE: Two EFO traits for one disease should be collected to array - hypothetical example: + # Glucose tolerance test & NMR Glucose + ("FinnGen r11", "Glucose", "http://www.ebi.ac.uk/efo/EFO_0002571"), + ("FinnGen r11", "Glucose", "http://www.ebi.ac.uk/efo/EFO_0004468"), + # NOTE: EFO that does not map, due to study not from Finngen - hypothetical example. + ("PheWAS 2024", "Glucose", "http://www.ebi.ac.uk/efo/EFO_0000001"), ] - curation_df = spark.createDataFrame( - data=curation_table_data, - schema=t.StructType( - [ - t.StructField("STUDY", t.StringType(), nullable=False), - t.StructField("PROPERTY_VALUE", t.StringType(), nullable=False), - t.StructField("SEMANTIC_TAG", t.StringType(), nullable=False), - ] - ), + return data + + +@pytest.fixture() +def efo_mappings_df_mock( + spark: SparkSession, efo_mappings_mock: list[tuple[str, str, str]] +) -> DataFrame: + """EFO mappings dataframe mock.""" + schema = T.StructType( + [ + T.StructField("STUDY", T.StringType(), nullable=False), + T.StructField("PROPERTY_VALUE", T.StringType(), nullable=False), + T.StructField("SEMANTIC_TAG", T.StringType(), nullable=False), + ] ) + data = spark.createDataFrame(data=efo_mappings_mock, schema=schema) + return data - study_index = StudyIndex(_df=study_index_df, _schema=study_index_df.schema) - assert isinstance( - FinnGenStudyIndex.join_efo_mapping( - study_index, - finngen_release_prefix="FINNGEN_R11_", - efo_curation_mapping=curation_df, - ), - StudyIndex, + +@pytest.fixture() +def urlopen_mock( + efo_mappings_mock: list[tuple[str, str, str, str]], + finngen_phenotype_table_mock: str, +) -> Callable[[str], MagicMock]: + """Mock object for requesting urlopen objects with proper encoding. + + This mock object allows to call `read` and `readlines` methods on two endpoints: + - https://finngen_phenotypes -> finngen_phenotype_table_mock + - https://efo_mappings -> efo_mappings_mock + + The return values are mocks of the source data respectively. + """ + + def mock_response(url: str) -> MagicMock: + """Mock urllib.request.urlopen.""" + match url: + case "https://finngen_phenotypes": + value = finngen_phenotype_table_mock + case "https://efo_mappings": + value = "\n".join(["\t".join(row) + "\n" for row in efo_mappings_mock]) + case _: + value = "" + mock_open = MagicMock() + mock_open.read.return_value = value.encode() + mock_open.readlines.return_value = value.encode().splitlines(keepends=True) + return mock_open + + return mock_response + + +@pytest.mark.step_test +def test_finngen_study_index_step( + monkeypatch: pytest.MonkeyPatch, + session: Session, + tmp_path: Path, + urlopen_mock: Callable[[str], MagicMock], +) -> None: + """Test step that generates finngen study index. + + FIXME: Currently we miss following columns when reading from source. + 'biosampleFromSourceId' + 'publicationTitle' + 'diseaseIds' + 'publicationDate' + 'geneId' + 'backgroundDiseaseIds' + 'pubmedId' + 'publicationJournal' + 'qualityControls' + 'backgroundTraitFromSourceMappedIds' + 'publicationFirstAuthor' + 'replicationSamples' + 'analysisFlags' + 'condition' + """ + with monkeypatch.context() as m: + m.setattr("gentropy.datasource.finngen.study_index.urlopen", urlopen_mock) + m.setattr("gentropy.finngen_studies.urlopen", urlopen_mock) + output_path = str(tmp_path / "study_index") + FinnGenStudiesStep( + session=session, + finngen_study_index_out=output_path, + finngen_phenotype_table_url="https://finngen_phenotypes", + finngen_release_prefix="FINNGEN_R11", + finngen_summary_stats_url_prefix="gs://finngen_data/sumstats", + finngen_summary_stats_url_suffix=".gz", + efo_curation_mapping_url="https://efo_mappings", + sample_size=5_000_000, + ) + study_index = StudyIndex.from_parquet(session=session, path=output_path) + # fmt: off + assert study_index.df.count() == 3, "Expected 3 rows that come from the input table." + assert "traitFromSourceMappedIds" in study_index.df.columns, "Expected that EFO terms were joined to the study_index table." + # fmt: on + + +def test_finngen_study_index_from_source( + monkeypatch: pytest.MonkeyPatch, + spark: SparkSession, + urlopen_mock: Callable[[str], MagicMock], +) -> None: + """Test study index from source.""" + with monkeypatch.context() as m: + m.setattr("gentropy.datasource.finngen.study_index.urlopen", urlopen_mock) + expected_sample_size = 5_000_000 + expected_project_id = "FINNGEN_R11" + study_index = FinnGenStudyIndex.from_source( + spark, + finngen_phenotype_table_url="https://finngen_phenotypes", + finngen_release_prefix=expected_project_id, + finngen_summary_stats_url_prefix="gs://finngen-public-data-r11/summary_stats/finngen_R11_", + finngen_summary_stats_url_suffix=".gz", + sample_size=expected_sample_size, + ) + # fmt: off + assert isinstance(study_index, StudyIndex), "Expect that we deal with StudyIndex object." + + all_columns = StudyIndex.get_schema().fieldNames() + assert set(all_columns).issuperset(set(study_index.df.columns)), "Expect all columns can be found in the schema of StudyIndex." + assert study_index.df.count() == 3, "Expect two rows at the study_index, as in the input." + + rows = study_index.df.collect() + expected_study_ids = ["AB1_ACTINOMYCOSIS", "GLUCOSE", "SOME_OTHER_TRAIT"] + assert "studyId" in study_index.df.columns, "Expect that studyId column exists." + assert sorted([v["studyId"] for v in rows]) == expected_study_ids, "Expect that studyIds are populated from input." + + assert "projectId" in study_index.df.columns, "Expect that projectId column exists." + assert {v["projectId"] for v in rows} == {expected_project_id}, "Expect projectId column is correctly populated." + + expected_sumstat_locations = [ + "gs://finngen-public-data-r11/summary_stats/finngen_R11_AB1_ACTINOMYCOSIS.gz", + "gs://finngen-public-data-r11/summary_stats/finngen_R11_GLUCOSE.gz", + "gs://finngen-public-data-r11/summary_stats/finngen_R11_SOME_OTHER_TRAIT.gz", + ] + assert "summarystatsLocation" in study_index.df.columns, "Expect that summarystatsLocation column exists." + sumstat_locations = sorted([v["summarystatsLocation"] for v in rows]) + assert sumstat_locations == expected_sumstat_locations, "Expect that summarystatsLocation is populated." + assert "ldPopulationStructure" in study_index.df.columns, "Expect that ldPopulationStructure column exists." + for row in rows: + ld_struct = row["ldPopulationStructure"][0] + assert ld_struct["ldPopulation"] == "fin", "Expect fin ld population structure." + assert ld_struct["relativeSampleSize"] == pytest.approx(1.0), "Expect relative sample size if fixed to be 1.0." + + assert "discoverySamples" in study_index.df.columns, "Expect that discoverySamples column exists." + for row in rows: + ds_struct = row["discoverySamples"][0] + assert ds_struct["ancestry"] == "Finnish", "Expect Finnish ancestry." + assert ds_struct["sampleSize"] == expected_sample_size, "Expect sample size to be fixed." + # fmt: on + + +def test_finngen_study_index_add_efos( + finngen_study_index_mock: StudyIndex, + efo_mappings_df_mock: DataFrame, +) -> None: + """Test finngen study index add efo ids.""" + efo_column_name = "traitFromSourceMappedIds" + # Expect that EFO column is not present when study index is generated. + assert efo_column_name not in finngen_study_index_mock.df.columns + study_index = FinnGenStudyIndex.join_efo_mapping( + finngen_study_index_mock, + finngen_release_prefix="FINNGEN_R11_", + efo_curation_mapping=efo_mappings_df_mock, ) + # fmt: off + assert isinstance(study_index, StudyIndex), "Expect we have the StudyIndex object after joining EFOs." + assert efo_column_name in study_index.df.columns, "Expect that EFO column is present after joining EFOs." + assert study_index.df.count() == 3, "Expect we do not drop any studies, even if no EFO has been found." + # fmt: on + efos = { + row["studyId"]: sorted(row[efo_column_name]) + for row in study_index.df.select(efo_column_name, "studyId").collect() + } + expected_efos = { + "STUDY_1": ["EFO_0007128"], + "STUDY_2": [], + "STUDY_3": ["EFO_0002571", "EFO_0004468"], + } + assert expected_efos == efos, "Expect that EFOs are correctly assigned." From b525117be9ed75f3bde2b7934145654b4d018f2c Mon Sep 17 00:00:00 2001 From: David Ochoa Date: Wed, 25 Sep 2024 11:41:43 +0100 Subject: [PATCH 058/188] fix: clean unused study_locus step parameter (#786) --- src/gentropy/config.py | 1 - src/gentropy/study_locus_validation.py | 2 -- 2 files changed, 3 deletions(-) diff --git a/src/gentropy/config.py b/src/gentropy/config.py index 3293a882a..c56a9dfb3 100644 --- a/src/gentropy/config.py +++ b/src/gentropy/config.py @@ -503,7 +503,6 @@ class StudyLocusValidationStepConfig(StepConfig): valid_study_locus_path: str = MISSING invalid_study_locus_path: str = MISSING invalid_qc_reasons: list[str] = MISSING - gwas_significance: float = WindowBasedClumpingStepConfig.gwas_significance _target_: str = "gentropy.study_locus_validation.StudyLocusValidationStep" diff --git a/src/gentropy/study_locus_validation.py b/src/gentropy/study_locus_validation.py index 287cd5645..fc69f6855 100644 --- a/src/gentropy/study_locus_validation.py +++ b/src/gentropy/study_locus_validation.py @@ -19,7 +19,6 @@ def __init__( session: Session, study_index_path: str, study_locus_path: list[str], - gwas_significance: float, valid_study_locus_path: str, invalid_study_locus_path: str, invalid_qc_reasons: list[str] = [], @@ -30,7 +29,6 @@ def __init__( session (Session): Session object. study_index_path (str): Path to study index file. study_locus_path (list[str]): Path to study locus dataset. - gwas_significance (float): GWAS significance threshold. valid_study_locus_path (str): Path to write the valid records. invalid_study_locus_path (str): Path to write the output file. invalid_qc_reasons (list[str]): List of invalid quality check reason names from `StudyLocusQualityCheck` (e.g. ['SUBSIGNIFICANT_FLAG']). From 51125c77e5d837a049bdf8dc141f40263b301302 Mon Sep 17 00:00:00 2001 From: Szymon Szyszkowski <69353402+project-defiant@users.noreply.github.com> Date: Thu, 26 Sep 2024 14:00:54 +0200 Subject: [PATCH 059/188] fix(vep_parser): use nested schema for insilico predictors (#789) --- src/gentropy/common/spark_helpers.py | 52 ++++++++++++++++++- src/gentropy/datasource/ensembl/vep_parser.py | 23 ++++---- tests/gentropy/data_samples/vep_sample.jsonl | 2 + .../datasource/ensembl/test_vep_variants.py | 37 +++++++++++++ 4 files changed, 102 insertions(+), 12 deletions(-) diff --git a/src/gentropy/common/spark_helpers.py b/src/gentropy/common/spark_helpers.py index 791fb913d..680975ef6 100644 --- a/src/gentropy/common/spark_helpers.py +++ b/src/gentropy/common/spark_helpers.py @@ -382,6 +382,8 @@ def order_array_of_structs_by_two_fields( """Sort array of structs by a field in descending order and by an other field in an ascending order. This function doesn't deal with null values, assumes the sort columns are not nullable. + The sorting function compares the descending_column first, in case when two values from descending_column are equal + it compares the ascending_column. When values in both columns are equal, the rows order is preserved. Args: array_name (str): Column name with array of structs @@ -406,6 +408,20 @@ def order_array_of_structs_by_two_fields( |[{1.0, 45, First}, {1.0, 125, Second}, {0.5, 232, Third}, {0.5, 233, Fourth}]| +-----------------------------------------------------------------------------+ + >>> data = [(1.0, 45, 'First'), (1.0, 45, 'Second'), (0.5, 233, 'Fourth'), (1.0, 125, 'Third'),] + >>> ( + ... spark.createDataFrame(data, ['col1', 'col2', 'ranking']) + ... .groupBy(f.lit('c')) + ... .agg(f.collect_list(f.struct('col1','col2', 'ranking')).alias('list')) + ... .select(order_array_of_structs_by_two_fields('list', 'col1', 'col2').alias('sorted_list')) + ... .show(truncate=False) + ... ) + +----------------------------------------------------------------------------+ + |sorted_list | + +----------------------------------------------------------------------------+ + |[{1.0, 45, First}, {1.0, 45, Second}, {1.0, 125, Third}, {0.5, 233, Fourth}]| + +----------------------------------------------------------------------------+ + """ return f.expr( f""" @@ -425,6 +441,7 @@ def order_array_of_structs_by_two_fields( when left.{descending_column} > right.{descending_column} then -1 when left.{descending_column} == right.{descending_column} and left.{ascending_column} > right.{ascending_column} then 1 when left.{descending_column} == right.{descending_column} and left.{ascending_column} < right.{ascending_column} then -1 + when left.{ascending_column} == right.{ascending_column} and left.{descending_column} == right.{descending_column} then 0 end) """ ) @@ -525,7 +542,7 @@ def get_value_from_row(row: Row, column: str) -> Any: def enforce_schema( - expected_schema: t.StructType, + expected_schema: t.ArrayType | t.StructType | Column | str, ) -> Callable[..., Any]: """A function to enforce the schema of a function output follows expectation. @@ -541,7 +558,7 @@ def my_function() -> t.StructType: return ... Args: - expected_schema (t.StructType): The expected schema of the output. + expected_schema (t.ArrayType | t.StructType | Column | str): The expected schema of the output. Returns: Callable[..., Any]: A decorator function. @@ -687,3 +704,34 @@ def get_standard_error_from_confidence_interval(lower: Column, upper: Column) -> """ return (upper - lower) / (2 * 1.96) + + +def get_nested_struct_schema(dtype: t.DataType) -> t.StructType: + """Get the bottom StructType from a nested ArrayType type. + + Args: + dtype (t.DataType): The nested data structure. + + Returns: + t.StructType: The nested struct schema. + + Raises: + TypeError: If the input data type is not a nested struct. + + Examples: + >>> get_nested_struct_schema(t.ArrayType(t.StructType([t.StructField('a', t.StringType())]))) + StructType([StructField('a', StringType(), True)]) + + >>> get_nested_struct_schema(t.ArrayType(t.ArrayType(t.StructType([t.StructField("a", t.StringType())])))) + StructType([StructField('a', StringType(), True)]) + """ + if isinstance(dtype, t.StructField): + dtype = dtype.dataType + + match dtype: + case t.StructType(fields=_): + return dtype + case t.ArrayType(elementType=dtype): + return get_nested_struct_schema(dtype) + case _: + raise TypeError("The input data type must be a nested struct.") diff --git a/src/gentropy/datasource/ensembl/vep_parser.py b/src/gentropy/datasource/ensembl/vep_parser.py index 4b70a36e6..d84b58407 100644 --- a/src/gentropy/datasource/ensembl/vep_parser.py +++ b/src/gentropy/datasource/ensembl/vep_parser.py @@ -14,6 +14,7 @@ from gentropy.common.schemas import parse_spark_schema from gentropy.common.spark_helpers import ( enforce_schema, + get_nested_struct_schema, map_column_by_dictionary, order_array_of_structs_by_field, order_array_of_structs_by_two_fields, @@ -26,14 +27,16 @@ class VariantEffectPredictorParser: """Collection of methods to parse VEP output in json format.""" + # NOTE: Due to the fact that the comparison of the xrefs is done om the base of rsids + # if the field `colocalised_variants` have multiple rsids, this extracting xrefs will result in + # an array of xref structs, rather then the struct itself. - # Schema description of the dbXref object: DBXREF_SCHEMA = VariantIndex.get_schema()["dbXrefs"].dataType # Schema description of the in silico predictor object: - IN_SILICO_PREDICTOR_SCHEMA = VariantIndex.get_schema()[ - "inSilicoPredictors" - ].dataType + IN_SILICO_PREDICTOR_SCHEMA = get_nested_struct_schema( + VariantIndex.get_schema()["inSilicoPredictors"] + ) # Schema for the allele frequency column: ALLELE_FREQUENCY_SCHEMA = VariantIndex.get_schema()["alleleFrequencies"].dataType @@ -350,12 +353,12 @@ def _get_max_alpha_missense(transcripts: Column) -> Column: ... .select(VariantEffectPredictorParser._get_max_alpha_missense(f.col('transcripts')).alias('am')) ... .show(truncate=False) ... ) - +------------------------------------------------------+ - |am | - +------------------------------------------------------+ - |[{max alpha missense, assessment 1, 0.4, null, gene1}]| - |[{max alpha missense, null, null, null, gene1}] | - +------------------------------------------------------+ + +----------------------------------------------------+ + |am | + +----------------------------------------------------+ + |{max alpha missense, assessment 1, 0.4, null, gene1}| + |{max alpha missense, null, null, null, gene1} | + +----------------------------------------------------+ """ return f.transform( diff --git a/tests/gentropy/data_samples/vep_sample.jsonl b/tests/gentropy/data_samples/vep_sample.jsonl index 2a3cb05dc..ec8ab7dbe 100644 --- a/tests/gentropy/data_samples/vep_sample.jsonl +++ b/tests/gentropy/data_samples/vep_sample.jsonl @@ -1,2 +1,4 @@ {"most_severe_consequence":"missense_variant","input":"17\t29510931\trs2153029597\tT\tC","assembly_name":"GRCh38","transcript_consequences":[{"consequence_terms":["downstream_gene_variant"],"gene_id":"ENSG00000238007","hgvsg":"17:g.29510931T>C","cadd_phred":28.9,"strand":1,"canonical":1,"impact":"MODIFIER","tssdistance":498066,"variant_allele":"C","cadd_raw":5.156509,"transcript_id":"ENST00000436028","distance":494419},{"hgvsg":"17:g.29510931T>C","consequence_terms":["downstream_gene_variant"],"gene_id":"ENSG00000222363","strand":1,"impact":"MODIFIER","canonical":1,"cadd_phred":28.9,"variant_allele":"C","tssdistance":122371,"transcript_id":"ENST00000410431","distance":122248,"cadd_raw":5.156509},{"cadd_raw":5.156509,"transcript_id":"ENST00000581240","distance":128696,"tssdistance":128696,"variant_allele":"C","cadd_phred":28.9,"strand":1,"impact":"MODIFIER","canonical":1,"consequence_terms":["upstream_gene_variant"],"gene_id":"ENSG00000263370","hgvsg":"17:g.29510931T>C"},{"consequence_terms":["downstream_gene_variant"],"gene_id":"ENSG00000264007","hgvsg":"17:g.29510931T>C","cadd_phred":28.9,"strand":-1,"impact":"MODIFIER","canonical":1,"tssdistance":111323,"variant_allele":"C","cadd_raw":5.156509,"transcript_id":"ENST00000582367","distance":110686},{"cadd_raw":5.156509,"distance":49616,"transcript_id":"ENST00000307201","appris":"P1","tssdistance":56106,"uniparc":["UPI00001C1FC9"],"swissprot":["Q6UXT9.120"],"variant_allele":"C","cadd_phred":28.9,"mane_select":"NM_198147.3","impact":"MODIFIER","canonical":1,"strand":-1,"gene_id":"ENSG00000168792","consequence_terms":["downstream_gene_variant"],"hgvsg":"17:g.29510931T>C"},{"strand":1,"impact":"MODIFIER","canonical":1,"cadd_phred":28.9,"hgvsg":"17:g.29510931T>C","consequence_terms":["upstream_gene_variant"],"gene_id":"ENSG00000264290","transcript_id":"ENST00000579050","distance":58649,"cadd_raw":5.156509,"variant_allele":"C","tssdistance":58649},{"strand":1,"canonical":1,"impact":"MODIFIER","cadd_phred":28.9,"hgvsg":"17:g.29510931T>C","consequence_terms":["upstream_gene_variant"],"gene_id":"ENSG00000263657","transcript_id":"ENST00000577846","distance":250172,"cadd_raw":5.156509,"variant_allele":"C","tssdistance":250172},{"variant_allele":"C","swissprot":["Q6QEF8.143"],"uniparc":["UPI0000DA4C55"],"tssdistance":111981,"transcript_id":"ENST00000388767","distance":103831,"cadd_raw":5.156509,"uniprot_isoform":["Q6QEF8-5"],"hgvsg":"17:g.29510931T>C","consequence_terms":["downstream_gene_variant"],"gene_id":"ENSG00000167549","strand":-1,"canonical":1,"impact":"MODIFIER","mane_select":"NM_032854.4","cadd_phred":28.9},{"hgvsg":"17:g.29510931T>C","consequence_terms":["upstream_gene_variant"],"gene_id":"ENSG00000263781","strand":-1,"impact":"MODIFIER","canonical":1,"cadd_phred":28.9,"variant_allele":"C","tssdistance":489291,"transcript_id":"ENST00000580924","distance":489291,"cadd_raw":5.156509},{"strand":1,"impact":"MODIFIER","canonical":1,"mane_select":"NM_198529.4","cadd_phred":28.9,"uniprot_isoform":["A4FU69-1"],"hgvsg":"17:g.29510931T>C","consequence_terms":["upstream_gene_variant"],"gene_id":"ENSG00000176927","appris":"P1","transcript_id":"ENST00000394835","distance":430703,"cadd_raw":5.156509,"variant_allele":"C","swissprot":["A4FU69.119"],"uniparc":["UPI0000E59EF5"],"tssdistance":430703},{"cdna_start":2399,"tssdistance":120568,"amino_acids":"L/P","swissprot":["Q7L7X3.173"],"transcript_id":"ENST00000261716","appris":"P1","consequence_terms":["missense_variant"],"trembl":["A0A024QZ70.65"],"cds_start":1643,"mane_select":"NM_020791.4","cadd_phred":28.9,"strand":1,"cds_end":1643,"impact":"MODERATE","canonical":1,"uniparc":["UPI000004A033"],"variant_allele":"C","cadd_raw":5.156509,"sift_score":0,"protein_start":548,"cdna_end":2399,"gene_id":"ENSG00000160551","uniprot_isoform":["Q7L7X3-1"],"codons":"cTg/cCg","sift_prediction":"deleterious_low_confidence","hgvsg":"17:g.29510931T>C","alphamissense":{"am_class":"likely_pathogenic","am_pathogenicity":0.9994},"protein_end":548,"polyphen_score":0.999,"polyphen_prediction":"probably_damaging"},{"uniparc":["UPI0000246D82"],"tssdistance":82201,"variant_allele":"C","swissprot":["Q86YJ7.146"],"cadd_raw":5.156509,"transcript_id":"ENST00000394859","appris":"P1","distance":82201,"consequence_terms":["upstream_gene_variant"],"gene_id":"ENSG00000198720","uniprot_isoform":["Q86YJ7-1"],"hgvsg":"17:g.29510931T>C","trembl":["A0A024QZ29.60"],"mane_select":"NM_152345.5","cadd_phred":28.9,"strand":1,"impact":"MODIFIER","canonical":1},{"transcript_id":"ENST00000459235","distance":372075,"cadd_raw":5.156509,"variant_allele":"C","tssdistance":372075,"strand":1,"impact":"MODIFIER","canonical":1,"cadd_phred":28.9,"hgvsg":"17:g.29510931T>C","consequence_terms":["upstream_gene_variant"],"gene_id":"ENSG00000239129"},{"tssdistance":205754,"variant_allele":"C","cadd_raw":5.156509,"distance":205348,"transcript_id":"ENST00000493028","gene_id":"ENSG00000240531","consequence_terms":["downstream_gene_variant"],"hgvsg":"17:g.29510931T>C","cadd_phred":28.9,"impact":"MODIFIER","canonical":1,"strand":-1},{"consequence_terms":["downstream_gene_variant"],"gene_id":"ENSG00000284162","hgvsg":"17:g.29510931T>C","cadd_phred":28.9,"strand":1,"canonical":1,"impact":"MODIFIER","tssdistance":120269,"variant_allele":"C","cadd_raw":5.156509,"transcript_id":"ENST00000580425","distance":120201},{"tssdistance":49616,"variant_allele":"C","cadd_raw":5.156509,"transcript_id":"ENST00000581474","distance":49616,"consequence_terms":["upstream_gene_variant"],"gene_id":"ENSG00000264031","hgvsg":"17:g.29510931T>C","cadd_phred":28.9,"strand":1,"canonical":1,"impact":"MODIFIER"},{"hgvsg":"17:g.29510931T>C","gene_id":"ENSG00000222858","consequence_terms":["downstream_gene_variant"],"impact":"MODIFIER","canonical":1,"strand":-1,"cadd_phred":28.9,"variant_allele":"C","tssdistance":130771,"distance":130680,"transcript_id":"ENST00000410926","cadd_raw":5.156509},{"tssdistance":461583,"variant_allele":"C","cadd_raw":5.156509,"transcript_id":"ENST00000581995","distance":461583,"consequence_terms":["upstream_gene_variant"],"gene_id":"ENSG00000264435","hgvsg":"17:g.29510931T>C","cadd_phred":28.9,"strand":1,"canonical":1,"impact":"MODIFIER"},{"gene_id":"ENSG00000179761","consequence_terms":["downstream_gene_variant"],"hgvsg":"17:g.29510931T>C","mane_select":"NM_016518.3","cadd_phred":28.9,"canonical":1,"impact":"MODIFIER","strand":1,"tssdistance":467790,"uniparc":["UPI00001410B0"],"swissprot":["Q9P0Z9.165"],"variant_allele":"C","cadd_raw":5.156509,"distance":453715,"appris":"P1","transcript_id":"ENST00000323372"},{"strand":-1,"canonical":1,"impact":"MODIFIER","cadd_phred":28.9,"hgvsg":"17:g.29510931T>C","consequence_terms":["upstream_gene_variant"],"gene_id":"ENSG00000253064","transcript_id":"ENST00000517255","distance":86064,"cadd_raw":5.156509,"variant_allele":"C","tssdistance":86064},{"tssdistance":313146,"variant_allele":"C","cadd_raw":5.156509,"distance":313146,"transcript_id":"ENST00000580309","gene_id":"ENSG00000264050","consequence_terms":["upstream_gene_variant"],"hgvsg":"17:g.29510931T>C","cadd_phred":28.9,"canonical":1,"impact":"MODIFIER","strand":-1},{"variant_allele":"C","tssdistance":134916,"transcript_id":"ENST00000582881","distance":133865,"cadd_raw":5.156509,"hgvsg":"17:g.29510931T>C","consequence_terms":["downstream_gene_variant"],"gene_id":"ENSG00000265625","strand":-1,"impact":"MODIFIER","canonical":1,"cadd_phred":28.9},{"hgvsg":"17:g.29510931T>C","gene_id":"ENSG00000240074","consequence_terms":["upstream_gene_variant"],"impact":"MODIFIER","canonical":1,"strand":1,"cadd_phred":28.9,"variant_allele":"C","tssdistance":344828,"distance":344828,"transcript_id":"ENST00000478775","cadd_raw":5.156509},{"cadd_phred":28.9,"canonical":1,"impact":"MODIFIER","strand":-1,"gene_id":"ENSG00000264647","consequence_terms":["downstream_gene_variant"],"hgvsg":"17:g.29510931T>C","cadd_raw":5.156509,"distance":80772,"transcript_id":"ENST00000584986","tssdistance":81310,"variant_allele":"C"},{"variant_allele":"C","tssdistance":65531,"transcript_id":"ENST00000365335","distance":65531,"cadd_raw":5.156509,"hgvsg":"17:g.29510931T>C","consequence_terms":["upstream_gene_variant"],"gene_id":"ENSG00000202205","strand":-1,"canonical":1,"impact":"MODIFIER","cadd_phred":28.9},{"gene_id":"ENSG00000266111","consequence_terms":["downstream_gene_variant"],"hgvsg":"17:g.29510931T>C","cadd_phred":28.9,"impact":"MODIFIER","canonical":1,"strand":1,"tssdistance":158862,"variant_allele":"C","cadd_raw":5.156509,"distance":106826,"transcript_id":"ENST00000584958"},{"variant_allele":"C","tssdistance":265770,"distance":264816,"transcript_id":"ENST00000580031","cadd_raw":5.156509,"hgvsg":"17:g.29510931T>C","gene_id":"ENSG00000265713","consequence_terms":["downstream_gene_variant"],"canonical":1,"impact":"MODIFIER","strand":-1,"cadd_phred":28.9},{"consequence_terms":["downstream_gene_variant"],"gene_id":"ENSG00000108255","uniprot_isoform":["P05813-1"],"hgvsg":"17:g.29510931T>C","mane_select":"NM_005208.5","cadd_phred":28.9,"strand":1,"impact":"MODIFIER","canonical":1,"uniparc":["UPI00001283CF"],"tssdistance":264072,"variant_allele":"C","swissprot":["P05813.205"],"cadd_raw":5.156509,"transcript_id":"ENST00000225387","appris":"P1","distance":256437},{"consequence_terms":["upstream_gene_variant"],"gene_id":"ENSG00000264808","hgvsg":"17:g.29510931T>C","cadd_phred":28.9,"strand":-1,"canonical":1,"impact":"MODIFIER","tssdistance":120702,"variant_allele":"C","cadd_raw":5.156509,"transcript_id":"ENST00000685798","distance":120702},{"cadd_phred":28.9,"strand":-1,"canonical":1,"impact":"MODIFIER","consequence_terms":["downstream_gene_variant"],"gene_id":"ENSG00000290082","hgvsg":"17:g.29510931T>C","cadd_raw":5.156509,"transcript_id":"ENST00000702873","distance":56892,"tssdistance":57602,"variant_allele":"C"},{"mane_select":"NM_078471.4","cadd_phred":28.9,"strand":-1,"canonical":1,"impact":"MODIFIER","consequence_terms":["upstream_gene_variant"],"gene_id":"ENSG00000196535","uniprot_isoform":["Q92614-1"],"hgvsg":"17:g.29510931T>C","cadd_raw":5.156509,"appris":"P4","transcript_id":"ENST00000527372","distance":330533,"uniparc":["UPI0000167F32"],"tssdistance":330533,"variant_allele":"C","swissprot":["Q92614.216"]},{"cadd_raw":5.156509,"transcript_id":"ENST00000492004","distance":170109,"tssdistance":170109,"variant_allele":"C","cadd_phred":28.9,"strand":-1,"impact":"MODIFIER","canonical":1,"consequence_terms":["upstream_gene_variant"],"gene_id":"ENSG00000239256","hgvsg":"17:g.29510931T>C"},{"gene_id":"ENSG00000263709","consequence_terms":["downstream_gene_variant"],"hgvsg":"17:g.29510931T>C","cadd_phred":28.9,"canonical":1,"impact":"MODIFIER","strand":1,"tssdistance":370448,"variant_allele":"C","cadd_raw":5.156509,"distance":355442,"transcript_id":"ENST00000582196"},{"consequence_terms":["upstream_gene_variant"],"gene_id":"ENSG00000252657","hgvsg":"17:g.29510931T>C","cadd_phred":28.9,"strand":1,"impact":"MODIFIER","canonical":1,"tssdistance":266688,"variant_allele":"C","cadd_raw":5.156509,"transcript_id":"ENST00000516848","distance":266688},{"trembl":["F5H527.88"],"mane_select":"NM_001282129.2","cadd_phred":28.9,"strand":-1,"impact":"MODIFIER","canonical":1,"consequence_terms":["downstream_gene_variant"],"gene_id":"ENSG00000141298","hgvsg":"17:g.29510931T>C","cadd_raw":5.156509,"transcript_id":"ENST00000540801","appris":"A1","distance":115007,"uniparc":["UPI0002065A97"],"tssdistance":419297,"variant_allele":"C"},{"tssdistance":216783,"uniparc":["UPI00001B078D"],"swissprot":["Q7Z417.159"],"variant_allele":"C","cadd_raw":5.156509,"distance":216783,"transcript_id":"ENST00000225388","appris":"P1","gene_id":"ENSG00000108256","consequence_terms":["upstream_gene_variant"],"hgvsg":"17:g.29510931T>C","uniprot_isoform":["Q7Z417-1"],"mane_select":"NM_020772.3","cadd_phred":28.9,"impact":"MODIFIER","canonical":1,"strand":-1},{"consequence_terms":["downstream_gene_variant"],"gene_id":"ENSG00000108262","uniprot_isoform":["Q9Y2X7-1"],"hgvsg":"17:g.29510931T>C","mane_select":"NM_014030.4","cadd_phred":28.9,"strand":-1,"impact":"MODIFIER","canonical":1,"uniparc":["UPI000013C867"],"tssdistance":78717,"variant_allele":"C","swissprot":["Q9Y2X7.219"],"cadd_raw":5.156509,"transcript_id":"ENST00000225394","appris":"A1","distance":62544},{"variant_allele":"C","tssdistance":499922,"transcript_id":"ENST00000581964","distance":499922,"cadd_raw":5.156509,"hgvsg":"17:g.29510931T>C","consequence_terms":["upstream_gene_variant"],"gene_id":"ENSG00000263613","strand":-1,"impact":"MODIFIER","canonical":1,"cadd_phred":28.9},{"variant_allele":"C","tssdistance":306457,"transcript_id":"ENST00000580812","distance":306457,"cadd_raw":5.156509,"hgvsg":"17:g.29510931T>C","consequence_terms":["upstream_gene_variant"],"gene_id":"ENSG00000178082","strand":-1,"impact":"MODIFIER","canonical":1,"cadd_phred":28.9},{"variant_allele":"C","tssdistance":352471,"distance":352471,"transcript_id":"ENST00000584258","cadd_raw":5.156509,"hgvsg":"17:g.29510931T>C","gene_id":"ENSG00000263477","consequence_terms":["upstream_gene_variant"],"canonical":1,"impact":"MODIFIER","strand":1,"cadd_phred":28.9},{"cadd_raw":5.156509,"transcript_id":"ENST00000301057","appris":"P1","distance":57770,"uniparc":["UPI000003B08D"],"tssdistance":57770,"variant_allele":"C","swissprot":["Q8NBR0.130"],"mane_select":"NM_138349.4","cadd_phred":28.9,"strand":1,"impact":"MODIFIER","canonical":1,"consequence_terms":["upstream_gene_variant"],"gene_id":"ENSG00000167543","hgvsg":"17:g.29510931T>C"}],"allele_string":"T/C","seq_region_name":"17","strand":1,"end":29510931,"start":29510931,"colocated_variants":[{"clin_sig":["pathogenic"],"clin_sig_allele":"C:pathogenic","phenotype_or_disease":1,"strand":1,"allele_string":"T/C","start":29510931,"id":"rs2153029597","seq_region_name":"17","pubmed":[33565190],"end":29510931,"var_synonyms":{"ClinVar":["RCV001731168","VCV001300172"],"OMIM":[610266.0003]}}],"id":"rs2153029597"} {"strand":1,"seq_region_name":"9","allele_string":"C/T","transcript_consequences":[{"hgvsg":"9:g.82445881C>T","consequence_terms":["upstream_gene_variant"],"gene_id":"ENSG00000228046","strand":-1,"impact":"MODIFIER","canonical":1,"cadd_phred":7.002,"variant_allele":"T","tssdistance":17856,"transcript_id":"ENST00000392516","distance":17856,"cadd_raw":0.6583},{"cadd_phred":7.002,"impact":"MODIFIER","canonical":1,"strand":1,"gene_id":"ENSG00000225085","consequence_terms":["downstream_gene_variant"],"hgvsg":"9:g.82445881C>T","cadd_raw":0.6583,"distance":39642,"transcript_id":"ENST00000436084","tssdistance":40693,"variant_allele":"T"},{"cadd_raw":0.6583,"transcript_id":"ENST00000637606","tssdistance":468267,"variant_allele":"T","cadd_phred":7.002,"canonical":1,"impact":"MODIFIER","strand":1,"gene_id":"ENSG00000290551","consequence_terms":["intron_variant","non_coding_transcript_variant"],"hgvsg":"9:g.82445881C>T"},{"gene_id":"ENSG00000278988","consequence_terms":["upstream_gene_variant"],"hgvsg":"9:g.82445881C>T","cadd_phred":7.002,"canonical":1,"impact":"MODIFIER","strand":1,"tssdistance":97837,"variant_allele":"T","cadd_raw":0.6583,"distance":97837,"transcript_id":"ENST00000623079"},{"swissprot":["Q6ZQQ2.115"],"variant_allele":"T","tssdistance":457109,"uniparc":["UPI00001C10A6"],"distance":450628,"appris":"P1","transcript_id":"ENST00000344803","cadd_raw":0.6583,"hgvsg":"9:g.82445881C>T","gene_id":"ENSG00000214929","consequence_terms":["downstream_gene_variant"],"impact":"MODIFIER","canonical":1,"strand":1,"cadd_phred":7.002,"mane_select":"NM_001001670.3"},{"cadd_phred":7.002,"impact":"MODIFIER","canonical":1,"strand":-1,"gene_id":"ENSG00000230360","consequence_terms":["upstream_gene_variant"],"hgvsg":"9:g.82445881C>T","cadd_raw":0.6583,"distance":357113,"transcript_id":"ENST00000417796","tssdistance":357113,"variant_allele":"T"},{"cadd_raw":0.6583,"transcript_id":"ENST00000422010","distance":5775,"tssdistance":5775,"variant_allele":"T","cadd_phred":7.002,"strand":1,"canonical":1,"impact":"MODIFIER","consequence_terms":["upstream_gene_variant"],"gene_id":"ENSG00000232749","hgvsg":"9:g.82445881C>T"},{"tssdistance":12976,"variant_allele":"T","cadd_raw":0.6583,"transcript_id":"ENST00000438986","distance":12976,"consequence_terms":["upstream_gene_variant"],"gene_id":"ENSG00000228123","hgvsg":"9:g.82445881C>T","cadd_phred":7.002,"strand":-1,"canonical":1,"impact":"MODIFIER"},{"tssdistance":382199,"variant_allele":"T","cadd_raw":0.6583,"transcript_id":"ENST00000434692","distance":382199,"consequence_terms":["upstream_gene_variant"],"gene_id":"ENSG00000231649","hgvsg":"9:g.82445881C>T","cadd_phred":7.002,"strand":-1,"canonical":1,"impact":"MODIFIER"},{"tssdistance":298911,"variant_allele":"T","cadd_raw":0.6583,"transcript_id":"ENST00000432491","distance":298186,"consequence_terms":["downstream_gene_variant"],"gene_id":"ENSG00000233309","hgvsg":"9:g.82445881C>T","cadd_phred":7.002,"strand":-1,"canonical":1,"impact":"MODIFIER"},{"canonical":1,"impact":"MODIFIER","strand":1,"cadd_phred":7.002,"hgvsg":"9:g.82445881C>T","gene_id":"ENSG00000235377","consequence_terms":["downstream_gene_variant"],"distance":314249,"transcript_id":"ENST00000445918","cadd_raw":0.6583,"variant_allele":"T","tssdistance":315129},{"variant_allele":"T","tssdistance":17682,"distance":17588,"transcript_id":"ENST00000636401","cadd_raw":0.6583,"hgvsg":"9:g.82445881C>T","gene_id":"ENSG00000228430","consequence_terms":["downstream_gene_variant"],"impact":"MODIFIER","canonical":1,"strand":1,"cadd_phred":7.002},{"cadd_raw":0.6583,"transcript_id":"ENST00000585776","distance":468792,"tssdistance":468792,"variant_allele":"T","cadd_phred":7.002,"strand":-1,"impact":"MODIFIER","canonical":1,"consequence_terms":["upstream_gene_variant"],"gene_id":"ENSG00000267559","hgvsg":"9:g.82445881C>T"},{"impact":"MODIFIER","canonical":1,"strand":1,"cadd_phred":7.002,"hgvsg":"9:g.82445881C>T","gene_id":"ENSG00000237770","consequence_terms":["downstream_gene_variant"],"distance":473751,"transcript_id":"ENST00000429999","cadd_raw":0.6583,"variant_allele":"T","tssdistance":479317},{"distance":166671,"transcript_id":"ENST00000661177","cadd_raw":0.6583,"variant_allele":"T","tssdistance":200703,"impact":"MODIFIER","canonical":1,"strand":-1,"cadd_phred":7.002,"hgvsg":"9:g.82445881C>T","gene_id":"ENSG00000286612","consequence_terms":["downstream_gene_variant"]},{"mane_select":"NM_207416.3","cadd_phred":7.002,"impact":"MODIFIER","canonical":1,"strand":1,"gene_id":"ENSG00000186788","consequence_terms":["downstream_gene_variant"],"hgvsg":"9:g.82445881C>T","cadd_raw":0.6583,"distance":495788,"appris":"P1","transcript_id":"ENST00000445385","tssdistance":502381,"uniparc":["UPI000048D678"],"swissprot":["P0C874.81"],"variant_allele":"T"}],"assembly_name":"GRCh38","input":"9\t82445881\t9_82445881_C_T\tC\tT","most_severe_consequence":"intron_variant","id":"9_82445881_C_T","colocated_variants":[{"phenotype_or_disease":1,"strand":1,"allele_string":"C/G/T","frequencies":{"T":{"gnomadg":0.01197,"gnomadg_amr":0.0191,"gnomadg_afr":0.003331,"gnomadg_asj":0.02364,"eas":0,"amr":0.0216,"gnomadg_eas":0,"sas":0,"gnomadg_nfe":0.01704,"gnomadg_fin":0.009992,"gnomadg_mid":0.006329,"afr":0,"gnomadg_oth":0.01772,"gnomadg_ami":0.003289,"af":0.0068,"eur":0.0189,"gnomadg_sas":0.0004142}},"start":82445881,"id":"rs117517710","seq_region_name":"9","pubmed":[31073882],"end":82445881}],"end":82445881,"start":82445881} +{"assembly_name":"GRCh38","seq_region_name":"20","id":"rs1555828246","start":10645397,"strand":1,"transcript_consequences":[{"hgvsg":"20:g.10645397C>T","canonical":1,"strand":-1,"distance":295769,"consequence_terms":["upstream_gene_variant"],"cadd_raw":4.925023,"cadd_phred":27.5,"variant_allele":"T","gene_id":"ENSG00000214835","impact":"MODIFIER","transcript_id":"ENST00000446637","tssdistance":295769},{"impact":"MODIFIER","transcript_id":"ENST00000417299","tssdistance":51552,"gene_id":"ENSG00000224961","distance":51552,"consequence_terms":["upstream_gene_variant"],"cadd_raw":4.925023,"variant_allele":"T","cadd_phred":27.5,"canonical":1,"hgvsg":"20:g.10645397C>T","strand":1},{"consequence_terms":["upstream_gene_variant"],"distance":355907,"variant_allele":"T","cadd_phred":27.5,"cadd_raw":4.925023,"strand":1,"hgvsg":"20:g.10645397C>T","canonical":1,"transcript_id":"ENST00000605338","impact":"MODIFIER","tssdistance":355907,"gene_id":"ENSG00000270777"},{"gene_id":"ENSG00000235036","transcript_id":"ENST00000456064","tssdistance":31168,"impact":"MODIFIER","canonical":1,"hgvsg":"20:g.10645397C>T","strand":-1,"distance":31168,"consequence_terms":["upstream_gene_variant"],"cadd_phred":27.5,"variant_allele":"T","cadd_raw":4.925023},{"hgvsg":"20:g.10645397C>T","canonical":1,"strand":-1,"cadd_phred":27.5,"variant_allele":"T","cadd_raw":4.925023,"distance":107881,"consequence_terms":["downstream_gene_variant"],"gene_id":"ENSG00000234900","transcript_id":"ENST00000418690","impact":"MODIFIER","tssdistance":119889},{"strand":1,"hgvsg":"20:g.10645397C>T","canonical":1,"cadd_raw":4.925023,"cadd_phred":27.5,"variant_allele":"T","consequence_terms":["downstream_gene_variant"],"distance":444573,"gene_id":"ENSG00000230506","transcript_id":"ENST00000662058","impact":"MODIFIER","tssdistance":472875},{"cadd_phred":27.5,"variant_allele":"T","cadd_raw":4.925023,"consequence_terms":["upstream_gene_variant"],"distance":211175,"strand":-1,"canonical":1,"hgvsg":"20:g.10645397C>T","uniparc":["UPI0000D483F7"],"mane_select":"NM_001394149.2","tssdistance":211175,"transcript_id":"ENST00000713549","impact":"MODIFIER","gene_id":"ENSG00000285508"},{"impact":"MODIFIER","transcript_id":"ENST00000666915","tssdistance":472696,"gene_id":"ENSG00000232448","consequence_terms":["downstream_gene_variant"],"distance":458657,"cadd_raw":4.925023,"variant_allele":"T","cadd_phred":27.5,"strand":1,"canonical":1,"hgvsg":"20:g.10645397C>T"},{"consequence_terms":["downstream_gene_variant"],"distance":310699,"cadd_raw":4.925023,"variant_allele":"T","cadd_phred":27.5,"strand":1,"canonical":1,"hgvsg":"20:g.10645397C>T","transcript_id":"ENST00000416198","impact":"MODIFIER","tssdistance":310978,"gene_id":"ENSG00000237005"},{"cadd_phred":27.5,"variant_allele":"T","cadd_raw":4.925023,"distance":229936,"consequence_terms":["downstream_gene_variant"],"hgvsg":"20:g.10645397C>T","canonical":1,"strand":-1,"tssdistance":263882,"transcript_id":"ENST00000448859","impact":"MODIFIER","gene_id":"ENSG00000232900"},{"impact":"MODIFIER","transcript_id":"ENST00000649912","tssdistance":211175,"appris":"P1","gene_id":"ENSG00000285723","trembl":["Q9HB66.115"],"cadd_raw":4.925023,"variant_allele":"T","cadd_phred":27.5,"distance":211175,"consequence_terms":["upstream_gene_variant"],"canonical":1,"hgvsg":"20:g.10645397C>T","strand":-1,"mane_select":"NM_001394148.2","uniparc":["UPI000006FBAA"]},{"transcript_id":"ENST00000347364","tssdistance":211175,"impact":"MODIFIER","appris":"P1","gene_id":"ENSG00000125863","cadd_phred":27.5,"variant_allele":"T","cadd_raw":4.925023,"swissprot":["Q9NPJ1.195"],"consequence_terms":["upstream_gene_variant"],"distance":211175,"strand":-1,"canonical":1,"hgvsg":"20:g.10645397C>T","uniparc":["UPI000012F199"],"mane_select":"NM_170784.3"},{"tssdistance":4298,"transcript_id":"ENST00000615931","impact":"MODIFIER","gene_id":"ENSG00000273745","cadd_raw":4.925023,"variant_allele":"T","cadd_phred":27.5,"distance":4239,"consequence_terms":["downstream_gene_variant"],"canonical":1,"hgvsg":"20:g.10645397C>T","strand":-1},{"cadd_phred":27.5,"variant_allele":"T","cadd_raw":4.925023,"consequence_terms":["downstream_gene_variant"],"distance":257591,"strand":1,"hgvsg":"20:g.10645397C>T","canonical":1,"impact":"MODIFIER","transcript_id":"ENST00000441308","tssdistance":259618,"gene_id":"ENSG00000230750"},{"consequence_terms":["downstream_gene_variant"],"distance":17367,"cadd_raw":4.925023,"variant_allele":"T","cadd_phred":27.5,"swissprot":["Q5VYV7.120"],"uniparc":["UPI00001D8318"],"mane_select":"NM_001009608.3","strand":1,"hgvsg":"20:g.10645397C>T","canonical":1,"appris":"P1","transcript_id":"ENST00000334534","impact":"MODIFIER","tssdistance":210092,"gene_id":"ENSG00000149346"},{"gene_id":"ENSG00000125899","transcript_id":"ENST00000659767","tssdistance":350896,"impact":"MODIFIER","hgvsg":"20:g.10645397C>T","canonical":1,"strand":1,"cadd_raw":4.925023,"cadd_phred":27.5,"variant_allele":"T","distance":350896,"consequence_terms":["upstream_gene_variant"]},{"cadd_raw":4.925023,"variant_allele":"T","cadd_phred":27.5,"distance":335492,"consequence_terms":["downstream_gene_variant"],"canonical":1,"hgvsg":"20:g.10645397C>T","strand":1,"transcript_id":"ENST00000688853","tssdistance":336975,"impact":"MODIFIER","gene_id":"ENSG00000289505"},{"appris":"P3","impact":"MODIFIER","transcript_id":"ENST00000254976","tssdistance":426567,"gene_id":"ENSG00000132639","uniprot_isoform":["P60880-1"],"distance":337979,"consequence_terms":["downstream_gene_variant"],"swissprot":["P60880.188"],"cadd_raw":4.925023,"cadd_phred":27.5,"variant_allele":"T","mane_select":"NM_130811.4","uniparc":["UPI0000001103"],"hgvsg":"20:g.10645397C>T","canonical":1,"strand":1},{"strand":1,"canonical":1,"hgvsg":"20:g.10645397C>T","consequence_terms":["upstream_gene_variant"],"distance":27531,"cadd_raw":4.925023,"variant_allele":"T","cadd_phred":27.5,"gene_id":"ENSG00000270792","transcript_id":"ENST00000605292","impact":"MODIFIER","tssdistance":27531},{"hgvsg":"20:g.10645397C>T","canonical":1,"strand":-1,"distance":276678,"consequence_terms":["upstream_gene_variant"],"cadd_phred":27.5,"variant_allele":"T","cadd_raw":4.925023,"gene_id":"ENSG00000227906","impact":"MODIFIER","transcript_id":"ENST00000421143","tssdistance":276678},{"distance":243185,"consequence_terms":["downstream_gene_variant"],"variant_allele":"T","cadd_phred":27.5,"cadd_raw":4.925023,"canonical":1,"hgvsg":"20:g.10645397C>T","strand":-1,"tssdistance":243691,"transcript_id":"ENST00000406588","impact":"MODIFIER","gene_id":"ENSG00000217809"},{"uniprot_isoform":["P78504-1"],"cdna_end":2541,"appris":"P1","transcript_id":"ENST00000254958","impact":"MODERATE","tssdistance":28602,"sift_prediction":"deleterious","codons":"tGt/tAt","uniparc":["UPI00000498B5"],"strand":-1,"canonical":1,"swissprot":["P78504.228"],"cds_start":2072,"gene_id":"ENSG00000101384","cds_end":2072,"protein_start":691,"sift_score":0,"mane_select":"NM_000214.3","hgvsg":"20:g.10645397C>T","consequence_terms":["missense_variant"],"protein_end":691,"cadd_raw":4.925023,"cadd_phred":27.5,"variant_allele":"T","cdna_start":2541,"amino_acids":"C/Y"},{"canonical":1,"hgvsg":"20:g.10645397C>T","strand":-1,"cadd_phred":27.5,"variant_allele":"T","cadd_raw":4.925023,"distance":326644,"consequence_terms":["upstream_gene_variant"],"gene_id":"ENSG00000286936","transcript_id":"ENST00000664194","tssdistance":326644,"impact":"MODIFIER"}],"input":"20\t10645397\trs1555828246\tC\tT\t.\t.\t.","allele_string":"C/T","end":10645397,"colocated_variants":[{"end":10645397,"allele_string":"C/T","strand":1,"id":"rs1555828246","seq_region_name":"20","start":10645397},{"end":10645397,"allele_string":"C/T","phenotype_or_disease":1,"clin_sig":["uncertain_significance"],"pubmed":[26076142,21752016],"strand":1,"clin_sig_allele":"T:uncertain_significance","start":10645397,"seq_region_name":"20","var_synonyms":{"ClinVar":["RCV002260566","VCV001693298"]}}],"most_severe_consequence":"missense_variant"} +{"input":"20\t10649087\trs863223652\tG\tA\t.\t.\t.","transcript_consequences":[{"strand":1,"canonical":1,"hgvsg":"20:g.10649087G>A","cadd_phred":40,"variant_allele":"A","cadd_raw":9.333171,"consequence_terms":["upstream_gene_variant"],"distance":352217,"gene_id":"ENSG00000270777","transcript_id":"ENST00000605338","impact":"MODIFIER","tssdistance":352217},{"impact":"MODIFIER","transcript_id":"ENST00000417299","tssdistance":47862,"gene_id":"ENSG00000224961","cadd_raw":9.333171,"cadd_phred":40,"variant_allele":"A","distance":47862,"consequence_terms":["upstream_gene_variant"],"hgvsg":"20:g.10649087G>A","canonical":1,"strand":1},{"gene_id":"ENSG00000214835","impact":"MODIFIER","transcript_id":"ENST00000446637","tssdistance":299459,"strand":-1,"hgvsg":"20:g.10649087G>A","canonical":1,"variant_allele":"A","cadd_phred":40,"cadd_raw":9.333171,"consequence_terms":["upstream_gene_variant"],"distance":299459},{"transcript_id":"ENST00000456064","impact":"MODIFIER","tssdistance":34858,"gene_id":"ENSG00000235036","distance":34858,"consequence_terms":["upstream_gene_variant"],"cadd_phred":40,"variant_allele":"A","cadd_raw":9.333171,"canonical":1,"hgvsg":"20:g.10649087G>A","strand":-1},{"transcript_id":"ENST00000662058","tssdistance":476565,"impact":"MODIFIER","gene_id":"ENSG00000230506","consequence_terms":["downstream_gene_variant"],"distance":448263,"variant_allele":"A","cadd_phred":40,"cadd_raw":9.333171,"strand":1,"canonical":1,"hgvsg":"20:g.10649087G>A"},{"impact":"MODIFIER","transcript_id":"ENST00000418690","tssdistance":116199,"gene_id":"ENSG00000234900","cadd_raw":9.333171,"variant_allele":"A","cadd_phred":40,"distance":104191,"consequence_terms":["downstream_gene_variant"],"hgvsg":"20:g.10649087G>A","canonical":1,"strand":-1},{"gene_id":"ENSG00000232448","transcript_id":"ENST00000666915","tssdistance":476386,"impact":"MODIFIER","hgvsg":"20:g.10649087G>A","canonical":1,"strand":1,"cadd_raw":9.333171,"cadd_phred":40,"variant_allele":"A","distance":462347,"consequence_terms":["downstream_gene_variant"]},{"variant_allele":"A","cadd_phred":40,"cadd_raw":9.333171,"distance":214865,"consequence_terms":["upstream_gene_variant"],"hgvsg":"20:g.10649087G>A","canonical":1,"strand":-1,"mane_select":"NM_001394149.2","uniparc":["UPI0000D483F7"],"impact":"MODIFIER","transcript_id":"ENST00000713549","tssdistance":214865,"gene_id":"ENSG00000285508"},{"transcript_id":"ENST00000416198","impact":"MODIFIER","tssdistance":314668,"gene_id":"ENSG00000237005","consequence_terms":["downstream_gene_variant"],"distance":314389,"cadd_raw":9.333171,"cadd_phred":40,"variant_allele":"A","strand":1,"canonical":1,"hgvsg":"20:g.10649087G>A"},{"gene_id":"ENSG00000289505","tssdistance":340665,"transcript_id":"ENST00000688853","impact":"MODIFIER","hgvsg":"20:g.10649087G>A","canonical":1,"strand":1,"distance":339182,"consequence_terms":["downstream_gene_variant"],"variant_allele":"A","cadd_phred":40,"cadd_raw":9.333171},{"impact":"MODIFIER","transcript_id":"ENST00000659767","tssdistance":347206,"gene_id":"ENSG00000125899","distance":347206,"consequence_terms":["upstream_gene_variant"],"cadd_phred":40,"variant_allele":"A","cadd_raw":9.333171,"hgvsg":"20:g.10649087G>A","canonical":1,"strand":1},{"consequence_terms":["upstream_gene_variant"],"distance":214865,"variant_allele":"A","cadd_phred":40,"cadd_raw":9.333171,"swissprot":["Q9NPJ1.195"],"uniparc":["UPI000012F199"],"mane_select":"NM_170784.3","strand":-1,"hgvsg":"20:g.10649087G>A","canonical":1,"appris":"P1","transcript_id":"ENST00000347364","tssdistance":214865,"impact":"MODIFIER","gene_id":"ENSG00000125863"},{"gene_id":"ENSG00000285723","appris":"P1","tssdistance":214865,"transcript_id":"ENST00000649912","impact":"MODIFIER","mane_select":"NM_001394148.2","uniparc":["UPI000006FBAA"],"hgvsg":"20:g.10649087G>A","canonical":1,"strand":-1,"distance":214865,"consequence_terms":["upstream_gene_variant"],"trembl":["Q9HB66.115"],"cadd_phred":40,"variant_allele":"A","cadd_raw":9.333171},{"strand":-1,"hgvsg":"20:g.10649087G>A","canonical":1,"consequence_terms":["downstream_gene_variant"],"distance":549,"variant_allele":"A","cadd_phred":40,"cadd_raw":9.333171,"gene_id":"ENSG00000273745","impact":"MODIFIER","transcript_id":"ENST00000615931","tssdistance":608},{"consequence_terms":["downstream_gene_variant"],"distance":261281,"cadd_raw":9.333171,"variant_allele":"A","cadd_phred":40,"strand":1,"canonical":1,"hgvsg":"20:g.10649087G>A","transcript_id":"ENST00000441308","tssdistance":263308,"impact":"MODIFIER","gene_id":"ENSG00000230750"},{"strand":-1,"hgvsg":"20:g.10649087G>A","canonical":1,"cadd_phred":40,"variant_allele":"A","cadd_raw":9.333171,"consequence_terms":["downstream_gene_variant"],"distance":226246,"gene_id":"ENSG00000232900","transcript_id":"ENST00000448859","impact":"MODIFIER","tssdistance":260192},{"appris":"P1","transcript_id":"ENST00000334534","tssdistance":213782,"impact":"MODIFIER","gene_id":"ENSG00000149346","consequence_terms":["downstream_gene_variant"],"distance":21057,"cadd_raw":9.333171,"variant_allele":"A","cadd_phred":40,"swissprot":["Q5VYV7.120"],"uniparc":["UPI00001D8318"],"mane_select":"NM_001009608.3","strand":1,"hgvsg":"20:g.10649087G>A","canonical":1},{"consequence_terms":["downstream_gene_variant"],"distance":341669,"cadd_phred":40,"variant_allele":"A","cadd_raw":9.333171,"swissprot":["P60880.188"],"uniparc":["UPI0000001103"],"mane_select":"NM_130811.4","strand":1,"canonical":1,"hgvsg":"20:g.10649087G>A","appris":"P3","transcript_id":"ENST00000254976","tssdistance":430257,"impact":"MODIFIER","gene_id":"ENSG00000132639","uniprot_isoform":["P60880-1"]},{"gene_id":"ENSG00000227906","transcript_id":"ENST00000421143","impact":"MODIFIER","tssdistance":280368,"strand":-1,"canonical":1,"hgvsg":"20:g.10649087G>A","cadd_raw":9.333171,"variant_allele":"A","cadd_phred":40,"consequence_terms":["upstream_gene_variant"],"distance":280368},{"consequence_terms":["downstream_gene_variant"],"distance":239495,"cadd_phred":40,"variant_allele":"A","cadd_raw":9.333171,"strand":-1,"canonical":1,"hgvsg":"20:g.10649087G>A","transcript_id":"ENST00000406588","tssdistance":240001,"impact":"MODIFIER","gene_id":"ENSG00000217809"},{"strand":1,"hgvsg":"20:g.10649087G>A","canonical":1,"consequence_terms":["upstream_gene_variant"],"distance":23841,"variant_allele":"A","cadd_phred":40,"cadd_raw":9.333171,"gene_id":"ENSG00000270792","impact":"MODIFIER","transcript_id":"ENST00000605292","tssdistance":23841},{"gene_id":"ENSG00000286936","transcript_id":"ENST00000664194","impact":"MODIFIER","tssdistance":330334,"strand":-1,"canonical":1,"hgvsg":"20:g.10649087G>A","cadd_raw":9.333171,"cadd_phred":40,"variant_allele":"A","consequence_terms":["upstream_gene_variant"],"distance":330334},{"transcript_id":"ENST00000254958","impact":"HIGH","tssdistance":24912,"lof_info":"PERCENTILE:0.374350560568772,GERP_DIST:2349.53755103406,BP_DIST:2273,DIST_FROM_LAST_EXON:1816,50_BP_RULE:PASS,ANN_ORF:237.018,MAX_ORF:237.018","codons":"Cag/Tag","cdna_end":1838,"appris":"P1","uniprot_isoform":["P78504-1"],"swissprot":["P78504.228"],"lof":"HC","strand":-1,"canonical":1,"uniparc":["UPI00000498B5"],"cds_end":1369,"protein_start":457,"cds_start":1369,"gene_id":"ENSG00000101384","cadd_raw":9.333171,"variant_allele":"A","cadd_phred":40,"cdna_start":1838,"amino_acids":"Q/*","consequence_terms":["stop_gained"],"protein_end":457,"hgvsg":"20:g.10649087G>A","mane_select":"NM_000214.3"}],"strand":1,"colocated_variants":[{"strand":1,"start":10649087,"seq_region_name":"20","id":"rs1555828721","end":10649087,"allele_string":"G/A"},{"id":"rs863223652","var_synonyms":{"ClinVar":["RCV002383649","VCV001770992"]},"seq_region_name":"20","clin_sig_allele":"A:pathogenic","start":10649087,"strand":1,"clin_sig":["pathogenic"],"phenotype_or_disease":1,"allele_string":"G/A","end":10649087}],"most_severe_consequence":"stop_gained","allele_string":"G/A","end":10649087,"id":"rs863223652","assembly_name":"GRCh38","seq_region_name":"20","start":10649087} diff --git a/tests/gentropy/datasource/ensembl/test_vep_variants.py b/tests/gentropy/datasource/ensembl/test_vep_variants.py index 97f255cf0..5757fa2f5 100644 --- a/tests/gentropy/datasource/ensembl/test_vep_variants.py +++ b/tests/gentropy/datasource/ensembl/test_vep_variants.py @@ -7,6 +7,7 @@ import pytest from pyspark.sql import DataFrame from pyspark.sql import functions as f +from pyspark.sql import types as t from gentropy.dataset.variant_index import VariantIndex from gentropy.datasource.ensembl.vep_parser import VariantEffectPredictorParser @@ -118,6 +119,21 @@ def test_extract_variant_index_from_vep( assert isinstance( variant_index, VariantIndex ), "VariantIndex object not created." + in_silico_schema = t.ArrayType( + t.StructType( + [ + t.StructField("method", t.StringType(), True), + t.StructField("assessment", t.StringType(), True), + t.StructField("score", t.FloatType(), True), + t.StructField("assessmentFlag", t.StringType(), True), + t.StructField("targetId", t.StringType(), True), + ] + ) + ) + assert ( + variant_index.df.select("inSilicoPredictors").schema.fields[0].dataType + == in_silico_schema + ), "In silico schema is not correct." def test_process(self: TestVEPParser) -> None: """Test process method.""" @@ -144,3 +160,24 @@ def test_variant_count(self: TestVEPParser) -> None: assert ( self.raw_vep_output.count() == self.processed_vep_output.count() ), f"Incorrect number of variants in processed VEP output: expected {self.raw_vep_output.count()}, got {self.processed_vep_output.count()}." + + def test_collection(self: TestVEPParser) -> None: + """Test if the collection of VEP variantIndex runs without failures.""" + assert ( + len(self.processed_vep_output.collect()) + == self.processed_vep_output.count() + ), "Collection performed incorrectly." + + def test_ensembl_transcripts_no_duplicates(self: TestVEPParser) -> None: + """Test if in single row all ensembl target ids (gene ids) do not have duplicates.""" + targets = ( + self.processed_vep_output.limit(1) + .select(f.explode("transcriptConsequences").alias("t")) + .select("t.targetId") + .collect() + ) + + asserted_targets = [t["targetId"] for t in targets] + assert len(asserted_targets) == len( + set(asserted_targets) + ), "Duplicate ensembl transcripts in a single row." From 9f833297a1c374d6cb61fdcbfade51b5efb5203e Mon Sep 17 00:00:00 2001 From: Szymon Szyszkowski <69353402+project-defiant@users.noreply.github.com> Date: Thu, 26 Sep 2024 18:16:29 +0200 Subject: [PATCH 060/188] fix: remove study_index_path from coloc step (#791) --- src/gentropy/config.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/gentropy/config.py b/src/gentropy/config.py index c56a9dfb3..3a67e7868 100644 --- a/src/gentropy/config.py +++ b/src/gentropy/config.py @@ -36,7 +36,6 @@ class ColocalisationConfig(StepConfig): """Colocalisation step configuration.""" credible_set_path: str = MISSING - study_index_path: str = MISSING coloc_path: str = MISSING colocalisation_method: str = MISSING _target_: str = "gentropy.colocalisation.ColocalisationStep" From a135d26001acf9d5abc4b9b4b0906de956bfae93 Mon Sep 17 00:00:00 2001 From: Szymon Szyszkowski <69353402+project-defiant@users.noreply.github.com> Date: Fri, 27 Sep 2024 16:35:51 +0200 Subject: [PATCH 061/188] fix(safe_array_union): allow for sorting nested structs (#793) * fix: remove study_index_path from coloc step * fix(safe_array_union): sort struct fields in array --------- Co-authored-by: Szymon Szyszkowski --- src/gentropy/common/spark_helpers.py | 88 ++++++++++++++++++- src/gentropy/dataset/variant_index.py | 14 ++- .../datasource/open_targets/variants.py | 1 - 3 files changed, 98 insertions(+), 5 deletions(-) diff --git a/src/gentropy/common/spark_helpers.py b/src/gentropy/common/spark_helpers.py index 680975ef6..3fdabfbcc 100644 --- a/src/gentropy/common/spark_helpers.py +++ b/src/gentropy/common/spark_helpers.py @@ -614,14 +614,21 @@ def rename_all_columns(df: DataFrame, prefix: str) -> DataFrame: ) -def safe_array_union(a: Column, b: Column) -> Column: +def safe_array_union( + a: Column, b: Column, fields_order: list[str] | None = None +) -> Column: """Merge the content of two optional columns. - The function assumes the array columns have the same schema. Otherwise, the function will fail. + The function assumes the array columns have the same schema. + If the `fields_order` is passed, the function assumes that it deals with array of structs and sorts the nested + struct fields by the provided `fields_order` before conducting array_merge. + If the `fields_order` is not passed and both columns are > type then function assumes struct fields have the same order, + otherwise the function will raise an AnalysisException. Args: a (Column): One optional array column. b (Column): The other optional array column. + fields_order (list[str] | None): The order of the fields in the struct. Defaults to None. Returns: Column: array column with merged content. @@ -644,12 +651,89 @@ def safe_array_union(a: Column, b: Column) -> Column: | null| +------+ + >>> schema="arr2: array>, arr: array>" + >>> data = [([(1,"a",), (2, "c")],[("a", 1,)]),] + >>> df = spark.createDataFrame(data=data, schema=schema) + >>> df.select(safe_array_union(f.col("arr"), f.col("arr2"), fields_order=["a", "b"]).alias("merged")).show() + +----------------+ + | merged| + +----------------+ + |[{a, 1}, {c, 2}]| + +----------------+ + + >>> schema="arr2: array>, arr: array>" + >>> data = [([(1,"a",), (2, "c")],[("a", 1,)]),] + >>> df = spark.createDataFrame(data=data, schema=schema) + >>> df.select(safe_array_union(f.col("arr"), f.col("arr2")).alias("merged")).show() # doctest: +IGNORE_EXCEPTION_DETAIL + Traceback (most recent call last): + pyspark.sql.utils.AnalysisException: ... """ + if fields_order: + # sort the nested struct fields by the provided order + a = sort_array_struct_by_columns(a, fields_order) + b = sort_array_struct_by_columns(b, fields_order) return f.when(a.isNotNull() & b.isNotNull(), f.array_union(a, b)).otherwise( f.coalesce(a, b) ) + +def sort_array_struct_by_columns(column: Column, fields_order: list[str]) -> Column: + """Sort nested struct fields by provided fields order. + + Args: + column (Column): Column with array of structs. + fields_order (list[str]): List of field names to sort by. + + Returns: + Column: Sorted column. + + Examples: + >>> schema="arr: array>" + >>> data = [([(1,"a",), (2, "c")],)] + >>> fields_order = ["a", "b"] + >>> df = spark.createDataFrame(data=data, schema=schema) + >>> df.select(sort_array_struct_by_columns(f.col("arr"), fields_order).alias("sorted")).show() + +----------------+ + | sorted| + +----------------+ + |[{c, 2}, {a, 1}]| + +----------------+ + + """ + column_name = extract_column_name(column) + fields_order_expr = ", ".join([f"x.{field}" for field in fields_order]) + return f.expr( + f"sort_array(transform({column_name}, x -> struct({fields_order_expr})), False)" + ).alias(column_name) + + +def extract_column_name(column: Column) -> str: + """Extract column name from a column expression. + + Args: + column (Column): Column expression. + + Returns: + str: Column name. + + Raises: + ValueError: If the column name cannot be extracted. + + Examples: + >>> extract_column_name(f.col('col1')) + 'col1' + >>> extract_column_name(f.sort_array(f.col('col1'))) + 'sort_array(col1, true)' + """ + pattern = re.compile("^Column<'(?P.*)'>?") + + _match = pattern.search(str(column)) + if not _match: + raise ValueError(f"Cannot extract column name from {column}") + return _match.group("name") + + def create_empty_column_if_not_exists( col_name: str, col_schema: t.DataType = t.NullType() ) -> Column: diff --git a/src/gentropy/dataset/variant_index.py b/src/gentropy/dataset/variant_index.py index 1cc1eac1b..2f24cd985 100644 --- a/src/gentropy/dataset/variant_index.py +++ b/src/gentropy/dataset/variant_index.py @@ -6,9 +6,11 @@ from typing import TYPE_CHECKING import pyspark.sql.functions as f +import pyspark.sql.types as t from gentropy.common.schemas import parse_spark_schema from gentropy.common.spark_helpers import ( + get_nested_struct_schema, get_record_with_maximum_value, normalise_column, rename_all_columns, @@ -131,6 +133,7 @@ def add_annotation( # Prefix for renaming columns: prefix = "annotation_" + # Generate select expressions that to merge and import columns from annotation: select_expressions = [] @@ -141,10 +144,17 @@ def add_annotation( # If an annotation column can be found in both datasets: if (column in self.df.columns) and (column in annotation_source.df.columns): # Arrays are merged: - if "ArrayType" in field.dataType.__str__(): + if isinstance(field.dataType, t.ArrayType): + fields_order = None + if isinstance(field.dataType.elementType, t.StructType): + # Extract the schema of the array to get the order of the fields: + array_schema = [ + field for field in VariantIndex.get_schema().fields if field.name == column + ][0].dataType + fields_order = get_nested_struct_schema(array_schema).fieldNames() select_expressions.append( safe_array_union( - f.col(column), f.col(f"{prefix}{column}") + f.col(column), f.col(f"{prefix}{column}"), fields_order ).alias(column) ) # Non-array columns are coalesced: diff --git a/src/gentropy/datasource/open_targets/variants.py b/src/gentropy/datasource/open_targets/variants.py index 03018438b..5b6822ae6 100644 --- a/src/gentropy/datasource/open_targets/variants.py +++ b/src/gentropy/datasource/open_targets/variants.py @@ -95,7 +95,6 @@ def as_vcf_df( variant_df = variant_df.withColumn( col, create_empty_column_if_not_exists(col) ) - return ( variant_df.filter(f.col("variantId").isNotNull()) .withColumn( From 26483c9866ca44ffc952d49c37075326baa218eb Mon Sep 17 00:00:00 2001 From: Yakov Date: Fri, 27 Sep 2024 23:06:43 +0100 Subject: [PATCH 062/188] fix: fix bag in neglog_pvalue_to_mantissa_and_exponent (#795) --- src/gentropy/common/spark_helpers.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/gentropy/common/spark_helpers.py b/src/gentropy/common/spark_helpers.py index 3fdabfbcc..4d24212a2 100644 --- a/src/gentropy/common/spark_helpers.py +++ b/src/gentropy/common/spark_helpers.py @@ -270,13 +270,13 @@ def neglog_pvalue_to_mantissa_and_exponent(p_value: Column) -> tuple[Column, Col +--------+--------------+--------------+ |negLogPv|pValueMantissa|pValueExponent| +--------+--------------+--------------+ - | 4.56| 3.6307805| -5| - | 2109.23| 1.6982436| -2110| + | 4.56| 2.7542286| -5| + | 2109.23| 5.8884363| -2110| +--------+--------------+--------------+ """ exponent: Column = f.ceil(p_value) - mantissa: Column = f.pow(f.lit(10), (p_value - exponent + f.lit(1))) + mantissa: Column = f.pow(f.lit(10), (exponent - p_value)) return ( mantissa.cast(t.FloatType()).alias("pValueMantissa"), @@ -677,7 +677,6 @@ def safe_array_union( ) - def sort_array_struct_by_columns(column: Column, fields_order: list[str]) -> Column: """Sort nested struct fields by provided fields order. From 88f62d44010ebd44e8b2e6957f7694e1d750cd12 Mon Sep 17 00:00:00 2001 From: Daniel Suveges Date: Mon, 30 Sep 2024 12:31:56 +0100 Subject: [PATCH 063/188] fix(schema): recursive validation of arbitrarily deep nested structure (#790) * fix(schema): recursive validation of arbitrariliy deep nested structure * chore: pre-commit auto fixes [...] * fix: docstring issues * fix: failing tests are fixed * test: skipping tests that are failing because bug in vep parser * test(schemas): adding tests for schema comparison functions * test: removing skip as the vep parser logic is fixed * fix: addressing review comments * fix(schemas): removing schema flattening function * chore: pre-commit auto fixes [...] --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Szymon Szyszkowski <69353402+project-defiant@users.noreply.github.com> --- src/gentropy/common/schemas.py | 224 +++++++++++--- src/gentropy/dataset/dataset.py | 52 +--- tests/gentropy/common/test_schema_methods.py | 303 +++++++++++++++++++ tests/gentropy/dataset/test_study_index.py | 14 +- tests/gentropy/method/test_clump.py | 4 +- tests/gentropy/test_schemas.py | 10 +- 6 files changed, 510 insertions(+), 97 deletions(-) create mode 100644 tests/gentropy/common/test_schema_methods.py diff --git a/src/gentropy/common/schemas.py b/src/gentropy/common/schemas.py index 1dcd75a22..624e3e0e1 100644 --- a/src/gentropy/common/schemas.py +++ b/src/gentropy/common/schemas.py @@ -1,66 +1,212 @@ """Methods for handling schemas.""" + from __future__ import annotations import importlib.resources as pkg_resources import json -from collections import namedtuple -from typing import Any +from collections import defaultdict -import pyspark.sql.types as t +from pyspark.sql.types import ArrayType, StructType from gentropy.assets import schemas -def parse_spark_schema(schema_json: str) -> t.StructType: +class SchemaValidationError(Exception): + """This exception is raised when a schema validation fails.""" + + def __init__( + self: SchemaValidationError, message: str, errors: defaultdict[str, list[str]] + ) -> None: + """Initialize the SchemaValidationError. + + Args: + message (str): The message to be displayed. + errors (defaultdict[str, list[str]]): The collection of observed discrepancies + """ + super().__init__(message) + self.message = message # Explicitly set the message attribute + self.errors = errors + + def __str__(self: SchemaValidationError) -> str: + """Return a string representation of the exception. + + Returns: + str: The string representation of the exception. + """ + stringified_errors = "\n ".join( + [f'{k}: {",".join(v)}' for k, v in self.errors.items()] + ) + return f"{self.message}\nErrors:\n {stringified_errors}" + + +def parse_spark_schema(schema_json: str) -> StructType: """Parse Spark schema from JSON. Args: schema_json (str): JSON filename containing spark schema in the schemas package Returns: - t.StructType: Spark schema + StructType: Spark schema """ core_schema = json.loads( pkg_resources.read_text(schemas, schema_json, encoding="utf-8") ) - return t.StructType.fromJson(core_schema) + return StructType.fromJson(core_schema) -def flatten_schema(schema: t.StructType, prefix: str = "") -> list[Any]: - """It takes a Spark schema and returns a list of all fields in the schema once flattened. +def compare_array_schemas( + observed_schema: ArrayType, + expected_schema: ArrayType, + parent_field_name: str | None = None, + schema_issues: defaultdict[str, list[str]] | None = None, +) -> defaultdict[str, list[str]]: + """Compare two array schemas. + + The comparison is done recursively, so nested structs are also compared. Args: - schema (t.StructType): The schema of the dataframe - prefix (str): The prefix to prepend to the field names. Defaults to "". + observed_schema (ArrayType): The observed schema. + expected_schema (ArrayType): The expected schema. + parent_field_name (str | None): The parent field name. Defaults to None. + schema_issues (defaultdict[str, list[str]] | None): The schema issues. Defaults to None. Returns: - list[Any]: A list of all the columns in the dataframe. - - Examples: - >>> from pyspark.sql.types import ArrayType, StringType, StructField, StructType - >>> schema = StructType( - ... [ - ... StructField("studyLocusId", StringType(), False), - ... StructField("locus", ArrayType(StructType([StructField("variantId", StringType(), False)])), False) - ... ] - ... ) - >>> df = spark.createDataFrame([("A", [{"variantId": "varA"}]), ("B", [{"variantId": "varB"}])], schema) - >>> flatten_schema(df.schema) - [Field(name='studyLocusId', dataType=StringType()), Field(name='locus', dataType=ArrayType(StructType([]), True)), Field(name='locus.variantId', dataType=StringType())] + defaultdict[str, list[str]]: The schema issues. """ - Field = namedtuple("Field", ["name", "dataType"]) - fields = [] - for field in schema.fields: - name = f"{prefix}.{field.name}" if prefix else field.name - dtype = field.dataType - if isinstance(dtype, t.StructType): - fields.append(Field(name, t.ArrayType(t.StructType()))) - fields += flatten_schema(dtype, prefix=name) - elif isinstance(dtype, t.ArrayType) and isinstance( - dtype.elementType, t.StructType - ): - fields.append(Field(name, t.ArrayType(t.StructType()))) - fields += flatten_schema(dtype.elementType, prefix=name) - else: - fields.append(Field(name, dtype)) - return fields + # Create default values if not provided: + if schema_issues is None: + schema_issues = defaultdict(list) + + if parent_field_name is None: + parent_field_name = "" + + observed_type = observed_schema.elementType.typeName() + expected_type = expected_schema.elementType.typeName() + + # If element types are not matching, no further tests are needed: + if observed_type != expected_type: + schema_issues["columns_with_non_matching_type"].append( + f'For column "{parent_field_name}[]" found {observed_type} instead of {expected_type}' + ) + + # If element type is a struct, resolve nesting: + elif (observed_type == "struct") and (expected_type == "struct"): + schema_issues = compare_struct_schemas( + observed_schema.elementType, + expected_schema.elementType, + f"{parent_field_name}[].", + schema_issues, + ) + + # If element type is an array, resolve nesting: + elif (observed_type == "array") and (expected_type == "array"): + schema_issues = compare_array_schemas( + observed_schema.elementType, + expected_schema.elementType, + parent_field_name, + schema_issues, + ) + + return schema_issues + + +def compare_struct_schemas( + observed_schema: StructType, + expected_schema: StructType, + parent_field_name: str | None = None, + schema_issues: defaultdict[str, list[str]] | None = None, +) -> defaultdict[str, list[str]]: + """Compare two struct schemas. + + The comparison is done recursively, so nested structs are also compared. + + Checking logic: + 1. Checking for duplicated columns in the observed schema. + 2. Checking for missing mandatory columns in the observed schema. + 3. Now we know that all mandatory columns are present, we can iterate over the observed schema and compare the types. + 4. Flagging unexpected columns in the observed schema. + 5. Flagging columns with non-matching types. + 6. If a column is a struct -> call compare_struct_schemas + 7. If a column is an array -> call compare_array_schemas + 8. Return dictionary with issues. + + Args: + observed_schema (StructType): The observed schema. + expected_schema (StructType): The expected schema. + parent_field_name (str | None): The parent field name. Defaults to None. + schema_issues (defaultdict[str, list[str]] | None): The schema issues. Defaults to None. + + Returns: + defaultdict[str, list[str]]: The schema issues. + """ + # Create default values if not provided: + if schema_issues is None: + schema_issues = defaultdict(list) + + if parent_field_name is None: + parent_field_name = "" + + # Flagging duplicated columns if present: + if duplicated_columns := list( + { + f"{parent_field_name}{field.name}" + for field in observed_schema + if list(observed_schema).count(field) > 1 + } + ): + schema_issues["duplicated_columns"] += duplicated_columns + + # Testing mandatory fields: + required_fields = [x.name for x in expected_schema if not x.nullable] + if missing_required_fields := [ + f"{parent_field_name}{req}" + for req in required_fields + if not any(field.name == req for field in observed_schema) + ]: + schema_issues["missing_mandatory_columns"] += missing_required_fields + + # Converting schema to dictionaries for easier comparison: + observed_schema_dict = {field.name: field for field in observed_schema} + expected_schema_dict = {field.name: field for field in expected_schema} + + # Testing optional fields and types: + for field_name, field in observed_schema_dict.items(): + # Testing observed field name, if name is not matched, no further tests are needed: + if field_name not in expected_schema_dict: + schema_issues["unexpected_columns"].append( + f"{parent_field_name}{field_name}" + ) + continue + + # When we made sure the field is in both schemas, extracting field type information: + observed_type = field.dataType + observed_type_name = field.dataType.typeName() + + expected_type = expected_schema_dict[field_name].dataType + expected_type_name = expected_schema_dict[field_name].dataType.typeName() + + # Flagging non-matching types if types don't match, jumping to next field: + if observed_type_name != expected_type_name: + schema_issues["columns_with_non_matching_type"].append( + f'For column "{parent_field_name}{field_name}" found {observed_type_name} instead of {expected_type_name}' + ) + continue + + # If column is a struct, resolve nesting: + if observed_type_name == "struct": + schema_issues = compare_struct_schemas( + observed_type, + expected_type, + f"{parent_field_name}{field_name}.", + schema_issues, + ) + # If column is an array, resolve nesting: + elif observed_type_name == "array": + schema_issues = compare_array_schemas( + observed_type, + expected_type, + f"{parent_field_name}{field_name}[]", + schema_issues, + ) + + return schema_issues diff --git a/src/gentropy/dataset/dataset.py b/src/gentropy/dataset/dataset.py index e56ef2ecc..f49d062d3 100644 --- a/src/gentropy/dataset/dataset.py +++ b/src/gentropy/dataset/dataset.py @@ -13,7 +13,7 @@ from pyspark.sql.window import Window from typing_extensions import Self -from gentropy.common.schemas import flatten_schema +from gentropy.common.schemas import SchemaValidationError, compare_struct_schemas if TYPE_CHECKING: from enum import Enum @@ -142,57 +142,15 @@ def validate_schema(self: Dataset) -> None: """Validate DataFrame schema against expected class schema. Raises: - ValueError: DataFrame schema is not valid + SchemaValidationError: If the DataFrame schema does not match the expected schema """ expected_schema = self._schema - expected_fields = flatten_schema(expected_schema) observed_schema = self._df.schema - observed_fields = flatten_schema(observed_schema) # Unexpected fields in dataset - if unexpected_field_names := [ - x.name - for x in observed_fields - if x.name not in [y.name for y in expected_fields] - ]: - raise ValueError( - f"The {unexpected_field_names} fields are not included in DataFrame schema: {expected_fields}" - ) - - # Required fields not in dataset - required_fields = [x.name for x in expected_schema if not x.nullable] - if missing_required_fields := [ - req - for req in required_fields - if not any(field.name == req for field in observed_fields) - ]: - raise ValueError( - f"The {missing_required_fields} fields are required but missing: {required_fields}" - ) - - # Fields with duplicated names - if duplicated_fields := [ - x for x in set(observed_fields) if observed_fields.count(x) > 1 - ]: - raise ValueError( - f"The following fields are duplicated in DataFrame schema: {duplicated_fields}" - ) - - # Fields with different datatype - observed_field_types = { - field.name: type(field.dataType) for field in observed_fields - } - expected_field_types = { - field.name: type(field.dataType) for field in expected_fields - } - if fields_with_different_observed_datatype := [ - name - for name, observed_type in observed_field_types.items() - if name in expected_field_types - and observed_type != expected_field_types[name] - ]: - raise ValueError( - f"The following fields present differences in their datatypes: {fields_with_different_observed_datatype}." + if discrepancies := compare_struct_schemas(observed_schema, expected_schema): + raise SchemaValidationError( + f"Schema validation failed for {type(self).__name__}", discrepancies ) def valid_rows(self: Self, invalid_flags: list[str], invalid: bool = False) -> Self: diff --git a/tests/gentropy/common/test_schema_methods.py b/tests/gentropy/common/test_schema_methods.py new file mode 100644 index 000000000..8ed1342b5 --- /dev/null +++ b/tests/gentropy/common/test_schema_methods.py @@ -0,0 +1,303 @@ +"""Tests methods dealing with schema comparison.""" + +from __future__ import annotations + +from collections import defaultdict + +from pyspark.sql.types import ( + ArrayType, + IntegerType, + StringType, + StructField, + StructType, +) + +from gentropy.common.schemas import ( + compare_array_schemas, + compare_struct_schemas, +) + + +class TestSchemaComparisonMethods: + """Class for testing schema comparison methods.""" + + STRUCT_FIELD_STRING = StructField("a", StringType(), True) + STRUCT_FIELD_STRING_MANDATORY = StructField("a", StringType(), False) + STRUCT_FIELD_INTEGER = StructField("b", IntegerType(), True) + STRUCT_FIELD_WRONGTYPE = StructField("a", IntegerType(), True) + + def test_struct_validation_return_type(self: TestSchemaComparisonMethods) -> None: + """Test successful validation of StructType.""" + observed = StructType([self.STRUCT_FIELD_STRING, self.STRUCT_FIELD_INTEGER]) + expected = StructType([self.STRUCT_FIELD_STRING, self.STRUCT_FIELD_INTEGER]) + + discrepancy = compare_struct_schemas(observed, expected) + assert isinstance(discrepancy, defaultdict) + + def test_struct_validation_success(self: TestSchemaComparisonMethods) -> None: + """Test successful validation of StructType.""" + observed = StructType([self.STRUCT_FIELD_STRING, self.STRUCT_FIELD_INTEGER]) + expected = StructType([self.STRUCT_FIELD_STRING, self.STRUCT_FIELD_INTEGER]) + + discrepancy = compare_struct_schemas(observed, expected) + assert not discrepancy + + def test_struct_validation_non_matching_type( + self: TestSchemaComparisonMethods, + ) -> None: + """Test unsuccessful validation of StructType.""" + observed = StructType([self.STRUCT_FIELD_STRING]) + expected = StructType([self.STRUCT_FIELD_WRONGTYPE]) + + discrepancy = compare_struct_schemas(observed, expected) + + # Test there's a discrepancy: + assert discrepancy + + # Test that the discrepancy is in the field name: + assert "columns_with_non_matching_type" in discrepancy + + def test_struct_validation_missing_mandatory( + self: TestSchemaComparisonMethods, + ) -> None: + """Test unsuccessful validation of StructType.""" + observed = StructType([self.STRUCT_FIELD_INTEGER]) + expected = StructType( + [self.STRUCT_FIELD_STRING_MANDATORY, self.STRUCT_FIELD_INTEGER] + ) + + discrepancy = compare_struct_schemas(observed, expected) + + # Test there's a discrepancy: + assert discrepancy + + # Test that the discrepancy is in the field name: + assert "missing_mandatory_columns" in discrepancy + + # Test that the right column is flagged as missing: + assert ( + self.STRUCT_FIELD_STRING_MANDATORY.name + in discrepancy["missing_mandatory_columns"] + ) + + def test_struct_validation_unexpected_column( + self: TestSchemaComparisonMethods, + ) -> None: + """Test unsuccessful validation of StructType.""" + observed = StructType( + [self.STRUCT_FIELD_STRING_MANDATORY, self.STRUCT_FIELD_INTEGER] + ) + expected = StructType([self.STRUCT_FIELD_STRING_MANDATORY]) + + discrepancy = compare_struct_schemas(observed, expected) + + # Test there's a discrepancy: + assert discrepancy + + # Test that the discrepancy is in the field name: + assert "unexpected_columns" in discrepancy + + # Test that the right column is flagged as unexpected: + assert self.STRUCT_FIELD_INTEGER.name in discrepancy["unexpected_columns"] + + def test_struct_validation_duplicated_columns( + self: TestSchemaComparisonMethods, + ) -> None: + """Test unsuccessful validation of StructType.""" + observed = StructType( + [ + self.STRUCT_FIELD_STRING, + self.STRUCT_FIELD_STRING, + self.STRUCT_FIELD_INTEGER, + ] + ) + expected = StructType([self.STRUCT_FIELD_STRING, self.STRUCT_FIELD_INTEGER]) + + discrepancy = compare_struct_schemas(observed, expected) + + # Test there's a discrepancy: + assert discrepancy + + # Test that the discrepancy is in the field name: + assert "duplicated_columns" in discrepancy + + # Test that the right column is flagged as duplicated: + assert self.STRUCT_FIELD_STRING.name in discrepancy["duplicated_columns"] + + def test_struct_validation_success_nested_struct( + self: TestSchemaComparisonMethods, + ) -> None: + """Test successful validation of nested StructType.""" + nested_struct = StructType( + [self.STRUCT_FIELD_STRING, self.STRUCT_FIELD_INTEGER] + ) + + observed = StructType([StructField("c", nested_struct)]) + expected = StructType([StructField("c", nested_struct)]) + + discrepancy = compare_struct_schemas(observed, expected) + assert not discrepancy + + def test_struct_validation_non_matching_type_nested_struct( + self: TestSchemaComparisonMethods, + ) -> None: + """Test unsuccessful validation of nested StructType.""" + nested_struct = StructType([self.STRUCT_FIELD_STRING]) + + observed = StructType([StructField("c", nested_struct)]) + expected = StructType( + [StructField("c", StructType([self.STRUCT_FIELD_WRONGTYPE]))] + ) + + discrepancy = compare_struct_schemas(observed, expected) + + # Test there's a discrepancy: + assert discrepancy + + # Test that the discrepancy is in the field name: + assert "columns_with_non_matching_type" in discrepancy + + def test_array_validation_success(self: TestSchemaComparisonMethods) -> None: + """Test successful validation of ArrayType.""" + observed = ArrayType(StringType()) + expected = ArrayType(StringType()) + + discrepancy = compare_array_schemas(observed, expected) + assert not discrepancy + + def test_array_validation_non_matching_type( + self: TestSchemaComparisonMethods, + ) -> None: + """Test unsuccessful validation of ArrayType.""" + observed = ArrayType(StringType()) + expected = ArrayType(IntegerType()) + + discrepancy = compare_array_schemas(observed, expected) + + # Test there's a discrepancy: + assert discrepancy + + # Test that the discrepancy is in the field name: + assert "columns_with_non_matching_type" in discrepancy + + def test_array_validation_nested_array(self: TestSchemaComparisonMethods) -> None: + """Test successful validation of nested ArrayType.""" + nested_array = ArrayType(StringType()) + + observed = ArrayType(nested_array) + expected = ArrayType(nested_array) + + discrepancy = compare_array_schemas(observed, expected) + assert not discrepancy + + def test_array_validation_non_matching_type_nested_array( + self: TestSchemaComparisonMethods, + ) -> None: + """Test unsuccessful validation of nested ArrayType.""" + observed = ArrayType(ArrayType(StringType())) + expected = ArrayType(ArrayType(IntegerType())) + + discrepancy = compare_array_schemas(observed, expected) + + # Test there's a discrepancy: + assert discrepancy + + # Test that the discrepancy is in the field name: + assert "columns_with_non_matching_type" in discrepancy + + def test_struct_validation_success_nested_with_array( + self: TestSchemaComparisonMethods, + ) -> None: + """Test successful validation of nested StructType with ArrayType.""" + nested_array = StructField("a", ArrayType(StringType()), True) + nested_struct = StructType([self.STRUCT_FIELD_STRING, nested_array]) + + observed = StructType([StructField("c", nested_struct, True)]) + expected = StructType([StructField("c", nested_struct, True)]) + + discrepancy = compare_struct_schemas(observed, expected) + assert not discrepancy + + def test_struct_validation_non_matching_type_nested_with_array( + self: TestSchemaComparisonMethods, + ) -> None: + """Test unsuccessful validation of nested StructType with ArrayType.""" + nested_array = StructField("a", ArrayType(StringType()), True) + nested_array_wrong_type = StructField("a", ArrayType(IntegerType()), True) + nested_struct = StructType([self.STRUCT_FIELD_STRING, nested_array]) + nested_struct_wrong_type = StructType( + [self.STRUCT_FIELD_STRING, nested_array_wrong_type] + ) + observed = StructType([StructField("c", nested_struct, True)]) + expected = StructType([StructField("c", nested_struct_wrong_type, True)]) + + discrepancy = compare_struct_schemas(observed, expected) + + # Test there's a discrepancy: + assert discrepancy + + # Test that the discrepancy is in the field name: + assert "columns_with_non_matching_type" in discrepancy + + def test_struct_validation_failing_with_multiple_reasons( + self: TestSchemaComparisonMethods, + ) -> None: + """Test unsuccessful validation of StructType with multiple issues.""" + observed = StructType( + [ + StructField( + "a", + ArrayType( + ArrayType( + StructType( + [ + StructField("a", IntegerType(), False), + StructField("c", StringType(), True), + StructField("c", StringType(), True), + ] + ), + False, + ), + False, + ), + False, + ), + ] + ) + + expected = StructType( + [ + StructField( + "a", + ArrayType( + ArrayType( + StructType( + [ + StructField("b", IntegerType(), False), + StructField("c", StringType(), True), + StructField("d", StringType(), True), + ] + ), + False, + ), + False, + ), + False, + ), + ] + ) + + discrepancy = compare_struct_schemas(observed, expected) + + # Test there's a discrepancy: + assert discrepancy + + # Test if the returned list of discrepancies is correct: + assert discrepancy == defaultdict( + list, + { + "duplicated_columns": ["a[][].c"], + "missing_mandatory_columns": ["a[][].b"], + "unexpected_columns": ["a[][].a"], + }, + ) diff --git a/tests/gentropy/dataset/test_study_index.py b/tests/gentropy/dataset/test_study_index.py index 3bdd7a5cb..fee3a2557 100644 --- a/tests/gentropy/dataset/test_study_index.py +++ b/tests/gentropy/dataset/test_study_index.py @@ -167,14 +167,14 @@ def _setup(self: TestGeneValidation, spark: SparkSession) -> None: """Setup fixture.""" self.study_index = StudyIndex( _df=spark.createDataFrame(self.STUDY_DATA, self.STUDY_COLUMNS).withColumn( - "qualityControls", f.array() + "qualityControls", f.array().cast("array") ), _schema=StudyIndex.get_schema(), ) self.study_index_no_gene = StudyIndex( _df=spark.createDataFrame(self.STUDY_DATA, self.STUDY_COLUMNS) - .withColumn("qualityControls", f.array()) + .withColumn("qualityControls", f.array().cast("array")) .drop("geneId"), _schema=StudyIndex.get_schema(), ) @@ -231,7 +231,7 @@ def _setup(self: TestUniquenessValidation, spark: SparkSession) -> None: """Setup fixture.""" self.study_index = StudyIndex( _df=spark.createDataFrame(self.STUDY_DATA, self.STUDY_COLUMNS).withColumn( - "qualityControls", f.array() + "qualityControls", f.array().cast("array") ), _schema=StudyIndex.get_schema(), ) @@ -279,7 +279,7 @@ def _setup(self: TestStudyTypeValidation, spark: SparkSession) -> None: """Setup fixture.""" self.study_index = StudyIndex( _df=spark.createDataFrame(self.STUDY_DATA, self.STUDY_COLUMNS).withColumn( - "qualityControls", f.array() + "qualityControls", f.array().cast("array") ), _schema=StudyIndex.get_schema(), ) @@ -346,8 +346,10 @@ def _setup(self: TestDiseaseValidation, spark: SparkSession) -> None: spark.createDataFrame(self.STUDY_DATA, self.STUDY_COLUMNS) .groupBy("studyId", "studyType", "projectId") .agg(f.collect_set("efo").alias("traitFromSourceMappedIds")) - .withColumn("qualityControls", f.array()) - .withColumn("backgroundTraitFromSourceMappedIds", f.array()) + .withColumn("qualityControls", f.array().cast("array")) + .withColumn( + "backgroundTraitFromSourceMappedIds", f.array().cast("array") + ) ) study_df.show() # Mock study index: diff --git a/tests/gentropy/method/test_clump.py b/tests/gentropy/method/test_clump.py index 1e754df3a..757c79305 100644 --- a/tests/gentropy/method/test_clump.py +++ b/tests/gentropy/method/test_clump.py @@ -135,7 +135,9 @@ def test_flagging(self: TestIsLeadLinked) -> None: """Test flagging of lead variants.""" # Create the study locus and clump: sl_flagged = StudyLocus( - _df=self.df.drop("expected_flag").withColumn("qualityControls", f.array()), + _df=self.df.drop("expected_flag").withColumn( + "qualityControls", f.array().cast("array") + ), _schema=StudyLocus.get_schema(), ).clump() diff --git a/tests/gentropy/test_schemas.py b/tests/gentropy/test_schemas.py index 1af72c149..6840e3207 100644 --- a/tests/gentropy/test_schemas.py +++ b/tests/gentropy/test_schemas.py @@ -12,6 +12,8 @@ import pytest from pyspark.sql.types import StructType +from gentropy.common.schemas import SchemaValidationError + if TYPE_CHECKING: from _pytest.fixtures import FixtureRequest @@ -90,7 +92,7 @@ def test_validate_schema_extra_field( mock_dataset_instance: V2G | GeneIndex, ) -> None: """Test that validate_schema raises an error if the observed schema has an extra field.""" - with pytest.raises(ValueError, match="extraField"): + with pytest.raises(SchemaValidationError, match="extraField"): mock_dataset_instance.df = mock_dataset_instance.df.withColumn( "extraField", f.lit("extra") ) @@ -103,7 +105,7 @@ def test_validate_schema_missing_field( mock_dataset_instance: V2G | GeneIndex, ) -> None: """Test that validate_schema raises an error if the observed schema is missing a required field, geneId in this case.""" - with pytest.raises(ValueError, match="geneId"): + with pytest.raises(SchemaValidationError, match="geneId"): mock_dataset_instance.df = mock_dataset_instance.df.drop("geneId") @pytest.mark.parametrize( @@ -114,7 +116,7 @@ def test_validate_schema_duplicated_field( mock_dataset_instance: V2G | GeneIndex, ) -> None: """Test that validate_schema raises an error if the observed schema has a duplicated field, geneId in this case.""" - with pytest.raises(ValueError, match="geneId"): + with pytest.raises(SchemaValidationError, match="geneId"): mock_dataset_instance.df = mock_dataset_instance.df.select( "*", f.lit("A").alias("geneId") ) @@ -127,7 +129,7 @@ def test_validate_schema_different_datatype( mock_dataset_instance: V2G | GeneIndex, ) -> None: """Test that validate_schema raises an error if any field in the observed schema has a different type than expected.""" - with pytest.raises(ValueError, match="geneId"): + with pytest.raises(SchemaValidationError, match="geneId"): mock_dataset_instance.df = mock_dataset_instance.df.withColumn( "geneId", f.lit(1) ) From 8b253a5fc1c050e5018be4575c36a2ff49b2a408 Mon Sep 17 00:00:00 2001 From: Yakov Date: Mon, 30 Sep 2024 13:55:57 +0100 Subject: [PATCH 064/188] fix: adding data specific p-value filters (#788) * fix: adding data specific fillters * fix: removing variables * fix: adding options to init --------- Co-authored-by: Daniel Suveges --- src/gentropy/config.py | 7 ++++++ src/gentropy/eqtl_catalogue.py | 23 ++++++++++++------ src/gentropy/finngen_finemapping_ingestion.py | 24 ++++++++++++------- src/gentropy/pics.py | 15 ++++++++---- 4 files changed, 49 insertions(+), 20 deletions(-) diff --git a/src/gentropy/config.py b/src/gentropy/config.py index 3a67e7868..0a1f9438a 100644 --- a/src/gentropy/config.py +++ b/src/gentropy/config.py @@ -121,10 +121,16 @@ class GWASCatalogSumstatsPreprocessConfig(StepConfig): class EqtlCatalogueConfig(StepConfig): """eQTL Catalogue step configuration.""" + session: Any = field( + default_factory=lambda: { + "start_hail": True, + } + ) eqtl_catalogue_paths_imported: str = MISSING eqtl_catalogue_study_index_out: str = MISSING eqtl_catalogue_credible_sets_out: str = MISSING mqtl_quantification_methods_blacklist: list[str] = field(default_factory=lambda: []) + eqtl_lead_pvalue_threshold: float = 1e-3 _target_: str = "gentropy.eqtl_catalogue.EqtlCatalogueStep" @@ -168,6 +174,7 @@ class FinngenFinemappingConfig(StepConfig): _target_: str = ( "gentropy.finngen_finemapping_ingestion.FinnGenFinemappingIngestionStep" ) + finngen_finemapping_lead_pvalue_threshold: float = 1e-5 @dataclass diff --git a/src/gentropy/eqtl_catalogue.py b/src/gentropy/eqtl_catalogue.py index 7adc5d8a2..3ad61ddea 100644 --- a/src/gentropy/eqtl_catalogue.py +++ b/src/gentropy/eqtl_catalogue.py @@ -3,6 +3,7 @@ from __future__ import annotations from gentropy.common.session import Session +from gentropy.config import EqtlCatalogueConfig from gentropy.datasource.eqtl_catalogue.finemapping import EqtlCatalogueFinemapping from gentropy.datasource.eqtl_catalogue.study_index import EqtlCatalogueStudyIndex @@ -20,6 +21,7 @@ def __init__( eqtl_catalogue_paths_imported: str, eqtl_catalogue_study_index_out: str, eqtl_catalogue_credible_sets_out: str, + eqtl_lead_pvalue_threshold: float = EqtlCatalogueConfig().eqtl_lead_pvalue_threshold, ) -> None: """Run eQTL Catalogue ingestion step. @@ -29,6 +31,7 @@ def __init__( eqtl_catalogue_paths_imported (str): Input eQTL Catalogue fine mapping results path. eqtl_catalogue_study_index_out (str): Output eQTL Catalogue study index path. eqtl_catalogue_credible_sets_out (str): Output eQTL Catalogue credible sets path. + eqtl_lead_pvalue_threshold (float, optional): Lead p-value threshold. Defaults to EqtlCatalogueConfig().eqtl_lead_pvalue_threshold. """ # Extract studies_metadata = EqtlCatalogueStudyIndex.read_studies_from_source( @@ -58,13 +61,19 @@ def __init__( processed_susie_df = EqtlCatalogueFinemapping.parse_susie_results( credible_sets_df, lbf_df, studies_metadata ) - credible_sets = EqtlCatalogueFinemapping.from_susie_results(processed_susie_df) - study_index = EqtlCatalogueStudyIndex.from_susie_results(processed_susie_df) - # Load - study_index.df.write.mode(session.write_mode).parquet( - eqtl_catalogue_study_index_out + ( + EqtlCatalogueStudyIndex.from_susie_results(processed_susie_df) + # Writing the output: + .df.write.mode(session.write_mode) + .parquet(eqtl_catalogue_study_index_out) ) - credible_sets.df.write.mode(session.write_mode).parquet( - eqtl_catalogue_credible_sets_out + + ( + EqtlCatalogueFinemapping.from_susie_results(processed_susie_df) + # Flagging sub-significnat loci: + .validate_lead_pvalue(pvalue_cutoff=eqtl_lead_pvalue_threshold) + # Writing the output: + .df.write.mode(session.write_mode) + .parquet(eqtl_catalogue_credible_sets_out) ) diff --git a/src/gentropy/finngen_finemapping_ingestion.py b/src/gentropy/finngen_finemapping_ingestion.py index 80089cf68..ca5ca1656 100644 --- a/src/gentropy/finngen_finemapping_ingestion.py +++ b/src/gentropy/finngen_finemapping_ingestion.py @@ -20,6 +20,7 @@ def __init__( finngen_finemapping_out: str, finngen_susie_finemapping_snp_files: str = FinngenFinemappingConfig().finngen_susie_finemapping_snp_files, finngen_susie_finemapping_cs_summary_files: str = FinngenFinemappingConfig().finngen_susie_finemapping_cs_summary_files, + finngen_finemapping_lead_pvalue_threshold: float = FinngenFinemappingConfig().finngen_finemapping_lead_pvalue_threshold, ) -> None: """Run FinnGen finemapping ingestion step. @@ -28,16 +29,21 @@ def __init__( finngen_finemapping_out (str): Output path for the finemapping results in StudyLocus format. finngen_susie_finemapping_snp_files(str): Path to the FinnGen SuSIE finemapping results. finngen_susie_finemapping_cs_summary_files (str): FinnGen SuSIE summaries for CS filters(LBF>2). + finngen_finemapping_lead_pvalue_threshold (float): Lead p-value threshold. """ # Read finemapping outputs from the input paths. - finngen_finemapping_df = FinnGenFinemapping.from_finngen_susie_finemapping( - spark=session.spark, - finngen_susie_finemapping_snp_files=finngen_susie_finemapping_snp_files, - finngen_susie_finemapping_cs_summary_files=finngen_susie_finemapping_cs_summary_files, - ) - - # Write the output. - finngen_finemapping_df.df.write.mode(session.write_mode).parquet( - finngen_finemapping_out + ( + FinnGenFinemapping.from_finngen_susie_finemapping( + spark=session.spark, + finngen_susie_finemapping_snp_files=finngen_susie_finemapping_snp_files, + finngen_susie_finemapping_cs_summary_files=finngen_susie_finemapping_cs_summary_files, + ) + # Flagging sub-significnat loci: + .validate_lead_pvalue( + pvalue_cutoff=finngen_finemapping_lead_pvalue_threshold + ) + # Writing the output: + .df.write.mode(session.write_mode) + .parquet(finngen_finemapping_out) ) diff --git a/src/gentropy/pics.py b/src/gentropy/pics.py index e80a37eb6..f96f54997 100644 --- a/src/gentropy/pics.py +++ b/src/gentropy/pics.py @@ -3,6 +3,7 @@ from __future__ import annotations from gentropy.common.session import Session +from gentropy.config import WindowBasedClumpingStepConfig from gentropy.dataset.study_locus import CredibleInterval, StudyLocus from gentropy.method.pics import PICS @@ -28,8 +29,14 @@ def __init__( session, study_locus_ld_annotated_in ) # PICS - picsed_sl = PICS.finemap(study_locus_ld_annotated).filter_credible_set( - credible_interval=CredibleInterval.IS99 + ( + PICS.finemap(study_locus_ld_annotated) + .filter_credible_set(credible_interval=CredibleInterval.IS99) + # Flagging sub-significnat loci: + .validate_lead_pvalue( + pvalue_cutoff=WindowBasedClumpingStepConfig().gwas_significance + ) + # Writing the output: + .df.write.mode(session.write_mode) + .parquet(picsed_study_locus_out) ) - # Write - picsed_sl.df.write.mode(session.write_mode).parquet(picsed_study_locus_out) From 5c58e58cd23b4d9566503ae7ebca32f7f8d26c4f Mon Sep 17 00:00:00 2001 From: Vivien Ho <56025826+vivienho@users.noreply.github.com> Date: Mon, 30 Sep 2024 14:29:13 +0100 Subject: [PATCH 065/188] feat: change `StudyLocusId` hashing method to md5 (and change `StudyLocusId` to string type) (#783) * feat: change studyLocusId to string in schema * feat: change studyLocusId of example data to string in tests * feat: change hashing method to md5 * test: remove test_assign_study_locus_id__null_variant_id as validation will have removed null ids * fix: change studyLocusId to string in remaining files * fix: ensure inputs to assign_study_locus_id are columns and not strings * fix: change studyLocusId to string in remaining files * chore: update assign_study_locus_id docstring with updated output * chore: update assign_study_locus_id docstring with updated output (again) * fix: change studyLocusId to string in recently merged files * feat: move hashing logic to generate_identifier function in Dataset class --------- Co-authored-by: Daniel Suveges --- .../assets/schemas/colocalisation.json | 4 +- src/gentropy/assets/schemas/l2g_feature.json | 2 +- .../assets/schemas/l2g_gold_standard.json | 2 +- .../assets/schemas/l2g_predictions.json | 2 +- src/gentropy/assets/schemas/study_locus.json | 2 +- .../assets/schemas/study_locus_overlap.json | 4 +- src/gentropy/dataset/dataset.py | 15 +++ src/gentropy/dataset/study_locus.py | 34 ++--- .../datasource/eqtl_catalogue/finemapping.py | 2 +- .../datasource/finngen/finemapping.py | 2 +- .../datasource/gwas_catalog/associations.py | 6 +- .../open_targets/l2g_gold_standard.py | 2 +- src/gentropy/l2g.py | 17 ++- src/gentropy/method/locus_breaker_clumping.py | 4 +- src/gentropy/method/pics.py | 2 +- src/gentropy/method/window_based_clumping.py | 2 +- src/gentropy/susie_finemapper.py | 4 +- tests/gentropy/conftest.py | 6 +- tests/gentropy/dataset/test_colocalisation.py | 6 +- tests/gentropy/dataset/test_l2g.py | 46 +++---- .../dataset/test_l2g_feature_matrix.py | 9 +- tests/gentropy/dataset/test_study_locus.py | 125 ++++++++---------- .../dataset/test_study_locus_overlap.py | 10 +- .../dataset/test_study_locus_overlaps.py | 22 +-- .../test_gwas_catalog_associations.py | 4 +- .../datasource/open_targets/test_variants.py | 2 +- tests/gentropy/method/test_clump.py | 2 +- .../method/test_colocalisation_method.py | 22 +-- 28 files changed, 177 insertions(+), 183 deletions(-) diff --git a/src/gentropy/assets/schemas/colocalisation.json b/src/gentropy/assets/schemas/colocalisation.json index 6e1163cfe..7d05c849a 100644 --- a/src/gentropy/assets/schemas/colocalisation.json +++ b/src/gentropy/assets/schemas/colocalisation.json @@ -4,13 +4,13 @@ { "name": "leftStudyLocusId", "nullable": false, - "type": "long", + "type": "string", "metadata": {} }, { "name": "rightStudyLocusId", "nullable": false, - "type": "long", + "type": "string", "metadata": {} }, { diff --git a/src/gentropy/assets/schemas/l2g_feature.json b/src/gentropy/assets/schemas/l2g_feature.json index 3139a57e4..314b4dde0 100644 --- a/src/gentropy/assets/schemas/l2g_feature.json +++ b/src/gentropy/assets/schemas/l2g_feature.json @@ -3,7 +3,7 @@ "fields": [ { "name": "studyLocusId", - "type": "long", + "type": "string", "nullable": false, "metadata": {} }, diff --git a/src/gentropy/assets/schemas/l2g_gold_standard.json b/src/gentropy/assets/schemas/l2g_gold_standard.json index cf19d6b52..6af921d61 100644 --- a/src/gentropy/assets/schemas/l2g_gold_standard.json +++ b/src/gentropy/assets/schemas/l2g_gold_standard.json @@ -3,7 +3,7 @@ "fields": [ { "name": "studyLocusId", - "type": "long", + "type": "string", "nullable": false, "metadata": {} }, diff --git a/src/gentropy/assets/schemas/l2g_predictions.json b/src/gentropy/assets/schemas/l2g_predictions.json index 16b274207..238ff4087 100644 --- a/src/gentropy/assets/schemas/l2g_predictions.json +++ b/src/gentropy/assets/schemas/l2g_predictions.json @@ -3,7 +3,7 @@ "fields": [ { "name": "studyLocusId", - "type": "long", + "type": "string", "nullable": false, "metadata": {} }, diff --git a/src/gentropy/assets/schemas/study_locus.json b/src/gentropy/assets/schemas/study_locus.json index a8d15aba6..52a19f941 100644 --- a/src/gentropy/assets/schemas/study_locus.json +++ b/src/gentropy/assets/schemas/study_locus.json @@ -4,7 +4,7 @@ "metadata": {}, "name": "studyLocusId", "nullable": false, - "type": "long" + "type": "string" }, { "metadata": {}, diff --git a/src/gentropy/assets/schemas/study_locus_overlap.json b/src/gentropy/assets/schemas/study_locus_overlap.json index 22ba7705e..0c4319827 100644 --- a/src/gentropy/assets/schemas/study_locus_overlap.json +++ b/src/gentropy/assets/schemas/study_locus_overlap.json @@ -4,13 +4,13 @@ "metadata": {}, "name": "leftStudyLocusId", "nullable": false, - "type": "long" + "type": "string" }, { "metadata": {}, "name": "rightStudyLocusId", "nullable": false, - "type": "long" + "type": "string" }, { "metadata": {}, diff --git a/src/gentropy/dataset/dataset.py b/src/gentropy/dataset/dataset.py index f49d062d3..d033e129d 100644 --- a/src/gentropy/dataset/dataset.py +++ b/src/gentropy/dataset/dataset.py @@ -310,3 +310,18 @@ def flag_duplicates(test_column: Column) -> Column: ) > 1 ) + + @staticmethod + def generate_identifier(uniqueness_defining_columns: list[str]) -> Column: + """Hashes the provided columns to generate a unique identifier. + + Args: + uniqueness_defining_columns (list[str]): list of columns defining uniqueness + + Returns: + Column: column with a unique identifier + """ + hashable_columns = [f.when(f.col(column).cast("string").isNull(), f.lit("None")) + .otherwise(f.col(column).cast("string")) + for column in uniqueness_defining_columns] + return f.md5(f.concat(*hashable_columns)) diff --git a/src/gentropy/dataset/study_locus.py b/src/gentropy/dataset/study_locus.py index e3706eaf0..a4d35e7d5 100644 --- a/src/gentropy/dataset/study_locus.py +++ b/src/gentropy/dataset/study_locus.py @@ -447,38 +447,28 @@ def _align_overlapping_tags( ) @staticmethod - def assign_study_locus_id( - study_id_col: Column, - variant_id_col: Column, - finemapping_col: Column = None, - ) -> Column: - """Hashes a column with a variant ID and a study ID to extract a consistent studyLocusId. + def assign_study_locus_id(uniqueness_defining_columns: list[str]) -> Column: + """Hashes the provided columns to extract a consistent studyLocusId. Args: - study_id_col (Column): column name with a study ID - variant_id_col (Column): column name with a variant ID - finemapping_col (Column, optional): column with fine mapping methodology + uniqueness_defining_columns (list[str]): list of columns defining uniqueness Returns: Column: column with a study locus ID Examples: >>> df = spark.createDataFrame([("GCST000001", "1_1000_A_C", "SuSiE-inf"), ("GCST000002", "1_1000_A_C", "pics")]).toDF("studyId", "variantId", "finemappingMethod") - >>> df.withColumn("study_locus_id", StudyLocus.assign_study_locus_id(f.col("studyId"), f.col("variantId"), f.col("finemappingMethod"))).show() - +----------+----------+-----------------+-------------------+ - | studyId| variantId|finemappingMethod| study_locus_id| - +----------+----------+-----------------+-------------------+ - |GCST000001|1_1000_A_C| SuSiE-inf|3801266831619496075| - |GCST000002|1_1000_A_C| pics|1581844826999194430| - +----------+----------+-----------------+-------------------+ + >>> df.withColumn("study_locus_id", StudyLocus.assign_study_locus_id(["studyId", "variantId", "finemappingMethod"])).show(truncate=False) + +----------+----------+-----------------+--------------------------------+ + |studyId |variantId |finemappingMethod|study_locus_id | + +----------+----------+-----------------+--------------------------------+ + |GCST000001|1_1000_A_C|SuSiE-inf |109804fe1e20c94231a31bafd71b566e| + |GCST000002|1_1000_A_C|pics |de310be4558e0482c9cc359c97d37773| + +----------+----------+-----------------+--------------------------------+ """ - if finemapping_col is None: - finemapping_col = f.lit(None).cast(StringType()) - variant_id_col = f.coalesce(variant_id_col, f.rand().cast("string")) - return f.xxhash64(study_id_col, variant_id_col, finemapping_col).alias( - "studyLocusId" - ) + return Dataset.generate_identifier(uniqueness_defining_columns).alias("studyLocusId") + @classmethod def calculate_credible_set_log10bf(cls: type[StudyLocus], logbfs: Column) -> Column: diff --git a/src/gentropy/datasource/eqtl_catalogue/finemapping.py b/src/gentropy/datasource/eqtl_catalogue/finemapping.py index 11ec5bef1..0808b7016 100644 --- a/src/gentropy/datasource/eqtl_catalogue/finemapping.py +++ b/src/gentropy/datasource/eqtl_catalogue/finemapping.py @@ -260,7 +260,7 @@ def from_susie_results( .select( *study_locus_cols, StudyLocus.assign_study_locus_id( - f.col("studyId"), f.col("variantId"), f.col("finemappingMethod") + ["studyId", "variantId", "finemappingMethod"] ), StudyLocus.calculate_credible_set_log10bf( f.col("locus.logBF") diff --git a/src/gentropy/datasource/finngen/finemapping.py b/src/gentropy/datasource/finngen/finemapping.py index 092a79372..3c83ba8ff 100644 --- a/src/gentropy/datasource/finngen/finemapping.py +++ b/src/gentropy/datasource/finngen/finemapping.py @@ -471,7 +471,7 @@ def from_finngen_susie_finemapping( ).withColumn( "studyLocusId", StudyLocus.assign_study_locus_id( - f.col("studyId"), f.col("variantId"), f.col("finemappingMethod") + ["studyId", "variantId", "finemappingMethod"] ), ) diff --git a/src/gentropy/datasource/gwas_catalog/associations.py b/src/gentropy/datasource/gwas_catalog/associations.py index dd9aa3fe2..b34944b11 100644 --- a/src/gentropy/datasource/gwas_catalog/associations.py +++ b/src/gentropy/datasource/gwas_catalog/associations.py @@ -9,7 +9,7 @@ from typing import TYPE_CHECKING import pyspark.sql.functions as f -from pyspark.sql.types import DoubleType, FloatType, IntegerType, LongType +from pyspark.sql.types import DoubleType, FloatType, IntegerType, StringType from pyspark.sql.window import Window from gentropy.assets import data @@ -1109,7 +1109,7 @@ def from_source( """ return StudyLocusGWASCatalog( _df=gwas_associations.withColumn( - "studyLocusId", f.monotonically_increasing_id().cast(LongType()) + "studyLocusId", f.monotonically_increasing_id().cast(StringType()) ) .transform( # Map/harmonise variants to variant annotation dataset: @@ -1188,7 +1188,7 @@ def update_study_id( .drop("subStudyDescription", "updatedStudyId") ).withColumn( "studyLocusId", - StudyLocus.assign_study_locus_id(f.col("studyId"), f.col("variantId")), + StudyLocus.assign_study_locus_id(["studyId", "variantId"]), ) return self diff --git a/src/gentropy/datasource/open_targets/l2g_gold_standard.py b/src/gentropy/datasource/open_targets/l2g_gold_standard.py index 2cfcd62f8..26d5a0253 100644 --- a/src/gentropy/datasource/open_targets/l2g_gold_standard.py +++ b/src/gentropy/datasource/open_targets/l2g_gold_standard.py @@ -52,7 +52,7 @@ def parse_positive_curation( ) .withColumn( "studyLocusId", - StudyLocus.assign_study_locus_id(f.col("studyId"), f.col("variantId")), + StudyLocus.assign_study_locus_id(["studyId", "variantId"]), ) .groupBy("studyLocusId", "studyId", "variantId", "geneId") .agg(f.collect_set("source").alias("sources")) diff --git a/src/gentropy/l2g.py b/src/gentropy/l2g.py index 6f80d826e..ff8c6c8ff 100644 --- a/src/gentropy/l2g.py +++ b/src/gentropy/l2g.py @@ -207,17 +207,22 @@ def _generate_feature_matrix(self, write_feature_matrix: bool) -> L2GFeatureMatr study_locus_overlap = StudyLocus( _df=self.credible_set.df.join( f.broadcast( - self.gs_curation.select( - StudyLocus.assign_study_locus_id( - f.col("association_info.otg_id"), # studyId - f.concat_ws( # variantId + self.gs_curation + .withColumn( + "variantId", + f.concat_ws( "_", f.col("sentinel_variant.locus_GRCh38.chromosome"), f.col("sentinel_variant.locus_GRCh38.position"), f.col("sentinel_variant.alleles.reference"), f.col("sentinel_variant.alleles.alternative"), - ), - ).alias("studyLocusId"), + ) + ) + .select( + StudyLocus.assign_study_locus_id( + ["association_info.otg_id", # studyId + "variantId"] + ), ) ), "studyLocusId", diff --git a/src/gentropy/method/locus_breaker_clumping.py b/src/gentropy/method/locus_breaker_clumping.py index 0ca7ae29b..fd7661a22 100644 --- a/src/gentropy/method/locus_breaker_clumping.py +++ b/src/gentropy/method/locus_breaker_clumping.py @@ -112,8 +112,8 @@ def locus_breaker( .cast(t.ArrayType(t.StringType())) .alias("qualityControls"), StudyLocus.assign_study_locus_id( - f.col("studyId"), f.col("variantId") - ).alias("studyLocusId"), + ["studyId", "variantId"] + ), ) ), _schema=StudyLocus.get_schema(), diff --git a/src/gentropy/method/pics.py b/src/gentropy/method/pics.py index 2de06f512..5fd084efd 100644 --- a/src/gentropy/method/pics.py +++ b/src/gentropy/method/pics.py @@ -257,7 +257,7 @@ def finemap( .withColumn( "studyLocusId", StudyLocus.assign_study_locus_id( - "studyId", "variantId", "finemappingMethod" + ["studyId", "variantId", "finemappingMethod"] ), ) .drop("neglog_pvalue") diff --git a/src/gentropy/method/window_based_clumping.py b/src/gentropy/method/window_based_clumping.py index 9ef747abf..3ab15d42f 100644 --- a/src/gentropy/method/window_based_clumping.py +++ b/src/gentropy/method/window_based_clumping.py @@ -247,7 +247,7 @@ def clump( .withColumn( "studyLocusId", StudyLocus.assign_study_locus_id( - f.col("studyId"), f.col("variantId") + ["studyId", "variantId"] ), ) # Initialize QC column as array of strings: diff --git a/src/gentropy/susie_finemapper.py b/src/gentropy/susie_finemapper.py index 587ea7963..26c73e20f 100644 --- a/src/gentropy/susie_finemapper.py +++ b/src/gentropy/susie_finemapper.py @@ -95,7 +95,7 @@ def __init__( .df.withColumn( "studyLocusId", StudyLocus.assign_study_locus_id( - "studyId", "variantId", "finemappingMethod" + ["studyId", "variantId", "finemappingMethod"] ), ) .collect()[0] @@ -247,7 +247,7 @@ def susie_inf_to_studylocus( .withColumn( "studyLocusId", StudyLocus.assign_study_locus_id( - f.col("studyId"), f.col("variantId"), f.col("finemappingMethod") + ["studyId", "variantId", "finemappingMethod"] ), ) .select( diff --git a/tests/gentropy/conftest.py b/tests/gentropy/conftest.py index 4045833f9..21f05dcf3 100644 --- a/tests/gentropy/conftest.py +++ b/tests/gentropy/conftest.py @@ -617,10 +617,10 @@ def mock_l2g_feature_matrix(spark: SparkSession) -> L2GFeatureMatrix: return L2GFeatureMatrix( _df=spark.createDataFrame( [ - (1, "gene1", 100.0, None), - (2, "gene2", 1000.0, 0.0), + ("1", "gene1", 100.0, None), + ("2", "gene2", 1000.0, 0.0), ], - "studyLocusId LONG, geneId STRING, distanceTssMean FLOAT, distanceTssMinimum FLOAT", + "studyLocusId STRING, geneId STRING, distanceTssMean FLOAT, distanceTssMinimum FLOAT", ), with_gold_standard=False, ) diff --git a/tests/gentropy/dataset/test_colocalisation.py b/tests/gentropy/dataset/test_colocalisation.py index 8f2766fb4..c15653787 100644 --- a/tests/gentropy/dataset/test_colocalisation.py +++ b/tests/gentropy/dataset/test_colocalisation.py @@ -72,12 +72,12 @@ def _setup(self: TestAppendStudyMetadata, spark: SparkSession) -> None: _df=spark.createDataFrame( [ ( - 1, + "1", "var1", "gwas1", ), ( - 2, + "2", "var2", "eqtl1", ), @@ -100,7 +100,7 @@ def _setup(self: TestAppendStudyMetadata, spark: SparkSession) -> None: ) self.sample_colocalisation = Colocalisation( _df=spark.createDataFrame( - [(1, 2, "eqtl", "X", "COLOC", 1, 0.9)], + [("1", "2", "eqtl", "X", "COLOC", 1, 0.9)], [ "leftStudyLocusId", "rightStudyLocusId", diff --git a/tests/gentropy/dataset/test_l2g.py b/tests/gentropy/dataset/test_l2g.py index 2523b97dd..125352f8e 100644 --- a/tests/gentropy/dataset/test_l2g.py +++ b/tests/gentropy/dataset/test_l2g.py @@ -43,44 +43,44 @@ def test_filter_unique_associations(spark: SparkSession) -> None: """Test filter_unique_associations.""" mock_l2g_gs_df = spark.createDataFrame( [ - (1, "variant1", "study1", "gene1", "positive"), + ("1", "variant1", "study1", "gene1", "positive"), ( - 2, + "2", "variant2", "study1", "gene1", "negative", ), # in the same locus as sl1 and pointing to same gene, has to be dropped ( - 3, + "3", "variant3", "study1", "gene1", "positive", ), # in diff locus as sl1 and pointing to same gene, has to be kept ( - 4, + "4", "variant4", "study1", "gene2", "positive", ), # in same locus as sl1 and pointing to diff gene, has to be kept ], - "studyLocusId LONG, variantId STRING, studyId STRING, geneId STRING, goldStandardSet STRING", + "studyLocusId STRING, variantId STRING, studyId STRING, geneId STRING, goldStandardSet STRING", ) mock_sl_overlap_df = spark.createDataFrame( - [(1, 2, "eqtl", "variant2"), (1, 4, "eqtl", "variant4")], - "leftStudyLocusId LONG, rightStudyLocusId LONG, rightStudyType STRING, tagVariantId STRING", + [("1", "2", "eqtl", "variant2"), ("1", "4", "eqtl", "variant4")], + "leftStudyLocusId STRING, rightStudyLocusId STRING, rightStudyType STRING, tagVariantId STRING", ) expected_df = spark.createDataFrame( [ - (1, "variant1", "study1", "gene1", "positive"), - (3, "variant3", "study1", "gene1", "positive"), - (4, "variant4", "study1", "gene2", "positive"), + ("1", "variant1", "study1", "gene1", "positive"), + ("3", "variant3", "study1", "gene1", "positive"), + ("4", "variant4", "study1", "gene2", "positive"), ], - "studyLocusId LONG, variantId STRING, studyId STRING, geneId STRING, goldStandardSet STRING", + "studyLocusId STRING, variantId STRING, studyId STRING, geneId STRING, goldStandardSet STRING", ) mock_l2g_gs = L2GGoldStandard( @@ -99,30 +99,30 @@ def test_remove_false_negatives(spark: SparkSession) -> None: """Test `remove_false_negatives`.""" mock_l2g_gs_df = spark.createDataFrame( [ - (1, "variant1", "study1", "gene1", "positive"), + ("1", "variant1", "study1", "gene1", "positive"), ( - 2, + "2", "variant2", "study1", "gene2", "negative", ), # gene2 is a partner of gene1, has to be dropped ( - 3, + "3", "variant3", "study1", "gene3", "negative", ), # gene 3 is not a partner of gene1, has to be kept ( - 4, + "4", "variant4", "study1", "gene4", "positive", ), # gene 4 is a partner of gene1, has to be kept because it's positive ], - "studyLocusId LONG, variantId STRING, studyId STRING, geneId STRING, goldStandardSet STRING", + "studyLocusId STRING, variantId STRING, studyId STRING, geneId STRING, goldStandardSet STRING", ) mock_interactions_df = spark.createDataFrame( @@ -136,11 +136,11 @@ def test_remove_false_negatives(spark: SparkSession) -> None: expected_df = spark.createDataFrame( [ - (1, "variant1", "study1", "gene1", "positive"), - (3, "variant3", "study1", "gene3", "negative"), - (4, "variant4", "study1", "gene4", "positive"), + ("1", "variant1", "study1", "gene1", "positive"), + ("3", "variant3", "study1", "gene3", "negative"), + ("4", "variant4", "study1", "gene4", "positive"), ], - "studyLocusId LONG, variantId STRING, studyId STRING, geneId STRING, goldStandardSet STRING", + "studyLocusId STRING, variantId STRING, studyId STRING, geneId STRING, goldStandardSet STRING", ) mock_l2g_gs = L2GGoldStandard( @@ -161,10 +161,10 @@ def test_l2g_feature_constructor_with_schema_mismatch( fm = L2GFeatureMatrix( _df=spark.createDataFrame( [ - (1, "gene1", 100.0), - (2, "gene2", 1000.0), + ("1", "gene1", 100.0), + ("2", "gene2", 1000.0), ], - "studyLocusId LONG, geneId STRING, distanceTssMean DOUBLE", + "studyLocusId STRING, geneId STRING, distanceTssMean DOUBLE", ), with_gold_standard=False, ) diff --git a/tests/gentropy/dataset/test_l2g_feature_matrix.py b/tests/gentropy/dataset/test_l2g_feature_matrix.py index 09460ee85..b74b6330a 100644 --- a/tests/gentropy/dataset/test_l2g_feature_matrix.py +++ b/tests/gentropy/dataset/test_l2g_feature_matrix.py @@ -8,7 +8,6 @@ from pyspark.sql.types import ( ArrayType, DoubleType, - LongType, StringType, StructField, StructType, @@ -81,7 +80,7 @@ def _setup(self: TestFromFeaturesList, spark: SparkSession) -> None: _df=spark.createDataFrame( [ ( - 1, + "1", "var1", "gwas1", [ @@ -90,7 +89,7 @@ def _setup(self: TestFromFeaturesList, spark: SparkSession) -> None: ], ), ( - 2, + "2", "var2", "eqtl1", [ @@ -100,7 +99,7 @@ def _setup(self: TestFromFeaturesList, spark: SparkSession) -> None: ], schema=StructType( [ - StructField("studyLocusId", LongType(), True), + StructField("studyLocusId", StringType(), True), StructField("variantId", StringType(), True), StructField("studyId", StringType(), True), StructField( @@ -136,7 +135,7 @@ def _setup(self: TestFromFeaturesList, spark: SparkSession) -> None: ) self.sample_colocalisation = Colocalisation( _df=spark.createDataFrame( - [(1, 2, "eqtl", "X", "COLOC", 1, 0.9)], + [("1", "2", "eqtl", "X", "COLOC", 1, 0.9)], [ "leftStudyLocusId", "rightStudyLocusId", diff --git a/tests/gentropy/dataset/test_study_locus.py b/tests/gentropy/dataset/test_study_locus.py index 29cbffad2..3240cdb02 100644 --- a/tests/gentropy/dataset/test_study_locus.py +++ b/tests/gentropy/dataset/test_study_locus.py @@ -12,7 +12,6 @@ ArrayType, BooleanType, DoubleType, - LongType, StringType, StructField, StructType, @@ -41,8 +40,8 @@ True, [ { - "leftStudyLocusId": 1, - "rightStudyLocusId": 2, + "leftStudyLocusId": "1", + "rightStudyLocusId": "2", "rightStudyType": "eqtl", "chromosome": "1", "tagVariantId": "commonTag", @@ -52,8 +51,8 @@ }, }, { - "leftStudyLocusId": 1, - "rightStudyLocusId": 2, + "leftStudyLocusId": "1", + "rightStudyLocusId": "2", "rightStudyType": "eqtl", "chromosome": "1", "tagVariantId": "nonCommonTag", @@ -78,7 +77,7 @@ def test_find_overlaps_semantic( # 2 associations with a common variant in the locus [ { - "studyLocusId": 1, + "studyLocusId": "1", "variantId": "lead1", "studyId": "study1", "studyType": "gwas", @@ -88,7 +87,7 @@ def test_find_overlaps_semantic( "chromosome": "1", }, { - "studyLocusId": 2, + "studyLocusId": "2", "variantId": "lead2", "studyId": "study2", "studyType": "eqtl", @@ -109,7 +108,7 @@ def test_find_overlaps_semantic( # 2 associations with no common variants in the locus [ { - "studyLocusId": 1, + "studyLocusId": "1", "variantId": "lead1", "studyId": "study1", "studyType": "gwas", @@ -119,7 +118,7 @@ def test_find_overlaps_semantic( "chromosome": "1", }, { - "studyLocusId": 2, + "studyLocusId": "2", "variantId": "lead2", "studyId": "study2", "studyType": "eqtl", @@ -164,14 +163,14 @@ def test_filter_by_study_type( [ { # from gwas - "studyLocusId": 1, + "studyLocusId": "1", "variantId": "lead1", "studyId": "study1", "studyType": "gwas", }, { # from eqtl - "studyLocusId": 2, + "studyLocusId": "2", "variantId": "lead2", "studyId": "study2", "studyType": "eqtl", @@ -203,20 +202,6 @@ def test_filter_credible_set(mock_study_locus: StudyLocus) -> None: ) -def test_assign_study_locus_id__null_variant_id(spark: SparkSession) -> None: - """Test assign study locus id when variant id is null for the same study.""" - df = spark.createDataFrame( - [("GCST000001", None), ("GCST000001", None)], - schema="studyId: string, variantId: string", - ).withColumn( - "studyLocusId", - StudyLocus.assign_study_locus_id(f.col("studyId"), f.col("variantId")), - ) - assert ( - df.select("studyLocusId").distinct().count() == 2 - ), "studyLocusId is not unique when variantId is null" - - @pytest.mark.parametrize( ("observed", "expected"), [ @@ -224,7 +209,7 @@ def test_assign_study_locus_id__null_variant_id(spark: SparkSession) -> None: # Locus is not null, should return union between variants in locus and lead variant [ ( - 1, + "1", "traitA", "22_varA", [ @@ -247,7 +232,7 @@ def test_assign_study_locus_id__null_variant_id(spark: SparkSession) -> None: ( # locus is null, should return lead variant [ - (1, "traitA", "22_varA", None), + ("1", "traitA", "22_varA", None), ], [ ( @@ -265,7 +250,7 @@ def test_unique_variants_in_locus( # assert isinstance(mock_study_locus.test_unique_variants_in_locus(), DataFrame) schema = StructType( [ - StructField("studyLocusId", LongType(), True), + StructField("studyLocusId", StringType(), True), StructField("studyId", StringType(), True), StructField("variantId", StringType(), True), StructField( @@ -308,7 +293,7 @@ def test_clump(mock_study_locus: StudyLocus) -> None: [ # Observed ( - 1, + "1", "traitA", "leadB", [{"variantId": "tagVariantA", "posteriorProbability": 1.0}], @@ -317,7 +302,7 @@ def test_clump(mock_study_locus: StudyLocus) -> None: [ # Expected ( - 1, + "1", "traitA", "leadB", [ @@ -336,7 +321,7 @@ def test_clump(mock_study_locus: StudyLocus) -> None: [ # Observed ( - 1, + "1", "traitA", "leadA", [ @@ -353,7 +338,7 @@ def test_clump(mock_study_locus: StudyLocus) -> None: [ # Expected ( - 1, + "1", "traitA", "leadA", [ @@ -408,7 +393,7 @@ def test_clump(mock_study_locus: StudyLocus) -> None: [ # Observed ( - 1, + "1", "traitA", "leadB", None, @@ -417,7 +402,7 @@ def test_clump(mock_study_locus: StudyLocus) -> None: [ # Expected ( - 1, + "1", "traitA", "leadB", None, @@ -429,7 +414,7 @@ def test_clump(mock_study_locus: StudyLocus) -> None: [ # Observed ( - 1, + "1", "traitA", "leadB", [], @@ -438,7 +423,7 @@ def test_clump(mock_study_locus: StudyLocus) -> None: [ # Expected ( - 1, + "1", "traitA", "leadB", None, @@ -453,7 +438,7 @@ def test_annotate_credible_sets( """Test annotate_credible_sets.""" schema = StructType( [ - StructField("studyLocusId", LongType(), True), + StructField("studyLocusId", StringType(), True), StructField("studyId", StringType(), True), StructField("variantId", StringType(), True), StructField( @@ -556,12 +541,12 @@ class TestStudyLocusVariantValidation: STUDYLOCUS_DATA = [ # First studylocus passes qc: - (1, "v1", "s1", "v1"), - (1, "v1", "s1", "v2"), - (1, "v1", "s1", "v3"), + ("1", "v1", "s1", "v1"), + ("1", "v1", "s1", "v2"), + ("1", "v1", "s1", "v3"), # Second studylocus passes qc: - (2, "v1", "s1", "v1"), - (2, "v1", "s1", "v5"), + ("2", "v1", "s1", "v1"), + ("2", "v1", "s1", "v5"), ] STUDYLOCUS_HEADER = ["studyLocusId", "variantId", "studyId", "tagVariantId"] @@ -578,7 +563,7 @@ def _setup(self: TestStudyLocusVariantValidation, spark: SparkSession) -> None: self.credible_set = StudyLocus( _df=( spark.createDataFrame(self.STUDYLOCUS_DATA, self.STUDYLOCUS_HEADER) - .withColumn("studyLocusId", f.col("studyLocusId").cast(t.LongType())) + .withColumn("studyLocusId", f.col("studyLocusId").cast(t.StringType())) .withColumn("qualityControls", f.array()) .groupBy("studyLocusId", "variantId", "studyId") .agg( @@ -619,7 +604,7 @@ def test_validation_correctness(self: TestStudyLocusVariantValidation) -> None: # Check that the right one is flagged: assert ( validated.filter( - (f.size("qualityControls") > 0) & (f.col("studyLocusId") == 2) + (f.size("qualityControls") > 0) & (f.col("studyLocusId") == "2") ).count() == 1 ) @@ -630,17 +615,17 @@ class TestStudyLocusValidation: STUDY_LOCUS_DATA = [ # Won't be flagged: - (1, "v1", "s1", 1.0, -8, []), + ("1", "v1", "s1", 1.0, -8, []), # Already flagged, needs to be tested if the flag reamins unique: - (2, "v2", "s2", 5.0, -4, [StudyLocusQualityCheck.SUBSIGNIFICANT_FLAG.value]), + ("2", "v2", "s2", 5.0, -4, [StudyLocusQualityCheck.SUBSIGNIFICANT_FLAG.value]), # To be flagged: - (3, "v3", "s3", 1.0, -4, []), - (4, "v4", "s4", 5.0, -3, []), + ("3", "v3", "s3", 1.0, -4, []), + ("4", "v4", "s4", 5.0, -3, []), ] STUDY_LOCUS_SCHEMA = t.StructType( [ - t.StructField("studyLocusId", t.LongType(), False), + t.StructField("studyLocusId", t.StringType(), False), t.StructField("variantId", t.StringType(), False), t.StructField("studyId", t.StringType(), False), t.StructField("pValueMantissa", t.FloatType(), False), @@ -779,7 +764,7 @@ def _setup(self: TestStudyLocusWindowClumping, spark: SparkSession) -> None: ).withColumns( { "studyLocusId": f.monotonically_increasing_id().cast( - t.LongType() + t.StringType() ), "pValueMantissa": f.lit(1).cast(t.FloatType()), "variantId": f.concat( @@ -839,23 +824,23 @@ class TestStudyLocusRedundancyFlagging: """Collection of tests related to flagging redundant credible sets.""" STUDY_LOCUS_DATA = [ - (1, "v1", "s1", "pics", []), - (2, "v2", "s1", "pics", [StudyLocusQualityCheck.TOP_HIT.value]), - (3, "v3", "s1", "pics", []), - (3, "v3", "s1", "pics", []), - (1, "v1", "s1", "pics", [StudyLocusQualityCheck.TOP_HIT.value]), - (1, "v1", "s2", "pics", [StudyLocusQualityCheck.TOP_HIT.value]), - (1, "v1", "s2", "pics", [StudyLocusQualityCheck.TOP_HIT.value]), - (1, "v1", "s3", "SuSie", []), - (1, "v1", "s3", "pics", [StudyLocusQualityCheck.TOP_HIT.value]), - (1, "v1", "s4", "pics", []), - (1, "v1", "s4", "SuSie", []), - (1, "v1", "s4", "pics", [StudyLocusQualityCheck.TOP_HIT.value]), + ("1", "v1", "s1", "pics", []), + ("2", "v2", "s1", "pics", [StudyLocusQualityCheck.TOP_HIT.value]), + ("3", "v3", "s1", "pics", []), + ("3", "v3", "s1", "pics", []), + ("1", "v1", "s1", "pics", [StudyLocusQualityCheck.TOP_HIT.value]), + ("1", "v1", "s2", "pics", [StudyLocusQualityCheck.TOP_HIT.value]), + ("1", "v1", "s2", "pics", [StudyLocusQualityCheck.TOP_HIT.value]), + ("1", "v1", "s3", "SuSie", []), + ("1", "v1", "s3", "pics", [StudyLocusQualityCheck.TOP_HIT.value]), + ("1", "v1", "s4", "pics", []), + ("1", "v1", "s4", "SuSie", []), + ("1", "v1", "s4", "pics", [StudyLocusQualityCheck.TOP_HIT.value]), ] STUDY_LOCUS_SCHEMA = t.StructType( [ - t.StructField("studyLocusId", t.LongType(), False), + t.StructField("studyLocusId", t.StringType(), False), t.StructField("variantId", t.StringType(), False), t.StructField("studyId", t.StringType(), False), t.StructField("finemappingMethod", t.StringType(), False), @@ -912,7 +897,7 @@ class TestStudyLocusSuSiERedundancyFlagging: STUDY_LOCUS_DATA: Any = [ # to be flagged due to v4 ( - 1, + "1", "v1", "s1", "X", @@ -928,7 +913,7 @@ class TestStudyLocusSuSiERedundancyFlagging: ), # to be flagged due to v4 ( - 2, + "2", "v2", "s1", "X", @@ -943,7 +928,7 @@ class TestStudyLocusSuSiERedundancyFlagging: ), # NOT to be flagged (outside regions) ( - 3, + "3", "v3", "s1", "X", @@ -958,7 +943,7 @@ class TestStudyLocusSuSiERedundancyFlagging: ), # NOT to be flagged (SuSie-Inf credible set) ( - 4, + "4", "v4", "s1", "X", @@ -970,7 +955,7 @@ class TestStudyLocusSuSiERedundancyFlagging: ), # NOT to be flagged (Unresolved LD) ( - 5, + "5", "v5", "s1", "X", @@ -984,7 +969,7 @@ class TestStudyLocusSuSiERedundancyFlagging: ), # NOT to be flagged (different study) ( - 6, + "6", "v6", "s2", "X", @@ -1001,7 +986,7 @@ class TestStudyLocusSuSiERedundancyFlagging: STUDY_LOCUS_SCHEMA = t.StructType( [ - t.StructField("studyLocusId", t.LongType(), False), + t.StructField("studyLocusId", t.StringType(), False), t.StructField("variantId", t.StringType(), False), t.StructField("studyId", t.StringType(), False), t.StructField("chromosome", t.StringType(), False), diff --git a/tests/gentropy/dataset/test_study_locus_overlap.py b/tests/gentropy/dataset/test_study_locus_overlap.py index 7e591df30..5dcba19c9 100644 --- a/tests/gentropy/dataset/test_study_locus_overlap.py +++ b/tests/gentropy/dataset/test_study_locus_overlap.py @@ -19,19 +19,19 @@ def test_convert_to_square_matrix(spark: SparkSession) -> None: mock_sl_overlap = StudyLocusOverlap( _df=spark.createDataFrame( [ - (1, 2, "eqtl", "variant2"), + ("1", "2", "eqtl", "variant2"), ], - "leftStudyLocusId LONG, rightStudyLocusId LONG, rightStudyType STRING, tagVariantId STRING", + "leftStudyLocusId STRING, rightStudyLocusId STRING, rightStudyType STRING, tagVariantId STRING", ), _schema=StudyLocusOverlap.get_schema(), ) expected_df = spark.createDataFrame( [ - (1, 2, "eqtl", "variant2"), - (2, 1, "eqtl", "variant2"), + ("1", "2", "eqtl", "variant2"), + ("2", "1", "eqtl", "variant2"), ], - "leftStudyLocusId LONG, rightStudyLocusId LONG, rightStudyType STRING, tagVariantId STRING", + "leftStudyLocusId STRING, rightStudyLocusId STRING, rightStudyType STRING, tagVariantId STRING", ) observed_df = mock_sl_overlap._convert_to_square_matrix().df diff --git a/tests/gentropy/dataset/test_study_locus_overlaps.py b/tests/gentropy/dataset/test_study_locus_overlaps.py index 745f07ed2..58dc95039 100644 --- a/tests/gentropy/dataset/test_study_locus_overlaps.py +++ b/tests/gentropy/dataset/test_study_locus_overlaps.py @@ -34,21 +34,21 @@ def test_study_locus_overlap_from_associations(mock_study_locus: StudyLocus) -> # observed - input DataFrame representing gwas and nongwas data to find overlapping signals [ { - "studyLocusId": 1, + "studyLocusId": "1", "studyId": "A", "studyType": "gwas", "chromosome": "1", "tagVariantId": "A", }, { - "studyLocusId": 2, + "studyLocusId": "2", "studyId": "B", "studyType": "eqtl", "chromosome": "1", "tagVariantId": "A", }, { - "studyLocusId": 3, + "studyLocusId": "3", "studyId": "C", "studyType": "gwas", "chromosome": "1", @@ -59,14 +59,14 @@ def test_study_locus_overlap_from_associations(mock_study_locus: StudyLocus) -> False, # expected - output DataFrame with overlapping signals [ - {"leftStudyLocusId": 1, "rightStudyLocusId": 2, "chromosome": "1"}, + {"leftStudyLocusId": "1", "rightStudyLocusId": "2", "chromosome": "1"}, ], ), ( # observed - input DataFrame representing intra-study data to find overlapping signals in the same study [ { - "studyLocusId": 1, + "studyLocusId": "1", "studyId": "A", "studyType": "gwas", "chromosome": "1", @@ -74,7 +74,7 @@ def test_study_locus_overlap_from_associations(mock_study_locus: StudyLocus) -> "tagVariantId": "A", }, { - "studyLocusId": 2, + "studyLocusId": "2", "studyId": "A", "studyType": "gwas", "chromosome": "1", @@ -82,7 +82,7 @@ def test_study_locus_overlap_from_associations(mock_study_locus: StudyLocus) -> "tagVariantId": "A", }, { - "studyLocusId": 3, + "studyLocusId": "3", "studyId": "B", "studyType": "gwas", "chromosome": "1", @@ -93,7 +93,7 @@ def test_study_locus_overlap_from_associations(mock_study_locus: StudyLocus) -> # intrastudy - bool of whether or not to use inter-study or intra-study logic True, # expected - output DataFrame with overlapping signals - [{"leftStudyLocusId": 2, "rightStudyLocusId": 1, "chromosome": "1"}], + [{"leftStudyLocusId": "2", "rightStudyLocusId": "1", "chromosome": "1"}], ), ], ) @@ -106,7 +106,7 @@ def test_overlapping_peaks( """Test overlapping signals between GWAS-GWAS and GWAS-Molecular trait to make sure that mQTLs are always on the right.""" mock_schema = t.StructType( [ - t.StructField("studyLocusId", t.LongType()), + t.StructField("studyLocusId", t.StringType()), t.StructField("studyId", t.StringType()), t.StructField("studyType", t.StringType()), t.StructField("chromosome", t.StringType()), @@ -116,8 +116,8 @@ def test_overlapping_peaks( ) expected_schema = t.StructType( [ - t.StructField("leftStudyLocusId", t.LongType()), - t.StructField("rightStudyLocusId", t.LongType()), + t.StructField("leftStudyLocusId", t.StringType()), + t.StructField("rightStudyLocusId", t.StringType()), t.StructField("chromosome", t.StringType()), ] ) diff --git a/tests/gentropy/datasource/gwas_catalog/test_gwas_catalog_associations.py b/tests/gentropy/datasource/gwas_catalog/test_gwas_catalog_associations.py index 130097f25..fe9608bf0 100644 --- a/tests/gentropy/datasource/gwas_catalog/test_gwas_catalog_associations.py +++ b/tests/gentropy/datasource/gwas_catalog/test_gwas_catalog_associations.py @@ -4,7 +4,7 @@ from pyspark.sql import DataFrame from pyspark.sql import functions as f -from pyspark.sql.types import LongType +from pyspark.sql.types import StringType from gentropy.dataset.variant_index import VariantIndex from gentropy.datasource.gwas_catalog.associations import ( @@ -71,7 +71,7 @@ def test_map_variants_to_variant_index( assert isinstance( GWASCatalogCuratedAssociationsParser._map_variants_to_gnomad_variants( sample_gwas_catalog_associations.withColumn( - "studyLocusId", f.monotonically_increasing_id().cast(LongType()) + "studyLocusId", f.monotonically_increasing_id().cast(StringType()) ), mock_variant_index, ), diff --git a/tests/gentropy/datasource/open_targets/test_variants.py b/tests/gentropy/datasource/open_targets/test_variants.py index 247a9d81e..6aa22e628 100644 --- a/tests/gentropy/datasource/open_targets/test_variants.py +++ b/tests/gentropy/datasource/open_targets/test_variants.py @@ -25,7 +25,7 @@ def test_as_vcf_df_credible_set( df_credible_set_df = spark.createDataFrame( [ { - "studyLocusId": 1, + "studyLocusId": "1", "variantId": "1_2_C_G", "studyId": "study1", "locus": [ diff --git a/tests/gentropy/method/test_clump.py b/tests/gentropy/method/test_clump.py index 757c79305..ed07608db 100644 --- a/tests/gentropy/method/test_clump.py +++ b/tests/gentropy/method/test_clump.py @@ -88,7 +88,7 @@ class TestIsLeadLinked: SCHEMA = t.StructType( [ t.StructField("studyId", t.StringType(), True), - t.StructField("studyLocusId", t.LongType(), True), + t.StructField("studyLocusId", t.StringType(), True), t.StructField("chromosome", t.StringType(), True), t.StructField("variantId", t.StringType(), True), t.StructField("pValueMantissa", t.FloatType(), True), diff --git a/tests/gentropy/method/test_colocalisation_method.py b/tests/gentropy/method/test_colocalisation_method.py index e292784c1..1d788eb1f 100644 --- a/tests/gentropy/method/test_colocalisation_method.py +++ b/tests/gentropy/method/test_colocalisation_method.py @@ -7,7 +7,7 @@ import pytest from pandas.testing import assert_frame_equal from pyspark.sql import SparkSession -from pyspark.sql.types import DoubleType, LongType, StringType, StructField, StructType +from pyspark.sql.types import DoubleType, StringType, StructField, StructType from gentropy.dataset.colocalisation import Colocalisation from gentropy.dataset.study_locus_overlap import StudyLocusOverlap @@ -27,8 +27,8 @@ def test_coloc(mock_study_locus_overlap: StudyLocusOverlap) -> None: # observed overlap [ { - "leftStudyLocusId": 1, - "rightStudyLocusId": 2, + "leftStudyLocusId": "1", + "rightStudyLocusId": "2", "rightStudyType": "eqtl", "chromosome": "1", "tagVariantId": "snp", @@ -51,16 +51,16 @@ def test_coloc(mock_study_locus_overlap: StudyLocusOverlap) -> None: # observed overlap [ { - "leftStudyLocusId": 1, - "rightStudyLocusId": 2, + "leftStudyLocusId": "1", + "rightStudyLocusId": "2", "rightStudyType": "eqtl", "chromosome": "1", "tagVariantId": "snp1", "statistics": {"left_logBF": 10.3, "right_logBF": 10.5}, }, { - "leftStudyLocusId": 1, - "rightStudyLocusId": 2, + "leftStudyLocusId": "1", + "rightStudyLocusId": "2", "rightStudyType": "eqtl", "chromosome": "1", "tagVariantId": "snp2", @@ -120,8 +120,8 @@ def test_coloc_no_logbf( spark.createDataFrame( [ { - "leftStudyLocusId": 1, - "rightStudyLocusId": 2, + "leftStudyLocusId": "1", + "rightStudyLocusId": "2", "rightStudyType": "eqtl", "chromosome": "1", "tagVariantId": "snp", @@ -133,8 +133,8 @@ def test_coloc_no_logbf( ], schema=StructType( [ - StructField("leftStudyLocusId", LongType(), False), - StructField("rightStudyLocusId", LongType(), False), + StructField("leftStudyLocusId", StringType(), False), + StructField("rightStudyLocusId", StringType(), False), StructField("rightStudyType", StringType(), False), StructField("chromosome", StringType(), False), StructField("tagVariantId", StringType(), False), From b7ccfae18d30982022e31bde194b5068f8c53d0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Irene=20L=C3=B3pez=20Santiago?= <45119610+ireneisdoomed@users.noreply.github.com> Date: Tue, 1 Oct 2024 09:49:32 +0100 Subject: [PATCH 066/188] feat: drop `v2g` and reimplement distance features (#771) * refactor(L2GFeatureMatrix): remove schema validation * refactor(FeatureFactory): reshape feature generation WIP * chore: pre-commit auto fixes [...] * chore: set l2gfeature properties with decorator * chore(l2gfeature): make credible_set and input_dependency instance attributes * chore(l2gfeature): make credible_set and input_dependency instance attributes * chore(featurefactory): distanceTssMeanFeature working * refactor(l2g): improve step dependency management * feat: implement * chore: fix mypy issues * feat: l2gfeaturematrix.from_features_list working * chore: comment out obsolete refs * chore(L2GFeatureMatrix): change `mode` attribute to `with_gold_standard` * refactor(l2g): move feature matrix writing to training module * feat(L2GFeatureMatrix): accept L2GGoldStandard or StudyLocus as inputs * feat: implement methods to build a feature matrix based on a studylocus/L2GGoldStandard instance * feat: coloc logic prototype * feat(l2g): filter non gwas credible sets at the start of the step * feat: rewrite colocalisation feature factory * test: add `test_colocalisation_feature_type` * test(colocalisation): add test_extract_maximum_coloc_probability_per_region_and_gene * feat(L2GFeatureInputLoader): support multiple deps by passing loader as kwarg * test: add integration tests `test_build_feature_matrix` * feat(variant_index): add `get_distance_to_gene` and deprecate `get_distance_from_tss` * feat(variant_index): deprecate `get_most_severe_transcript_consequence` * feat(variant_index): add `get_loftee` and deprecate `get_plof_v2g` * chore: reduce v2g assesments to intervals * feat(feature_factory): add distance to footprint features * test: refactor `test_feature_factory_return_type` * feat(feature_factory): add all distance neighbourhood features * chore: delete v2g * feat(feature_factory): add all colocalisation neighbourhood features * chore: final v2g deletion * chore: drop config yamls * refactor: move feature classes to datasets module * docs: update feature docs * fix: import * test: add semantic `TestCommonColocalisationFeatureLogic` * test: add semantic `TestCommonDistanceFeatureLogic` * refactor: separate features into diff modules * fix: documentation references * feat: implement distance to sentinel and adapt definitions * docs: update distance class names * fix: add all variant index mandatory fields in tests * fix(schema_validator): remove extra `[]` from parent prefix * fix: convert studylocusid to string in tests * revert: revert 72ea515fb3ea9cb07c448072be2449f4ced0dab3 (it was ok) * fix: adapt test --- docs/howto/command_line/run_step_in_cli.md | 1 - docs/python_api/datasets/l2g_feature.md | 29 - .../datasets/l2g_features/_l2g_feature.md | 11 + .../datasets/l2g_features/colocalisation.md | 27 + .../datasets/l2g_features/distance.md | 19 + docs/python_api/datasets/variant_to_gene.md | 9 - docs/python_api/methods/l2g/_l2g.md | 7 +- docs/python_api/steps/variant_to_gene_step.md | 5 - notebooks/Release_QC_metrics.ipynb | 85 +- src/gentropy/assets/schemas/v2g.json | 77 -- src/gentropy/common/spark_helpers.py | 6 +- src/gentropy/config.py | 47 +- src/gentropy/dataset/colocalisation.py | 1 + src/gentropy/dataset/intervals.py | 34 +- src/gentropy/dataset/l2g_feature.py | 506 ----------- src/gentropy/dataset/l2g_features/__init__.py | 3 + .../dataset/l2g_features/colocalisation.py | 791 ++++++++++++++++++ src/gentropy/dataset/l2g_features/distance.py | 422 ++++++++++ .../dataset/l2g_features/l2g_feature.py | 65 ++ src/gentropy/dataset/l2g_gold_standard.py | 10 +- src/gentropy/dataset/v2g.py | 51 -- src/gentropy/dataset/variant_index.py | 202 ++--- src/gentropy/datasource/ensembl/vep_parser.py | 6 +- .../open_targets/l2g_gold_standard.py | 28 +- src/gentropy/l2g.py | 51 +- src/gentropy/method/l2g/feature_factory.py | 40 +- src/gentropy/variant_to_gene.py | 119 --- tests/gentropy/conftest.py | 37 +- tests/gentropy/dataset/test_intervals.py | 18 - tests/gentropy/dataset/test_l2g.py | 2 +- tests/gentropy/dataset/test_l2g_feature.py | 441 +++++++++- tests/gentropy/dataset/test_v2g.py | 23 - tests/gentropy/dataset/test_variant_index.py | 62 +- .../open_targets/test_l2g_gold_standard.py | 74 +- tests/gentropy/test_schemas.py | 30 +- 35 files changed, 2093 insertions(+), 1246 deletions(-) delete mode 100644 docs/python_api/datasets/l2g_feature.md create mode 100644 docs/python_api/datasets/l2g_features/_l2g_feature.md create mode 100644 docs/python_api/datasets/l2g_features/colocalisation.md create mode 100644 docs/python_api/datasets/l2g_features/distance.md delete mode 100644 docs/python_api/datasets/variant_to_gene.md delete mode 100644 docs/python_api/steps/variant_to_gene_step.md delete mode 100644 src/gentropy/assets/schemas/v2g.json delete mode 100644 src/gentropy/dataset/l2g_feature.py create mode 100644 src/gentropy/dataset/l2g_features/__init__.py create mode 100644 src/gentropy/dataset/l2g_features/colocalisation.py create mode 100644 src/gentropy/dataset/l2g_features/distance.py create mode 100644 src/gentropy/dataset/l2g_features/l2g_feature.py delete mode 100644 src/gentropy/dataset/v2g.py delete mode 100644 src/gentropy/variant_to_gene.py delete mode 100644 tests/gentropy/dataset/test_intervals.py delete mode 100644 tests/gentropy/dataset/test_v2g.py diff --git a/docs/howto/command_line/run_step_in_cli.md b/docs/howto/command_line/run_step_in_cli.md index ac7d55ff9..b935d84fb 100644 --- a/docs/howto/command_line/run_step_in_cli.md +++ b/docs/howto/command_line/run_step_in_cli.md @@ -24,7 +24,6 @@ Available options: ukbiobank variant_annotation variant_index - variant_to_gene Set the environment variable HYDRA_FULL_ERROR=1 for a complete stack trace. ``` diff --git a/docs/python_api/datasets/l2g_feature.md b/docs/python_api/datasets/l2g_feature.md deleted file mode 100644 index bdab67e7c..000000000 --- a/docs/python_api/datasets/l2g_feature.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -title: L2G Feature ---- - -## Abstract Class - -::: gentropy.dataset.l2g_feature.L2GFeature - -## Feature Classes - -### Derived from colocalisation - -::: gentropy.dataset.l2g_feature.EQtlColocClppMaximumFeature -::: gentropy.dataset.l2g_feature.PQtlColocClppMaximumFeature -::: gentropy.dataset.l2g_feature.SQtlColocClppMaximumFeature -::: gentropy.dataset.l2g_feature.TuQtlColocClppMaximumFeature -::: gentropy.dataset.l2g_feature.EQtlColocH4MaximumFeature -::: gentropy.dataset.l2g_feature.PQtlColocH4MaximumFeature -::: gentropy.dataset.l2g_feature.SQtlColocH4MaximumFeature -::: gentropy.dataset.l2g_feature.TuQtlColocH4MaximumFeature - -### Derived from distance - -::: gentropy.dataset.l2g_feature.DistanceTssMinimumFeature -::: gentropy.dataset.l2g_feature.DistanceTssMeanFeature - -## Schema - ---8<-- "assets/schemas/l2g_feature.md" diff --git a/docs/python_api/datasets/l2g_features/_l2g_feature.md b/docs/python_api/datasets/l2g_features/_l2g_feature.md new file mode 100644 index 000000000..b2f6f8187 --- /dev/null +++ b/docs/python_api/datasets/l2g_features/_l2g_feature.md @@ -0,0 +1,11 @@ +--- +title: L2G Feature +--- + +## Abstract Class + +::: gentropy.dataset.l2g_features.l2g_feature.L2GFeature + +## Schema + +--8<-- "assets/schemas/l2g_feature.md" diff --git a/docs/python_api/datasets/l2g_features/colocalisation.md b/docs/python_api/datasets/l2g_features/colocalisation.md new file mode 100644 index 000000000..a3928c4ab --- /dev/null +++ b/docs/python_api/datasets/l2g_features/colocalisation.md @@ -0,0 +1,27 @@ +--- +title: From colocalisation +--- + +## List of features + +::: gentropy.dataset.l2g_features.colocalisation.EQtlColocClppMaximumFeature +::: gentropy.dataset.l2g_features.colocalisation.PQtlColocClppMaximumFeature +::: gentropy.dataset.l2g_features.colocalisation.SQtlColocClppMaximumFeature +::: gentropy.dataset.l2g_features.colocalisation.TuQtlColocClppMaximumFeature +::: gentropy.dataset.l2g_features.colocalisation.EQtlColocH4MaximumFeature +::: gentropy.dataset.l2g_features.colocalisation.PQtlColocH4MaximumFeature +::: gentropy.dataset.l2g_features.colocalisation.SQtlColocH4MaximumFeature +::: gentropy.dataset.l2g_features.colocalisation.TuQtlColocH4MaximumFeature +::: gentropy.dataset.l2g_features.colocalisation.EQtlColocClppMaximumNeighbourhoodFeature +::: gentropy.dataset.l2g_features.colocalisation.PQtlColocClppMaximumNeighbourhoodFeature +::: gentropy.dataset.l2g_features.colocalisation.SQtlColocClppMaximumNeighbourhoodFeature +::: gentropy.dataset.l2g_features.colocalisation.TuQtlColocClppMaximumNeighbourhoodFeature +::: gentropy.dataset.l2g_features.colocalisation.EQtlColocH4MaximumNeighbourhoodFeature +::: gentropy.dataset.l2g_features.colocalisation.PQtlColocH4MaximumNeighbourhoodFeature +::: gentropy.dataset.l2g_features.colocalisation.SQtlColocH4MaximumNeighbourhoodFeature +::: gentropy.dataset.l2g_features.colocalisation.TuQtlColocH4MaximumNeighbourhoodFeature + +## Common logic + +::: gentropy.dataset.l2g_features.colocalisation.common_colocalisation_feature_logic +::: gentropy.dataset.l2g_features.colocalisation.common_neighbourhood_colocalisation_feature_logic diff --git a/docs/python_api/datasets/l2g_features/distance.md b/docs/python_api/datasets/l2g_features/distance.md new file mode 100644 index 000000000..e426b2952 --- /dev/null +++ b/docs/python_api/datasets/l2g_features/distance.md @@ -0,0 +1,19 @@ +--- +title: From distance +--- + +## List of features + +::: gentropy.dataset.l2g_features.distance.DistanceSentinelTssFeature +::: gentropy.dataset.l2g_features.distance.DistanceSentinelTssNeighbourhoodFeature +::: gentropy.dataset.l2g_features.distance.DistanceTssMeanFeature +::: gentropy.dataset.l2g_features.distance.DistanceTssMeanNeighbourhoodFeature +::: gentropy.dataset.l2g_features.distance.DistanceSentinelFootprintFeature +::: gentropy.dataset.l2g_features.distance.DistanceSentinelFootprintNeighbourhoodFeature +::: gentropy.dataset.l2g_features.distance.DistanceFootprintMeanFeature +::: gentropy.dataset.l2g_features.distance.DistanceFootprintMeanNeighbourhoodFeature + +## Common logic + +::: gentropy.dataset.l2g_features.distance.common_distance_feature_logic +::: gentropy.dataset.l2g_features.distance.common_neighbourhood_distance_feature_logic diff --git a/docs/python_api/datasets/variant_to_gene.md b/docs/python_api/datasets/variant_to_gene.md deleted file mode 100644 index 2af67df92..000000000 --- a/docs/python_api/datasets/variant_to_gene.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: Variant-to-gene ---- - -::: gentropy.dataset.v2g.V2G - -## Schema - ---8<-- "assets/schemas/v2g.md" diff --git a/docs/python_api/methods/l2g/_l2g.md b/docs/python_api/methods/l2g/_l2g.md index fca3ba79d..bbd7dad66 100644 --- a/docs/python_api/methods/l2g/_l2g.md +++ b/docs/python_api/methods/l2g/_l2g.md @@ -9,13 +9,10 @@ The **“locus-to-gene” (L2G)** model derives features to prioritize likely ca - **Chromatin Interaction:** (e.g., promoter-capture Hi-C) - **Variant Pathogenicity:** (from VEP) -The L2G model is distinct from the variant-to-gene (V2G) pipeline in that it: - -- Uses a machine-learning model to learn the weights of each evidence source based on a gold standard of previously identified causal genes. -- Relies upon fine-mapping and colocalization data. - Some of the predictive features weight variant-to-gene (or genomic region-to-gene) evidence based on the posterior probability that the variant is causal, determined through fine-mapping of the GWAS association. +For a more detailed description of how each feature is computed, see [the L2G Feature documentation](../../datasets/l2g_features/_l2g_feature.md). + Details of the L2G model are provided in our Nature Genetics publication (ref - [Nature Genetics Publication](https://www.nature.com/articles/s41588-021-00945-5)): - **Title:** An open approach to systematically prioritize causal variants and genes at all published human GWAS trait-associated loci. diff --git a/docs/python_api/steps/variant_to_gene_step.md b/docs/python_api/steps/variant_to_gene_step.md deleted file mode 100644 index db1c1fd20..000000000 --- a/docs/python_api/steps/variant_to_gene_step.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: variant_to_gene ---- - -::: gentropy.variant_to_gene.V2GStep diff --git a/notebooks/Release_QC_metrics.ipynb b/notebooks/Release_QC_metrics.ipynb index aa0924711..4eb27015b 100644 --- a/notebooks/Release_QC_metrics.ipynb +++ b/notebooks/Release_QC_metrics.ipynb @@ -13,21 +13,17 @@ "1. Import necessary modules and set up the release path and version.\n", "2. Load and analyze the variant index data:\n", " - Count the number of unique variants.\n", - "3. Load and analyze the variant-to-gene (v2g) data:\n", - " - Count the number of unique variants and total variant-to-gene assignments.\n", - " - Count the number of v2g assignments where the score is > 0.8.\n", - " - Plot a histogram/density plot for the \"score\" column.\n", - "4. Load and analyze the study index data for different data sources (FinnGen, GWASCat, eQTLcat):\n", + "3. Load and analyze the study index data for different data sources (FinnGen, GWASCat, eQTLcat):\n", " - Count the number of unique studies for each data source.\n", - "5. Analyze the credible sets for each datasource (Finngen, gwascat, eqtlcat):\n", + "4. Analyze the credible sets for each datasource (Finngen, gwascat, eqtlcat):\n", " - Analyze the credible sets:\n", " - Count the number of unique credible sets and unique study IDs.\n", " - Plot a scatter plot of the credible set size vs. the top posterior probability.\n", " - Count the number of credible sets with a top SNP posterior probability > 0.9..\n", - "6. Analyze colocalization data:\n", + "5. Analyze colocalization data:\n", " - Count the total number of colocalizations and the number with clpp > 0.8.\n", " - Calculate the average number of overlaps per credible set.\n", - "7. Analyze locus-to-gene (L2G) predictions:\n", + "6. Analyze locus-to-gene (L2G) predictions:\n", " - Load the locus-to-gene predictions data.\n", " - How many Studylocus contains a \"good\" l2g prediction? (l2g_score > 0.5)\n", " - How does l2g perform based on different datasource inputs? (impossible to tell)\n", @@ -126,79 +122,6 @@ "#variant_index.filter(variant_index[\"alleleFrequencies.populationName\"] > 0.05).show(10, False)" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "#### 3. Load and analyze the variant-to-gene (v2g) data:\n", - " - Count the number of unique variants and total variant-to-gene assignments.\n", - " - Count the number of v2g assignments where the score is > 0.8." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Unique variants in v2g release: 5090991 , total variant to gene assignments: 105771851 , number of v2g assignments where score > 0.8: 23176515 ( 4.552 %)\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Summary of v2g_score: Mean: 0.5909395615801637 L.quart: 0.29 Median: 0.62 U.quart: 0.94\n" - ] - } - ], - "source": [ - "#v2g_path='gs://genetics_etl_python_playground/releases/24.03/variant_to_gene'\n", - "v2g_path=f\"{release_path}/{release_ver}/variant_to_gene\"\n", - "v2g=session.spark.read.parquet(v2g_path, recursiveFileLookup=True)\n", - "\n", - "#How many variants?\n", - "sample_size_quartiles = v2g.stat.approxQuantile(\"score\", [0.25, 0.5, 0.75], 0.01)\n", - "#v2g.select().toPandas().plot.hist()\n", - "#v2g.show()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - " - Plot a histogram/density plot for the \"score\" column." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "#The histogram/density plot for “score”\n", - "# Out of mem error:\n", - "#v2g.select(f.col(\"score\")).toPandas().plot.hist(bins=10, alpha=0.5, label=\"v2g scores\")" - ] - }, { "cell_type": "markdown", "metadata": {}, diff --git a/src/gentropy/assets/schemas/v2g.json b/src/gentropy/assets/schemas/v2g.json deleted file mode 100644 index afbe401dd..000000000 --- a/src/gentropy/assets/schemas/v2g.json +++ /dev/null @@ -1,77 +0,0 @@ -{ - "type": "struct", - "fields": [ - { - "name": "geneId", - "type": "string", - "nullable": false, - "metadata": {} - }, - { - "name": "variantId", - "type": "string", - "nullable": false, - "metadata": {} - }, - { - "name": "distance", - "type": "long", - "nullable": true, - "metadata": {} - }, - { - "name": "chromosome", - "type": "string", - "nullable": false, - "metadata": {} - }, - { - "name": "datatypeId", - "type": "string", - "nullable": false, - "metadata": {} - }, - { - "name": "datasourceId", - "type": "string", - "nullable": false, - "metadata": {} - }, - { - "name": "score", - "type": "double", - "nullable": true, - "metadata": {} - }, - { - "name": "resourceScore", - "type": "double", - "nullable": true, - "metadata": {} - }, - { - "name": "pmid", - "type": "string", - "nullable": true, - "metadata": {} - }, - { - "name": "biofeature", - "type": "string", - "nullable": true, - "metadata": {} - }, - { - "name": "variantFunctionalConsequenceId", - "type": "string", - "nullable": true, - "metadata": {} - }, - { - "name": "isHighQualityPlof", - "type": "boolean", - "nullable": true, - "metadata": {} - } - ] -} diff --git a/src/gentropy/common/spark_helpers.py b/src/gentropy/common/spark_helpers.py index 4d24212a2..8f60956e7 100644 --- a/src/gentropy/common/spark_helpers.py +++ b/src/gentropy/common/spark_helpers.py @@ -6,7 +6,7 @@ import sys from functools import reduce, wraps from itertools import chain -from typing import TYPE_CHECKING, Any, Callable, Dict, Iterable, Optional, TypeVar +from typing import TYPE_CHECKING, Any, Callable, Iterable, Optional, TypeVar import pyspark.sql.functions as f import pyspark.sql.types as t @@ -447,14 +447,14 @@ def order_array_of_structs_by_two_fields( ) -def map_column_by_dictionary(col: Column, mapping_dict: Dict[str, str]) -> Column: +def map_column_by_dictionary(col: Column, mapping_dict: dict[str, str]) -> Column: """Map column values to dictionary values by key. Missing consequence label will be converted to None, unmapped consequences will be mapped as None. Args: col (Column): Column containing labels to map. - mapping_dict (Dict[str, str]): Dictionary with mapping key/value pairs. + mapping_dict (dict[str, str]): Dictionary with mapping key/value pairs. Returns: Column: Column with mapped values. diff --git a/src/gentropy/config.py b/src/gentropy/config.py index 0a1f9438a..6f94cc9ed 100644 --- a/src/gentropy/config.py +++ b/src/gentropy/config.py @@ -2,7 +2,7 @@ import os from dataclasses import dataclass, field -from typing import Any, Dict, List +from typing import Any, List from hail import __file__ as hail_location from hydra.core.config_store import ConfigStore @@ -235,7 +235,7 @@ class LocusToGeneConfig(StepConfig): run_mode: str = MISSING predictions_path: str = MISSING credible_set_path: str = MISSING - variant_gene_path: str = MISSING + variant_index_path: str = MISSING colocalisation_path: str = MISSING study_index_path: str = MISSING model_path: str | None = None @@ -254,6 +254,16 @@ class LocusToGeneConfig(StepConfig): "pQtlColocH4Maximum", "sQtlColocH4Maximum", "tuQtlColocH4Maximum", + # distance to gene footprint + "distanceSentinelFootprint", + "distanceSentinelFootprintNeighbourhood", + "distanceFootprintMean", + "distanceFootprintMeanNeighbourhood", + # distance to gene tss + "distanceTssMean", + "distanceTssMeanNeighbourhood", + "distanceSentinelTss", + "distanceSentinelTssNeighbourhood", ] ) hyperparameters: dict[str, Any] = field( @@ -357,38 +367,6 @@ class ConvertToVcfStepConfig(StepConfig): _target_: str = "gentropy.variant_index.ConvertToVcfStep" -@dataclass -class VariantToGeneConfig(StepConfig): - """V2G step configuration.""" - - variant_index_path: str = MISSING - gene_index_path: str = MISSING - vep_consequences_path: str = MISSING - liftover_chain_file_path: str = MISSING - liftover_max_length_difference: int = 100 - max_distance: int = 500_000 - approved_biotypes: List[str] = field( - default_factory=lambda: [ - "protein_coding", - "3prime_overlapping_ncRNA", - "antisense", - "bidirectional_promoter_lncRNA", - "IG_C_gene", - "IG_D_gene", - "IG_J_gene", - "IG_V_gene", - "lincRNA", - "macro_lncRNA", - "non_coding", - "sense_intronic", - "sense_overlapping", - ] - ) - interval_sources: Dict[str, str] = field(default_factory=dict) - v2g_path: str = MISSING - _target_: str = "gentropy.variant_to_gene.V2GStep" - - @dataclass class LocusBreakerClumpingConfig(StepConfig): """Locus breaker clumping step configuration.""" @@ -565,7 +543,6 @@ def register_config() -> None: cs.store(group="step", name="ukb_ppp_eur_sumstat_preprocess", node=UkbPppEurConfig) cs.store(group="step", name="variant_index", node=VariantIndexConfig) cs.store(group="step", name="variant_to_vcf", node=ConvertToVcfStepConfig) - cs.store(group="step", name="variant_to_gene", node=VariantToGeneConfig) cs.store( group="step", name="window_based_clumping", node=WindowBasedClumpingStepConfig ) diff --git a/src/gentropy/dataset/colocalisation.py b/src/gentropy/dataset/colocalisation.py index 9e9035488..c85209462 100644 --- a/src/gentropy/dataset/colocalisation.py +++ b/src/gentropy/dataset/colocalisation.py @@ -18,6 +18,7 @@ from pyspark.sql.types import StructType from gentropy.dataset.study_index import StudyIndex + from gentropy.dataset.study_locus import StudyLocus from functools import reduce diff --git a/src/gentropy/dataset/intervals.py b/src/gentropy/dataset/intervals.py index c3b9136c9..37158810b 100644 --- a/src/gentropy/dataset/intervals.py +++ b/src/gentropy/dataset/intervals.py @@ -1,22 +1,19 @@ """Interval dataset.""" + from __future__ import annotations from dataclasses import dataclass from typing import TYPE_CHECKING -import pyspark.sql.functions as f - from gentropy.common.Liftover import LiftOverSpark from gentropy.common.schemas import parse_spark_schema from gentropy.dataset.dataset import Dataset from gentropy.dataset.gene_index import GeneIndex -from gentropy.dataset.v2g import V2G if TYPE_CHECKING: from pyspark.sql import SparkSession from pyspark.sql.types import StructType - from gentropy.dataset.variant_index import VariantIndex @dataclass @@ -74,32 +71,3 @@ def from_source( source_class = source_to_class[source_name] data = source_class.read(spark, source_path) # type: ignore return source_class.parse(data, gene_index, lift) # type: ignore - - def v2g(self: Intervals, variant_index: VariantIndex) -> V2G: - """Convert intervals into V2G by intersecting with a variant index. - - Args: - variant_index (VariantIndex): Variant index dataset - - Returns: - V2G: Variant-to-gene evidence dataset - """ - return V2G( - _df=( - self.df.alias("interval") - .join( - variant_index.df.selectExpr( - "chromosome as vi_chromosome", "variantId", "position" - ).alias("vi"), - on=[ - f.col("vi.vi_chromosome") == f.col("interval.chromosome"), - f.col("vi.position").between( - f.col("interval.start"), f.col("interval.end") - ), - ], - how="inner", - ) - .drop("start", "end", "vi_chromosome", "position") - ), - _schema=V2G.get_schema(), - ) diff --git a/src/gentropy/dataset/l2g_feature.py b/src/gentropy/dataset/l2g_feature.py deleted file mode 100644 index 319570cfd..000000000 --- a/src/gentropy/dataset/l2g_feature.py +++ /dev/null @@ -1,506 +0,0 @@ -"""L2G Feature Dataset with a collection of methods that extract features from the gentropy datasets to be fed in L2G.""" - -from __future__ import annotations - -from abc import ABC, abstractmethod -from dataclasses import dataclass -from typing import TYPE_CHECKING, Any - -import pyspark.sql.functions as f - -from gentropy.common.schemas import parse_spark_schema -from gentropy.common.spark_helpers import convert_from_wide_to_long -from gentropy.dataset.colocalisation import Colocalisation -from gentropy.dataset.dataset import Dataset -from gentropy.dataset.l2g_gold_standard import L2GGoldStandard -from gentropy.dataset.study_index import StudyIndex -from gentropy.dataset.study_locus import StudyLocus -from gentropy.dataset.v2g import V2G - -if TYPE_CHECKING: - from pyspark.sql import DataFrame - from pyspark.sql.types import StructType - - -@dataclass -class L2GFeature(Dataset, ABC): - """Locus-to-gene feature dataset.""" - - def __post_init__( - self: L2GFeature, - feature_dependency_type: Any = None, - credible_set: StudyLocus | None = None, - ) -> None: - """Initializes a L2GFeature dataset. Any child class of L2GFeature must implement the `compute` method. - - Args: - feature_dependency_type (Any): The dependency that the L2GFeature dataset depends on. Defaults to None. - credible_set (StudyLocus | None): The credible set that the L2GFeature dataset is based on. Defaults to None. - """ - super().__post_init__() - self.feature_dependency_type = feature_dependency_type - self.credible_set = credible_set - - @classmethod - def get_schema(cls: type[L2GFeature]) -> StructType: - """Provides the schema for the L2GFeature dataset. - - Returns: - StructType: Schema for the L2GFeature dataset - """ - return parse_spark_schema("l2g_feature.json") - - @classmethod - @abstractmethod - def compute( - cls: type[L2GFeature], - study_loci_to_annotate: StudyLocus | L2GGoldStandard, - feature_dependency: Any, - ) -> L2GFeature: - """Computes the L2GFeature dataset. - - Args: - study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation - feature_dependency (Any): The dependency that the L2GFeature class needs to compute the feature - Returns: - L2GFeature: a L2GFeature dataset - - Raises: - NotImplementedError: This method must be implemented in the child classes - """ - raise NotImplementedError("Must be implemented in the child classes") - - -def _common_colocalisation_feature_logic( - study_loci_to_annotate: StudyLocus | L2GGoldStandard, - colocalisation_method: str, - colocalisation_metric: str, - feature_name: str, - qtl_type: str, - *, - colocalisation: Colocalisation, - study_index: StudyIndex, - study_locus: StudyLocus, -) -> DataFrame: - """Wrapper to call the logic that creates a type of colocalisation features. - - Args: - study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation - colocalisation_method (str): The colocalisation method to filter the data by - colocalisation_metric (str): The colocalisation metric to use - feature_name (str): The name of the feature to create - qtl_type (str): The type of QTL to filter the data by - colocalisation (Colocalisation): Dataset with the colocalisation results - study_index (StudyIndex): Study index to fetch study type and gene - study_locus (StudyLocus): Study locus to traverse between colocalisation and study index - - Returns: - DataFrame: Feature annotation in long format with the columns: studyLocusId, geneId, featureName, featureValue - """ - joining_cols = ( - ["studyLocusId", "geneId"] - if isinstance(study_loci_to_annotate, L2GGoldStandard) - else ["studyLocusId"] - ) - return convert_from_wide_to_long( - study_loci_to_annotate.df.join( - colocalisation.extract_maximum_coloc_probability_per_region_and_gene( - study_locus, - study_index, - filter_by_colocalisation_method=colocalisation_method, - filter_by_qtl=qtl_type, - ), - on=joining_cols, - ) - .selectExpr( - "studyLocusId", - "geneId", - f"{colocalisation_metric} as {feature_name}", - ) - .distinct(), - id_vars=("studyLocusId", "geneId"), - var_name="featureName", - value_name="featureValue", - ) - - -class EQtlColocClppMaximumFeature(L2GFeature): - """Max CLPP for each (study, locus, gene) aggregating over all eQTLs.""" - - feature_dependency_type = [Colocalisation, StudyIndex, StudyLocus] - feature_name = "eQtlColocClppMaximum" - - @classmethod - def compute( - cls: type[EQtlColocClppMaximumFeature], - study_loci_to_annotate: StudyLocus | L2GGoldStandard, - feature_dependency: dict[str, Any], - ) -> EQtlColocClppMaximumFeature: - """Computes the feature. - - Args: - study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation - feature_dependency (dict[str, Any]): Dictionary with the dependencies required. They are passed as keyword arguments. - - Returns: - EQtlColocClppMaximumFeature: Feature dataset - """ - colocalisation_method = "ECaviar" - colocalisation_metric = "clpp" - qtl_type = "eqtl" - - return cls( - _df=_common_colocalisation_feature_logic( - study_loci_to_annotate, - colocalisation_method, - colocalisation_metric, - cls.feature_name, - qtl_type, - **feature_dependency, - ), - _schema=cls.get_schema(), - ) - - -class PQtlColocClppMaximumFeature(L2GFeature): - """Max CLPP for each (study, locus, gene) aggregating over all pQTLs.""" - - feature_dependency_type = [Colocalisation, StudyIndex, StudyLocus] - feature_name = "pQtlColocClppMaximum" - - @classmethod - def compute( - cls: type[PQtlColocClppMaximumFeature], - study_loci_to_annotate: StudyLocus | L2GGoldStandard, - feature_dependency: dict[str, Any], - ) -> PQtlColocClppMaximumFeature: - """Computes the feature. - - Args: - study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation - feature_dependency (dict[str, Any]): Dataset with the colocalisation results - - Returns: - PQtlColocClppMaximumFeature: Feature dataset - """ - colocalisation_method = "ECaviar" - colocalisation_metric = "clpp" - qtl_type = "pqtl" - return cls( - _df=_common_colocalisation_feature_logic( - study_loci_to_annotate, - colocalisation_method, - colocalisation_metric, - cls.feature_name, - qtl_type, - **feature_dependency, - ), - _schema=cls.get_schema(), - ) - - -class SQtlColocClppMaximumFeature(L2GFeature): - """Max CLPP for each (study, locus, gene) aggregating over all sQTLs.""" - - feature_dependency_type = [Colocalisation, StudyIndex, StudyLocus] - feature_name = "sQtlColocClppMaximum" - - @classmethod - def compute( - cls: type[SQtlColocClppMaximumFeature], - study_loci_to_annotate: StudyLocus | L2GGoldStandard, - feature_dependency: dict[str, Any], - ) -> SQtlColocClppMaximumFeature: - """Computes the feature. - - Args: - study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation - feature_dependency (dict[str, Any]): Dataset with the colocalisation results - - Returns: - SQtlColocClppMaximumFeature: Feature dataset - """ - colocalisation_method = "ECaviar" - colocalisation_metric = "clpp" - qtl_type = "sqtl" - return cls( - _df=_common_colocalisation_feature_logic( - study_loci_to_annotate, - colocalisation_method, - colocalisation_metric, - cls.feature_name, - qtl_type, - **feature_dependency, - ), - _schema=cls.get_schema(), - ) - - -class TuQtlColocClppMaximumFeature(L2GFeature): - """Max CLPP for each (study, locus, gene) aggregating over all tuQTLs.""" - - feature_dependency_type = [Colocalisation, StudyIndex, StudyLocus] - feature_name = "tuQtlColocClppMaximum" - - @classmethod - def compute( - cls: type[TuQtlColocClppMaximumFeature], - study_loci_to_annotate: StudyLocus | L2GGoldStandard, - feature_dependency: dict[str, Any], - ) -> TuQtlColocClppMaximumFeature: - """Computes the feature. - - Args: - study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation - feature_dependency (dict[str, Any]): Dataset with the colocalisation results - - Returns: - TuQtlColocClppMaximumFeature: Feature dataset - """ - colocalisation_method = "ECaviar" - colocalisation_metric = "clpp" - qtl_type = "tuqtl" - return cls( - _df=_common_colocalisation_feature_logic( - study_loci_to_annotate, - colocalisation_method, - colocalisation_metric, - cls.feature_name, - qtl_type, - **feature_dependency, - ), - _schema=cls.get_schema(), - ) - - -class EQtlColocH4MaximumFeature(L2GFeature): - """Max CLPP for each (study, locus, gene) aggregating over all eQTLs.""" - - feature_dependency_type = [Colocalisation, StudyIndex, StudyLocus] - feature_name = "eQtlColocH4Maximum" - - @classmethod - def compute( - cls: type[EQtlColocH4MaximumFeature], - study_loci_to_annotate: StudyLocus | L2GGoldStandard, - feature_dependency: dict[str, Any], - ) -> EQtlColocH4MaximumFeature: - """Computes the feature. - - Args: - study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation - feature_dependency (dict[str, Any]): Dataset with the colocalisation results - - Returns: - EQtlColocH4MaximumFeature: Feature dataset - """ - colocalisation_method = "Coloc" - colocalisation_metric = "h4" - qtl_type = "eqtl" - return cls( - _df=_common_colocalisation_feature_logic( - study_loci_to_annotate, - colocalisation_method, - colocalisation_metric, - cls.feature_name, - qtl_type, - **feature_dependency, - ), - _schema=cls.get_schema(), - ) - - -class PQtlColocH4MaximumFeature(L2GFeature): - """Max CLPP for each (study, locus, gene) aggregating over all pQTLs.""" - - feature_dependency_type = [Colocalisation, StudyIndex, StudyLocus] - feature_name = "pQtlColocH4Maximum" - - @classmethod - def compute( - cls: type[PQtlColocH4MaximumFeature], - study_loci_to_annotate: StudyLocus | L2GGoldStandard, - feature_dependency: dict[str, Any], - ) -> PQtlColocH4MaximumFeature: - """Computes the feature. - - Args: - study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation - feature_dependency (dict[str, Any]): Dataset with the colocalisation results - - Returns: - PQtlColocH4MaximumFeature: Feature dataset - """ - colocalisation_method = "Coloc" - colocalisation_metric = "h4" - qtl_type = "pqtl" - return cls( - _df=_common_colocalisation_feature_logic( - study_loci_to_annotate, - colocalisation_method, - colocalisation_metric, - cls.feature_name, - qtl_type, - **feature_dependency, - ), - _schema=cls.get_schema(), - ) - - -class SQtlColocH4MaximumFeature(L2GFeature): - """Max CLPP for each (study, locus, gene) aggregating over all sQTLs.""" - - feature_dependency_type = [Colocalisation, StudyIndex, StudyLocus] - feature_name = "sQtlColocH4Maximum" - - @classmethod - def compute( - cls: type[SQtlColocH4MaximumFeature], - study_loci_to_annotate: StudyLocus | L2GGoldStandard, - feature_dependency: dict[str, Any], - ) -> SQtlColocH4MaximumFeature: - """Computes the feature. - - Args: - study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation - feature_dependency (dict[str, Any]): Dataset with the colocalisation results - - Returns: - SQtlColocH4MaximumFeature: Feature dataset - """ - colocalisation_method = "Coloc" - colocalisation_metric = "h4" - qtl_type = "sqtl" - return cls( - _df=_common_colocalisation_feature_logic( - study_loci_to_annotate, - colocalisation_method, - colocalisation_metric, - cls.feature_name, - qtl_type, - **feature_dependency, - ), - _schema=cls.get_schema(), - ) - - -class TuQtlColocH4MaximumFeature(L2GFeature): - """Max H4 for each (study, locus, gene) aggregating over all tuQTLs.""" - - feature_dependency_type = [Colocalisation, StudyIndex, StudyLocus] - feature_name = "tuQtlColocH4Maximum" - - @classmethod - def compute( - cls: type[TuQtlColocH4MaximumFeature], - study_loci_to_annotate: StudyLocus | L2GGoldStandard, - feature_dependency: dict[str, Any], - ) -> TuQtlColocH4MaximumFeature: - """Computes the feature. - - Args: - study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation - feature_dependency (dict[str, Any]): Dataset with the colocalisation results - - Returns: - TuQtlColocH4MaximumFeature: Feature dataset - """ - colocalisation_method = "Coloc" - colocalisation_metric = "h4" - qtl_type = "tuqtl" - return cls( - _df=_common_colocalisation_feature_logic( - study_loci_to_annotate, - colocalisation_method, - colocalisation_metric, - cls.feature_name, - qtl_type, - **feature_dependency, - ), - _schema=cls.get_schema(), - ) - - -class DistanceTssMinimumFeature(L2GFeature): - """Minimum distance of all tagging variants to gene TSS.""" - - @classmethod - def compute( - cls: type[DistanceTssMinimumFeature], - study_loci_to_annotate: StudyLocus | L2GGoldStandard, - feature_dependency: V2G, - ) -> L2GFeature: - """Computes the feature. - - Args: - study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation - feature_dependency (V2G): Dataset that contains the distance information - - Returns: - L2GFeature: Feature dataset - - Raises: - NotImplementedError: Not implemented - """ - raise NotImplementedError - - -class DistanceTssMeanFeature(L2GFeature): - """Average distance of all tagging variants to gene TSS. - - NOTE: to be rewritten taking variant index as input - """ - - fill_na_value = 500_000 - feature_dependency_type = V2G - - @classmethod - def compute( - cls: type[DistanceTssMeanFeature], - study_loci_to_annotate: StudyLocus | L2GGoldStandard, - feature_dependency: V2G, - ) -> DistanceTssMeanFeature: - """Computes the feature. - - Args: - study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation - feature_dependency (V2G): Dataset that contains the distance information - - Returns: - DistanceTssMeanFeature: Feature dataset - """ - agg_expr = f.mean("weightedScore").alias("distanceTssMean") - # Everything but expresion is common logic - v2g = feature_dependency.df.filter(f.col("datasourceId") == "canonical_tss") - wide_df = ( - study_loci_to_annotate.df.withColumn( - "variantInLocus", f.explode_outer("locus") - ) - .select( - "studyLocusId", - f.col("variantInLocus.variantId").alias("variantInLocusId"), - f.col("variantInLocus.posteriorProbability").alias( - "variantInLocusPosteriorProbability" - ), - ) - .join( - v2g.selectExpr("variantId as variantInLocusId", "geneId", "score"), - on="variantInLocusId", - how="inner", - ) - .withColumn( - "weightedScore", - f.col("score") * f.col("variantInLocusPosteriorProbability"), - ) - .groupBy("studyLocusId", "geneId") - .agg(agg_expr) - ) - return cls( - _df=convert_from_wide_to_long( - wide_df, - id_vars=("studyLocusId", "geneId"), - var_name="featureName", - value_name="featureValue", - ), - _schema=cls.get_schema(), - ) diff --git a/src/gentropy/dataset/l2g_features/__init__.py b/src/gentropy/dataset/l2g_features/__init__.py new file mode 100644 index 000000000..ce15cedfe --- /dev/null +++ b/src/gentropy/dataset/l2g_features/__init__.py @@ -0,0 +1,3 @@ +"""Feature factories for L2G.""" + +from __future__ import annotations diff --git a/src/gentropy/dataset/l2g_features/colocalisation.py b/src/gentropy/dataset/l2g_features/colocalisation.py new file mode 100644 index 000000000..c44573b72 --- /dev/null +++ b/src/gentropy/dataset/l2g_features/colocalisation.py @@ -0,0 +1,791 @@ +"""Collection of methods that extract features from the colocalisation datasets.""" + +from __future__ import annotations + +from typing import TYPE_CHECKING, Any + +import pyspark.sql.functions as f +from pyspark.sql import Window + +from gentropy.common.spark_helpers import convert_from_wide_to_long +from gentropy.dataset.colocalisation import Colocalisation +from gentropy.dataset.l2g_features.l2g_feature import L2GFeature +from gentropy.dataset.l2g_gold_standard import L2GGoldStandard +from gentropy.dataset.study_index import StudyIndex +from gentropy.dataset.study_locus import StudyLocus + +if TYPE_CHECKING: + from pyspark.sql import DataFrame + + +def common_colocalisation_feature_logic( + study_loci_to_annotate: StudyLocus | L2GGoldStandard, + colocalisation_method: str, + colocalisation_metric: str, + feature_name: str, + qtl_type: str, + *, + colocalisation: Colocalisation, + study_index: StudyIndex, + study_locus: StudyLocus, +) -> DataFrame: + """Wrapper to call the logic that creates a type of colocalisation features. + + Args: + study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation + colocalisation_method (str): The colocalisation method to filter the data by + colocalisation_metric (str): The colocalisation metric to use + feature_name (str): The name of the feature to create + qtl_type (str): The type of QTL to filter the data by + colocalisation (Colocalisation): Dataset with the colocalisation results + study_index (StudyIndex): Study index to fetch study type and gene + study_locus (StudyLocus): Study locus to traverse between colocalisation and study index + + Returns: + DataFrame: Feature annotation in long format with the columns: studyLocusId, geneId, featureName, featureValue + """ + joining_cols = ( + ["studyLocusId", "geneId"] + if isinstance(study_loci_to_annotate, L2GGoldStandard) + else ["studyLocusId"] + ) + return ( + study_loci_to_annotate.df.join( + colocalisation.extract_maximum_coloc_probability_per_region_and_gene( + study_locus, + study_index, + filter_by_colocalisation_method=colocalisation_method, + filter_by_qtl=qtl_type, + ), + on=joining_cols, + ) + .selectExpr( + "studyLocusId", + "geneId", + f"{colocalisation_metric} as {feature_name}", + ) + .distinct() + ) + + +def common_neighbourhood_colocalisation_feature_logic( + study_loci_to_annotate: StudyLocus | L2GGoldStandard, + colocalisation_method: str, + colocalisation_metric: str, + feature_name: str, + qtl_type: str, + *, + colocalisation: Colocalisation, + study_index: StudyIndex, + study_locus: StudyLocus, +) -> DataFrame: + """Wrapper to call the logic that creates a type of colocalisation features. + + Args: + study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation + colocalisation_method (str): The colocalisation method to filter the data by + colocalisation_metric (str): The colocalisation metric to use + feature_name (str): The name of the feature to create + qtl_type (str): The type of QTL to filter the data by + colocalisation (Colocalisation): Dataset with the colocalisation results + study_index (StudyIndex): Study index to fetch study type and gene + study_locus (StudyLocus): Study locus to traverse between colocalisation and study index + + Returns: + DataFrame: Feature annotation in long format with the columns: studyLocusId, geneId, featureName, featureValue + """ + # First maximum colocalisation score for each studylocus, gene + local_feature_name = feature_name.replace("Neighbourhood", "") + local_max = common_colocalisation_feature_logic( + study_loci_to_annotate, + colocalisation_method, + colocalisation_metric, + local_feature_name, + qtl_type, + colocalisation=colocalisation, + study_index=study_index, + study_locus=study_locus, + ) + return ( + # Then compute maximum score in the vicinity (feature will be the same for any gene associated with a studyLocus) + local_max.withColumn( + "regional_maximum", + f.max(local_feature_name).over(Window.partitionBy("studyLocusId")), + ) + .withColumn(feature_name, f.col("regional_maximum") - f.col(local_feature_name)) + .drop("regional_maximum", local_feature_name) + ) + + +class EQtlColocClppMaximumFeature(L2GFeature): + """Max CLPP for each (study, locus, gene) aggregating over all eQTLs.""" + + feature_dependency_type = [Colocalisation, StudyIndex, StudyLocus] + feature_name = "eQtlColocClppMaximum" + + @classmethod + def compute( + cls: type[EQtlColocClppMaximumFeature], + study_loci_to_annotate: StudyLocus | L2GGoldStandard, + feature_dependency: dict[str, Any], + ) -> EQtlColocClppMaximumFeature: + """Computes the feature. + + Args: + study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation + feature_dependency (dict[str, Any]): Dictionary with the dependencies required. They are passed as keyword arguments. + + Returns: + EQtlColocClppMaximumFeature: Feature dataset + """ + colocalisation_method = "ECaviar" + colocalisation_metric = "clpp" + qtl_type = "eqtl" + + return cls( + _df=convert_from_wide_to_long( + common_colocalisation_feature_logic( + study_loci_to_annotate, + colocalisation_method, + colocalisation_metric, + cls.feature_name, + qtl_type, + **feature_dependency, + ), + id_vars=("studyLocusId", "geneId"), + var_name="featureName", + value_name="featureValue", + ), + _schema=cls.get_schema(), + ) + + +class EQtlColocClppMaximumNeighbourhoodFeature(L2GFeature): + """Max CLPP for each (study, locus) aggregating over all eQTLs.""" + + feature_dependency_type = [Colocalisation, StudyIndex, StudyLocus] + feature_name = "eQtlColocClppMaximumNeighbourhood" + + @classmethod + def compute( + cls: type[EQtlColocClppMaximumNeighbourhoodFeature], + study_loci_to_annotate: StudyLocus | L2GGoldStandard, + feature_dependency: dict[str, Any], + ) -> EQtlColocClppMaximumNeighbourhoodFeature: + """Computes the feature. + + Args: + study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation + feature_dependency (dict[str, Any]): Dictionary with the dependencies required. They are passed as keyword arguments. + + Returns: + EQtlColocClppMaximumNeighbourhoodFeature: Feature dataset + """ + colocalisation_method = "ECaviar" + colocalisation_metric = "clpp" + qtl_type = "eqtl" + + return cls( + _df=convert_from_wide_to_long( + common_neighbourhood_colocalisation_feature_logic( + study_loci_to_annotate, + colocalisation_method, + colocalisation_metric, + cls.feature_name, + qtl_type, + **feature_dependency, + ), + id_vars=("studyLocusId", "geneId"), + var_name="featureName", + value_name="featureValue", + ), + _schema=cls.get_schema(), + ) + + +class PQtlColocClppMaximumFeature(L2GFeature): + """Max CLPP for each (study, locus, gene) aggregating over all pQTLs.""" + + feature_dependency_type = [Colocalisation, StudyIndex, StudyLocus] + feature_name = "pQtlColocClppMaximum" + + @classmethod + def compute( + cls: type[PQtlColocClppMaximumFeature], + study_loci_to_annotate: StudyLocus | L2GGoldStandard, + feature_dependency: dict[str, Any], + ) -> PQtlColocClppMaximumFeature: + """Computes the feature. + + Args: + study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation + feature_dependency (dict[str, Any]): Dataset with the colocalisation results + + Returns: + PQtlColocClppMaximumFeature: Feature dataset + """ + colocalisation_method = "ECaviar" + colocalisation_metric = "clpp" + qtl_type = "pqtl" + return cls( + _df=convert_from_wide_to_long( + common_colocalisation_feature_logic( + study_loci_to_annotate, + colocalisation_method, + colocalisation_metric, + cls.feature_name, + qtl_type, + **feature_dependency, + ), + id_vars=("studyLocusId", "geneId"), + var_name="featureName", + value_name="featureValue", + ), + _schema=cls.get_schema(), + ) + + +class PQtlColocClppMaximumNeighbourhoodFeature(L2GFeature): + """Max CLPP for each (study, locus, gene) aggregating over all pQTLs.""" + + feature_dependency_type = [Colocalisation, StudyIndex, StudyLocus] + feature_name = "pQtlColocClppMaximumNeighbourhood" + + @classmethod + def compute( + cls: type[PQtlColocClppMaximumNeighbourhoodFeature], + study_loci_to_annotate: StudyLocus | L2GGoldStandard, + feature_dependency: dict[str, Any], + ) -> PQtlColocClppMaximumNeighbourhoodFeature: + """Computes the feature. + + Args: + study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation + feature_dependency (dict[str, Any]): Dataset with the colocalisation results + + Returns: + PQtlColocClppMaximumNeighbourhoodFeature: Feature dataset + """ + colocalisation_method = "ECaviar" + colocalisation_metric = "clpp" + qtl_type = "pqtl" + return cls( + _df=convert_from_wide_to_long( + common_neighbourhood_colocalisation_feature_logic( + study_loci_to_annotate, + colocalisation_method, + colocalisation_metric, + cls.feature_name, + qtl_type, + **feature_dependency, + ), + id_vars=("studyLocusId", "geneId"), + var_name="featureName", + value_name="featureValue", + ), + _schema=cls.get_schema(), + ) + + +class SQtlColocClppMaximumFeature(L2GFeature): + """Max CLPP for each (study, locus, gene) aggregating over all sQTLs.""" + + feature_dependency_type = [Colocalisation, StudyIndex, StudyLocus] + feature_name = "sQtlColocClppMaximum" + + @classmethod + def compute( + cls: type[SQtlColocClppMaximumFeature], + study_loci_to_annotate: StudyLocus | L2GGoldStandard, + feature_dependency: dict[str, Any], + ) -> SQtlColocClppMaximumFeature: + """Computes the feature. + + Args: + study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation + feature_dependency (dict[str, Any]): Dataset with the colocalisation results + + Returns: + SQtlColocClppMaximumFeature: Feature dataset + """ + colocalisation_method = "ECaviar" + colocalisation_metric = "clpp" + qtl_type = "sqtl" + return cls( + _df=convert_from_wide_to_long( + common_colocalisation_feature_logic( + study_loci_to_annotate, + colocalisation_method, + colocalisation_metric, + cls.feature_name, + qtl_type, + **feature_dependency, + ), + id_vars=("studyLocusId", "geneId"), + var_name="featureName", + value_name="featureValue", + ), + _schema=cls.get_schema(), + ) + + +class SQtlColocClppMaximumNeighbourhoodFeature(L2GFeature): + """Max CLPP for each (study, locus, gene) aggregating over all sQTLs.""" + + feature_dependency_type = [Colocalisation, StudyIndex, StudyLocus] + feature_name = "sQtlColocClppMaximumNeighbourhood" + + @classmethod + def compute( + cls: type[SQtlColocClppMaximumNeighbourhoodFeature], + study_loci_to_annotate: StudyLocus | L2GGoldStandard, + feature_dependency: dict[str, Any], + ) -> SQtlColocClppMaximumNeighbourhoodFeature: + """Computes the feature. + + Args: + study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation + feature_dependency (dict[str, Any]): Dataset with the colocalisation results + + Returns: + SQtlColocClppMaximumNeighbourhoodFeature: Feature dataset + """ + colocalisation_method = "ECaviar" + colocalisation_metric = "clpp" + qtl_type = "sqtl" + return cls( + _df=convert_from_wide_to_long( + common_neighbourhood_colocalisation_feature_logic( + study_loci_to_annotate, + colocalisation_method, + colocalisation_metric, + cls.feature_name, + qtl_type, + **feature_dependency, + ), + id_vars=("studyLocusId", "geneId"), + var_name="featureName", + value_name="featureValue", + ), + _schema=cls.get_schema(), + ) + + +class TuQtlColocClppMaximumFeature(L2GFeature): + """Max CLPP for each (study, locus, gene) aggregating over all tuQTLs.""" + + feature_dependency_type = [Colocalisation, StudyIndex, StudyLocus] + feature_name = "tuQtlColocClppMaximum" + + @classmethod + def compute( + cls: type[TuQtlColocClppMaximumFeature], + study_loci_to_annotate: StudyLocus | L2GGoldStandard, + feature_dependency: dict[str, Any], + ) -> TuQtlColocClppMaximumFeature: + """Computes the feature. + + Args: + study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation + feature_dependency (dict[str, Any]): Dataset with the colocalisation results + + Returns: + TuQtlColocClppMaximumFeature: Feature dataset + """ + colocalisation_method = "ECaviar" + colocalisation_metric = "clpp" + qtl_type = "tuqtl" + return cls( + _df=convert_from_wide_to_long( + common_colocalisation_feature_logic( + study_loci_to_annotate, + colocalisation_method, + colocalisation_metric, + cls.feature_name, + qtl_type, + **feature_dependency, + ), + id_vars=("studyLocusId", "geneId"), + var_name="featureName", + value_name="featureValue", + ), + _schema=cls.get_schema(), + ) + + +class TuQtlColocClppMaximumNeighbourhoodFeature(L2GFeature): + """Max CLPP for each (study, locus) aggregating over all tuQTLs.""" + + feature_dependency_type = [Colocalisation, StudyIndex, StudyLocus] + feature_name = "tuQtlColocClppMaximumNeighbourhood" + + @classmethod + def compute( + cls: type[TuQtlColocClppMaximumNeighbourhoodFeature], + study_loci_to_annotate: StudyLocus | L2GGoldStandard, + feature_dependency: dict[str, Any], + ) -> TuQtlColocClppMaximumNeighbourhoodFeature: + """Computes the feature. + + Args: + study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation + feature_dependency (dict[str, Any]): Dataset with the colocalisation results + + Returns: + TuQtlColocClppMaximumNeighbourhoodFeature: Feature dataset + """ + colocalisation_method = "ECaviar" + colocalisation_metric = "clpp" + qtl_type = "tuqtl" + return cls( + _df=convert_from_wide_to_long( + common_neighbourhood_colocalisation_feature_logic( + study_loci_to_annotate, + colocalisation_method, + colocalisation_metric, + cls.feature_name, + qtl_type, + **feature_dependency, + ), + id_vars=("studyLocusId", "geneId"), + var_name="featureName", + value_name="featureValue", + ), + _schema=cls.get_schema(), + ) + + +class EQtlColocH4MaximumFeature(L2GFeature): + """Max H4 for each (study, locus, gene) aggregating over all eQTLs.""" + + feature_dependency_type = [Colocalisation, StudyIndex, StudyLocus] + feature_name = "eQtlColocH4Maximum" + + @classmethod + def compute( + cls: type[EQtlColocH4MaximumFeature], + study_loci_to_annotate: StudyLocus | L2GGoldStandard, + feature_dependency: dict[str, Any], + ) -> EQtlColocH4MaximumFeature: + """Computes the feature. + + Args: + study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation + feature_dependency (dict[str, Any]): Dataset with the colocalisation results + + Returns: + EQtlColocH4MaximumFeature: Feature dataset + """ + colocalisation_method = "Coloc" + colocalisation_metric = "h4" + qtl_type = "eqtl" + return cls( + _df=convert_from_wide_to_long( + common_colocalisation_feature_logic( + study_loci_to_annotate, + colocalisation_method, + colocalisation_metric, + cls.feature_name, + qtl_type, + **feature_dependency, + ), + id_vars=("studyLocusId", "geneId"), + var_name="featureName", + value_name="featureValue", + ), + _schema=cls.get_schema(), + ) + + +class EQtlColocH4MaximumNeighbourhoodFeature(L2GFeature): + """Max H4 for each (study, locus) aggregating over all eQTLs.""" + + feature_dependency_type = [Colocalisation, StudyIndex, StudyLocus] + feature_name = "eQtlColocH4MaximumNeighbourhood" + + @classmethod + def compute( + cls: type[EQtlColocH4MaximumNeighbourhoodFeature], + study_loci_to_annotate: StudyLocus | L2GGoldStandard, + feature_dependency: dict[str, Any], + ) -> EQtlColocH4MaximumNeighbourhoodFeature: + """Computes the feature. + + Args: + study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation + feature_dependency (dict[str, Any]): Dataset with the colocalisation results + + Returns: + EQtlColocH4MaximumNeighbourhoodFeature: Feature dataset + """ + colocalisation_method = "Coloc" + colocalisation_metric = "h4" + qtl_type = "eqtl" + return cls( + _df=convert_from_wide_to_long( + common_neighbourhood_colocalisation_feature_logic( + study_loci_to_annotate, + colocalisation_method, + colocalisation_metric, + cls.feature_name, + qtl_type, + **feature_dependency, + ), + id_vars=("studyLocusId", "geneId"), + var_name="featureName", + value_name="featureValue", + ), + _schema=cls.get_schema(), + ) + + +class PQtlColocH4MaximumFeature(L2GFeature): + """Max H4 for each (study, locus, gene) aggregating over all pQTLs.""" + + feature_dependency_type = [Colocalisation, StudyIndex, StudyLocus] + feature_name = "pQtlColocH4Maximum" + + @classmethod + def compute( + cls: type[PQtlColocH4MaximumFeature], + study_loci_to_annotate: StudyLocus | L2GGoldStandard, + feature_dependency: dict[str, Any], + ) -> PQtlColocH4MaximumFeature: + """Computes the feature. + + Args: + study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation + feature_dependency (dict[str, Any]): Dataset with the colocalisation results + + Returns: + PQtlColocH4MaximumFeature: Feature dataset + """ + colocalisation_method = "Coloc" + colocalisation_metric = "h4" + qtl_type = "pqtl" + return cls( + _df=convert_from_wide_to_long( + common_colocalisation_feature_logic( + study_loci_to_annotate, + colocalisation_method, + colocalisation_metric, + cls.feature_name, + qtl_type, + **feature_dependency, + ), + id_vars=("studyLocusId", "geneId"), + var_name="featureName", + value_name="featureValue", + ), + _schema=cls.get_schema(), + ) + + +class PQtlColocH4MaximumNeighbourhoodFeature(L2GFeature): + """Max H4 for each (study, locus) aggregating over all pQTLs.""" + + feature_dependency_type = [Colocalisation, StudyIndex, StudyLocus] + feature_name = "pQtlColocH4MaximumNeighbourhood" + + @classmethod + def compute( + cls: type[PQtlColocH4MaximumNeighbourhoodFeature], + study_loci_to_annotate: StudyLocus | L2GGoldStandard, + feature_dependency: dict[str, Any], + ) -> PQtlColocH4MaximumNeighbourhoodFeature: + """Computes the feature. + + Args: + study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation + feature_dependency (dict[str, Any]): Dataset with the colocalisation results + + Returns: + PQtlColocH4MaximumNeighbourhoodFeature: Feature dataset + """ + colocalisation_method = "Coloc" + colocalisation_metric = "h4" + qtl_type = "pqtl" + return cls( + _df=convert_from_wide_to_long( + common_neighbourhood_colocalisation_feature_logic( + study_loci_to_annotate, + colocalisation_method, + colocalisation_metric, + cls.feature_name, + qtl_type, + **feature_dependency, + ), + id_vars=("studyLocusId", "geneId"), + var_name="featureName", + value_name="featureValue", + ), + _schema=cls.get_schema(), + ) + + +class SQtlColocH4MaximumFeature(L2GFeature): + """Max H4 for each (study, locus, gene) aggregating over all sQTLs.""" + + feature_dependency_type = [Colocalisation, StudyIndex, StudyLocus] + feature_name = "sQtlColocH4Maximum" + + @classmethod + def compute( + cls: type[SQtlColocH4MaximumFeature], + study_loci_to_annotate: StudyLocus | L2GGoldStandard, + feature_dependency: dict[str, Any], + ) -> SQtlColocH4MaximumFeature: + """Computes the feature. + + Args: + study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation + feature_dependency (dict[str, Any]): Dataset with the colocalisation results + + Returns: + SQtlColocH4MaximumFeature: Feature dataset + """ + colocalisation_method = "Coloc" + colocalisation_metric = "h4" + qtl_type = "sqtl" + return cls( + _df=convert_from_wide_to_long( + common_colocalisation_feature_logic( + study_loci_to_annotate, + colocalisation_method, + colocalisation_metric, + cls.feature_name, + qtl_type, + **feature_dependency, + ), + id_vars=("studyLocusId", "geneId"), + var_name="featureName", + value_name="featureValue", + ), + _schema=cls.get_schema(), + ) + + +class SQtlColocH4MaximumNeighbourhoodFeature(L2GFeature): + """Max H4 for each (study, locus) aggregating over all sQTLs.""" + + feature_dependency_type = [Colocalisation, StudyIndex, StudyLocus] + feature_name = "sQtlColocH4MaximumNeighbourhood" + + @classmethod + def compute( + cls: type[SQtlColocH4MaximumNeighbourhoodFeature], + study_loci_to_annotate: StudyLocus | L2GGoldStandard, + feature_dependency: dict[str, Any], + ) -> SQtlColocH4MaximumNeighbourhoodFeature: + """Computes the feature. + + Args: + study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation + feature_dependency (dict[str, Any]): Dataset with the colocalisation results + + Returns: + SQtlColocH4MaximumNeighbourhoodFeature: Feature dataset + """ + colocalisation_method = "Coloc" + colocalisation_metric = "h4" + qtl_type = "sqtl" + return cls( + _df=convert_from_wide_to_long( + common_neighbourhood_colocalisation_feature_logic( + study_loci_to_annotate, + colocalisation_method, + colocalisation_metric, + cls.feature_name, + qtl_type, + **feature_dependency, + ), + id_vars=("studyLocusId", "geneId"), + var_name="featureName", + value_name="featureValue", + ), + _schema=cls.get_schema(), + ) + + +class TuQtlColocH4MaximumFeature(L2GFeature): + """Max H4 for each (study, locus, gene) aggregating over all tuQTLs.""" + + feature_dependency_type = [Colocalisation, StudyIndex, StudyLocus] + feature_name = "tuQtlColocH4Maximum" + + @classmethod + def compute( + cls: type[TuQtlColocH4MaximumFeature], + study_loci_to_annotate: StudyLocus | L2GGoldStandard, + feature_dependency: dict[str, Any], + ) -> TuQtlColocH4MaximumFeature: + """Computes the feature. + + Args: + study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation + feature_dependency (dict[str, Any]): Dataset with the colocalisation results + + Returns: + TuQtlColocH4MaximumFeature: Feature dataset + """ + colocalisation_method = "Coloc" + colocalisation_metric = "h4" + qtl_type = "tuqtl" + return cls( + _df=convert_from_wide_to_long( + common_colocalisation_feature_logic( + study_loci_to_annotate, + colocalisation_method, + colocalisation_metric, + cls.feature_name, + qtl_type, + **feature_dependency, + ), + id_vars=("studyLocusId", "geneId"), + var_name="featureName", + value_name="featureValue", + ), + _schema=cls.get_schema(), + ) + + +class TuQtlColocH4MaximumNeighbourhoodFeature(L2GFeature): + """Max H4 for each (study, locus) aggregating over all tuQTLs.""" + + feature_dependency_type = [Colocalisation, StudyIndex, StudyLocus] + feature_name = "tuQtlColocH4MaximumNeighbourhood" + + @classmethod + def compute( + cls: type[TuQtlColocH4MaximumNeighbourhoodFeature], + study_loci_to_annotate: StudyLocus | L2GGoldStandard, + feature_dependency: dict[str, Any], + ) -> TuQtlColocH4MaximumNeighbourhoodFeature: + """Computes the feature. + + Args: + study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation + feature_dependency (dict[str, Any]): Dataset with the colocalisation results + + Returns: + TuQtlColocH4MaximumNeighbourhoodFeature: Feature dataset + """ + colocalisation_method = "Coloc" + colocalisation_metric = "h4" + qtl_type = "tuqtl" + return cls( + _df=convert_from_wide_to_long( + common_colocalisation_feature_logic( + study_loci_to_annotate, + colocalisation_method, + colocalisation_metric, + cls.feature_name, + qtl_type, + **feature_dependency, + ), + id_vars=("studyLocusId", "geneId"), + var_name="featureName", + value_name="featureValue", + ), + _schema=cls.get_schema(), + ) diff --git a/src/gentropy/dataset/l2g_features/distance.py b/src/gentropy/dataset/l2g_features/distance.py new file mode 100644 index 000000000..ea030108c --- /dev/null +++ b/src/gentropy/dataset/l2g_features/distance.py @@ -0,0 +1,422 @@ +"""Collection of methods that extract distance features from the variant index dataset.""" + +from __future__ import annotations + +from typing import TYPE_CHECKING, Any + +import pyspark.sql.functions as f +from pyspark.sql import Window + +from gentropy.common.spark_helpers import convert_from_wide_to_long +from gentropy.dataset.l2g_features.l2g_feature import L2GFeature +from gentropy.dataset.l2g_gold_standard import L2GGoldStandard +from gentropy.dataset.study_locus import StudyLocus +from gentropy.dataset.variant_index import VariantIndex + +if TYPE_CHECKING: + from pyspark.sql import DataFrame + + +def common_distance_feature_logic( + study_loci_to_annotate: StudyLocus | L2GGoldStandard, + *, + variant_index: VariantIndex, + feature_name: str, + distance_type: str, + genomic_window: int = 500_000, +) -> DataFrame: + """Calculate the distance feature that correlates a variant in a credible set with a gene. + + The distance is weighted by the posterior probability of the variant to factor in its contribution to the trait when we look at the average distance score for all variants in the credible set. + + Args: + study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation + variant_index (VariantIndex): The dataset containing distance to gene information + feature_name (str): The name of the feature + distance_type (str): The type of distance to gene + genomic_window (int): The maximum window size to consider + + Returns: + DataFrame: Feature dataset + """ + distances_dataset = variant_index.get_distance_to_gene(distance_type=distance_type) + if "Mean" in feature_name: + # Weighting by the SNP contribution is only applied when we are averaging all distances + distance_score_expr = ( + f.lit(genomic_window) - f.col(distance_type) + f.lit(1) + ) * f.col("posteriorProbability") + agg_expr = f.mean(f.col("distance_score")) + df = study_loci_to_annotate.df.withColumn( + "variantInLocus", f.explode_outer("locus") + ).select( + "studyLocusId", + f.col("variantInLocus.variantId").alias("variantId"), + f.col("variantInLocus.posteriorProbability").alias("posteriorProbability"), + ) + elif "Sentinel" in feature_name: + # For minimum distances we calculate the unweighted distance between the sentinel (lead) and the gene. This + distance_score_expr = f.lit(genomic_window) - f.col(distance_type) + f.lit(1) + agg_expr = f.first(f.col("distance_score")) + df = study_loci_to_annotate.df.select("studyLocusId", "variantId") + return ( + df.join( + distances_dataset.withColumnRenamed("targetId", "geneId"), + on="variantId", + how="inner", + ) + .withColumn("distance_score", f.log10(distance_score_expr)) + .groupBy("studyLocusId", "geneId") + .agg(agg_expr.alias(feature_name)) + ) + + +def common_neighbourhood_distance_feature_logic( + study_loci_to_annotate: StudyLocus | L2GGoldStandard, + *, + variant_index: VariantIndex, + feature_name: str, + distance_type: str, + genomic_window: int = 500_000, +) -> DataFrame: + """Calculate the distance feature that correlates any variant in a credible set with any gene nearby the locus. The distance is weighted by the posterior probability of the variant to factor in its contribution to the trait. + + Args: + study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation + variant_index (VariantIndex): The dataset containing distance to gene information + feature_name (str): The name of the feature + distance_type (str): The type of distance to gene + genomic_window (int): The maximum window size to consider + + Returns: + DataFrame: Feature dataset + """ + local_feature_name = feature_name.replace("Neighbourhood", "") + # First compute mean distances to a gene + local_metric = common_distance_feature_logic( + study_loci_to_annotate, + feature_name=local_feature_name, + distance_type=distance_type, + variant_index=variant_index, + genomic_window=genomic_window, + ) + return ( + # Then compute mean distance in the vicinity (feature will be the same for any gene associated with a studyLocus) + local_metric.withColumn( + "regional_metric", + f.mean(f.col(local_feature_name)).over(Window.partitionBy("studyLocusId")), + ) + .withColumn(feature_name, f.col(local_feature_name) - f.col("regional_metric")) + .drop("regional_metric", local_feature_name) + ) + + +class DistanceTssMeanFeature(L2GFeature): + """Average distance of all tagging variants to gene TSS.""" + + fill_na_value = 500_000 + feature_dependency_type = VariantIndex + feature_name = "distanceTssMean" + + @classmethod + def compute( + cls: type[DistanceTssMeanFeature], + study_loci_to_annotate: StudyLocus | L2GGoldStandard, + feature_dependency: dict[str, Any], + ) -> DistanceTssMeanFeature: + """Computes the feature. + + Args: + study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation + feature_dependency (dict[str, Any]): Dataset that contains the distance information + + Returns: + DistanceTssMeanFeature: Feature dataset + """ + distance_type = "distanceFromTss" + return cls( + _df=convert_from_wide_to_long( + common_distance_feature_logic( + study_loci_to_annotate, + feature_name=cls.feature_name, + distance_type=distance_type, + **feature_dependency, + ), + id_vars=("studyLocusId", "geneId"), + var_name="featureName", + value_name="featureValue", + ), + _schema=cls.get_schema(), + ) + + +class DistanceTssMeanNeighbourhoodFeature(L2GFeature): + """Minimum mean distance to TSS for all genes in the vicinity of a studyLocus.""" + + fill_na_value = 500_000 + feature_dependency_type = VariantIndex + feature_name = "distanceTssMeanNeighbourhood" + + @classmethod + def compute( + cls: type[DistanceTssMeanNeighbourhoodFeature], + study_loci_to_annotate: StudyLocus | L2GGoldStandard, + feature_dependency: dict[str, Any], + ) -> DistanceTssMeanNeighbourhoodFeature: + """Computes the feature. + + Args: + study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation + feature_dependency (dict[str, Any]): Dataset that contains the distance information + + Returns: + DistanceTssMeanNeighbourhoodFeature: Feature dataset + """ + distance_type = "distanceFromTss" + return cls( + _df=convert_from_wide_to_long( + common_neighbourhood_distance_feature_logic( + study_loci_to_annotate, + feature_name=cls.feature_name, + distance_type=distance_type, + **feature_dependency, + ), + id_vars=("studyLocusId", "geneId"), + var_name="featureName", + value_name="featureValue", + ), + _schema=cls.get_schema(), + ) + + +class DistanceSentinelTssFeature(L2GFeature): + """Distance of the sentinel variant to gene TSS. This is not weighted by the causal probability.""" + + fill_na_value = 500_000 + feature_dependency_type = VariantIndex + feature_name = "distanceSentinelTss" + + @classmethod + def compute( + cls: type[DistanceSentinelTssFeature], + study_loci_to_annotate: StudyLocus | L2GGoldStandard, + feature_dependency: dict[str, Any], + ) -> DistanceSentinelTssFeature: + """Computes the feature. + + Args: + study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation + feature_dependency (dict[str, Any]): Dataset that contains the distance information + + Returns: + DistanceSentinelTssFeature: Feature dataset + """ + distance_type = "distanceFromTss" + return cls( + _df=convert_from_wide_to_long( + common_distance_feature_logic( + study_loci_to_annotate, + feature_name=cls.feature_name, + distance_type=distance_type, + **feature_dependency, + ), + id_vars=("studyLocusId", "geneId"), + var_name="featureName", + value_name="featureValue", + ), + _schema=cls.get_schema(), + ) + + +class DistanceSentinelTssNeighbourhoodFeature(L2GFeature): + """Distance between the sentinel variant and a gene TSS as a relation of the distnace with all the genes in the vicinity of a studyLocus. This is not weighted by the causal probability.""" + + fill_na_value = 500_000 + feature_dependency_type = VariantIndex + feature_name = "distanceSentinelTssNeighbourhood" + + @classmethod + def compute( + cls: type[DistanceSentinelTssNeighbourhoodFeature], + study_loci_to_annotate: StudyLocus | L2GGoldStandard, + feature_dependency: dict[str, Any], + ) -> DistanceSentinelTssNeighbourhoodFeature: + """Computes the feature. + + Args: + study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation + feature_dependency (dict[str, Any]): Dataset that contains the distance information + + Returns: + DistanceSentinelTssNeighbourhoodFeature: Feature dataset + """ + distance_type = "distanceFromTss" + return cls( + _df=convert_from_wide_to_long( + common_neighbourhood_distance_feature_logic( + study_loci_to_annotate, + feature_name=cls.feature_name, + distance_type=distance_type, + **feature_dependency, + ), + id_vars=("studyLocusId", "geneId"), + var_name="featureName", + value_name="featureValue", + ), + _schema=cls.get_schema(), + ) + + +class DistanceFootprintMeanFeature(L2GFeature): + """Average distance of all tagging variants to the footprint of a gene.""" + + fill_na_value = 500_000 + feature_dependency_type = VariantIndex + feature_name = "distanceFootprintMean" + + @classmethod + def compute( + cls: type[DistanceFootprintMeanFeature], + study_loci_to_annotate: StudyLocus | L2GGoldStandard, + feature_dependency: dict[str, Any], + ) -> DistanceFootprintMeanFeature: + """Computes the feature. + + Args: + study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation + feature_dependency (dict[str, Any]): Dataset that contains the distance information + + Returns: + DistanceFootprintMeanFeature: Feature dataset + """ + distance_type = "distanceFromFootprint" + return cls( + _df=convert_from_wide_to_long( + common_distance_feature_logic( + study_loci_to_annotate, + feature_name=cls.feature_name, + distance_type=distance_type, + **feature_dependency, + ), + id_vars=("studyLocusId", "geneId"), + var_name="featureName", + value_name="featureValue", + ), + _schema=cls.get_schema(), + ) + + +class DistanceFootprintMeanNeighbourhoodFeature(L2GFeature): + """Minimum mean distance to footprint for all genes in the vicinity of a studyLocus.""" + + fill_na_value = 500_000 + feature_dependency_type = VariantIndex + feature_name = "distanceFootprintMeanNeighbourhood" + + @classmethod + def compute( + cls: type[DistanceFootprintMeanNeighbourhoodFeature], + study_loci_to_annotate: StudyLocus | L2GGoldStandard, + feature_dependency: dict[str, Any], + ) -> DistanceFootprintMeanNeighbourhoodFeature: + """Computes the feature. + + Args: + study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation + feature_dependency (dict[str, Any]): Dataset that contains the distance information + + Returns: + DistanceFootprintMeanNeighbourhoodFeature: Feature dataset + """ + distance_type = "distanceFromFootprint" + return cls( + _df=convert_from_wide_to_long( + common_neighbourhood_distance_feature_logic( + study_loci_to_annotate, + feature_name=cls.feature_name, + distance_type=distance_type, + **feature_dependency, + ), + id_vars=("studyLocusId", "geneId"), + var_name="featureName", + value_name="featureValue", + ), + _schema=cls.get_schema(), + ) + + +class DistanceSentinelFootprintFeature(L2GFeature): + """Distance between the sentinel variant and the footprint of a gene.""" + + fill_na_value = 500_000 + feature_dependency_type = VariantIndex + feature_name = "distanceSentinelFootprintMinimum" + + @classmethod + def compute( + cls: type[DistanceSentinelFootprintFeature], + study_loci_to_annotate: StudyLocus | L2GGoldStandard, + feature_dependency: dict[str, Any], + ) -> DistanceSentinelFootprintFeature: + """Computes the feature. + + Args: + study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation + feature_dependency (dict[str, Any]): Dataset that contains the distance information + + Returns: + DistanceSentinelFootprintFeature: Feature dataset + """ + distance_type = "distanceFromFootprint" + return cls( + _df=convert_from_wide_to_long( + common_distance_feature_logic( + study_loci_to_annotate, + feature_name=cls.feature_name, + distance_type=distance_type, + **feature_dependency, + ), + id_vars=("studyLocusId", "geneId"), + var_name="featureName", + value_name="featureValue", + ), + _schema=cls.get_schema(), + ) + + +class DistanceSentinelFootprintNeighbourhoodFeature(L2GFeature): + """Distance between the sentinel variant and a gene footprint as a relation of the distnace with all the genes in the vicinity of a studyLocus. This is not weighted by the causal probability.""" + + fill_na_value = 500_000 + feature_dependency_type = VariantIndex + feature_name = "DistanceSentinelFootprintNeighbourhoodFeature" + + @classmethod + def compute( + cls: type[DistanceSentinelFootprintNeighbourhoodFeature], + study_loci_to_annotate: StudyLocus | L2GGoldStandard, + feature_dependency: dict[str, Any], + ) -> DistanceSentinelFootprintNeighbourhoodFeature: + """Computes the feature. + + Args: + study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation + feature_dependency (dict[str, Any]): Dataset that contains the distance information + + Returns: + DistanceSentinelFootprintNeighbourhoodFeature: Feature dataset + """ + distance_type = "distanceFromFootprint" + return cls( + _df=convert_from_wide_to_long( + common_neighbourhood_distance_feature_logic( + study_loci_to_annotate, + feature_name=cls.feature_name, + distance_type=distance_type, + **feature_dependency, + ), + id_vars=("studyLocusId", "geneId"), + var_name="featureName", + value_name="featureValue", + ), + _schema=cls.get_schema(), + ) diff --git a/src/gentropy/dataset/l2g_features/l2g_feature.py b/src/gentropy/dataset/l2g_features/l2g_feature.py new file mode 100644 index 000000000..7073ca758 --- /dev/null +++ b/src/gentropy/dataset/l2g_features/l2g_feature.py @@ -0,0 +1,65 @@ +"""L2G Feature Dataset with a collection of methods that extract features from the gentropy datasets to be fed in L2G.""" + +from __future__ import annotations + +from abc import ABC, abstractmethod +from dataclasses import dataclass +from typing import TYPE_CHECKING, Any + +from gentropy.common.schemas import parse_spark_schema +from gentropy.dataset.dataset import Dataset + +if TYPE_CHECKING: + from pyspark.sql.types import StructType + + from gentropy.dataset.l2g_gold_standard import L2GGoldStandard + from gentropy.dataset.study_locus import StudyLocus + + +@dataclass +class L2GFeature(Dataset, ABC): + """Locus-to-gene feature dataset that serves as template to generate each of the features that inform about locus to gene assignments.""" + + def __post_init__( + self: L2GFeature, + feature_dependency_type: Any = None, + credible_set: StudyLocus | None = None, + ) -> None: + """Initializes a L2GFeature dataset. Any child class of L2GFeature must implement the `compute` method. + + Args: + feature_dependency_type (Any): The dependency that the L2GFeature dataset depends on. Defaults to None. + credible_set (StudyLocus | None): The credible set that the L2GFeature dataset is based on. Defaults to None. + """ + super().__post_init__() + self.feature_dependency_type = feature_dependency_type + self.credible_set = credible_set + + @classmethod + def get_schema(cls: type[L2GFeature]) -> StructType: + """Provides the schema for the L2GFeature dataset. + + Returns: + StructType: Schema for the L2GFeature dataset + """ + return parse_spark_schema("l2g_feature.json") + + @classmethod + @abstractmethod + def compute( + cls: type[L2GFeature], + study_loci_to_annotate: StudyLocus | L2GGoldStandard, + feature_dependency: Any, + ) -> L2GFeature: + """Computes the L2GFeature dataset. + + Args: + study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation + feature_dependency (Any): The dependency that the L2GFeature class needs to compute the feature + Returns: + L2GFeature: a L2GFeature dataset + + Raises: + NotImplementedError: This method must be implemented in the child classes + """ + raise NotImplementedError("Must be implemented in the child classes") diff --git a/src/gentropy/dataset/l2g_gold_standard.py b/src/gentropy/dataset/l2g_gold_standard.py index 89f4c5f5d..064f6cc0e 100644 --- a/src/gentropy/dataset/l2g_gold_standard.py +++ b/src/gentropy/dataset/l2g_gold_standard.py @@ -18,7 +18,7 @@ from gentropy.dataset.l2g_feature_matrix import L2GFeatureMatrix from gentropy.dataset.study_locus_overlap import StudyLocusOverlap - from gentropy.dataset.v2g import V2G + from gentropy.dataset.variant_index import VariantIndex @dataclass @@ -33,16 +33,16 @@ class L2GGoldStandard(Dataset): def from_otg_curation( cls: type[L2GGoldStandard], gold_standard_curation: DataFrame, - v2g: V2G, study_locus_overlap: StudyLocusOverlap, + variant_index: VariantIndex, interactions: DataFrame, ) -> L2GGoldStandard: """Initialise L2GGoldStandard from source dataset. Args: gold_standard_curation (DataFrame): Gold standard curation dataframe, extracted from - v2g (V2G): Variant to gene dataset to bring distance between a variant and a gene's TSS study_locus_overlap (StudyLocusOverlap): Study locus overlap dataset to remove duplicated loci + variant_index (VariantIndex): Dataset to bring distance between a variant and a gene's footprint interactions (DataFrame): Gene-gene interactions dataset to remove negative cases where the gene interacts with a positive gene Returns: @@ -55,7 +55,9 @@ def from_otg_curation( interactions_df = cls.process_gene_interactions(interactions) return ( - OpenTargetsL2GGoldStandard.as_l2g_gold_standard(gold_standard_curation, v2g) + OpenTargetsL2GGoldStandard.as_l2g_gold_standard( + gold_standard_curation, variant_index + ) # .filter_unique_associations(study_locus_overlap) .remove_false_negatives(interactions_df) ) diff --git a/src/gentropy/dataset/v2g.py b/src/gentropy/dataset/v2g.py deleted file mode 100644 index 04bad2113..000000000 --- a/src/gentropy/dataset/v2g.py +++ /dev/null @@ -1,51 +0,0 @@ -"""V2G dataset.""" -from __future__ import annotations - -from dataclasses import dataclass -from typing import TYPE_CHECKING - -import pyspark.sql.functions as f - -from gentropy.common.schemas import parse_spark_schema -from gentropy.dataset.dataset import Dataset - -if TYPE_CHECKING: - from pyspark.sql.types import StructType - - from gentropy.dataset.gene_index import GeneIndex - - -@dataclass -class V2G(Dataset): - """Variant-to-gene (V2G) evidence dataset. - - A variant-to-gene (V2G) evidence is understood as any piece of evidence that supports the association of a variant with a likely causal gene. The evidence can sometimes be context-specific and refer to specific `biofeatures` (e.g. cell types) - """ - - @classmethod - def get_schema(cls: type[V2G]) -> StructType: - """Provides the schema for the V2G dataset. - - Returns: - StructType: Schema for the V2G dataset - """ - return parse_spark_schema("v2g.json") - - def filter_by_genes(self: V2G, genes: GeneIndex) -> V2G: - """Filter V2G dataset by genes. - - Args: - genes (GeneIndex): Gene index dataset to filter by - - Returns: - V2G: V2G dataset filtered by genes - """ - self.df = self._df.join(genes.df.select("geneId"), on="geneId", how="inner") - return self - - def extract_distance_tss_minimum(self: V2G) -> None: - """Extract minimum distance to TSS.""" - self.df = self._df.filter(f.col("distance")).withColumn( - "distanceTssMinimum", - f.expr("min(distTss) OVER (PARTITION BY studyLocusId)"), - ) diff --git a/src/gentropy/dataset/variant_index.py b/src/gentropy/dataset/variant_index.py index 2f24cd985..4d53d741a 100644 --- a/src/gentropy/dataset/variant_index.py +++ b/src/gentropy/dataset/variant_index.py @@ -12,18 +12,15 @@ from gentropy.common.spark_helpers import ( get_nested_struct_schema, get_record_with_maximum_value, - normalise_column, rename_all_columns, safe_array_union, ) from gentropy.dataset.dataset import Dataset -from gentropy.dataset.v2g import V2G if TYPE_CHECKING: from pyspark.sql import Column, DataFrame from pyspark.sql.types import StructType - from gentropy.dataset.gene_index import GeneIndex @dataclass @@ -231,165 +228,106 @@ def filter_by_variant(self: VariantIndex, df: DataFrame) -> VariantIndex: _schema=self.schema, ) - def get_transcript_consequence_df( - self: VariantIndex, gene_index: GeneIndex | None = None - ) -> DataFrame: - """Dataframe of exploded transcript consequences. - - Optionally the trancript consequences can be reduced to the universe of a gene index. - - Args: - gene_index (GeneIndex | None): A gene index. Defaults to None. - - Returns: - DataFrame: A dataframe exploded by transcript consequences with the columns variantId, chromosome, transcriptConsequence - """ - # exploding the array removes records without VEP annotation - transript_consequences = self.df.withColumn( - "transcriptConsequence", f.explode("transcriptConsequences") - ).select( - "variantId", - "chromosome", - "position", - "transcriptConsequence", - f.col("transcriptConsequence.targetId").alias("geneId"), - ) - if gene_index: - transript_consequences = transript_consequences.join( - f.broadcast(gene_index.df), - on=["chromosome", "geneId"], - ) - return transript_consequences - - def get_distance_to_tss( + def get_distance_to_gene( self: VariantIndex, - gene_index: GeneIndex, + *, + distance_type: str = "distanceFromTss", max_distance: int = 500_000, - ) -> V2G: - """Extracts variant to gene assignments for variants falling within a window of a gene's TSS. + ) -> DataFrame: + """Extracts variant to gene assignments for variants falling within a window of a gene's TSS or footprint. Args: - gene_index (GeneIndex): A gene index to filter by. - max_distance (int): The maximum distance from the TSS to consider. Defaults to 500_000. + distance_type (str): The type of distance to use. Can be "distanceFromTss" or "distanceFromFootprint". Defaults to "distanceFromTss". + max_distance (int): The maximum distance to consider. Defaults to 500_000, the default window size for VEP. Returns: - V2G: variant to gene assignments with their distance to the TSS - """ - return V2G( - _df=( - self.df.alias("variant") - .join( - f.broadcast(gene_index.locations_lut()).alias("gene"), - on=[ - f.col("variant.chromosome") == f.col("gene.chromosome"), - f.abs(f.col("variant.position") - f.col("gene.tss")) - <= max_distance, - ], - how="inner", - ) - .withColumn( - "distance", f.abs(f.col("variant.position") - f.col("gene.tss")) - ) - .withColumn( - "inverse_distance", - max_distance - f.col("distance"), - ) - .transform(lambda df: normalise_column(df, "inverse_distance", "score")) - .select( - "variantId", - f.col("variant.chromosome").alias("chromosome"), - "distance", - "geneId", - "score", - f.lit("distance").alias("datatypeId"), - f.lit("canonical_tss").alias("datasourceId"), - ) - ), - _schema=V2G.get_schema(), - ) + DataFrame: A dataframe with the distance between a variant and a gene's TSS or footprint. - def get_plof_v2g(self: VariantIndex, gene_index: GeneIndex) -> V2G: - """Creates a dataset with variant to gene assignments with a flag indicating if the variant is predicted to be a loss-of-function variant by the LOFTEE algorithm. + Raises: + ValueError: Invalid distance type. + """ + if distance_type not in {"distanceFromTss", "distanceFromFootprint"}: + raise ValueError( + f"Invalid distance_type: {distance_type}. Must be 'distanceFromTss' or 'distanceFromFootprint'." + ) + df = self.df.select( + "variantId", f.explode("transcriptConsequences").alias("tc") + ).select("variantId", "tc.targetId", f"tc.{distance_type}") + if max_distance == 500_000: + return df + elif max_distance < 500_000: + return df.filter(f"{distance_type} <= {max_distance}") + else: + raise ValueError( + f"max_distance must be less than 500_000. Got {max_distance}." + ) - Optionally the trancript consequences can be reduced to the universe of a gene index. + def get_loftee(self: VariantIndex) -> DataFrame: + """Returns a dataframe with a flag indicating whether a variant is predicted to cause loss of function in a gene. The source of this information is the LOFTEE algorithm (https://github.com/konradjk/loftee). - Args: - gene_index (GeneIndex): A gene index to filter by. + !!! note, "This will return a filtered dataframe with only variants that have been annotated by LOFTEE." Returns: - V2G: variant to gene assignments from the LOFTEE algorithm + DataFrame: variant to gene assignments from the LOFTEE algorithm """ - return V2G( - _df=( - self.get_transcript_consequence_df(gene_index) - .filter(f.col("transcriptConsequence.lofteePrediction").isNotNull()) - .withColumn( - "isHighQualityPlof", - f.when( - f.col("transcriptConsequence.lofteePrediction") == "HC", True - ).when( - f.col("transcriptConsequence.lofteePrediction") == "LC", False - ), - ) - .withColumn( - "score", - f.when(f.col("isHighQualityPlof"), 1.0).when( - ~f.col("isHighQualityPlof"), 0 - ), - ) - .select( - "variantId", - "chromosome", - "geneId", - "isHighQualityPlof", - f.col("score"), - f.lit("vep").alias("datatypeId"), - f.lit("loftee").alias("datasourceId"), - ) - ), - _schema=V2G.get_schema(), + return ( + self.df.select("variantId", f.explode("transcriptConsequences").alias("tc")) + .filter(f.col("tc.lofteePrediction").isNotNull()) + .withColumn( + "isHighQualityPlof", + f.when(f.col("tc.lofteePrediction") == "HC", True).when( + f.col("tc.lofteePrediction") == "LC", False + ), + ) + .select( + "variantId", + f.col("tc.targetId"), + f.col("tc.lofteePrediction"), + "isHighQualityPlof", + ) ) - def get_most_severe_transcript_consequence( + def get_most_severe_gene_consequence( self: VariantIndex, + *, vep_consequences: DataFrame, - gene_index: GeneIndex, - ) -> V2G: - """Creates a dataset with variant to gene assignments based on VEP's predicted consequence of the transcript. - - Optionally the trancript consequences can be reduced to the universe of a gene index. + ) -> DataFrame: + """Returns a dataframe with the most severe consequence for a variant/gene pair. Args: vep_consequences (DataFrame): A dataframe of VEP consequences - gene_index (GeneIndex): A gene index to filter by. Defaults to None. Returns: - V2G: High and medium severity variant to gene assignments + DataFrame: A dataframe with the most severe consequence (plus a severity score) for a variant/gene pair """ - return V2G( - _df=self.get_transcript_consequence_df(gene_index) + return ( + self.df.select("variantId", f.explode("transcriptConsequences").alias("tc")) .select( "variantId", - "chromosome", - f.col("transcriptConsequence.targetId").alias("geneId"), - f.explode( - "transcriptConsequence.variantFunctionalConsequenceIds" - ).alias("variantFunctionalConsequenceId"), - f.lit("vep").alias("datatypeId"), - f.lit("variantConsequence").alias("datasourceId"), + f.col("tc.targetId"), + f.explode(f.col("tc.variantFunctionalConsequenceIds")).alias( + "variantFunctionalConsequenceId" + ), ) .join( - f.broadcast(vep_consequences), + # TODO: make this table a project config + f.broadcast( + vep_consequences.selectExpr( + "variantFunctionalConsequenceId", "score as severityScore" + ) + ), on="variantFunctionalConsequenceId", how="inner", ) - .drop("label") - .filter(f.col("score") != 0) - # A variant can have multiple predicted consequences on a transcript, the most severe one is selected + .filter(f.col("severityScore").isNull()) .transform( + # A variant can have multiple predicted consequences on a transcript, the most severe one is selected lambda df: get_record_with_maximum_value( - df, ["variantId", "geneId"], "score" + df, ["variantId", "targetId"], "severityScore" ) - ), - _schema=V2G.get_schema(), + ) + .withColumnRenamed( + "variantFunctionalConsequenceId", + "mostSevereVariantFunctionalConsequenceId", + ) ) diff --git a/src/gentropy/datasource/ensembl/vep_parser.py b/src/gentropy/datasource/ensembl/vep_parser.py index d84b58407..e3e36140d 100644 --- a/src/gentropy/datasource/ensembl/vep_parser.py +++ b/src/gentropy/datasource/ensembl/vep_parser.py @@ -3,7 +3,7 @@ from __future__ import annotations import importlib.resources as pkg_resources -from typing import TYPE_CHECKING, List +from typing import TYPE_CHECKING import pandas as pd from pyspark.sql import SparkSession @@ -529,14 +529,14 @@ def _collect_uniprot_accessions(trembl: Column, swissprot: Column) -> Column: ) @staticmethod - def _parse_variant_location_id(vep_input_field: Column) -> List[Column]: + def _parse_variant_location_id(vep_input_field: Column) -> list[Column]: r"""Parse variant identifier, chromosome, position, reference allele and alternate allele from VEP input field. Args: vep_input_field (Column): Column containing variant vcf string used as VEP input. Returns: - List[Column]: List of columns containing chromosome, position, reference allele and alternate allele. + list[Column]: List of columns containing chromosome, position, reference allele and alternate allele. """ variant_fields = f.split(vep_input_field, r"\t") return [ diff --git a/src/gentropy/datasource/open_targets/l2g_gold_standard.py b/src/gentropy/datasource/open_targets/l2g_gold_standard.py index 26d5a0253..21edcc201 100644 --- a/src/gentropy/datasource/open_targets/l2g_gold_standard.py +++ b/src/gentropy/datasource/open_targets/l2g_gold_standard.py @@ -9,7 +9,7 @@ from gentropy.dataset.l2g_gold_standard import L2GGoldStandard from gentropy.dataset.study_locus import StudyLocus -from gentropy.dataset.v2g import V2G +from gentropy.dataset.variant_index import VariantIndex class OpenTargetsL2GGoldStandard: @@ -60,7 +60,9 @@ def parse_positive_curation( @classmethod def expand_gold_standard_with_negatives( - cls: Type[OpenTargetsL2GGoldStandard], positive_set: DataFrame, v2g: V2G + cls: Type[OpenTargetsL2GGoldStandard], + positive_set: DataFrame, + variant_index: VariantIndex, ) -> DataFrame: """Create full set of positive and negative evidence of locus to gene associations. @@ -68,7 +70,7 @@ def expand_gold_standard_with_negatives( Args: positive_set (DataFrame): Positive set from curation - v2g (V2G): Variant to gene dataset to bring distance between a variant and a gene's TSS + variant_index (VariantIndex): Variant index to get distance to gene Returns: DataFrame: Full set of positive and negative evidence of locus to gene associations @@ -76,9 +78,13 @@ def expand_gold_standard_with_negatives( return ( positive_set.withColumnRenamed("geneId", "curated_geneId") .join( - v2g.df.selectExpr( - "variantId", "geneId as non_curated_geneId", "distance" - ).filter(f.col("distance") <= cls.LOCUS_TO_GENE_WINDOW), + variant_index.get_distance_to_gene() + .selectExpr( + "variantId", + "targetId as non_curated_geneId", + "distanceFromTss", + ) + .filter(f.col("distanceFromTss") <= cls.LOCUS_TO_GENE_WINDOW), on="variantId", how="left", ) @@ -86,7 +92,7 @@ def expand_gold_standard_with_negatives( "goldStandardSet", f.when( (f.col("curated_geneId") == f.col("non_curated_geneId")) - # to keep the positives that are outside the v2g dataset + # to keep the positives that are not part of the variant index | (f.col("non_curated_geneId").isNull()), f.lit(L2GGoldStandard.GS_POSITIVE_LABEL), ).otherwise(L2GGoldStandard.GS_NEGATIVE_LABEL), @@ -98,27 +104,27 @@ def expand_gold_standard_with_negatives( f.col("curated_geneId"), ).otherwise(f.col("non_curated_geneId")), ) - .drop("distance", "curated_geneId", "non_curated_geneId") + .drop("distanceFromTss", "curated_geneId", "non_curated_geneId") ) @classmethod def as_l2g_gold_standard( cls: type[OpenTargetsL2GGoldStandard], gold_standard_curation: DataFrame, - v2g: V2G, + variant_index: VariantIndex, ) -> L2GGoldStandard: """Initialise L2GGoldStandard from source dataset. Args: gold_standard_curation (DataFrame): Gold standard curation dataframe, extracted from https://github.com/opentargets/genetics-gold-standards - v2g (V2G): Variant to gene dataset to bring distance between a variant and a gene's TSS + variant_index (VariantIndex): Dataset to bring distance between a variant and a gene's footprint Returns: L2GGoldStandard: L2G Gold Standard dataset. False negatives have not yet been removed. """ return L2GGoldStandard( _df=cls.parse_positive_curation(gold_standard_curation).transform( - cls.expand_gold_standard_with_negatives, v2g + cls.expand_gold_standard_with_negatives, variant_index ), _schema=L2GGoldStandard.get_schema(), ) diff --git a/src/gentropy/l2g.py b/src/gentropy/l2g.py index ff8c6c8ff..9b9b7aa90 100644 --- a/src/gentropy/l2g.py +++ b/src/gentropy/l2g.py @@ -17,7 +17,7 @@ from gentropy.dataset.l2g_prediction import L2GPrediction from gentropy.dataset.study_index import StudyIndex from gentropy.dataset.study_locus import StudyLocus -from gentropy.dataset.v2g import V2G +from gentropy.dataset.variant_index import VariantIndex from gentropy.method.l2g.feature_factory import L2GFeatureInputLoader from gentropy.method.l2g.model import LocusToGeneModel from gentropy.method.l2g.trainer import LocusToGeneTrainer @@ -38,7 +38,7 @@ def __init__( model_path: str | None = None, credible_set_path: str, gold_standard_curation_path: str | None = None, - variant_gene_path: str | None = None, + variant_index_path: str | None = None, colocalisation_path: str | None = None, study_index_path: str | None = None, gene_interactions_path: str | None = None, @@ -59,7 +59,7 @@ def __init__( model_path (str | None): Path to the model. It can be either in the filesystem or the name on the Hugging Face Hub (in the form of username/repo_name). credible_set_path (str): Path to the credible set dataset necessary to build the feature matrix gold_standard_curation_path (str | None): Path to the gold standard curation file - variant_gene_path (str | None): Path to the variant-gene dataset + variant_index_path (str | None): Path to the variant index dataset colocalisation_path (str | None): Path to the colocalisation dataset study_index_path (str | None): Path to the study index dataset gene_interactions_path (str | None): Path to the gene interactions dataset @@ -96,8 +96,10 @@ def __init__( if study_index_path else None ) - self.v2g = ( - V2G.from_parquet(session, variant_gene_path) if variant_gene_path else None + self.variant_index = ( + VariantIndex.from_parquet(session, variant_index_path) + if variant_index_path + else None ) self.coloc = ( Colocalisation.from_parquet( @@ -107,7 +109,7 @@ def __init__( else None ) self.features_input_loader = L2GFeatureInputLoader( - v2g=self.v2g, + variant_index=self.variant_index, coloc=self.coloc, studies=self.studies, study_locus=self.credible_set, @@ -134,7 +136,7 @@ def run_predict(self) -> None: Raises: ValueError: If not all dependencies in prediction mode are set """ - if self.studies and self.v2g and self.coloc: + if self.studies and self.coloc: predictions = L2GPrediction.from_credible_set( self.session, self.credible_set, @@ -157,9 +159,9 @@ def run_train(self) -> None: if ( self.gs_curation and self.interactions - and self.v2g and self.wandb_run_name and self.model_path + and self.variant_index ): wandb_key = access_gcp_secret("wandb-key", "open-targets-genetics-dev") # Process gold standard and L2G features @@ -203,25 +205,30 @@ def _generate_feature_matrix(self, write_feature_matrix: bool) -> L2GFeatureMatr Raises: ValueError: If write_feature_matrix is set to True but a path is not provided or if dependencies to build features are not set. """ - if self.gs_curation and self.interactions and self.v2g: + if ( + self.gs_curation + and self.interactions + and self.studies + and self.variant_index + ): study_locus_overlap = StudyLocus( _df=self.credible_set.df.join( f.broadcast( - self.gs_curation - .withColumn( + self.gs_curation.withColumn( "variantId", f.concat_ws( - "_", - f.col("sentinel_variant.locus_GRCh38.chromosome"), - f.col("sentinel_variant.locus_GRCh38.position"), - f.col("sentinel_variant.alleles.reference"), - f.col("sentinel_variant.alleles.alternative"), - ) - ) - .select( + "_", + f.col("sentinel_variant.locus_GRCh38.chromosome"), + f.col("sentinel_variant.locus_GRCh38.position"), + f.col("sentinel_variant.alleles.reference"), + f.col("sentinel_variant.alleles.alternative"), + ), + ).select( StudyLocus.assign_study_locus_id( - ["association_info.otg_id", # studyId - "variantId"] + [ + "association_info.otg_id", # studyId + "variantId", + ] ), ) ), @@ -233,7 +240,7 @@ def _generate_feature_matrix(self, write_feature_matrix: bool) -> L2GFeatureMatr gold_standards = L2GGoldStandard.from_otg_curation( gold_standard_curation=self.gs_curation, - v2g=self.v2g, + variant_index=self.variant_index, study_locus_overlap=study_locus_overlap, interactions=self.interactions, ) diff --git a/src/gentropy/method/l2g/feature_factory.py b/src/gentropy/method/l2g/feature_factory.py index c0f0ef9b4..41084277f 100644 --- a/src/gentropy/method/l2g/feature_factory.py +++ b/src/gentropy/method/l2g/feature_factory.py @@ -4,17 +4,35 @@ from typing import Any, Iterator, Mapping -from gentropy.dataset.l2g_feature import ( +from gentropy.dataset.l2g_features.colocalisation import ( EQtlColocClppMaximumFeature, + EQtlColocClppMaximumNeighbourhoodFeature, EQtlColocH4MaximumFeature, - L2GFeature, + EQtlColocH4MaximumNeighbourhoodFeature, PQtlColocClppMaximumFeature, + PQtlColocClppMaximumNeighbourhoodFeature, PQtlColocH4MaximumFeature, + PQtlColocH4MaximumNeighbourhoodFeature, SQtlColocClppMaximumFeature, + SQtlColocClppMaximumNeighbourhoodFeature, SQtlColocH4MaximumFeature, + SQtlColocH4MaximumNeighbourhoodFeature, TuQtlColocClppMaximumFeature, + TuQtlColocClppMaximumNeighbourhoodFeature, TuQtlColocH4MaximumFeature, + TuQtlColocH4MaximumNeighbourhoodFeature, ) +from gentropy.dataset.l2g_features.distance import ( + DistanceFootprintMeanFeature, + DistanceFootprintMeanNeighbourhoodFeature, + DistanceSentinelFootprintFeature, + DistanceSentinelFootprintNeighbourhoodFeature, + DistanceSentinelTssFeature, + DistanceSentinelTssNeighbourhoodFeature, + DistanceTssMeanFeature, + DistanceTssMeanNeighbourhoodFeature, +) +from gentropy.dataset.l2g_features.l2g_feature import L2GFeature from gentropy.dataset.l2g_gold_standard import L2GGoldStandard from gentropy.dataset.study_locus import StudyLocus @@ -75,16 +93,30 @@ class FeatureFactory: """Factory class for creating features.""" feature_mapper: Mapping[str, type[L2GFeature]] = { - # "distanceTssMinimum": DistanceTssMinimumFeature, - # "distanceTssMean": DistanceTssMeanFeature, + "distanceSentinelTss": DistanceSentinelTssFeature, + "distanceSentinelTssNeighbourhood": DistanceSentinelTssNeighbourhoodFeature, + "distanceSentinelFootprint": DistanceSentinelFootprintFeature, + "distanceSentinelFootprintNeighbourhood": DistanceSentinelFootprintNeighbourhoodFeature, + "distanceTssMean": DistanceTssMeanFeature, + "distanceTssMeanNeighbourhood": DistanceTssMeanNeighbourhoodFeature, + "distanceFootprintMean": DistanceFootprintMeanFeature, + "distanceFootprintMeanNeighbourhood": DistanceFootprintMeanNeighbourhoodFeature, "eQtlColocClppMaximum": EQtlColocClppMaximumFeature, + "eQtlColocClppMaximumNeighbourhood": EQtlColocClppMaximumNeighbourhoodFeature, "pQtlColocClppMaximum": PQtlColocClppMaximumFeature, + "pQtlColocClppMaximumNeighbourhood": PQtlColocClppMaximumNeighbourhoodFeature, "sQtlColocClppMaximum": SQtlColocClppMaximumFeature, + "sQtlColocClppMaximumNeighbourhood": SQtlColocClppMaximumNeighbourhoodFeature, "tuQtlColocClppMaximum": TuQtlColocClppMaximumFeature, + "tuQtlColocClppMaximumNeighbourhood": TuQtlColocClppMaximumNeighbourhoodFeature, "eQtlColocH4Maximum": EQtlColocH4MaximumFeature, + "eQtlColocH4MaximumNeighbourhood": EQtlColocH4MaximumNeighbourhoodFeature, "pQtlColocH4Maximum": PQtlColocH4MaximumFeature, + "pQtlColocH4MaximumNeighbourhood": PQtlColocH4MaximumNeighbourhoodFeature, "sQtlColocH4Maximum": SQtlColocH4MaximumFeature, + "sQtlColocH4MaximumNeighbourhood": SQtlColocH4MaximumNeighbourhoodFeature, "tuQtlColocH4Maximum": TuQtlColocH4MaximumFeature, + "tuQtlColocH4MaximumNeighbourhood": TuQtlColocH4MaximumNeighbourhoodFeature, } def __init__( diff --git a/src/gentropy/variant_to_gene.py b/src/gentropy/variant_to_gene.py deleted file mode 100644 index cf21053d7..000000000 --- a/src/gentropy/variant_to_gene.py +++ /dev/null @@ -1,119 +0,0 @@ -"""Step to generate variant annotation dataset.""" - -from __future__ import annotations - -from functools import reduce - -from pyspark.sql import functions as f - -from gentropy.common.Liftover import LiftOverSpark -from gentropy.common.session import Session -from gentropy.dataset.gene_index import GeneIndex -from gentropy.dataset.intervals import Intervals -from gentropy.dataset.v2g import V2G -from gentropy.dataset.variant_index import VariantIndex - - -class V2GStep: - """Variant-to-gene (V2G) step. - - This step aims to generate a dataset that contains multiple pieces of evidence supporting the functional association of specific variants with genes. Some of the evidence types include: - - 1. Chromatin interaction experiments, e.g. Promoter Capture Hi-C (PCHi-C). - 2. In silico functional predictions, e.g. Variant Effect Predictor (VEP) from Ensembl. - 3. Distance between the variant and each gene's canonical transcription start site (TSS). - - Attributes: - session (Session): Session object. - variant_index_path (str): Input variant index path. - gene_index_path (str): Input gene index path. - vep_consequences_path (str): Input VEP consequences path. - liftover_chain_file_path (str): Path to GRCh37 to GRCh38 chain file. - liftover_max_length_difference: Maximum length difference for liftover. - max_distance (int): Maximum distance to consider. - approved_biotypes (list[str]): List of approved biotypes. - intervals (dict): Dictionary of interval sources. - v2g_path (str): Output V2G path. - """ - - def __init__( - self, - session: Session, - variant_index_path: str, - gene_index_path: str, - vep_consequences_path: str, - liftover_chain_file_path: str, - approved_biotypes: list[str], - interval_sources: dict[str, str], - v2g_path: str, - max_distance: int = 500_000, - liftover_max_length_difference: int = 100, - ) -> None: - """Run Variant-to-gene (V2G) step. - - Args: - session (Session): Session object. - variant_index_path (str): Input variant index path. - gene_index_path (str): Input gene index path. - vep_consequences_path (str): Input VEP consequences path. - liftover_chain_file_path (str): Path to GRCh37 to GRCh38 chain file. - approved_biotypes (list[str]): List of approved biotypes. - interval_sources (dict[str, str]): Dictionary of interval sources. - v2g_path (str): Output V2G path. - max_distance (int): Maximum distance to consider. - liftover_max_length_difference (int): Maximum length difference for liftover. - """ - # Read - gene_index = GeneIndex.from_parquet(session, gene_index_path) - vi = VariantIndex.from_parquet(session, variant_index_path).persist() - # Reading VEP consequence to score table and cast the score to the right type: - vep_consequences = session.spark.read.csv( - vep_consequences_path, sep="\t", header=True - ).withColumn("score", f.col("score").cast("double")) - - # Transform - lift = LiftOverSpark( - # lift over variants to hg38 - liftover_chain_file_path, - liftover_max_length_difference, - ) - gene_index_filtered = gene_index.filter_by_biotypes( - # Filter gene index by approved biotypes to define V2G gene universe - list(approved_biotypes) - ) - - intervals = Intervals( - _df=reduce( - lambda x, y: x.unionByName(y, allowMissingColumns=True), - # create interval instances by parsing each source - [ - Intervals.from_source( - session.spark, source_name, source_path, gene_index, lift - ).df - for source_name, source_path in interval_sources.items() - ], - ), - _schema=Intervals.get_schema(), - ) - v2g_datasets = [ - vi.get_distance_to_tss(gene_index_filtered, max_distance), - vi.get_most_severe_transcript_consequence( - vep_consequences, gene_index_filtered - ), - vi.get_plof_v2g(gene_index_filtered), - intervals.v2g(vi), - ] - v2g = V2G( - _df=reduce( - lambda x, y: x.unionByName(y, allowMissingColumns=True), - [dataset.df for dataset in v2g_datasets], - ).repartition("chromosome"), - _schema=V2G.get_schema(), - ) - - # Load - ( - v2g.df.write.partitionBy("chromosome") - .mode(session.write_mode) - .parquet(v2g_path) - ) diff --git a/tests/gentropy/conftest.py b/tests/gentropy/conftest.py index 21f05dcf3..a70c1a87d 100644 --- a/tests/gentropy/conftest.py +++ b/tests/gentropy/conftest.py @@ -25,7 +25,6 @@ from gentropy.dataset.study_locus import StudyLocus from gentropy.dataset.study_locus_overlap import StudyLocusOverlap from gentropy.dataset.summary_statistics import SummaryStatistics -from gentropy.dataset.v2g import V2G from gentropy.dataset.variant_index import VariantIndex from gentropy.datasource.eqtl_catalogue.finemapping import EqtlCatalogueFinemapping from gentropy.datasource.eqtl_catalogue.study_index import EqtlCatalogueStudyIndex @@ -252,29 +251,17 @@ def mock_intervals(spark: SparkSession) -> Intervals: @pytest.fixture() -def mock_v2g(spark: SparkSession) -> V2G: - """Mock v2g dataset.""" - v2g_schema = V2G.get_schema() - - data_spec = ( - dg.DataGenerator( - spark, - rows=400, - partitions=4, - randomSeedMethod="hash_fieldname", - ) - .withSchema(v2g_schema) - .withColumnSpec("distance", percentNulls=0.1) - .withColumnSpec("resourceScore", percentNulls=0.1) - .withColumnSpec("score", percentNulls=0.1) - .withColumnSpec("pmid", percentNulls=0.1) - .withColumnSpec("biofeature", percentNulls=0.1) - .withColumnSpec("variantFunctionalConsequenceId", percentNulls=0.1) - .withColumnSpec("isHighQualityPlof", percentNulls=0.1) +def mock_variant_consequence_to_score(spark: SparkSession) -> DataFrame: + """Slice of the VEP consequence to score table.""" + return spark.createDataFrame( + [ + ("SO_0001893", "transcript_ablation", 1.0), + ("SO_0001822", "inframe_deletion", 0.66), + ("SO_0001567", "stop_retained_variant", 0.33), + ], + ["variantFunctionalConsequenceId", "label", "score"], ) - return V2G(_df=data_spec.build(), _schema=v2g_schema) - @pytest.fixture() def mock_variant_index(spark: SparkSession) -> VariantIndex: @@ -386,9 +373,9 @@ def mock_summary_statistics_data(spark: SparkSession) -> DataFrame: # Allowing missingness: .withColumnSpec("standardError", percentNulls=0.1) # Making sure p-values are below 1: - ).build() + ) - return data_spec + return data_spec.build() @pytest.fixture() @@ -620,7 +607,7 @@ def mock_l2g_feature_matrix(spark: SparkSession) -> L2GFeatureMatrix: ("1", "gene1", 100.0, None), ("2", "gene2", 1000.0, 0.0), ], - "studyLocusId STRING, geneId STRING, distanceTssMean FLOAT, distanceTssMinimum FLOAT", + "studyLocusId STRING, geneId STRING, distanceTssMean FLOAT, distanceSentinelTssMinimum FLOAT", ), with_gold_standard=False, ) diff --git a/tests/gentropy/dataset/test_intervals.py b/tests/gentropy/dataset/test_intervals.py deleted file mode 100644 index 26d79acd1..000000000 --- a/tests/gentropy/dataset/test_intervals.py +++ /dev/null @@ -1,18 +0,0 @@ -"""Tests on LD index.""" - -from __future__ import annotations - -from typing import TYPE_CHECKING - -from gentropy.dataset.v2g import V2G - -if TYPE_CHECKING: - from gentropy.dataset.intervals import Intervals - from gentropy.dataset.variant_index import VariantIndex - - -def test_interval_v2g_creation( - mock_intervals: Intervals, mock_variant_index: VariantIndex -) -> None: - """Test creation of V2G from intervals.""" - assert isinstance(mock_intervals.v2g(mock_variant_index), V2G) diff --git a/tests/gentropy/dataset/test_l2g.py b/tests/gentropy/dataset/test_l2g.py index 125352f8e..f73b6f7c2 100644 --- a/tests/gentropy/dataset/test_l2g.py +++ b/tests/gentropy/dataset/test_l2g.py @@ -177,7 +177,7 @@ def test_calculate_feature_missingness_rate( spark: SparkSession, mock_l2g_feature_matrix: L2GFeatureMatrix ) -> None: """Test L2GFeatureMatrix.calculate_feature_missingness_rate.""" - expected_missingness = {"distanceTssMean": 0.0, "distanceTssMinimum": 1.0} + expected_missingness = {"distanceTssMean": 0.0, "distanceSentinelTssMinimum": 1.0} observed_missingness = mock_l2g_feature_matrix.calculate_feature_missingness_rate() assert isinstance(observed_missingness, dict) assert mock_l2g_feature_matrix.features_list is not None and len( diff --git a/tests/gentropy/dataset/test_l2g_feature.py b/tests/gentropy/dataset/test_l2g_feature.py index 82df2dd4f..18d8a4066 100644 --- a/tests/gentropy/dataset/test_l2g_feature.py +++ b/tests/gentropy/dataset/test_l2g_feature.py @@ -1,28 +1,62 @@ -"""Test L2G feature generation.""" +"""Test locus-to-gene feature generation.""" from __future__ import annotations from typing import TYPE_CHECKING, Any +import pyspark.sql.functions as f import pytest +from pyspark.sql.types import ( + ArrayType, + BooleanType, + IntegerType, + LongType, + StringType, + StructField, + StructType, +) -from gentropy.dataset.l2g_feature import ( +from gentropy.dataset.colocalisation import Colocalisation +from gentropy.dataset.l2g_features.colocalisation import ( EQtlColocClppMaximumFeature, + EQtlColocClppMaximumNeighbourhoodFeature, EQtlColocH4MaximumFeature, - L2GFeature, + EQtlColocH4MaximumNeighbourhoodFeature, PQtlColocClppMaximumFeature, + PQtlColocClppMaximumNeighbourhoodFeature, PQtlColocH4MaximumFeature, + PQtlColocH4MaximumNeighbourhoodFeature, SQtlColocClppMaximumFeature, + SQtlColocClppMaximumNeighbourhoodFeature, SQtlColocH4MaximumFeature, + SQtlColocH4MaximumNeighbourhoodFeature, TuQtlColocClppMaximumFeature, + TuQtlColocClppMaximumNeighbourhoodFeature, TuQtlColocH4MaximumFeature, + TuQtlColocH4MaximumNeighbourhoodFeature, + common_colocalisation_feature_logic, + common_neighbourhood_colocalisation_feature_logic, +) +from gentropy.dataset.l2g_features.distance import ( + DistanceFootprintMeanFeature, + DistanceFootprintMeanNeighbourhoodFeature, + DistanceSentinelFootprintFeature, + DistanceSentinelFootprintNeighbourhoodFeature, + DistanceSentinelTssFeature, + DistanceSentinelTssNeighbourhoodFeature, + DistanceTssMeanFeature, + DistanceTssMeanNeighbourhoodFeature, + common_distance_feature_logic, + common_neighbourhood_distance_feature_logic, ) +from gentropy.dataset.l2g_features.l2g_feature import L2GFeature +from gentropy.dataset.study_index import StudyIndex +from gentropy.dataset.study_locus import StudyLocus +from gentropy.dataset.variant_index import VariantIndex from gentropy.method.l2g.feature_factory import L2GFeatureInputLoader if TYPE_CHECKING: - from gentropy.dataset.colocalisation import Colocalisation - from gentropy.dataset.study_index import StudyIndex - from gentropy.dataset.study_locus import StudyLocus + from pyspark.sql import SparkSession @pytest.mark.parametrize( @@ -36,6 +70,22 @@ PQtlColocClppMaximumFeature, SQtlColocClppMaximumFeature, TuQtlColocClppMaximumFeature, + EQtlColocClppMaximumNeighbourhoodFeature, + PQtlColocClppMaximumNeighbourhoodFeature, + SQtlColocClppMaximumNeighbourhoodFeature, + TuQtlColocClppMaximumNeighbourhoodFeature, + EQtlColocH4MaximumNeighbourhoodFeature, + PQtlColocH4MaximumNeighbourhoodFeature, + SQtlColocH4MaximumNeighbourhoodFeature, + TuQtlColocH4MaximumNeighbourhoodFeature, + DistanceTssMeanFeature, + DistanceTssMeanNeighbourhoodFeature, + DistanceFootprintMeanFeature, + DistanceFootprintMeanNeighbourhoodFeature, + DistanceSentinelTssFeature, + DistanceSentinelTssNeighbourhoodFeature, + DistanceSentinelFootprintFeature, + DistanceSentinelFootprintNeighbourhoodFeature, ], ) def test_feature_factory_return_type( @@ -43,11 +93,13 @@ def test_feature_factory_return_type( mock_study_locus: StudyLocus, mock_colocalisation: Colocalisation, mock_study_index: StudyIndex, + mock_variant_index: VariantIndex, ) -> None: """Test that every feature factory returns a L2GFeature dataset.""" loader = L2GFeatureInputLoader( colocalisation=mock_colocalisation, study_index=mock_study_index, + variant_index=mock_variant_index, study_locus=mock_study_locus, ) feature_dataset = feature_class.compute( @@ -57,3 +109,380 @@ def test_feature_factory_return_type( ), ) assert isinstance(feature_dataset, L2GFeature) + + +class TestCommonColocalisationFeatureLogic: + """Test the common logic of the colocalisation features.""" + + def test__common_colocalisation_feature_logic( + self: TestCommonColocalisationFeatureLogic, + spark: SparkSession, + ) -> None: + """Test the common logic of the colocalisation features. + + The test data associates studyLocusId1 with gene1 based on the colocalisation with studyLocusId2 and studyLocusId3. + The H4 value of number 2 is higher, therefore the feature value should be based on that. + """ + feature_name = "eQtlColocH4Maximum" + observed_df = common_colocalisation_feature_logic( + self.sample_study_loci_to_annotate, + self.colocalisation_method, + self.colocalisation_metric, + feature_name, + self.qtl_type, + colocalisation=self.sample_colocalisation, + study_index=self.sample_studies, + study_locus=self.sample_study_locus, + ) + expected_df = spark.createDataFrame( + [ + { + "studyLocusId": "1", + "geneId": "gene1", + "eQtlColocH4Maximum": 0.81, + }, + { + "studyLocusId": "1", + "geneId": "gene2", + "eQtlColocH4Maximum": 0.9, + }, + ], + ).select("studyLocusId", "geneId", "eQtlColocH4Maximum") + assert ( + observed_df.collect() == expected_df.collect() + ), "The feature values are not as expected." + + def test__common_neighbourhood_colocalisation_feature_logic( + self: TestCommonColocalisationFeatureLogic, spark: SparkSession + ) -> None: + """Test the common logic of the neighbourhood colocalisation features.""" + feature_name = "eQtlColocH4MaximumNeighbourhood" + observed_df = common_neighbourhood_colocalisation_feature_logic( + self.sample_study_loci_to_annotate, + self.colocalisation_method, + self.colocalisation_metric, + feature_name, + self.qtl_type, + colocalisation=self.sample_colocalisation, + study_index=self.sample_studies, + study_locus=self.sample_study_locus, + ) + expected_df = spark.createDataFrame( + [ + { + "studyLocusId": "1", + "geneId": "gene1", + "eQtlColocH4MaximumNeighbourhood": 0.08999999999999997, + }, + { + "studyLocusId": "1", + "geneId": "gene2", + "eQtlColocH4MaximumNeighbourhood": 0.0, + }, + ], + ).select("studyLocusId", "geneId", "eQtlColocH4MaximumNeighbourhood") + assert ( + observed_df.collect() == expected_df.collect() + ), "The expected and observed dataframes do not match." + + @pytest.fixture(autouse=True) + def _setup(self: TestCommonColocalisationFeatureLogic, spark: SparkSession) -> None: + """Set up the test variables.""" + self.colocalisation_method = "Coloc" + self.colocalisation_metric = "h4" + self.qtl_type = "eqtl" + + self.sample_study_loci_to_annotate = StudyLocus( + _df=spark.createDataFrame( + [ + { + "studyLocusId": "1", + "variantId": "lead1", + "studyId": "study1", # this is a GWAS + "chromosome": "1", + }, + ] + ), + _schema=StudyLocus.get_schema(), + ) + self.sample_colocalisation = Colocalisation( + _df=spark.createDataFrame( + [ + { + "leftStudyLocusId": "1", + "rightStudyLocusId": "2", + "chromosome": "1", + "colocalisationMethod": "COLOC", + "numberColocalisingVariants": 1, + "h4": 0.81, + "rightStudyType": "eqtl", + }, + { + "leftStudyLocusId": "1", + "rightStudyLocusId": "3", # qtl linked to the same gene as studyLocusId 2 with a lower score + "chromosome": "1", + "colocalisationMethod": "COLOC", + "numberColocalisingVariants": 1, + "h4": 0.50, + "rightStudyType": "eqtl", + }, + { + "leftStudyLocusId": "1", + "rightStudyLocusId": "4", # qtl linked to a diff gene and with the highest score + "chromosome": "1", + "colocalisationMethod": "COLOC", + "numberColocalisingVariants": 1, + "h4": 0.90, + "rightStudyType": "eqtl", + }, + ], + schema=Colocalisation.get_schema(), + ), + _schema=Colocalisation.get_schema(), + ) + self.sample_study_locus = StudyLocus( + _df=spark.createDataFrame( + [ + { + "studyLocusId": "1", + "variantId": "lead1", + "studyId": "study1", # this is a GWAS + "chromosome": "1", + }, + { + "studyLocusId": "2", + "variantId": "lead1", + "studyId": "study2", # this is a QTL (same gee) + "chromosome": "1", + }, + { + "studyLocusId": "3", + "variantId": "lead1", + "studyId": "study3", # this is another QTL (same gene) + "chromosome": "1", + }, + { + "studyLocusId": "4", + "variantId": "lead1", + "studyId": "study4", # this is another QTL (diff gene) + "chromosome": "1", + }, + ] + ), + _schema=StudyLocus.get_schema(), + ) + self.sample_studies = StudyIndex( + _df=spark.createDataFrame( + [ + { + "studyId": "study1", + "studyType": "gwas", + "geneId": None, + "traitFromSource": "trait1", + "projectId": "project1", + }, + { + "studyId": "study2", + "studyType": "eqtl", + "geneId": "gene1", + "traitFromSource": "trait2", + "projectId": "project2", + }, + { + "studyId": "study3", + "studyType": "eqtl", + "geneId": "gene1", + "traitFromSource": "trait3", + "projectId": "project3", + }, + { + "studyId": "study4", + "studyType": "eqtl", + "geneId": "gene2", + "traitFromSource": "trait4", + "projectId": "project4", + }, + ] + ), + _schema=StudyIndex.get_schema(), + ) + + +class TestCommonDistanceFeatureLogic: + """Test the CommonDistanceFeatureLogic methods.""" + + @pytest.mark.parametrize( + ("feature_name", "expected_data"), + [ + ( + "distanceSentinelTss", + [ + { + "studyLocusId": "1", + "geneId": "gene1", + "distanceSentinelTss": 0.0, + }, + { + "studyLocusId": "1", + "geneId": "gene2", + "distanceSentinelTss": 0.95, + }, + ], + ), + ( + "distanceTssMean", + [ + {"studyLocusId": "1", "geneId": "gene1", "distanceTssMean": 0.09}, + {"studyLocusId": "1", "geneId": "gene2", "distanceTssMean": 0.65}, + ], + ), + ], + ) + def test_common_distance_feature_logic( + self: TestCommonDistanceFeatureLogic, + spark: SparkSession, + feature_name: str, + expected_data: dict[str, Any], + ) -> None: + """Test the logic of the function that extracts features from distance. + + 2 tests: + - distanceSentinelTss: distance of the sentinel is 10, the max distance is 10. In log scale, the score is 0. + - distanceTssMean: avg distance of any variant in the credible set, weighted by its posterior. + """ + observed_df = ( + common_distance_feature_logic( + self.sample_study_locus, + variant_index=self.sample_variant_index, + feature_name=feature_name, + distance_type=self.distance_type, + genomic_window=10, + ) + .withColumn(feature_name, f.round(f.col(feature_name), 2)) + .orderBy(feature_name) + ) + expected_df = ( + spark.createDataFrame(expected_data) + .select("studyLocusId", "geneId", feature_name) + .orderBy(feature_name) + ) + assert ( + observed_df.collect() == expected_df.collect() + ), f"Expected and observed dataframes are not equal for feature {feature_name}." + + def test_common_neighbourhood_colocalisation_feature_logic( + self: TestCommonDistanceFeatureLogic, + spark: SparkSession, + ) -> None: + """Test the logic of the function that extracts the distance between the sentinel of a credible set and the nearby genes.""" + feature_name = "distanceSentinelTssNeighbourhood" + observed_df = ( + common_neighbourhood_distance_feature_logic( + self.sample_study_locus, + variant_index=self.sample_variant_index, + feature_name=feature_name, + distance_type=self.distance_type, + genomic_window=10, + ) + .withColumn(feature_name, f.round(f.col(feature_name), 2)) + .orderBy(f.col(feature_name).asc()) + ) + expected_df = spark.createDataFrame( + (["1", "gene1", -0.48], ["1", "gene2", 0.48]), + ["studyLocusId", "geneId", feature_name], + ).orderBy(feature_name) + assert ( + observed_df.collect() == expected_df.collect() + ), "Output doesn't meet the expectation." + + @pytest.fixture(autouse=True) + def _setup(self: TestCommonDistanceFeatureLogic, spark: SparkSession) -> None: + """Set up testing fixtures.""" + self.distance_type = "distanceFromTss" + self.sample_study_locus = StudyLocus( + _df=spark.createDataFrame( + [ + { + "studyLocusId": "1", + "variantId": "lead1", + "studyId": "study1", + "locus": [ + { + "variantId": "lead1", + "posteriorProbability": 0.5, + }, + { + "variantId": "tag1", + "posteriorProbability": 0.5, + }, + ], + "chromosome": "1", + }, + ], + StudyLocus.get_schema(), + ), + _schema=StudyLocus.get_schema(), + ) + self.variant_index_schema = StructType( + [ + StructField("variantId", StringType(), True), + StructField("chromosome", StringType(), True), + StructField("position", IntegerType(), True), + StructField("referenceAllele", StringType(), True), + StructField("alternateAllele", StringType(), True), + StructField( + "transcriptConsequences", + ArrayType( + StructType( + [ + StructField("distanceFromTss", LongType(), True), + StructField("targetId", StringType(), True), + StructField("isEnsemblCanonical", BooleanType(), True), + ] + ) + ), + True, + ), + ] + ) + self.sample_variant_index = VariantIndex( + _df=spark.createDataFrame( + [ + ( + "lead1", + "chrom", + 1, + "A", + "T", + [ + { + "distanceFromTss": 10, + "targetId": "gene1", + "isEnsemblCanonical": True, + }, + { + "distanceFromTss": 2, + "targetId": "gene2", + "isEnsemblCanonical": True, + }, + ], + ), + ( + "tag1", + "chrom", + 1, + "A", + "T", + [ + { + "distanceFromTss": 5, + "targetId": "gene1", + "isEnsemblCanonical": True, + }, + ], + ), + ], + self.variant_index_schema, + ), + _schema=VariantIndex.get_schema(), + ) diff --git a/tests/gentropy/dataset/test_v2g.py b/tests/gentropy/dataset/test_v2g.py deleted file mode 100644 index 24a917508..000000000 --- a/tests/gentropy/dataset/test_v2g.py +++ /dev/null @@ -1,23 +0,0 @@ -"""Tests V2G dataset.""" - -from __future__ import annotations - -from typing import TYPE_CHECKING - -from gentropy.dataset.v2g import V2G - -if TYPE_CHECKING: - from gentropy.dataset.gene_index import GeneIndex - - -def test_v2g_creation(mock_v2g: V2G) -> None: - """Test v2g creation with mock data.""" - assert isinstance(mock_v2g, V2G) - - -def test_v2g_filter_by_genes(mock_v2g: V2G, mock_gene_index: GeneIndex) -> None: - """Test v2g filter by genes.""" - assert isinstance( - mock_v2g.filter_by_genes(mock_gene_index), - V2G, - ) diff --git a/tests/gentropy/dataset/test_variant_index.py b/tests/gentropy/dataset/test_variant_index.py index 12afba89f..29a6ef035 100644 --- a/tests/gentropy/dataset/test_variant_index.py +++ b/tests/gentropy/dataset/test_variant_index.py @@ -8,12 +8,10 @@ from pyspark.sql import functions as f from pyspark.sql import types as t -from gentropy.dataset.gene_index import GeneIndex -from gentropy.dataset.v2g import V2G from gentropy.dataset.variant_index import VariantIndex if TYPE_CHECKING: - from pyspark.sql import SparkSession + from pyspark.sql import DataFrame, SparkSession def test_variant_index_creation(mock_variant_index: VariantIndex) -> None: @@ -21,20 +19,6 @@ def test_variant_index_creation(mock_variant_index: VariantIndex) -> None: assert isinstance(mock_variant_index, VariantIndex) -def test_get_plof_v2g( - mock_variant_index: VariantIndex, mock_gene_index: GeneIndex -) -> None: - """Test get_plof_v2g with mock variant annotation.""" - assert isinstance(mock_variant_index.get_plof_v2g(mock_gene_index), V2G) - - -def test_get_distance_to_tss( - mock_variant_index: VariantIndex, mock_gene_index: GeneIndex -) -> None: - """Test get_distance_to_tss with mock variant annotation.""" - assert isinstance(mock_variant_index.get_distance_to_tss(mock_gene_index), V2G) - - class TestVariantIndex: """Collection of tests around the functionality and shape of the variant index.""" @@ -147,3 +131,47 @@ def test_rsid_column_updated(self: TestVariantIndex) -> None: .count() == 2 ) + + @pytest.mark.parametrize( + "distance_type", ["distanceFromTss", "distanceFromFootprint"] + ) + def test_get_distance_to_gene( + self: TestVariantIndex, mock_variant_index: VariantIndex, distance_type: str + ) -> None: + """Assert that the function returns a df with the requested columns.""" + expected_cols = ["variantId", "targetId", distance_type] + observed = mock_variant_index.get_distance_to_gene(distance_type=distance_type) + for col in expected_cols: + assert col in observed.columns, f"Column {col} not in {observed.columns}" + + def test_get_most_severe_gene_consequence( + self: TestVariantIndex, + mock_variant_index: VariantIndex, + mock_variant_consequence_to_score: DataFrame, + ) -> None: + """Assert that the function returns a df with the requested columns.""" + expected_cols = [ + "variantId", + "targetId", + "mostSevereVariantFunctionalConsequenceId", + "severityScore", + ] + observed = mock_variant_index.get_most_severe_gene_consequence( + vep_consequences=mock_variant_consequence_to_score + ) + for col in expected_cols: + assert col in observed.columns, f"Column {col} not in {observed.columns}" + + def test_get_loftee( + self: TestVariantIndex, mock_variant_index: VariantIndex + ) -> None: + """Assert that the function returns a df with the requested columns.""" + expected_cols = [ + "variantId", + "targetId", + "lofteePrediction", + "isHighQualityPlof", + ] + observed = mock_variant_index.get_loftee() + for col in expected_cols: + assert col in observed.columns, f"Column {col} not in {observed.columns}" diff --git a/tests/gentropy/datasource/open_targets/test_l2g_gold_standard.py b/tests/gentropy/datasource/open_targets/test_l2g_gold_standard.py index 78f97d48f..aa36359ca 100644 --- a/tests/gentropy/datasource/open_targets/test_l2g_gold_standard.py +++ b/tests/gentropy/datasource/open_targets/test_l2g_gold_standard.py @@ -6,11 +6,20 @@ import pytest from pyspark.sql import DataFrame +from pyspark.sql.types import ( + ArrayType, + BooleanType, + IntegerType, + LongType, + StringType, + StructField, + StructType, +) from gentropy.dataset.l2g_feature_matrix import L2GFeatureMatrix from gentropy.dataset.l2g_gold_standard import L2GGoldStandard from gentropy.dataset.study_index import StudyIndex -from gentropy.dataset.v2g import V2G +from gentropy.dataset.variant_index import VariantIndex from gentropy.datasource.open_targets.l2g_gold_standard import ( OpenTargetsL2GGoldStandard, ) @@ -25,13 +34,13 @@ def test_open_targets_as_l2g_gold_standard( sample_l2g_gold_standard: DataFrame, - mock_v2g: V2G, + mock_variant_index: VariantIndex, ) -> None: """Test L2G gold standard from OTG curation.""" assert isinstance( OpenTargetsL2GGoldStandard.as_l2g_gold_standard( sample_l2g_gold_standard, - mock_v2g, + mock_variant_index, ), L2GGoldStandard, ) @@ -81,19 +90,52 @@ def _setup(self: TestExpandGoldStandardWithNegatives, spark: SparkSession) -> No ["variantId", "geneId", "studyId"], ) - sample_v2g_df = spark.createDataFrame( - [ - ("variant1", "gene1", 5, "X", "X", "X"), - ("variant1", "gene3", 10, "X", "X", "X"), - ], + sample_variant_index_df = spark.createDataFrame( [ - "variantId", - "geneId", - "distance", - "chromosome", - "datatypeId", - "datasourceId", + ( + "variant1", + "chrom", + 1, + "A", + "T", + [ + { + "distanceFromTss": 5, + "targetId": "gene1", + "isEnsemblCanonical": True, + }, + { + "distanceFromTss": 10, + "targetId": "gene3", + "isEnsemblCanonical": True, + }, + ], + ), ], + StructType( + [ + StructField("variantId", StringType(), True), + StructField("chromosome", StringType(), True), + StructField("position", IntegerType(), True), + StructField("referenceAllele", StringType(), True), + StructField("alternateAllele", StringType(), True), + StructField( + "transcriptConsequences", + ArrayType( + StructType( + [ + StructField("distanceFromTss", LongType(), True), + StructField("targetId", StringType(), True), + StructField( + "isEnsemblCanonical", BooleanType(), True + ), + ] + ) + ), + True, + ), + ] + ), ) self.expected_expanded_gs = spark.createDataFrame( @@ -107,7 +149,9 @@ def _setup(self: TestExpandGoldStandardWithNegatives, spark: SparkSession) -> No self.observed_df = ( OpenTargetsL2GGoldStandard.expand_gold_standard_with_negatives( self.sample_positive_set, - V2G(_df=sample_v2g_df, _schema=V2G.get_schema()), + VariantIndex( + _df=sample_variant_index_df, _schema=VariantIndex.get_schema() + ), ) ) diff --git a/tests/gentropy/test_schemas.py b/tests/gentropy/test_schemas.py index 6840e3207..1b06076d0 100644 --- a/tests/gentropy/test_schemas.py +++ b/tests/gentropy/test_schemas.py @@ -18,7 +18,7 @@ from _pytest.fixtures import FixtureRequest from gentropy.dataset.gene_index import GeneIndex - from gentropy.dataset.v2g import V2G + from gentropy.dataset.l2g_prediction import L2GPrediction SCHEMA_DIR = "src/gentropy/assets/schemas" @@ -75,21 +75,23 @@ def test_schema_columns_camelcase(schema_json: str) -> None: class TestValidateSchema: - """Test validate_schema method using V2G (unnested) and GeneIndex (nested) as a testing dataset.""" + """Test validate_schema method using L2GPrediction (unnested) and GeneIndex (nested) as a testing dataset.""" @pytest.fixture() def mock_dataset_instance( self: TestValidateSchema, request: FixtureRequest - ) -> V2G | GeneIndex: + ) -> L2GPrediction | GeneIndex: """Meta fixture to return the value of any requested fixture.""" return request.getfixturevalue(request.param) @pytest.mark.parametrize( - "mock_dataset_instance", ["mock_v2g", "mock_gene_index"], indirect=True + "mock_dataset_instance", + ["mock_l2g_predictions", "mock_gene_index"], + indirect=True, ) def test_validate_schema_extra_field( self: TestValidateSchema, - mock_dataset_instance: V2G | GeneIndex, + mock_dataset_instance: L2GPrediction | GeneIndex, ) -> None: """Test that validate_schema raises an error if the observed schema has an extra field.""" with pytest.raises(SchemaValidationError, match="extraField"): @@ -98,22 +100,26 @@ def test_validate_schema_extra_field( ) @pytest.mark.parametrize( - "mock_dataset_instance", ["mock_v2g", "mock_gene_index"], indirect=True + "mock_dataset_instance", + ["mock_l2g_predictions", "mock_gene_index"], + indirect=True, ) def test_validate_schema_missing_field( self: TestValidateSchema, - mock_dataset_instance: V2G | GeneIndex, + mock_dataset_instance: L2GPrediction | GeneIndex, ) -> None: """Test that validate_schema raises an error if the observed schema is missing a required field, geneId in this case.""" with pytest.raises(SchemaValidationError, match="geneId"): mock_dataset_instance.df = mock_dataset_instance.df.drop("geneId") @pytest.mark.parametrize( - "mock_dataset_instance", ["mock_v2g", "mock_gene_index"], indirect=True + "mock_dataset_instance", + ["mock_l2g_predictions", "mock_gene_index"], + indirect=True, ) def test_validate_schema_duplicated_field( self: TestValidateSchema, - mock_dataset_instance: V2G | GeneIndex, + mock_dataset_instance: L2GPrediction | GeneIndex, ) -> None: """Test that validate_schema raises an error if the observed schema has a duplicated field, geneId in this case.""" with pytest.raises(SchemaValidationError, match="geneId"): @@ -122,11 +128,13 @@ def test_validate_schema_duplicated_field( ) @pytest.mark.parametrize( - "mock_dataset_instance", ["mock_v2g", "mock_gene_index"], indirect=True + "mock_dataset_instance", + ["mock_l2g_predictions", "mock_gene_index"], + indirect=True, ) def test_validate_schema_different_datatype( self: TestValidateSchema, - mock_dataset_instance: V2G | GeneIndex, + mock_dataset_instance: L2GPrediction | GeneIndex, ) -> None: """Test that validate_schema raises an error if any field in the observed schema has a different type than expected.""" with pytest.raises(SchemaValidationError, match="geneId"): From c3b8c2c8b4457047e3504f5d56817005a67be807 Mon Sep 17 00:00:00 2001 From: David Ochoa Date: Tue, 1 Oct 2024 10:02:36 +0100 Subject: [PATCH 067/188] feat: out sample LD qc reason (#798) Co-authored-by: Daniel Suveges --- src/gentropy/dataset/study_locus.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gentropy/dataset/study_locus.py b/src/gentropy/dataset/study_locus.py index a4d35e7d5..4616052aa 100644 --- a/src/gentropy/dataset/study_locus.py +++ b/src/gentropy/dataset/study_locus.py @@ -86,6 +86,7 @@ class StudyLocusQualityCheck(Enum): ) TOP_HIT = "Study locus from curated top hit" EXPLAINED_BY_SUSIE = "Study locus in region explained by a SuSiE credible set" + OUT_OF_SAMPLE_LD = "Study locus finemapped without in-sample LD reference" class CredibleInterval(Enum): From a5588ae6fa27b28809a63e5dce63d3164e94a9a9 Mon Sep 17 00:00:00 2001 From: Szymon Szyszkowski <69353402+project-defiant@users.noreply.github.com> Date: Tue, 1 Oct 2024 13:09:04 +0200 Subject: [PATCH 068/188] chore: drop redundant parameter (#802) Co-authored-by: Szymon Szyszkowski --- src/gentropy/config.py | 1 - src/gentropy/sumstat_qc_step.py | 4 +--- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/gentropy/config.py b/src/gentropy/config.py index 6f94cc9ed..33865d6ea 100644 --- a/src/gentropy/config.py +++ b/src/gentropy/config.py @@ -439,7 +439,6 @@ class GWASQCStep(StepConfig): gwas_path: str = MISSING output_path: str = MISSING - studyid: str = MISSING pval_threshold: float = MISSING _target_: str = "gentropy.sumstat_qc_step.SummaryStatisticsQCStep" diff --git a/src/gentropy/sumstat_qc_step.py b/src/gentropy/sumstat_qc_step.py index b5aed905e..333ab19f3 100644 --- a/src/gentropy/sumstat_qc_step.py +++ b/src/gentropy/sumstat_qc_step.py @@ -15,7 +15,6 @@ def __init__( session: Session, gwas_path: str, output_path: str, - studyid: str, pval_threshold: float = 1e-8, ) -> None: """Calculating quality control metrics on the provided GWAS study. @@ -24,7 +23,6 @@ def __init__( session (Session): Spark session gwas_path (str): Path to the GWAS summary statistics. output_path (str): Output path for the QC results. - studyid (str): Study ID for the QC. pval_threshold (float): P-value threshold for the QC. Default is 1e-8. """ @@ -35,5 +33,5 @@ def __init__( gwas=gwas, limit=100_000_000, pval_threshold=pval_threshold ) .write.mode(session.write_mode) - .parquet(output_path + "/qc_results_" + studyid) + .parquet(output_path) ) From d4b507049ca54c927e8d80da43449f93e931e28a Mon Sep 17 00:00:00 2001 From: Szymon Szyszkowski <69353402+project-defiant@users.noreply.github.com> Date: Tue, 1 Oct 2024 16:41:19 +0200 Subject: [PATCH 069/188] fix: align the schema of study_index for ukb ppp eur (#803) * fix(ukb_ppp_study_index): update column name to match schema * chore: add note that notebooks are not supported --------- Co-authored-by: Szymon Szyszkowski --- notebooks/README.md | 3 ++ notebooks/Release_QC_metrics.ipynb | 2 +- .../datasource/ukb_ppp_eur/study_index.py | 31 ++++++++----------- 3 files changed, 17 insertions(+), 19 deletions(-) create mode 100644 notebooks/README.md diff --git a/notebooks/README.md b/notebooks/README.md new file mode 100644 index 000000000..35132b6bf --- /dev/null +++ b/notebooks/README.md @@ -0,0 +1,3 @@ +# Notebooks + +The notebooks in listed in this directory are not actively maintained and updated. diff --git a/notebooks/Release_QC_metrics.ipynb b/notebooks/Release_QC_metrics.ipynb index 4eb27015b..5f9bf77c0 100644 --- a/notebooks/Release_QC_metrics.ipynb +++ b/notebooks/Release_QC_metrics.ipynb @@ -419,7 +419,7 @@ "# Number of studies\n", "eqtl_index=session.spark.read.parquet(eqtl_index_path, recursiveFileLookup=True)\n", "# Number of tissues, list of tissues\n", - "#eqtl_index.select(f.col(\"tissueFromSourceId\")).distinct().show(truncate=False)\n", + "#eqtl_index.select(f.col(\"biosampleFromSourceId\")).distinct().show(truncate=False)\n", "\n", "# Credible_set. Please use Daniels’ notebook as a reference. For each subfolder:\n", "# eqtl catalog susie:\n", diff --git a/src/gentropy/datasource/ukb_ppp_eur/study_index.py b/src/gentropy/datasource/ukb_ppp_eur/study_index.py index f694b9a47..8a3105f5d 100644 --- a/src/gentropy/datasource/ukb_ppp_eur/study_index.py +++ b/src/gentropy/datasource/ukb_ppp_eur/study_index.py @@ -1,4 +1,5 @@ """Study Index for Finngen data source.""" + from __future__ import annotations import pyspark.sql.functions as f @@ -29,9 +30,7 @@ def from_source( """ # In order to populate the nSamples column, we need to peek inside the summary stats dataframe. num_of_samples = ( - spark - .read - .parquet(raw_summary_stats_path) + spark.read.parquet(raw_summary_stats_path) .filter(f.col("chromosome") == "22") .groupBy("studyId") .agg(f.first("N").cast("integer").alias("nSamples")) @@ -45,7 +44,7 @@ def from_source( f.lit("UKB_PPP_EUR").alias("projectId"), f.col("_gentropy_study_id").alias("studyId"), f.col("UKBPPP_ProteinID").alias("traitFromSource"), - f.lit("UBERON_0001969").alias("tissueFromSourceId"), + f.lit("UBERON_0001969").alias("biosampleFromSourceId"), f.col("ensembl_id").alias("geneId"), f.lit(True).alias("hasSumstats"), f.col("_gentropy_summary_stats_link").alias("summarystatsLocation"), @@ -53,21 +52,17 @@ def from_source( .join(num_of_samples, "studyId", "inner") ) # Add population structure. - study_index_df = ( - study_index_df - .withColumn( - "discoverySamples", - f.array( - f.struct( - f.col("nSamples").cast("integer").alias("sampleSize"), - f.lit("European").alias("ancestry"), - ) + study_index_df = study_index_df.withColumn( + "discoverySamples", + f.array( + f.struct( + f.col("nSamples").cast("integer").alias("sampleSize"), + f.lit("European").alias("ancestry"), ) - ) - .withColumn( - "ldPopulationStructure", - cls.aggregate_and_map_ancestries(f.col("discoverySamples")), - ) + ), + ).withColumn( + "ldPopulationStructure", + cls.aggregate_and_map_ancestries(f.col("discoverySamples")), ) return StudyIndex( From ccb484ed880e4418db0886e5c549c418fb1258c4 Mon Sep 17 00:00:00 2001 From: Szymon Szyszkowski <69353402+project-defiant@users.noreply.github.com> Date: Tue, 1 Oct 2024 17:09:53 +0200 Subject: [PATCH 070/188] feat: force reinstallation of the gentropy on the cluster (#804) Co-authored-by: Szymon Szyszkowski --- utils/install_dependencies_on_cluster.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/utils/install_dependencies_on_cluster.sh b/utils/install_dependencies_on_cluster.sh index 6b76a7d60..b0a165c04 100644 --- a/utils/install_dependencies_on_cluster.sh +++ b/utils/install_dependencies_on_cluster.sh @@ -60,7 +60,9 @@ function main() { echo "Uninstalling previous version if it exists" pip uninstall -y gentropy echo "Install package..." - run_with_retry pip install --upgrade ${PACKAGENAME} + # NOTE: ensure the gentropy is reinstalled each time without version cache + # see https://pip.pypa.io/en/stable/cli/pip_install/#cmdoption-force-reinstall + run_with_retry pip install --force-reinstall ${PACKAGENAME} } From 1c396d2a8c9a92c97e0d2e387061cbff2b229d35 Mon Sep 17 00:00:00 2001 From: Daniel Suveges Date: Tue, 1 Oct 2024 17:01:43 +0100 Subject: [PATCH 071/188] feat(validation): adding credible set confidence annotation at validation time (#801) * feat: adding credible set confidence * feat: adding confidence assignment to the credible set validation step * fix: adding confidence field to schema * fix: schema * fix: confidence criteria * fix: finalising labels * fix: docstring typo * test: for credible set confidence assignment --- src/gentropy/assets/schemas/study_locus.json | 6 ++ src/gentropy/dataset/study_locus.py | 89 +++++++++++++++++++- src/gentropy/study_locus_validation.py | 2 + tests/gentropy/dataset/test_study_locus.py | 40 ++++++++- 4 files changed, 131 insertions(+), 6 deletions(-) diff --git a/src/gentropy/assets/schemas/study_locus.json b/src/gentropy/assets/schemas/study_locus.json index 52a19f941..5c7bf1178 100644 --- a/src/gentropy/assets/schemas/study_locus.json +++ b/src/gentropy/assets/schemas/study_locus.json @@ -241,6 +241,12 @@ }, "type": "array" } + }, + { + "metadata": {}, + "name": "confidence", + "nullable": true, + "type": "string" } ], "type": "struct" diff --git a/src/gentropy/dataset/study_locus.py b/src/gentropy/dataset/study_locus.py index 4616052aa..bf9998458 100644 --- a/src/gentropy/dataset/study_locus.py +++ b/src/gentropy/dataset/study_locus.py @@ -34,6 +34,28 @@ from gentropy.method.l2g.feature_factory import L2GFeatureInputLoader +class CredibleSetConfidenceClasses(Enum): + """Confidence assignments for credible sets, based on finemapping method and quality checks. + + List of confidence classes, from the highest to the lowest confidence level. + + Attributes: + FINEMAPPED_IN_SAMPLE_LD (str): SuSiE fine-mapped credible set with in-sample LD + FINEMAPPED_OUT_OF_SAMPLE_LD (str): SuSiE fine-mapped credible set with out-of-sample LD + PICSED_SUMMARY_STATS (str): PICS fine-mapped credible set extracted from summary statistics + PICSED_TOP_HIT (str): PICS fine-mapped credible set based on reported top hit + UNKNOWN (str): Unknown confidence, for credible sets which did not fit any of the above categories + """ + + FINEMAPPED_IN_SAMPLE_LD = "SuSiE fine-mapped credible set with in-sample LD" + FINEMAPPED_OUT_OF_SAMPLE_LD = "SuSiE fine-mapped credible set with out-of-sample LD" + PICSED_SUMMARY_STATS = ( + "PICS fine-mapped credible set extracted from summary statistics" + ) + PICSED_TOP_HIT = "PICS fine-mapped credible set based on reported top hit" + UNKNOWN = "Unknown confidence" + + class StudyLocusQualityCheck(Enum): """Study-Locus quality control options listing concerns on the quality of the association. @@ -468,8 +490,9 @@ def assign_study_locus_id(uniqueness_defining_columns: list[str]) -> Column: +----------+----------+-----------------+--------------------------------+ """ - return Dataset.generate_identifier(uniqueness_defining_columns).alias("studyLocusId") - + return Dataset.generate_identifier(uniqueness_defining_columns).alias( + "studyLocusId" + ) @classmethod def calculate_credible_set_log10bf(cls: type[StudyLocus], logbfs: Column) -> Column: @@ -1126,3 +1149,65 @@ def window_based_clumping( from gentropy.method.window_based_clumping import WindowBasedClumping return WindowBasedClumping.clump(self, window_size) + + def assign_confidence(self: StudyLocus) -> StudyLocus: + """Assign confidence to study locus. + + Returns: + StudyLocus: Study locus with confidence assigned. + """ + # Return self if the required columns are not in the dataframe: + if ( + "qualityControls" not in self.df.columns + or "finemappingMethod" not in self.df.columns + ): + return self + + # Assign confidence based on the presence of quality controls + df = self.df.withColumn( + "confidence", + f.when( + (f.col("finemappingMethod") == "SuSiE-inf") + & ( + ~f.array_contains( + f.col("qualityControls"), + StudyLocusQualityCheck.OUT_OF_SAMPLE_LD.value, + ) + ), + CredibleSetConfidenceClasses.FINEMAPPED_IN_SAMPLE_LD.value, + ) + .when( + (f.col("finemappingMethod") == "SuSiE-inf") + & ( + f.array_contains( + f.col("qualityControls"), + StudyLocusQualityCheck.OUT_OF_SAMPLE_LD.value, + ) + ), + CredibleSetConfidenceClasses.FINEMAPPED_OUT_OF_SAMPLE_LD.value, + ) + .when( + (f.col("finemappingMethod") == "pics") + & ( + ~f.array_contains( + f.col("qualityControls"), StudyLocusQualityCheck.TOP_HIT.value + ) + ), + CredibleSetConfidenceClasses.PICSED_SUMMARY_STATS.value, + ) + .when( + (f.col("finemappingMethod") == "pics") + & ( + f.array_contains( + f.col("qualityControls"), StudyLocusQualityCheck.TOP_HIT.value + ) + ), + CredibleSetConfidenceClasses.PICSED_TOP_HIT.value, + ) + .otherwise(CredibleSetConfidenceClasses.UNKNOWN.value), + ) + + return StudyLocus( + _df=df, + _schema=self.get_schema(), + ) diff --git a/src/gentropy/study_locus_validation.py b/src/gentropy/study_locus_validation.py index fc69f6855..486b31ca5 100644 --- a/src/gentropy/study_locus_validation.py +++ b/src/gentropy/study_locus_validation.py @@ -47,6 +47,8 @@ def __init__( .qc_explained_by_SuSiE() # Flagging credible sets in regions explained by SuSiE # Annotates credible intervals and filter to only keep 99% credible sets .filter_credible_set(credible_interval=CredibleInterval.IS99) + # Annotate credible set confidence: + .assign_confidence() ).persist() # we will need this for 2 types of outputs study_locus_with_qc.valid_rows( diff --git a/tests/gentropy/dataset/test_study_locus.py b/tests/gentropy/dataset/test_study_locus.py index 3240cdb02..3f6cfcb59 100644 --- a/tests/gentropy/dataset/test_study_locus.py +++ b/tests/gentropy/dataset/test_study_locus.py @@ -23,6 +23,7 @@ from gentropy.dataset.study_index import StudyIndex from gentropy.dataset.study_locus import ( CredibleInterval, + CredibleSetConfidenceClasses, StudyLocus, StudyLocusQualityCheck, ) @@ -615,12 +616,20 @@ class TestStudyLocusValidation: STUDY_LOCUS_DATA = [ # Won't be flagged: - ("1", "v1", "s1", 1.0, -8, []), + ("1", "v1", "s1", 1.0, -8, [], "pics"), # Already flagged, needs to be tested if the flag reamins unique: - ("2", "v2", "s2", 5.0, -4, [StudyLocusQualityCheck.SUBSIGNIFICANT_FLAG.value]), + ( + "2", + "v2", + "s2", + 5.0, + -4, + [StudyLocusQualityCheck.SUBSIGNIFICANT_FLAG.value], + "pics", + ), # To be flagged: - ("3", "v3", "s3", 1.0, -4, []), - ("4", "v4", "s4", 5.0, -3, []), + ("3", "v3", "s3", 1.0, -4, [], "SuSiE-inf"), + ("4", "v4", "s4", 5.0, -3, [], "unknown"), ] STUDY_LOCUS_SCHEMA = t.StructType( @@ -631,6 +640,7 @@ class TestStudyLocusValidation: t.StructField("pValueMantissa", t.FloatType(), False), t.StructField("pValueExponent", t.IntegerType(), False), t.StructField("qualityControls", t.ArrayType(t.StringType()), False), + t.StructField("finemappingMethod", t.StringType(), False), ] ) @@ -678,6 +688,28 @@ def test_return_type_pval_validation( self.study_locus.validate_lead_pvalue(test_pvalues), StudyLocus ) + def test_confidence_flag_return_type(self: TestStudyLocusValidation) -> None: + """Testing if the confidence flagging returns the right type.""" + assert isinstance(self.study_locus.assign_confidence(), StudyLocus) + + def test_confidence_flag_new_column(self: TestStudyLocusValidation) -> None: + """Testing if the confidence flagging adds a new column.""" + assert ( + self.study_locus.assign_confidence().df.columns + == self.study_locus.df.columns + ["confidence"] + ) + + def test_confidence_flag_unknown_confidence(self: TestStudyLocusValidation) -> None: + """Testing if the confidence flagging adds a new column.""" + assert ( + self.study_locus.assign_confidence() + .df.filter( + f.col("confidence") == CredibleSetConfidenceClasses.UNKNOWN.value + ) + .count() + == 1 + ) + @pytest.mark.parametrize( ("test_pvalues", "flagged_count"), [(1e-5, 3), (1e-4, 2)], From 9177dd44d6ba4abe3ed010a5177de6e97504eb3a Mon Sep 17 00:00:00 2001 From: Szymon Szyszkowski <69353402+project-defiant@users.noreply.github.com> Date: Wed, 2 Oct 2024 14:23:44 +0200 Subject: [PATCH 072/188] chore: make the lb clumping ingest the partitionned data (#806) Co-authored-by: Szymon Szyszkowski --- src/gentropy/locus_breaker_clumping.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/gentropy/locus_breaker_clumping.py b/src/gentropy/locus_breaker_clumping.py index 7f3649097..fde722354 100644 --- a/src/gentropy/locus_breaker_clumping.py +++ b/src/gentropy/locus_breaker_clumping.py @@ -1,4 +1,4 @@ -"""Step to apply linkageg based clumping on study-locus dataset.""" +"""Step to apply linkage based clumping on study-locus dataset.""" from __future__ import annotations @@ -47,7 +47,8 @@ def __init__( remove_mhc (bool, optional): If true will use exclude_region() to remove the MHC region. """ sum_stats = SummaryStatistics.from_parquet( - session, summary_statistics_input_path, recursiveFileLookup=True + session, + summary_statistics_input_path, ) lbc = sum_stats.locus_breaker_clumping( lbc_baseline_pvalue, From 174f8f945b2b02016aae14c9d11100a577463d57 Mon Sep 17 00:00:00 2001 From: Yakov Date: Wed, 2 Oct 2024 13:54:54 +0100 Subject: [PATCH 073/188] feat: adding filtering to susie finemapper (#796) * feat: adding filltering to susie fine_mapper * fix: correct options * fix: fix simulations * fix: correct clumping * fix: fix options * fix: fix for catching None * fix: adding LD and gwas_df as output * chore: changing defaults * chore: v1 * fix: spelling in susie_finemapper.py --------- Co-authored-by: Daniel-Considine <113430683+Daniel-Considine@users.noreply.github.com> --- src/gentropy/config.py | 4 +- src/gentropy/finemapping_simulations.py | 65 +++++----- src/gentropy/susie_finemapper.py | 159 +++++++++++++++--------- tests/gentropy/method/test_susie_inf.py | 6 +- 4 files changed, 142 insertions(+), 92 deletions(-) diff --git a/src/gentropy/config.py b/src/gentropy/config.py index 33865d6ea..e1068cfa6 100644 --- a/src/gentropy/config.py +++ b/src/gentropy/config.py @@ -417,8 +417,7 @@ class FinemapperConfig(StepConfig): study_locus_manifest_path: str = MISSING study_locus_index: int = MISSING max_causal_snps: int = MISSING - primary_signal_pval_threshold: float = MISSING - secondary_signal_pval_threshold: float = MISSING + lead_pval_threshold: float = MISSING purity_mean_r2_threshold: float = MISSING purity_min_r2_threshold: float = MISSING cs_lbf_thr: float = MISSING @@ -430,6 +429,7 @@ class FinemapperConfig(StepConfig): carma_time_limit: int = MISSING imputed_r2_threshold: float = MISSING ld_score_threshold: float = MISSING + ld_min_r2: float = MISSING _target_: str = "gentropy.susie_finemapper.SusieFineMapperStep" diff --git a/src/gentropy/finemapping_simulations.py b/src/gentropy/finemapping_simulations.py index 66a8f7855..92b30566c 100644 --- a/src/gentropy/finemapping_simulations.py +++ b/src/gentropy/finemapping_simulations.py @@ -139,40 +139,47 @@ def SimulationLoop( imputed_r2_threshold=0.9, ld_score_threshold=5, sum_pips=0.99, - primary_signal_pval_threshold=1e-2, - secondary_signal_pval_threshold=1e-2, + lead_pval_threshold=1, purity_mean_r2_threshold=0, purity_min_r2_threshold=0, cs_lbf_thr=2, + ld_min_r2=0.9, + locusStart=1, + locusEnd=2, ) - cred_set = CS_sim["study_locus"].df - - X = ld_index_pd["variantId"][x_cycle["indexes"]].tolist() - - cred_set = cred_set.withColumn("exploded_locus", col("locus.variantId")) - # Create a condition for each element in X - conditions = [array_contains(col("exploded_locus"), x) for x in X] - # Combine the conditions using the | operator - combined_condition = conditions[0] - for condition in conditions[1:]: - combined_condition = combined_condition | condition - # Create a new column that is True if any condition is True and False otherwise - cred_set = cred_set.withColumn("is_in_X", combined_condition) - - cred_set = cred_set.withColumn( - "is_in_lead", when(col("variantId").isin(X), 1).otherwise(0) - ) - - cred_set = cred_set.toPandas() - cred_set = cred_set[column_list] - if counter == 1: - cred_sets = cred_set - else: - # cred_sets = cred_sets.unionByName(cred_set) - cred_sets = pd.concat([cred_sets, cred_set], axis=0) - # cred_sets=cred_sets.merge(cred_set) - counter = counter + 1 + if CS_sim is not None: + cs_sl = CS_sim["study_locus"] + cred_set = cs_sl.df + + X = ld_index_pd["variantId"][x_cycle["indexes"]].tolist() + + cred_set = cred_set.withColumn( + "exploded_locus", col("locus.variantId") + ) + # Create a condition for each element in X + conditions = [array_contains(col("exploded_locus"), x) for x in X] + # Combine the conditions using the | operator + combined_condition = conditions[0] + for condition in conditions[1:]: + combined_condition = combined_condition | condition + # Create a new column that is True if any condition is True and False otherwise + cred_set = cred_set.withColumn("is_in_X", combined_condition) + + cred_set = cred_set.withColumn( + "is_in_lead", when(col("variantId").isin(X), 1).otherwise(0) + ) + + cred_set = cred_set.toPandas() + cred_set = cred_set[column_list] + + if counter == 1: + cred_sets = cred_set + else: + # cred_sets = cred_sets.unionByName(cred_set) + cred_sets = pd.concat([cred_sets, cred_set], axis=0) + # cred_sets=cred_sets.merge(cred_set) + counter = counter + 1 return cred_sets diff --git a/src/gentropy/susie_finemapper.py b/src/gentropy/susie_finemapper.py index 26c73e20f..1379ad89b 100644 --- a/src/gentropy/susie_finemapper.py +++ b/src/gentropy/susie_finemapper.py @@ -11,7 +11,7 @@ import pyspark.sql.functions as f import scipy as sc from pyspark.sql import DataFrame, Row, Window -from pyspark.sql.functions import row_number +from pyspark.sql.functions import desc, row_number from pyspark.sql.types import ( DoubleType, IntegerType, @@ -47,10 +47,9 @@ def __init__( study_locus_manifest_path: str, study_locus_index: int, max_causal_snps: int = 10, - primary_signal_pval_threshold: float = 1, - secondary_signal_pval_threshold: float = 1, + lead_pval_threshold: float = 1e-5, purity_mean_r2_threshold: float = 0, - purity_min_r2_threshold: float = 0, + purity_min_r2_threshold: float = 0.25, cs_lbf_thr: float = 2, sum_pips: float = 0.99, susie_est_tausq: bool = False, @@ -60,6 +59,7 @@ def __init__( carma_tau: float = 0.15, imputed_r2_threshold: float = 0.9, ld_score_threshold: float = 5, + ld_min_r2: float = 0.8, ) -> None: """Run fine-mapping on a studyLocusId from a collected studyLocus table. @@ -69,8 +69,7 @@ def __init__( study_locus_manifest_path (str): Path to the CSV manifest containing all study locus input and output locations. Should contain two columns: study_locus_input and study_locus_output study_locus_index (int): Index (0-based) of the locus in the manifest to process in this call max_causal_snps (int): Maximum number of causal variants in locus, default is 10 - primary_signal_pval_threshold (float): p-value threshold for the lead variant from the primary signal (credibleSetIndex==1), default is 5e-8 - secondary_signal_pval_threshold (float): p-value threshold for the lead variant from the secondary signals, default is 1e-7 + lead_pval_threshold (float): p-value threshold for the lead variant from CS, default is 1e-5 purity_mean_r2_threshold (float): thrshold for purity mean r2 qc metrics for filtering credible sets, default is 0 purity_min_r2_threshold (float): thrshold for purity min r2 qc metrics for filtering credible sets, default is 0.25 cs_lbf_thr (float): credible set logBF threshold for filtering credible sets, default is 2 @@ -82,6 +81,7 @@ def __init__( carma_tau (float): CARMA tau, shrinkage parameter imputed_r2_threshold (float): imputed R2 threshold, default is 0.9 ld_score_threshold (float): LD score threshold ofr imputation, default is 5 + ld_min_r2 (float): Threshold to filter CS by leads in high LD, default is 0.8 """ # Read locus manifest. study_locus_manifest = pd.read_csv(study_locus_manifest_path) @@ -108,12 +108,11 @@ def __init__( study_locus_row=study_locus, study_index=study_index, max_causal_snps=max_causal_snps, - primary_signal_pval_threshold=primary_signal_pval_threshold, - secondary_signal_pval_threshold=secondary_signal_pval_threshold, purity_mean_r2_threshold=purity_mean_r2_threshold, purity_min_r2_threshold=purity_min_r2_threshold, cs_lbf_thr=cs_lbf_thr, sum_pips=sum_pips, + lead_pval_threshold=lead_pval_threshold, susie_est_tausq=susie_est_tausq, run_carma=run_carma, run_sumstat_imputation=run_sumstat_imputation, @@ -121,35 +120,39 @@ def __init__( carma_time_limit=carma_time_limit, imputed_r2_threshold=imputed_r2_threshold, ld_score_threshold=ld_score_threshold, + ld_min_r2=ld_min_r2, ) if result_logging is not None: - # Write result - result_logging["study_locus"].df.write.mode(session.write_mode).parquet( - study_locus_output - ) - # Write log - result_logging["log"].to_parquet( - study_locus_output + ".log", - engine="pyarrow", - index=False, - ) + if result_logging["study_locus"] is not None: + # Write result + result_logging["study_locus"].df.write.mode(session.write_mode).parquet( + study_locus_output + ) + # Write log + result_logging["log"].to_parquet( + study_locus_output + ".log", + engine="pyarrow", + index=False, + ) @staticmethod - def susie_inf_to_studylocus( + def susie_inf_to_studylocus( # noqa: C901 susie_output: dict[str, Any], session: Session, studyId: str, region: str, variant_index: DataFrame, ld_matrix: np.ndarray, + locusStart: int, + locusEnd: int, cs_lbf_thr: float = 2, sum_pips: float = 0.99, - primary_signal_pval_threshold: float = 1, - secondary_signal_pval_threshold: float = 1, + lead_pval_threshold: float = 1, purity_mean_r2_threshold: float = 0, purity_min_r2_threshold: float = 0, - ) -> StudyLocus: + ld_min_r2: float = 0.9, + ) -> StudyLocus | None: """Convert SuSiE-inf output to StudyLocus DataFrame. Args: @@ -159,15 +162,17 @@ def susie_inf_to_studylocus( region (str): region variant_index (DataFrame): DataFrame with variant information ld_matrix (np.ndarray): LD matrix used for fine-mapping + locusStart (int): locus start + locusEnd (int): locus end cs_lbf_thr (float): credible set logBF threshold for filtering credible sets, default is 2 sum_pips (float): the expected sum of posterior probabilities in the locus, default is 0.99 (99% credible set) - primary_signal_pval_threshold (float): p-value threshold for the lead variant from the primary signal (credibleSetIndex==1) - secondary_signal_pval_threshold (float): p-value threshold for the lead variant from the secondary signals + lead_pval_threshold (float): p-value threshold for the lead variant from CS purity_mean_r2_threshold (float): thrshold for purity mean r2 qc metrics for filtering credible sets purity_min_r2_threshold (float): thrshold for purity min r2 qc metrics for filtering credible sets + ld_min_r2 (float): Threshold to fillter CS by leads in high LD, default is 0.9 Returns: - StudyLocus: StudyLocus object with fine-mapped credible sets + StudyLocus | None: StudyLocus object with fine-mapped credible sets """ # PLEASE DO NOT REMOVE THIS LINE pd.DataFrame.iteritems = pd.DataFrame.items @@ -333,37 +338,63 @@ def susie_inf_to_studylocus( mantissa, exponent = neglog_pvalue_to_mantissa_and_exponent( cred_sets.neglogpval ) - cred_sets = cred_sets.withColumn("pValueMantissa", mantissa) cred_sets = cred_sets.withColumn("pValueExponent", exponent) - cred_sets = cred_sets.withColumn( "pValueMantissa", f.col("pValueMantissa").cast("float") ) + # Filter by lead p-value, credible set logBF, purity mean r2 and purity min r2 cred_sets = cred_sets.filter( - (f.col("neglogpval") >= -np.log10(secondary_signal_pval_threshold)) - | (f.col("credibleSetIndex") == 1) + (f.col("neglogpval") >= -np.log10(lead_pval_threshold)) + & (f.col("credibleSetlog10BF") >= cs_lbf_thr * 0.4342944819) + & (f.col("purityMinR2") >= purity_min_r2_threshold) + & (f.col("purityMeanR2") >= purity_mean_r2_threshold) ) - cred_sets = cred_sets.filter( - (f.col("neglogpval") >= -np.log10(primary_signal_pval_threshold)) - | (f.col("credibleSetIndex") > 1) - ) + if cred_sets.count() == 0: + return None + + # Remove duplicated by lead variant + if cred_sets.count() > 1: + window = Window.partitionBy("variantId").orderBy("credibleSetIndex") + cred_sets = cred_sets.withColumn("rank", row_number().over(window)) + cred_sets = cred_sets.filter(cred_sets["rank"] == 1).drop("rank") + cred_sets = cred_sets.orderBy("credibleSetIndex") + + # Remove CSs with high LD between leads + if cred_sets.count() > 1: + cred_sets = cred_sets.orderBy(desc("neglogpval")) + lead_variantId_list = ( + cred_sets.select("variantId").toPandas()["variantId"].tolist() + ) + vlist_series = pd.Series(lead_variantId_list) + ind = vlist_series.map( + variant_index_df.set_index("variantId").index.get_loc + ) + ld_leads = ld_matrix[ind, :][:, ind] + ld_leads = ld_leads**2 + ld_leads = ld_leads - np.tril(ld_leads) + np.fill_diagonal(ld_leads, -1) + + lead_variantId_list_to_delete: list[str] = [] + for idx in range(len(lead_variantId_list)): + vId = lead_variantId_list[idx] + if vId in lead_variantId_list_to_delete: + continue + high_ld_indices = np.where(ld_leads[idx, :] >= ld_min_r2)[0] + if len(high_ld_indices) > 0: + lead_variantId_list_to_delete = ( + lead_variantId_list_to_delete + + list(np.array(lead_variantId_list)[high_ld_indices]) + ) + if len(lead_variantId_list_to_delete) > 0: + for vId in lead_variantId_list_to_delete: + cred_sets = cred_sets.filter(f.col("variantId") != vId) cred_sets = cred_sets.drop("neglogpval") - - cred_sets = cred_sets.filter( - (f.col("credibleSetlog10BF") >= cs_lbf_thr * 0.4342944819) - | (f.col("credibleSetIndex") == 1) - ) - - cred_sets = cred_sets.filter(f.col("purityMeanR2") >= purity_mean_r2_threshold) - cred_sets = cred_sets.filter(f.col("purityMinR2") >= purity_min_r2_threshold) - - window = Window.partitionBy("studyLocusId").orderBy("credibleSetIndex") - cred_sets = cred_sets.withColumn("rank", row_number().over(window)) - cred_sets = cred_sets.filter(cred_sets["rank"] == 1).drop("rank") + cred_sets = cred_sets.withColumn("locusStart", f.lit(locusStart)) + cred_sets = cred_sets.withColumn("locusEnd", f.lit(locusEnd)) return StudyLocus( _df=cred_sets, @@ -379,6 +410,8 @@ def susie_finemapper_from_prepared_dataframes( session: Session, studyId: str, region: str, + locusStart: int, + locusEnd: int, susie_est_tausq: bool = False, run_carma: bool = False, run_sumstat_imputation: bool = False, @@ -387,12 +420,12 @@ def susie_finemapper_from_prepared_dataframes( imputed_r2_threshold: float = 0.8, ld_score_threshold: float = 4, sum_pips: float = 0.99, - primary_signal_pval_threshold: float = 5e-8, - secondary_signal_pval_threshold: float = 1e-7, + lead_pval_threshold: float = 1e-5, purity_mean_r2_threshold: float = 0, purity_min_r2_threshold: float = 0.25, cs_lbf_thr: float = 2, - ) -> dict[str, Any]: + ld_min_r2: float = 0.9, + ) -> dict[str, Any] | None: """Susie fine-mapper function that uses LD, z-scores, variant info and other options for Fine-Mapping. Args: @@ -403,6 +436,8 @@ def susie_finemapper_from_prepared_dataframes( session (Session): Spark session studyId (str): study ID region (str): region + locusStart (int): locus start + locusEnd (int): locus end susie_est_tausq (bool): estimate tau squared, default is False run_carma (bool): run CARMA, default is False run_sumstat_imputation (bool): run summary statistics imputation, default is False @@ -411,14 +446,14 @@ def susie_finemapper_from_prepared_dataframes( imputed_r2_threshold (float): imputed R2 threshold, default is 0.8 ld_score_threshold (float): LD score threshold ofr imputation, default is 4 sum_pips (float): the expected sum of posterior probabilities in the locus, default is 0.99 (99% credible set) - primary_signal_pval_threshold (float): p-value threshold for the lead variant from the primary signal (credibleSetIndex==1) - secondary_signal_pval_threshold (float): p-value threshold for the lead variant from the secondary signals + lead_pval_threshold (float): p-value threshold for the lead variant from CS, default is 1e-5 purity_mean_r2_threshold (float): thrshold for purity mean r2 qc metrics for filtering credible sets purity_min_r2_threshold (float): thrshold for purity min r2 qc metrics for filtering credible sets cs_lbf_thr (float): credible set logBF threshold for filtering credible sets, default is 2 + ld_min_r2 (float): Threshold to fillter CS by leads in high LD, default is 0.9 Returns: - dict[str, Any]: dictionary with study locus, number of GWAS variants, number of LD variants, number of variants after merge, number of outliers, number of imputed variants, number of variants to fine-map + dict[str, Any] | None: dictionary with study locus, number of GWAS variants, number of LD variants, number of variants after merge, number of outliers, number of imputed variants, number of variants to fine-map """ # PLEASE DO NOT REMOVE THIS LINE pd.DataFrame.iteritems = pd.DataFrame.items @@ -542,11 +577,13 @@ def susie_finemapper_from_prepared_dataframes( variant_index=variant_index, sum_pips=sum_pips, ld_matrix=ld_to_fm, - primary_signal_pval_threshold=primary_signal_pval_threshold, - secondary_signal_pval_threshold=secondary_signal_pval_threshold, + lead_pval_threshold=lead_pval_threshold, purity_mean_r2_threshold=purity_mean_r2_threshold, purity_min_r2_threshold=purity_min_r2_threshold, cs_lbf_thr=cs_lbf_thr, + ld_min_r2=ld_min_r2, + locusStart=locusStart, + locusEnd=locusEnd, ) end_time = time.time() @@ -568,6 +605,8 @@ def susie_finemapper_from_prepared_dataframes( return { "study_locus": study_locus, "log": log_df, + "LD": ld_to_fm, + "GWAS_df": GWAS_df, } @staticmethod @@ -584,11 +623,11 @@ def susie_finemapper_one_sl_row_v4_ss_gathered_boundaries( imputed_r2_threshold: float = 0.9, ld_score_threshold: float = 5, sum_pips: float = 0.99, - primary_signal_pval_threshold: float = 5e-8, - secondary_signal_pval_threshold: float = 1e-7, + lead_pval_threshold: float = 1e-5, purity_mean_r2_threshold: float = 0, purity_min_r2_threshold: float = 0.25, cs_lbf_thr: float = 2, + ld_min_r2: float = 0.9, ) -> dict[str, Any] | None: """Susie fine-mapper function that uses study-locus row with collected locus, chromosome and position as inputs. @@ -605,11 +644,11 @@ def susie_finemapper_one_sl_row_v4_ss_gathered_boundaries( imputed_r2_threshold (float): imputed R2 threshold, default is 0.8 ld_score_threshold (float): LD score threshold ofr imputation, default is 4 sum_pips (float): the expected sum of posterior probabilities in the locus, default is 0.99 (99% credible set) - primary_signal_pval_threshold (float): p-value threshold for the lead variant from the primary signal (credibleSetIndex==1) - secondary_signal_pval_threshold (float): p-value threshold for the lead variant from the secondary signals + lead_pval_threshold (float): p-value threshold for the lead variant from CS, default is 1e-5 purity_mean_r2_threshold (float): thrshold for purity mean r2 qc metrics for filtering credible sets purity_min_r2_threshold (float): thrshold for purity min r2 qc metrics for filtering credible sets cs_lbf_thr (float): credible set logBF threshold for filtering credible sets, default is 2 + ld_min_r2 (float): Threshold to fillter CS by leads in high LD, default is 0.9 Returns: dict[str, Any] | None: dictionary with study locus, number of GWAS variants, number of LD variants, number of variants after merge, number of outliers, number of imputed variants, number of variants to fine-map, or None @@ -796,6 +835,8 @@ def susie_finemapper_one_sl_row_v4_ss_gathered_boundaries( session=session, studyId=studyId, region=region, + locusStart=int(locusStart), + locusEnd=int(locusEnd), susie_est_tausq=susie_est_tausq, run_carma=run_carma, run_sumstat_imputation=run_sumstat_imputation, @@ -804,11 +845,11 @@ def susie_finemapper_one_sl_row_v4_ss_gathered_boundaries( imputed_r2_threshold=imputed_r2_threshold, ld_score_threshold=ld_score_threshold, sum_pips=sum_pips, - primary_signal_pval_threshold=primary_signal_pval_threshold, - secondary_signal_pval_threshold=secondary_signal_pval_threshold, + lead_pval_threshold=lead_pval_threshold, purity_mean_r2_threshold=purity_mean_r2_threshold, purity_min_r2_threshold=purity_min_r2_threshold, cs_lbf_thr=cs_lbf_thr, + ld_min_r2=ld_min_r2, ) return out diff --git a/tests/gentropy/method/test_susie_inf.py b/tests/gentropy/method/test_susie_inf.py index 91227af0f..4885a3d8a 100644 --- a/tests/gentropy/method/test_susie_inf.py +++ b/tests/gentropy/method/test_susie_inf.py @@ -82,10 +82,12 @@ def test_SUSIE_inf_convert_to_study_locus( variant_index=gwas_df, cs_lbf_thr=2, ld_matrix=ld, - primary_signal_pval_threshold=1, - secondary_signal_pval_threshold=1, + lead_pval_threshold=1, purity_mean_r2_threshold=0, purity_min_r2_threshold=0, sum_pips=0.99, + ld_min_r2=1, + locusStart=1, + locusEnd=2, ) assert isinstance(L1, StudyLocus), "L1 is not an instance of StudyLocus" From 25a4820bfd68b1536dd45db16a9cfac280e9e3d7 Mon Sep 17 00:00:00 2001 From: Yakov Date: Wed, 2 Oct 2024 16:32:13 +0100 Subject: [PATCH 074/188] feat: add sumstat QC fields to schema (#809) * feat: add sumstat QC fields to schema * fix: fix of type * fix: fix for struct --- src/gentropy/assets/schemas/study_index.json | 32 ++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/gentropy/assets/schemas/study_index.json b/src/gentropy/assets/schemas/study_index.json index e18401917..0fe5f253d 100644 --- a/src/gentropy/assets/schemas/study_index.json +++ b/src/gentropy/assets/schemas/study_index.json @@ -256,6 +256,38 @@ "type": "string", "nullable": true, "metadata": {} + }, + { + "name": "sumStatQCPerformed", + "type": "boolean", + "nullable": true, + "metadata": {} + }, + { + "name": "sumStatQCValues", + "type": { + "type": "array", + "elementType": { + "type": "struct", + "fields": [ + { + "name": "QCCheckName", + "type": "string", + "nullable": true, + "metadata": {} + }, + { + "name": "QCCheckValue", + "type": "float", + "nullable": true, + "metadata": {} + } + ] + }, + "containsNull": true + }, + "nullable": true, + "metadata": {} } ] } From 70fd5931c02a30cdfe2df9382bf54d33be4f1e9d Mon Sep 17 00:00:00 2001 From: Tobi Alegbe Date: Thu, 3 Oct 2024 12:01:52 +0100 Subject: [PATCH 075/188] feat: fix biosample study validation (#810) * fix(biosample index): update biosample index validation step to only apply to non-gwas studies * fix(biosample index): revert to dropping * feat(biosample index): update test study index to test biosample index too * feat(biosample index): add biosampleId to study index schema --- src/gentropy/assets/schemas/study_index.json | 6 + src/gentropy/dataset/study_index.py | 6 +- src/gentropy/study_validation.py | 2 +- tests/gentropy/dataset/test_study_index.py | 112 ++++++++++++++----- 4 files changed, 92 insertions(+), 34 deletions(-) diff --git a/src/gentropy/assets/schemas/study_index.json b/src/gentropy/assets/schemas/study_index.json index 0fe5f253d..a2dac1bca 100644 --- a/src/gentropy/assets/schemas/study_index.json +++ b/src/gentropy/assets/schemas/study_index.json @@ -57,6 +57,12 @@ "nullable": true, "metadata": {} }, + { + "name": "biosampleId", + "type": "string", + "nullable": true, + "metadata": {} + }, { "name": "pubmedId", "type": "string", diff --git a/src/gentropy/dataset/study_index.py b/src/gentropy/dataset/study_index.py index 3f9b65097..143396894 100644 --- a/src/gentropy/dataset/study_index.py +++ b/src/gentropy/dataset/study_index.py @@ -417,7 +417,7 @@ def validate_biosample(self: StudyIndex, biosample_index: BiosampleIndex) -> Stu biosample_index (BiosampleIndex): Biosample index containing a reference of biosample identifiers e.g. cell types, tissues, cell lines, etc. Returns: - StudyIndex: with flagged studies if biosampleIndex could not be validated. + StudyIndex: where non-gwas studies are flagged if biosampleIndex could not be validated. """ biosample_set = biosample_index.df.select("biosampleId", f.lit(True).alias("isIdFound")) @@ -426,7 +426,7 @@ def validate_biosample(self: StudyIndex, biosample_index: BiosampleIndex) -> Stu .withColumn( "isIdFound", f.when( - f.col("isIdFound").isNull(), + (f.col("studyType") != "gwas") & (f.col("isIdFound").isNull()), f.lit(False), ).otherwise(f.lit(True)), ) @@ -438,7 +438,7 @@ def validate_biosample(self: StudyIndex, biosample_index: BiosampleIndex) -> Stu StudyQualityCheck.UNKNOWN_BIOSAMPLE, ), ) - .drop("isIdFound").drop("biosampleId") + .drop("isIdFound") ) return StudyIndex(_df=validated_df, _schema=StudyIndex.get_schema()) diff --git a/src/gentropy/study_validation.py b/src/gentropy/study_validation.py index e1337dd00..573298757 100644 --- a/src/gentropy/study_validation.py +++ b/src/gentropy/study_validation.py @@ -66,7 +66,7 @@ def __init__( .validate_study_type() # Flagging non-supported study types. .validate_target(target_index) # Flagging QTL studies with invalid targets .validate_disease(disease_index) # Flagging invalid EFOs - .validate_biosample(biosample_index) # Flagging studies with invalid biosamples + .validate_biosample(biosample_index) # Flagging QTL studies with invalid biosamples ).persist() # we will need this for 2 types of outputs study_index_with_qc.valid_rows( diff --git a/tests/gentropy/dataset/test_study_index.py b/tests/gentropy/dataset/test_study_index.py index fee3a2557..b4e092317 100644 --- a/tests/gentropy/dataset/test_study_index.py +++ b/tests/gentropy/dataset/test_study_index.py @@ -6,6 +6,7 @@ from pyspark.sql import DataFrame, SparkSession from pyspark.sql import functions as f +from gentropy.dataset.biosample_index import BiosampleIndex from gentropy.dataset.gene_index import GeneIndex from gentropy.dataset.study_index import StudyIndex @@ -143,55 +144,82 @@ def test_aggregate_samples_by_ancestry__correctness(spark: SparkSession) -> None ) -class TestGeneValidation: - """A small test suite to ensure the gene validation works as intended.""" +class TestQTLValidation: + """A small test suite to ensure the QTL study validation works as intended.""" GENE_DATA = [ ("ENSG00000102021", "1"), ("ENSG000001020", "1"), ] - GENE_COLUMNS = ["geneId", "chromosome"] + BIOSAMPLE_DATA = [("UBERON_00123", "lung"), ("CL_00321", "monocyte")] + BIOSAMPLE_COLUMNS = ["biosampleId", "biosampleName"] + STUDY_DATA = [ - ("s1", "eqtl", "p", "ENSG00000102021"), + ("s1", "eqtl", "p", "ENSG00000102021", "UBERON_00123"), # This is the only study to be flagged: QTL + Wrong gene - ("s2", "eqtl", "p", "cicaful"), - ("s3", "gwas", "p", None), - ("s4", "gwas", "p", "pocok"), + ("s2", "eqtl", "p", "cicaful", "UBERON_00123"), + # This is the only study to be flagged: QTL + Wrong biosample + ("s3", "sqtl", "p", "ENSG00000102021", "jibberish"), + ("s4", "gwas", "p", None, "anything"), + ("s5", "gwas", "p", "pocok", None), + ] + STUDY_COLUMNS = [ + "studyId", + "studyType", + "projectId", + "geneId", + "biosampleFromSourceId", ] - STUDY_COLUMNS = ["studyId", "studyType", "projectId", "geneId"] @pytest.fixture(autouse=True) - def _setup(self: TestGeneValidation, spark: SparkSession) -> None: + def _setup(self: TestQTLValidation, spark: SparkSession) -> None: """Setup fixture.""" - self.study_index = StudyIndex( - _df=spark.createDataFrame(self.STUDY_DATA, self.STUDY_COLUMNS).withColumn( - "qualityControls", f.array().cast("array") - ), - _schema=StudyIndex.get_schema(), - ) - self.study_index_no_gene = StudyIndex( - _df=spark.createDataFrame(self.STUDY_DATA, self.STUDY_COLUMNS) - .withColumn("qualityControls", f.array().cast("array")) - .drop("geneId"), - _schema=StudyIndex.get_schema(), - ) + def create_study_index(drop_column: str) -> StudyIndex: + df = spark.createDataFrame(self.STUDY_DATA, self.STUDY_COLUMNS) + df = df.withColumn("qualityControls", f.array().cast("array")) + if drop_column != "": + df = df.drop(drop_column) + return StudyIndex(_df=df, _schema=StudyIndex.get_schema()) + + self.study_index = create_study_index("") + self.study_index_no_gene = create_study_index("geneId") + self.study_index_no_biosample_id = create_study_index("biosampleId") self.gene_index = GeneIndex( _df=spark.createDataFrame(self.GENE_DATA, self.GENE_COLUMNS), _schema=GeneIndex.get_schema(), ) + self.biosample_index = BiosampleIndex( + _df=spark.createDataFrame(self.BIOSAMPLE_DATA, self.BIOSAMPLE_COLUMNS), + _schema=BiosampleIndex.get_schema(), + ) - def test_gene_validation_type(self: TestGeneValidation) -> None: - """Testing if the validation runs and returns the expected type.""" + def test_gene_validation_type(self: TestQTLValidation) -> None: + """Testing if the target validation runs and returns the expected type.""" validated = self.study_index.validate_target(self.gene_index) assert isinstance(validated, StudyIndex) - def test_gene_validation_correctness(self: TestGeneValidation) -> None: - """Testing if the gene validation only flags the expected studies.""" - validated = self.study_index.validate_target(self.gene_index).persist() + def test_biosample_validation_type(self: TestQTLValidation) -> None: + """Testing if the biosample validation runs and returns the expected type.""" + validated = self.study_index.validate_biosample(self.biosample_index) + assert isinstance(validated, StudyIndex) + + @pytest.mark.parametrize("gene_or_biosample", ["gene", "biosample"]) + def test_qtl_validation_correctness( + self: TestQTLValidation, gene_or_biosample: str + ) -> None: + """Testing if the QTL validation only flags the expected studies.""" + if gene_or_biosample == "gene": + validated = self.study_index.validate_target(self.gene_index).persist() + bad_study = "s2" + if gene_or_biosample == "biosample": + validated = self.study_index.validate_biosample( + self.biosample_index + ).persist() + bad_study = "s3" # Make sure there's only one flagged: assert validated.df.filter(f.size("qualityControls") != 0).count() == 1 @@ -201,11 +229,27 @@ def test_gene_validation_correctness(self: TestGeneValidation) -> None: 0 ]["studyId"] - assert flagged_study == "s2" + assert flagged_study == bad_study - def test_gene_validation_no_gene_column(self: TestGeneValidation) -> None: - """Testing what happens if no geneId column is present.""" - validated = self.study_index_no_gene.validate_target(self.gene_index) + def test_gene_validation_correctness(self: TestQTLValidation) -> None: + """Testing if the gene validation only flags the expected studies.""" + self.test_qtl_validation_correctness("gene") + + def test_biosample_validation_correctness(self: TestQTLValidation) -> None: + """Testing if the biosample validation only flags the expected studies.""" + self.test_qtl_validation_correctness("biosample") + + @pytest.mark.parametrize("gene_or_biosample", ["gene", "biosample"]) + def test_qtl_validation_no_relevant_column( + self: TestQTLValidation, gene_or_biosample: str + ) -> None: + """Testing what happens if no relevant column is present.""" + if gene_or_biosample == "gene": + validated = self.study_index_no_gene.validate_target(self.gene_index) + if gene_or_biosample == "biosample": + validated = self.study_index_no_biosample_id.validate_biosample( + self.biosample_index + ) # Asserty type: assert isinstance(validated, StudyIndex) @@ -213,6 +257,14 @@ def test_gene_validation_no_gene_column(self: TestGeneValidation) -> None: # Assert count: assert validated.df.count() == self.study_index.df.count() + def test_qtl_validation_no_gene_column(self: TestQTLValidation) -> None: + """Testing what happens if no gene column is present.""" + self.test_qtl_validation_no_relevant_column("gene") + + def test_qtl_validation_no_biosample_column(self: TestQTLValidation) -> None: + """Testing what happens if no biosample column is present.""" + self.test_qtl_validation_no_relevant_column("biosample") + class TestUniquenessValidation: """A small test suite to ensure the gene validation works as intended.""" From c286c3bb14224dd05ff21da7fec27ac07ffe1657 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Irene=20L=C3=B3pez=20Santiago?= <45119610+ireneisdoomed@users.noreply.github.com> Date: Thu, 3 Oct 2024 14:44:36 +0100 Subject: [PATCH 076/188] refactor(vep_parser): store consequence to impact score as a project config (#811) * refactor: set variant functional consequence to pathogenicity score as class attribute * chore: drop `VariantIndex.get_most_severe_gene_consequence` * chore(VariantIndex): make `CONSEQUENCE_TO_PATHOGENICITY_SCORE` a class attribute * fix(vep): convert `id_to_score_map` to `label_to_score_map` * chore: remove comment * refactor: move `consequence_to_pathogenicity_score` to `VariantIndexConfig` --- .../data/variant_consequence_to_score.tsv | 46 ------------- src/gentropy/common/spark_helpers.py | 4 +- src/gentropy/config.py | 64 ++++++++++++++++++- src/gentropy/dataset/variant_index.py | 56 ++-------------- src/gentropy/datasource/ensembl/vep_parser.py | 30 ++++----- tests/gentropy/dataset/test_variant_index.py | 20 +----- 6 files changed, 84 insertions(+), 136 deletions(-) delete mode 100644 src/gentropy/assets/data/variant_consequence_to_score.tsv diff --git a/src/gentropy/assets/data/variant_consequence_to_score.tsv b/src/gentropy/assets/data/variant_consequence_to_score.tsv deleted file mode 100644 index 589a855e6..000000000 --- a/src/gentropy/assets/data/variant_consequence_to_score.tsv +++ /dev/null @@ -1,46 +0,0 @@ -variantFunctionalConsequenceId label score -SO_0001893 transcript_ablation 1.0 -ECO_0000205 curator_inference -SO_0002165 trinucleotide_repeat_expansion -SO_0001574 splice_acceptor_variant 1.0 -SO_0001575 splice_donor_variant 1.0 -SO_0001587 stop_gained 1.0 -SO_0001589 frameshift_variant 1.0 -SO_0002012 start_lost 1.0 -SO_0001578 stop_lost 1.0 -SO_0001889 transcript_amplification 1.0 -SO_0001894 regulatory_region_ablation 0.66 -SO_0001583 missense_variant 0.66 -SO_0001818 protein_altering_variant 0.66 -SO_0001821 inframe_insertion 0.66 -SO_0001822 inframe_deletion 0.66 -SO_0001582 initiator_codon_variant -SO_0001630 splice_region_variant 0.33 -SO_0001626 incomplete_terminal_codon_variant 0.33 -SO_0001567 stop_retained_variant 0.33 -SO_0001819 synonymous_variant 0.33 -SO_0002019 start_retained_variant 0.33 -SO_0001619 non_coding_transcript_variant 0.0 -SO_0001620 mature_miRNA_variant 0.0 -SO_0001621 NMD_transcript_variant 0.1 -SO_0001623 5_prime_UTR_variant 0.1 -SO_0001624 3_prime_UTR_variant 0.1 -SO_0001627 intron_variant 0.1 -SO_0001792 non_coding_transcript_exon_variant 0.0 -SO_0001580 coding_sequence_variant 0.0 -SO_0001566 regulatory_region_variant 0.0 -SO_0001631 upstream_gene_variant 0.0 -SO_0001632 downstream_gene_variant 0.0 -SO_0001782 TF_binding_site_variant 0.0 -SO_0001891 regulatory_region_amplification 0.0 -SO_0001892 TFBS_amplification 0.0 -SO_0001895 TFBS_ablation 0.0 -SO_0001906 feature_truncation 0.0 -SO_0001907 feature_elongation 0.0 -SO_0001628 intergenic_variant 0.0 -SO_0001060 sequence_variant -SO_0001825 conservative_inframe_deletion -SO_0001787 splice_donor_5th_base_variant 0.66 -SO_0002170 splice_donor_region_variant 0.33 -SO_0002169 splice_polypyrimidine_tract_variant 0.33 -SO_0001968 coding_transcript_variant 0.1 diff --git a/src/gentropy/common/spark_helpers.py b/src/gentropy/common/spark_helpers.py index 8f60956e7..fb13763b0 100644 --- a/src/gentropy/common/spark_helpers.py +++ b/src/gentropy/common/spark_helpers.py @@ -447,14 +447,14 @@ def order_array_of_structs_by_two_fields( ) -def map_column_by_dictionary(col: Column, mapping_dict: dict[str, str]) -> Column: +def map_column_by_dictionary(col: Column, mapping_dict: dict[str, Any]) -> Column: """Map column values to dictionary values by key. Missing consequence label will be converted to None, unmapped consequences will be mapped as None. Args: col (Column): Column containing labels to map. - mapping_dict (dict[str, str]): Dictionary with mapping key/value pairs. + mapping_dict (dict[str, Any]): Dictionary with mapping key/value pairs. Returns: Column: Column with mapped values. diff --git a/src/gentropy/config.py b/src/gentropy/config.py index e1068cfa6..532b76e22 100644 --- a/src/gentropy/config.py +++ b/src/gentropy/config.py @@ -2,7 +2,7 @@ import os from dataclasses import dataclass, field -from typing import Any, List +from typing import Any, ClassVar, List, TypedDict from hail import __file__ as hail_location from hydra.core.config_store import ConfigStore @@ -348,11 +348,73 @@ class GnomadVariantConfig(StepConfig): class VariantIndexConfig(StepConfig): """Variant index step configuration.""" + class _ConsequenceToPathogenicityScoreMap(TypedDict): + """Typing definition for CONSEQUENCE_TO_PATHOGENICITY_SCORE.""" + + id: str + label: str + score: float + session: SessionConfig = SessionConfig() vep_output_json_path: str = MISSING variant_index_path: str = MISSING gnomad_variant_annotations_path: str | None = None hash_threshold: int = 300 + consequence_to_pathogenicity_score: ClassVar[ + list[_ConsequenceToPathogenicityScoreMap] + ] = [ + {"id": "SO_0001575", "label": "splice_donor_variant", "score": 1.0}, + {"id": "SO_0001589", "label": "frameshift_variant", "score": 1.0}, + {"id": "SO_0001574", "label": "splice_acceptor_variant", "score": 1.0}, + {"id": "SO_0001587", "label": "stop_gained", "score": 1.0}, + {"id": "SO_0002012", "label": "start_lost", "score": 1.0}, + {"id": "SO_0001578", "label": "stop_lost", "score": 1.0}, + {"id": "SO_0001893", "label": "transcript_ablation", "score": 1.0}, + {"id": "SO_0001822", "label": "inframe_deletion", "score": 0.66}, + { + "id": "SO_0001818", + "label": "protein_altering_variant", + "score": 0.66, + }, + {"id": "SO_0001821", "label": "inframe_insertion", "score": 0.66}, + { + "id": "SO_0001787", + "label": "splice_donor_5th_base_variant", + "score": 0.66, + }, + {"id": "SO_0001583", "label": "missense_variant", "score": 0.66}, + {"id": "SO_0001567", "label": "stop_retained_variant", "score": 0.33}, + {"id": "SO_0001630", "label": "splice_region_variant", "score": 0.33}, + {"id": "SO_0002019", "label": "start_retained_variant", "score": 0.33}, + { + "id": "SO_0002169", + "label": "splice_polypyrimidine_tract_variant", + "score": 0.33, + }, + {"id": "SO_0001819", "label": "synonymous_variant", "score": 0.33}, + { + "id": "SO_0002170", + "label": "splice_donor_region_variant", + "score": 0.33, + }, + {"id": "SO_0001624", "label": "3_prime_UTR_variant", "score": 0.1}, + {"id": "SO_0001623", "label": "5_prime_UTR_variant", "score": 0.1}, + {"id": "SO_0001627", "label": "intron_variant", "score": 0.1}, + { + "id": "SO_0001619", + "label": "non_coding_transcript_variant", + "score": 0.0, + }, + {"id": "SO_0001580", "label": "coding_sequence_variant", "score": 0.0}, + {"id": "SO_0001632", "label": "downstream_gene_variant", "score": 0.0}, + {"id": "SO_0001631", "label": "upstream_gene_variant", "score": 0.0}, + { + "id": "SO_0001792", + "label": "non_coding_transcript_exon_variant", + "score": 0.0, + }, + {"id": "SO_0001620", "label": "mature_miRNA_variant", "score": 0.0}, + ] _target_: str = "gentropy.variant_index.VariantIndexStep" diff --git a/src/gentropy/dataset/variant_index.py b/src/gentropy/dataset/variant_index.py index 4d53d741a..7277d1fb5 100644 --- a/src/gentropy/dataset/variant_index.py +++ b/src/gentropy/dataset/variant_index.py @@ -11,7 +11,6 @@ from gentropy.common.schemas import parse_spark_schema from gentropy.common.spark_helpers import ( get_nested_struct_schema, - get_record_with_maximum_value, rename_all_columns, safe_array_union, ) @@ -22,7 +21,6 @@ from pyspark.sql.types import StructType - @dataclass class VariantIndex(Dataset): """Dataset for representing variants and methods applied on them.""" @@ -130,7 +128,6 @@ def add_annotation( # Prefix for renaming columns: prefix = "annotation_" - # Generate select expressions that to merge and import columns from annotation: select_expressions = [] @@ -146,9 +143,13 @@ def add_annotation( if isinstance(field.dataType.elementType, t.StructType): # Extract the schema of the array to get the order of the fields: array_schema = [ - field for field in VariantIndex.get_schema().fields if field.name == column + field + for field in VariantIndex.get_schema().fields + if field.name == column ][0].dataType - fields_order = get_nested_struct_schema(array_schema).fieldNames() + fields_order = get_nested_struct_schema( + array_schema + ).fieldNames() select_expressions.append( safe_array_union( f.col(column), f.col(f"{prefix}{column}"), fields_order @@ -286,48 +287,3 @@ def get_loftee(self: VariantIndex) -> DataFrame: "isHighQualityPlof", ) ) - - def get_most_severe_gene_consequence( - self: VariantIndex, - *, - vep_consequences: DataFrame, - ) -> DataFrame: - """Returns a dataframe with the most severe consequence for a variant/gene pair. - - Args: - vep_consequences (DataFrame): A dataframe of VEP consequences - - Returns: - DataFrame: A dataframe with the most severe consequence (plus a severity score) for a variant/gene pair - """ - return ( - self.df.select("variantId", f.explode("transcriptConsequences").alias("tc")) - .select( - "variantId", - f.col("tc.targetId"), - f.explode(f.col("tc.variantFunctionalConsequenceIds")).alias( - "variantFunctionalConsequenceId" - ), - ) - .join( - # TODO: make this table a project config - f.broadcast( - vep_consequences.selectExpr( - "variantFunctionalConsequenceId", "score as severityScore" - ) - ), - on="variantFunctionalConsequenceId", - how="inner", - ) - .filter(f.col("severityScore").isNull()) - .transform( - # A variant can have multiple predicted consequences on a transcript, the most severe one is selected - lambda df: get_record_with_maximum_value( - df, ["variantId", "targetId"], "severityScore" - ) - ) - .withColumnRenamed( - "variantFunctionalConsequenceId", - "mostSevereVariantFunctionalConsequenceId", - ) - ) diff --git a/src/gentropy/datasource/ensembl/vep_parser.py b/src/gentropy/datasource/ensembl/vep_parser.py index e3e36140d..6931b96de 100644 --- a/src/gentropy/datasource/ensembl/vep_parser.py +++ b/src/gentropy/datasource/ensembl/vep_parser.py @@ -2,15 +2,12 @@ from __future__ import annotations -import importlib.resources as pkg_resources from typing import TYPE_CHECKING -import pandas as pd from pyspark.sql import SparkSession from pyspark.sql import functions as f from pyspark.sql import types as t -from gentropy.assets import data from gentropy.common.schemas import parse_spark_schema from gentropy.common.spark_helpers import ( enforce_schema, @@ -24,9 +21,12 @@ if TYPE_CHECKING: from pyspark.sql import Column, DataFrame +from gentropy.config import VariantIndexConfig + class VariantEffectPredictorParser: """Collection of methods to parse VEP output in json format.""" + # NOTE: Due to the fact that the comparison of the xrefs is done om the base of rsids # if the field `colocalised_variants` have multiple rsids, this extracting xrefs will result in # an array of xref structs, rather then the struct itself. @@ -568,22 +568,16 @@ def process_vep_output( Returns: DataFrame: processed data in the right shape. """ - so_df = pd.read_csv( - pkg_resources.open_text( - data, "variant_consequence_to_score.tsv", encoding="utf-8" - ), - sep="\t", - ) - - # Reading consequence to sequence ontology map: + # Consequence to sequence ontology map: sequence_ontology_map = { - row["label"]: row["variantFunctionalConsequenceId"] - for _, row in so_df.iterrows() + item["label"]: item["id"] + for item in VariantIndexConfig.consequence_to_pathogenicity_score + } + # Sequence ontology to score map: + label_to_score_map = { + item["label"]: item["score"] + for item in VariantIndexConfig.consequence_to_pathogenicity_score } - - # Reading score dictionary: - score_dictionary = {row["label"]: row["score"] for _, row in so_df.iterrows()} - # Processing VEP output: return ( vep_output @@ -694,7 +688,7 @@ def process_vep_output( f.transform( transcript.consequence_terms, lambda term: map_column_by_dictionary( - term, score_dictionary + term, label_to_score_map ), ) ) diff --git a/tests/gentropy/dataset/test_variant_index.py b/tests/gentropy/dataset/test_variant_index.py index 29a6ef035..15b102415 100644 --- a/tests/gentropy/dataset/test_variant_index.py +++ b/tests/gentropy/dataset/test_variant_index.py @@ -11,7 +11,7 @@ from gentropy.dataset.variant_index import VariantIndex if TYPE_CHECKING: - from pyspark.sql import DataFrame, SparkSession + from pyspark.sql import SparkSession def test_variant_index_creation(mock_variant_index: VariantIndex) -> None: @@ -144,24 +144,6 @@ def test_get_distance_to_gene( for col in expected_cols: assert col in observed.columns, f"Column {col} not in {observed.columns}" - def test_get_most_severe_gene_consequence( - self: TestVariantIndex, - mock_variant_index: VariantIndex, - mock_variant_consequence_to_score: DataFrame, - ) -> None: - """Assert that the function returns a df with the requested columns.""" - expected_cols = [ - "variantId", - "targetId", - "mostSevereVariantFunctionalConsequenceId", - "severityScore", - ] - observed = mock_variant_index.get_most_severe_gene_consequence( - vep_consequences=mock_variant_consequence_to_score - ) - for col in expected_cols: - assert col in observed.columns, f"Column {col} not in {observed.columns}" - def test_get_loftee( self: TestVariantIndex, mock_variant_index: VariantIndex ) -> None: From 8876fc1db5aaeb41d1e961ca24aaac57d17c1a2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Irene=20L=C3=B3pez=20Santiago?= <45119610+ireneisdoomed@users.noreply.github.com> Date: Thu, 3 Oct 2024 17:33:42 +0100 Subject: [PATCH 077/188] feat(l2g): implement variant consequence features from VEP (#805) * feat(variant_index): set variant functional consequence to pathogenicity score as class attribute * feat: add and test vep features * feat: add and test vep neighbourhood features * feat(vep_features): use only protein coding genes to look in the vicinity * chore: update feature list and other bits * fix: docs ref * refactor: set variant functional consequence to pathogenicity score as class attribute * chore: drop `VariantIndex.get_most_severe_gene_consequence` * chore(VariantIndex): make `CONSEQUENCE_TO_PATHOGENICITY_SCORE` a class attribute * fix(vep): convert `id_to_score_map` to `label_to_score_map` * chore: remove comment * chore: access max consequence score from variant index --- docs/python_api/datasets/l2g_features/vep.md | 15 + src/gentropy/config.py | 6 + src/gentropy/dataset/l2g_features/vep.py | 274 +++++++++++++++++++ src/gentropy/dataset/variant_index.py | 2 +- src/gentropy/l2g.py | 9 + src/gentropy/method/l2g/feature_factory.py | 10 + tests/gentropy/conftest.py | 13 - tests/gentropy/dataset/test_l2g_feature.py | 254 +++++++++++++++++ 8 files changed, 569 insertions(+), 14 deletions(-) create mode 100644 docs/python_api/datasets/l2g_features/vep.md create mode 100644 src/gentropy/dataset/l2g_features/vep.py diff --git a/docs/python_api/datasets/l2g_features/vep.md b/docs/python_api/datasets/l2g_features/vep.md new file mode 100644 index 000000000..d2715e977 --- /dev/null +++ b/docs/python_api/datasets/l2g_features/vep.md @@ -0,0 +1,15 @@ +--- +title: From VEP +--- + +## List of features + +::: gentropy.dataset.l2g_features.vep.VepMeanFeature +::: gentropy.dataset.l2g_features.vep.VepMeanNeighbourhoodFeature +::: gentropy.dataset.l2g_features.vep.VepMaximumFeature +::: gentropy.dataset.l2g_features.vep.VepMaximumNeighbourhoodFeature + +## Common logic + +::: gentropy.dataset.l2g_features.vep.common_vep_feature_logic +::: gentropy.dataset.l2g_features.vep.common_neighbourhood_vep_feature_logic diff --git a/src/gentropy/config.py b/src/gentropy/config.py index 532b76e22..6faf59602 100644 --- a/src/gentropy/config.py +++ b/src/gentropy/config.py @@ -238,6 +238,7 @@ class LocusToGeneConfig(StepConfig): variant_index_path: str = MISSING colocalisation_path: str = MISSING study_index_path: str = MISSING + gene_index_path: str = MISSING model_path: str | None = None feature_matrix_path: str | None = None gold_standard_curation_path: str | None = None @@ -264,6 +265,11 @@ class LocusToGeneConfig(StepConfig): "distanceTssMeanNeighbourhood", "distanceSentinelTss", "distanceSentinelTssNeighbourhood", + # vep + "vepMaximum", + "vepMaximumNeighbourhood", + "vepMean", + "vepMeanNeighbourhood", ] ) hyperparameters: dict[str, Any] = field( diff --git a/src/gentropy/dataset/l2g_features/vep.py b/src/gentropy/dataset/l2g_features/vep.py new file mode 100644 index 000000000..13ac05f91 --- /dev/null +++ b/src/gentropy/dataset/l2g_features/vep.py @@ -0,0 +1,274 @@ +"""Collection of methods that extract distance features from the variant index dataset.""" + +from __future__ import annotations + +from typing import TYPE_CHECKING, Any + +import pyspark.sql.functions as f +from pyspark.sql import Window + +from gentropy.common.spark_helpers import convert_from_wide_to_long +from gentropy.dataset.gene_index import GeneIndex +from gentropy.dataset.l2g_features.l2g_feature import L2GFeature +from gentropy.dataset.l2g_gold_standard import L2GGoldStandard +from gentropy.dataset.study_locus import StudyLocus +from gentropy.dataset.variant_index import VariantIndex + +if TYPE_CHECKING: + from pyspark.sql import DataFrame + + +def common_vep_feature_logic( + study_loci_to_annotate: L2GGoldStandard | StudyLocus, + *, + variant_index: VariantIndex, + feature_name: str, +) -> DataFrame: + """Extracts variant severity score computed from VEP. + + Args: + study_loci_to_annotate (L2GGoldStandard | StudyLocus): The dataset containing study loci that will be used for annotation + variant_index (VariantIndex): The dataset containing functional consequence information + feature_name (str): The name of the feature + + Returns: + DataFrame: Feature dataset + """ + # Variant/Target/Severity dataframe + consequences_dataset = variant_index.df.withColumn( + "transcriptConsequence", f.explode("transcriptConsequences") + ).select( + "variantId", + f.col("transcriptConsequence.targetId").alias("geneId"), + f.col("transcriptConsequence.consequenceScore").alias("severityScore"), + ) + if isinstance(study_loci_to_annotate, StudyLocus): + variants_df = ( + study_loci_to_annotate.df.withColumn( + "variantInLocus", f.explode_outer("locus") + ) + .select( + "studyLocusId", + f.col("variantInLocus.variantId").alias("variantId"), + f.col("variantInLocus.posteriorProbability").alias( + "posteriorProbability" + ), + ) + .join(consequences_dataset, "variantId") + ) + elif isinstance(study_loci_to_annotate, L2GGoldStandard): + variants_df = study_loci_to_annotate.df.select( + "studyLocusId", "variantId", f.lit(1.0).alias("posteriorProbability") + ).join(consequences_dataset, "variantId") + + if "Maximum" in feature_name: + agg_expr = f.max("severityScore") + elif "Mean" in feature_name: + variants_df = variants_df.withColumn( + "weightedScore", f.col("severityScore") * f.col("posteriorProbability") + ) + agg_expr = f.mean("weightedScore") + return variants_df.groupBy("studyLocusId", "geneId").agg( + agg_expr.alias(feature_name) + ) + + +def common_neighbourhood_vep_feature_logic( + study_loci_to_annotate: StudyLocus | L2GGoldStandard, + *, + variant_index: VariantIndex, + gene_index: GeneIndex, + feature_name: str, +) -> DataFrame: + """Extracts variant severity score computed from VEP for any gene, based on what is the mean score for protein coding genes that are nearby the locus. + + Args: + study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation + variant_index (VariantIndex): The dataset containing functional consequence information + gene_index (GeneIndex): The dataset containing the gene biotype + feature_name (str): The name of the feature + + Returns: + DataFrame: Feature dataset + """ + local_feature_name = feature_name.replace("Neighbourhood", "") + # First compute mean distances to a gene + local_metric = common_vep_feature_logic( + study_loci_to_annotate, + feature_name=local_feature_name, + variant_index=variant_index, + ) + return ( + # Then compute mean distance in the vicinity (feature will be the same for any gene associated with a studyLocus) + local_metric.join( + # Bring gene classification + gene_index.df.select("geneId", "biotype"), + "geneId", + "inner", + ) + .withColumn( + "regional_metric", + f.coalesce( + # Calculate mean based on protein coding genes + f.mean( + f.when( + f.col("biotype") == "protein_coding", f.col(local_feature_name) + ) + ).over(Window.partitionBy("studyLocusId")), + # Default to 0 if there are no protein coding genes + f.lit(0), + ), + ) + .withColumn(feature_name, f.col(local_feature_name) - f.col("regional_metric")) + .drop("regional_metric", local_feature_name, "biotype") + ) + + +class VepMaximumFeature(L2GFeature): + """Maximum functional consequence score among all variants in a credible set for a studyLocus/gene.""" + + feature_dependency_type = VariantIndex + feature_name = "vepMaximum" + + @classmethod + def compute( + cls: type[VepMaximumFeature], + study_loci_to_annotate: StudyLocus | L2GGoldStandard, + feature_dependency: dict[str, Any], + ) -> VepMaximumFeature: + """Computes the feature. + + Args: + study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation + feature_dependency (dict[str, Any]): Dataset that contains the functional consequence information + + Returns: + VepMaximumFeature: Feature dataset + """ + return cls( + _df=convert_from_wide_to_long( + common_vep_feature_logic( + study_loci_to_annotate=study_loci_to_annotate, + feature_name=cls.feature_name, + **feature_dependency, + ), + id_vars=("studyLocusId", "geneId"), + var_name="featureName", + value_name="featureValue", + ), + _schema=cls.get_schema(), + ) + + +class VepMaximumNeighbourhoodFeature(L2GFeature): + """Maximum functional consequence score among all variants in a credible set for a studyLocus/gene relative to the mean VEP score across all protein coding genes in the vicinity.""" + + feature_dependency_type = [VariantIndex, GeneIndex] + feature_name = "vepMaximumNeighbourhood" + + @classmethod + def compute( + cls: type[VepMaximumNeighbourhoodFeature], + study_loci_to_annotate: StudyLocus | L2GGoldStandard, + feature_dependency: dict[str, Any], + ) -> VepMaximumNeighbourhoodFeature: + """Computes the feature. + + Args: + study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation + feature_dependency (dict[str, Any]): Dataset that contains the functional consequence information + + Returns: + VepMaximumNeighbourhoodFeature: Feature dataset + """ + return cls( + _df=convert_from_wide_to_long( + common_neighbourhood_vep_feature_logic( + study_loci_to_annotate, + feature_name=cls.feature_name, + **feature_dependency, + ), + id_vars=("studyLocusId", "geneId"), + var_name="featureName", + value_name="featureValue", + ), + _schema=cls.get_schema(), + ) + + +class VepMeanFeature(L2GFeature): + """Average functional consequence score among all variants in a credible set for a studyLocus/gene. + + The mean severity score is weighted by the posterior probability of each variant. + """ + + feature_dependency_type = VariantIndex + feature_name = "vepMean" + + @classmethod + def compute( + cls: type[VepMeanFeature], + study_loci_to_annotate: StudyLocus | L2GGoldStandard, + feature_dependency: dict[str, Any], + ) -> VepMeanFeature: + """Computes the feature. + + Args: + study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation + feature_dependency (dict[str, Any]): Dataset that contains the functional consequence information + + Returns: + VepMeanFeature: Feature dataset + """ + return cls( + _df=convert_from_wide_to_long( + common_vep_feature_logic( + study_loci_to_annotate=study_loci_to_annotate, + feature_name=cls.feature_name, + **feature_dependency, + ), + id_vars=("studyLocusId", "geneId"), + var_name="featureName", + value_name="featureValue", + ), + _schema=cls.get_schema(), + ) + + +class VepMeanNeighbourhoodFeature(L2GFeature): + """Mean functional consequence score among all variants in a credible set for a studyLocus/gene relative to the mean VEP score across all protein coding genes in the vicinity. + + The mean severity score is weighted by the posterior probability of each variant. + """ + + feature_dependency_type = [VariantIndex, GeneIndex] + feature_name = "vepMeanNeighbourhood" + + @classmethod + def compute( + cls: type[VepMeanNeighbourhoodFeature], + study_loci_to_annotate: StudyLocus | L2GGoldStandard, + feature_dependency: dict[str, Any], + ) -> VepMeanNeighbourhoodFeature: + """Computes the feature. + + Args: + study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation + feature_dependency (dict[str, Any]): Dataset that contains the functional consequence information + + Returns: + VepMeanNeighbourhoodFeature: Feature dataset + """ + return cls( + _df=convert_from_wide_to_long( + common_neighbourhood_vep_feature_logic( + study_loci_to_annotate, + feature_name=cls.feature_name, + **feature_dependency, + ), + id_vars=("studyLocusId", "geneId"), + var_name="featureName", + value_name="featureValue", + ), + _schema=cls.get_schema(), + ) diff --git a/src/gentropy/dataset/variant_index.py b/src/gentropy/dataset/variant_index.py index 7277d1fb5..a1a2e2a4d 100644 --- a/src/gentropy/dataset/variant_index.py +++ b/src/gentropy/dataset/variant_index.py @@ -1,4 +1,4 @@ -"""Dataset definition for variant annotation.""" +"""Dataset definition for variant index.""" from __future__ import annotations diff --git a/src/gentropy/l2g.py b/src/gentropy/l2g.py index 9b9b7aa90..7962da484 100644 --- a/src/gentropy/l2g.py +++ b/src/gentropy/l2g.py @@ -12,6 +12,7 @@ from gentropy.common.utils import access_gcp_secret from gentropy.config import LocusToGeneConfig from gentropy.dataset.colocalisation import Colocalisation +from gentropy.dataset.gene_index import GeneIndex from gentropy.dataset.l2g_feature_matrix import L2GFeatureMatrix from gentropy.dataset.l2g_gold_standard import L2GGoldStandard from gentropy.dataset.l2g_prediction import L2GPrediction @@ -41,6 +42,7 @@ def __init__( variant_index_path: str | None = None, colocalisation_path: str | None = None, study_index_path: str | None = None, + gene_index_path: str | None = None, gene_interactions_path: str | None = None, predictions_path: str | None = None, feature_matrix_path: str | None = None, @@ -62,6 +64,7 @@ def __init__( variant_index_path (str | None): Path to the variant index dataset colocalisation_path (str | None): Path to the colocalisation dataset study_index_path (str | None): Path to the study index dataset + gene_index_path (str | None): Path to the gene index dataset gene_interactions_path (str | None): Path to the gene interactions dataset predictions_path (str | None): Path to the L2G predictions output dataset feature_matrix_path (str | None): Path to the L2G feature matrix output dataset @@ -108,11 +111,17 @@ def __init__( if colocalisation_path else None ) + self.gene_index = ( + GeneIndex.from_parquet(session, gene_index_path, recursiveFileLookup=True) + if gene_index_path + else None + ) self.features_input_loader = L2GFeatureInputLoader( variant_index=self.variant_index, coloc=self.coloc, studies=self.studies, study_locus=self.credible_set, + gene_index=self.gene_index, ) if run_mode == "predict": diff --git a/src/gentropy/method/l2g/feature_factory.py b/src/gentropy/method/l2g/feature_factory.py index 41084277f..41db44806 100644 --- a/src/gentropy/method/l2g/feature_factory.py +++ b/src/gentropy/method/l2g/feature_factory.py @@ -33,6 +33,12 @@ DistanceTssMeanNeighbourhoodFeature, ) from gentropy.dataset.l2g_features.l2g_feature import L2GFeature +from gentropy.dataset.l2g_features.vep import ( + VepMaximumFeature, + VepMaximumNeighbourhoodFeature, + VepMeanFeature, + VepMeanNeighbourhoodFeature, +) from gentropy.dataset.l2g_gold_standard import L2GGoldStandard from gentropy.dataset.study_locus import StudyLocus @@ -117,6 +123,10 @@ class FeatureFactory: "sQtlColocH4MaximumNeighbourhood": SQtlColocH4MaximumNeighbourhoodFeature, "tuQtlColocH4Maximum": TuQtlColocH4MaximumFeature, "tuQtlColocH4MaximumNeighbourhood": TuQtlColocH4MaximumNeighbourhoodFeature, + "vepMean": VepMeanFeature, + "vepMeanNeighbourhood": VepMeanNeighbourhoodFeature, + "vepMaximum": VepMaximumFeature, + "vepMaximumNeighbourhood": VepMaximumNeighbourhoodFeature, } def __init__( diff --git a/tests/gentropy/conftest.py b/tests/gentropy/conftest.py index a70c1a87d..f977e3f74 100644 --- a/tests/gentropy/conftest.py +++ b/tests/gentropy/conftest.py @@ -250,19 +250,6 @@ def mock_intervals(spark: SparkSession) -> Intervals: return Intervals(_df=data_spec.build(), _schema=interval_schema) -@pytest.fixture() -def mock_variant_consequence_to_score(spark: SparkSession) -> DataFrame: - """Slice of the VEP consequence to score table.""" - return spark.createDataFrame( - [ - ("SO_0001893", "transcript_ablation", 1.0), - ("SO_0001822", "inframe_deletion", 0.66), - ("SO_0001567", "stop_retained_variant", 0.33), - ], - ["variantFunctionalConsequenceId", "label", "score"], - ) - - @pytest.fixture() def mock_variant_index(spark: SparkSession) -> VariantIndex: """Mock variant index.""" diff --git a/tests/gentropy/dataset/test_l2g_feature.py b/tests/gentropy/dataset/test_l2g_feature.py index 18d8a4066..c674280ac 100644 --- a/tests/gentropy/dataset/test_l2g_feature.py +++ b/tests/gentropy/dataset/test_l2g_feature.py @@ -9,6 +9,7 @@ from pyspark.sql.types import ( ArrayType, BooleanType, + FloatType, IntegerType, LongType, StringType, @@ -17,6 +18,7 @@ ) from gentropy.dataset.colocalisation import Colocalisation +from gentropy.dataset.gene_index import GeneIndex from gentropy.dataset.l2g_features.colocalisation import ( EQtlColocClppMaximumFeature, EQtlColocClppMaximumNeighbourhoodFeature, @@ -50,6 +52,14 @@ common_neighbourhood_distance_feature_logic, ) from gentropy.dataset.l2g_features.l2g_feature import L2GFeature +from gentropy.dataset.l2g_features.vep import ( + VepMaximumFeature, + VepMaximumNeighbourhoodFeature, + VepMeanFeature, + VepMeanNeighbourhoodFeature, + common_neighbourhood_vep_feature_logic, + common_vep_feature_logic, +) from gentropy.dataset.study_index import StudyIndex from gentropy.dataset.study_locus import StudyLocus from gentropy.dataset.variant_index import VariantIndex @@ -86,6 +96,10 @@ DistanceSentinelTssNeighbourhoodFeature, DistanceSentinelFootprintFeature, DistanceSentinelFootprintNeighbourhoodFeature, + VepMaximumFeature, + VepMeanFeature, + VepMaximumNeighbourhoodFeature, + VepMeanNeighbourhoodFeature, ], ) def test_feature_factory_return_type( @@ -94,6 +108,7 @@ def test_feature_factory_return_type( mock_colocalisation: Colocalisation, mock_study_index: StudyIndex, mock_variant_index: VariantIndex, + mock_gene_index: GeneIndex, ) -> None: """Test that every feature factory returns a L2GFeature dataset.""" loader = L2GFeatureInputLoader( @@ -101,6 +116,7 @@ def test_feature_factory_return_type( study_index=mock_study_index, variant_index=mock_variant_index, study_locus=mock_study_locus, + gene_index=mock_gene_index, ) feature_dataset = feature_class.compute( study_loci_to_annotate=mock_study_locus, @@ -486,3 +502,241 @@ def _setup(self: TestCommonDistanceFeatureLogic, spark: SparkSession) -> None: ), _schema=VariantIndex.get_schema(), ) + + +class TestCommonVepFeatureLogic: + """Test the common_vep_feature_logic methods.""" + + @pytest.mark.parametrize( + ("feature_name", "expected_data"), + [ + ( + "vepMean", + [ + { + "studyLocusId": "1", + "geneId": "gene1", + "vepMean": "0.33", + }, + { + "studyLocusId": "1", + "geneId": "gene2", + "vepMean": "0.50", + }, + ], + ), + ( + "vepMaximum", + [ + { + "studyLocusId": "1", + "geneId": "gene1", + "vepMaximum": "0.66", + }, + { + "studyLocusId": "1", + "geneId": "gene2", + "vepMaximum": "1.00", + }, + ], + ), + ], + ) + def test_common_vep_feature_logic( + self: TestCommonVepFeatureLogic, + spark: SparkSession, + feature_name: str, + expected_data: dict[str, Any], + ) -> None: + """Test the logic of the function that extracts features from VEP's functional consequences.""" + observed_df = ( + common_vep_feature_logic( + self.sample_study_locus, + variant_index=self.sample_variant_index, + feature_name=feature_name, + ) + .orderBy(feature_name) + .withColumn( + feature_name, f.format_number(f.round(f.col(feature_name), 2), 2) + ) + ) + expected_df = ( + spark.createDataFrame(expected_data) + .orderBy(feature_name) + .select("studyLocusId", "geneId", feature_name) + ) + assert ( + observed_df.collect() == expected_df.collect() + ), f"Expected and observed dataframes are not equal for feature {feature_name}." + + def test_common_neighbourhood_vep_feature_logic_no_protein_coding( + self: TestCommonVepFeatureLogic, + spark: SparkSession, + ) -> None: + """Test the logic of the function that extracts the maximum severity score for a gene given the average of the maximum scores for all protein coding genes in the vicinity. + + Because the genes in the vicinity are all non coding, the neighbourhood features should equal the local ones. + """ + feature_name = "vepMaximumNeighbourhood" + sample_gene_index = GeneIndex( + _df=spark.createDataFrame( + [ + { + "geneId": "gene1", + "biotype": "lncRNA", + "chromosome": "1", + }, + { + "geneId": "gene2", + "biotype": "lncRNA", + "chromosome": "1", + }, + ], + GeneIndex.get_schema(), + ), + _schema=GeneIndex.get_schema(), + ) + observed_df = ( + common_neighbourhood_vep_feature_logic( + self.sample_study_locus, + variant_index=self.sample_variant_index, + gene_index=sample_gene_index, + feature_name=feature_name, + ) + .withColumn(feature_name, f.round(f.col(feature_name), 2)) + .orderBy(f.col(feature_name).asc()) + .select("studyLocusId", "geneId", feature_name) + ) + expected_df = ( + spark.createDataFrame( + (["1", "gene1", 0.66], ["1", "gene2", 1.0]), + ["studyLocusId", "geneId", feature_name], + ) + .orderBy(feature_name) + .select("studyLocusId", "geneId", feature_name) + ) + assert ( + observed_df.collect() == expected_df.collect() + ), "Output doesn't meet the expectation." + + def test_common_neighbourhood_vep_feature_logic( + self: TestCommonVepFeatureLogic, + spark: SparkSession, + ) -> None: + """Test the logic of the function that extracts the maximum severity score for a gene given the average of the maximum scores for all protein coding genes in the vicinity.""" + feature_name = "vepMaximumNeighbourhood" + sample_gene_index = GeneIndex( + _df=spark.createDataFrame( + [ + { + "geneId": "gene1", + "biotype": "protein_coding", + "chromosome": "1", + }, + { + "geneId": "gene2", + "biotype": "lncRNA", + "chromosome": "1", + }, + ], + GeneIndex.get_schema(), + ), + _schema=GeneIndex.get_schema(), + ) + observed_df = ( + common_neighbourhood_vep_feature_logic( + self.sample_study_locus, + variant_index=self.sample_variant_index, + gene_index=sample_gene_index, + feature_name=feature_name, + ) + .withColumn(feature_name, f.round(f.col(feature_name), 2)) + .orderBy(f.col(feature_name).asc()) + ) + expected_df = ( + spark.createDataFrame( + (["1", "gene1", 0.0], ["1", "gene2", 0.34]), + ["studyLocusId", "geneId", feature_name], + ) + .select("studyLocusId", "geneId", feature_name) + .orderBy(feature_name) + ) + assert ( + observed_df.collect() == expected_df.collect() + ), "Output doesn't meet the expectation." + + @pytest.fixture(autouse=True) + def _setup(self: TestCommonVepFeatureLogic, spark: SparkSession) -> None: + """Set up testing fixtures.""" + self.sample_study_locus = StudyLocus( + _df=spark.createDataFrame( + [ + { + "studyLocusId": "1", + "variantId": "var1", + "studyId": "study1", + "locus": [ + { + "variantId": "var1", + "posteriorProbability": 0.5, + }, + ], + "chromosome": "1", + }, + ], + StudyLocus.get_schema(), + ), + _schema=StudyLocus.get_schema(), + ) + self.sample_variant_index = VariantIndex( + _df=spark.createDataFrame( + [ + ( + "var1", + "chrom", + 1, + "A", + "T", + [ + { + "targetId": "gene1", + "consequenceScore": 0.66, + "isEnsemblCanonical": True, + }, + { + "targetId": "gene2", + "consequenceScore": 1.0, + "isEnsemblCanonical": True, + }, + ], + ), + ], + schema=StructType( + [ + StructField("variantId", StringType(), True), + StructField("chromosome", StringType(), True), + StructField("position", IntegerType(), True), + StructField("referenceAllele", StringType(), True), + StructField("alternateAllele", StringType(), True), + StructField( + "transcriptConsequences", + ArrayType( + StructType( + [ + StructField("targetId", StringType(), True), + StructField( + "isEnsemblCanonical", BooleanType(), True + ), + StructField( + "consequenceScore", FloatType(), True + ), + ] + ) + ), + True, + ), + ] + ), + ), + _schema=VariantIndex.get_schema(), + ) From fca55beb702250db1d8e4da893482d3dbb3fdaa5 Mon Sep 17 00:00:00 2001 From: Yakov Date: Thu, 3 Oct 2024 20:53:49 +0100 Subject: [PATCH 078/188] feat: optimisation of qc step (#813) * feat: optimisation of qc step * fix: adding Z2 filter * fix: v1 --- src/gentropy/config.py | 6 ++-- .../method/sumstat_quality_controls.py | 31 ++++--------------- src/gentropy/sumstat_qc_step.py | 2 +- tests/gentropy/method/test_qc_of_sumstats.py | 4 +-- 4 files changed, 13 insertions(+), 30 deletions(-) diff --git a/src/gentropy/config.py b/src/gentropy/config.py index 6faf59602..3ed439333 100644 --- a/src/gentropy/config.py +++ b/src/gentropy/config.py @@ -502,7 +502,7 @@ class FinemapperConfig(StepConfig): @dataclass -class GWASQCStep(StepConfig): +class SummaryStatisticsQCStepConfig(StepConfig): """GWAS QC step configuration.""" gwas_path: str = MISSING @@ -614,7 +614,9 @@ def register_config() -> None: group="step", name="window_based_clumping", node=WindowBasedClumpingStepConfig ) cs.store(group="step", name="susie_finemapping", node=FinemapperConfig) - cs.store(group="step", name="summary_statistics_qc", node=GWASQCStep) + cs.store( + group="step", name="summary_statistics_qc", node=SummaryStatisticsQCStepConfig + ) cs.store( group="step", name="locus_breaker_clumping", node=LocusBreakerClumpingConfig ) diff --git a/src/gentropy/method/sumstat_quality_controls.py b/src/gentropy/method/sumstat_quality_controls.py index 1647851de..eadfc58d6 100644 --- a/src/gentropy/method/sumstat_quality_controls.py +++ b/src/gentropy/method/sumstat_quality_controls.py @@ -69,13 +69,11 @@ def _calculate_logpval(z2: float) -> float: @staticmethod def sumstat_qc_pz_check( gwas_for_qc: SummaryStatistics, - limit: int = 10_000_000, ) -> DataFrame: """The PZ check for QC of GWAS summary statstics. It runs linear regression between reported p-values and p-values infered from z-scores. Args: gwas_for_qc (SummaryStatistics): The instance of the SummaryStatistics class. - limit (int): The limit for the number of variants to be used for the estimation. Returns: DataFrame: PySpark DataFrame with the results of the linear regression for each study. @@ -86,17 +84,10 @@ def sumstat_qc_pz_check( SummaryStatisticsQC._calculate_logpval, t.DoubleType() ) - window = Window.partitionBy("studyId").orderBy("studyId") - - gwas_df = ( - gwas_df.withColumn("row_num", row_number().over(window)) - .filter(f.col("row_num") <= limit) - .drop("row_num") - ) - qc_c = ( - gwas_df.withColumn("zscore", f.col("beta") / f.col("standardError")) - .withColumn("new_logpval", calculate_logpval_udf(f.col("zscore") ** 2)) + gwas_df.withColumn("Z2", (f.col("beta") / f.col("standardError")) ** 2) + .filter(f.col("Z2") <= 100) + .withColumn("new_logpval", calculate_logpval_udf(f.col("Z2"))) .withColumn("log_mantissa", log10("pValueMantissa")) .withColumn( "diffpval", @@ -194,24 +185,16 @@ def sumstat_n_eff_check( @staticmethod def gc_lambda_check( gwas_for_qc: SummaryStatistics, - limit: int = 10_000_000, ) -> DataFrame: """The genomic control lambda check for QC of GWAS summary statstics. Args: gwas_for_qc (SummaryStatistics): The instance of the SummaryStatistics class. - limit (int): The limit for the number of variants to be used for the estimation. Returns: DataFrame: PySpark DataFrame with the genomic control lambda for each study. """ gwas_df = gwas_for_qc._df - window = Window.partitionBy("studyId").orderBy("studyId") - gwas_df = ( - gwas_df.withColumn("row_num", row_number().over(window)) - .filter(f.col("row_num") <= limit) - .drop("row_num") - ) qc_c = ( gwas_df.select("studyId", "beta", "standardError") @@ -254,22 +237,20 @@ def number_of_snps( @staticmethod def get_quality_control_metrics( gwas: SummaryStatistics, - limit: int = 100_000_000, - pval_threshold: float = 5e-8, + pval_threshold: float = 1e-8, ) -> DataFrame: """The function calculates the quality control metrics for the summary statistics. Args: gwas (SummaryStatistics): The instance of the SummaryStatistics class. - limit (int): The limit for the number of variants to be used for the estimation. pval_threshold (float): The threshold for the p-value. Returns: DataFrame: PySpark DataFrame with the quality control metrics for the summary statistics. """ qc1 = SummaryStatisticsQC.sumstat_qc_beta_check(gwas_for_qc=gwas) - qc2 = SummaryStatisticsQC.sumstat_qc_pz_check(gwas_for_qc=gwas, limit=limit) - qc4 = SummaryStatisticsQC.gc_lambda_check(gwas_for_qc=gwas, limit=limit) + qc2 = SummaryStatisticsQC.sumstat_qc_pz_check(gwas_for_qc=gwas) + qc4 = SummaryStatisticsQC.gc_lambda_check(gwas_for_qc=gwas) qc5 = SummaryStatisticsQC.number_of_snps( gwas_for_qc=gwas, pval_threshold=pval_threshold ) diff --git a/src/gentropy/sumstat_qc_step.py b/src/gentropy/sumstat_qc_step.py index 333ab19f3..49ddc3c4a 100644 --- a/src/gentropy/sumstat_qc_step.py +++ b/src/gentropy/sumstat_qc_step.py @@ -30,7 +30,7 @@ def __init__( ( SummaryStatisticsQC.get_quality_control_metrics( - gwas=gwas, limit=100_000_000, pval_threshold=pval_threshold + gwas=gwas, pval_threshold=pval_threshold ) .write.mode(session.write_mode) .parquet(output_path) diff --git a/tests/gentropy/method/test_qc_of_sumstats.py b/tests/gentropy/method/test_qc_of_sumstats.py index 8f63e6ba2..cb8d3443e 100644 --- a/tests/gentropy/method/test_qc_of_sumstats.py +++ b/tests/gentropy/method/test_qc_of_sumstats.py @@ -17,7 +17,7 @@ def test_qc_functions( ) -> None: """Test all sumstat qc functions.""" gwas = sample_summary_statistics.sanity_filter() - QC = SummaryStatisticsQC.get_quality_control_metrics(gwas=gwas, limit=100000) + QC = SummaryStatisticsQC.get_quality_control_metrics(gwas=gwas, pval_threshold=5e-8) QC = QC.toPandas() assert QC["n_variants"].iloc[0] == 1663 @@ -55,7 +55,7 @@ def test_several_studyid( ) gwas._df = gwas_df - QC = SummaryStatisticsQC.get_quality_control_metrics(gwas=gwas, limit=100000) + QC = SummaryStatisticsQC.get_quality_control_metrics(gwas=gwas) QC = QC.toPandas() assert QC.shape == (2, 7) From 68c01689491ac2dba8c0accda9bed5aa64f4cc4f Mon Sep 17 00:00:00 2001 From: Szymon Szyszkowski <69353402+project-defiant@users.noreply.github.com> Date: Fri, 4 Oct 2024 10:40:13 +0200 Subject: [PATCH 079/188] fix(validation): add `qualityControls` column if missing in StudyLocus dataset when perfroming validation (#814) * fix: coalesce qualityControl column in credible set * fix: resolve missing qualityControls column when validating studyLocus * chore: whitespace * chore: use getter to infer qc column name * chore: drop show * chore: drop warnings for step_test(s) --------- Co-authored-by: Szymon Szyszkowski --- .gitignore | 1 + pyproject.toml | 2 +- src/gentropy/common/spark_helpers.py | 29 ++++++++++++++ src/gentropy/dataset/study_locus.py | 15 ++++++- .../finngen/test_finngen_finemapping.py | 40 +++++++++++++++++++ 5 files changed, 84 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index f4c85d797..b62418654 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ site/ .env .coverage* wandb/ +hail*.log diff --git a/pyproject.toml b/pyproject.toml index f61d82116..47829ddcf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -126,7 +126,7 @@ exclude = ["dist"] addopts = "-n auto --doctest-modules --cov=src/ --cov-report=xml" pythonpath = ["."] testpaths = ["tests/gentropy", "src/gentropy"] -marks = ["step_test"] +markers = ["step_test"] # Semi-strict mode for mypy [tool.mypy] diff --git a/src/gentropy/common/spark_helpers.py b/src/gentropy/common/spark_helpers.py index fb13763b0..4e40ac4f1 100644 --- a/src/gentropy/common/spark_helpers.py +++ b/src/gentropy/common/spark_helpers.py @@ -818,3 +818,32 @@ def get_nested_struct_schema(dtype: t.DataType) -> t.StructType: return get_nested_struct_schema(dtype) case _: raise TypeError("The input data type must be a nested struct.") + + +def get_struct_field_schema(schema: t.StructType, name: str) -> t.DataType: + """Get schema for underlying struct field. + + Args: + schema (t.StructType): Provided schema where the name should be looked in. + name (str): Name of the field to look in the schema + + Returns: + t.DataType: Data type of the StructField with provided name + + Raises: + ValueError: If provided name is not present in the input schema + + Examples: + >>> get_struct_field_schema(t.StructType([t.StructField("a", t.StringType())]), "a") + StringType() + + >>> get_struct_field_schema(t.StructType([t.StructField("a", t.StringType())]), "b") # doctest: +IGNORE_EXCEPTION_DETAIL + Traceback (most recent call last): + ... + ValueError: Provided name b is not present in the schema + + """ + matching_fields = [f for f in schema.fields if f.name == name] + if not matching_fields: + raise ValueError("Provided name %s is not present in the schema.", name) + return matching_fields[0].dataType diff --git a/src/gentropy/dataset/study_locus.py b/src/gentropy/dataset/study_locus.py index bf9998458..4d8136c8e 100644 --- a/src/gentropy/dataset/study_locus.py +++ b/src/gentropy/dataset/study_locus.py @@ -14,6 +14,8 @@ from gentropy.common.schemas import parse_spark_schema from gentropy.common.spark_helpers import ( calculate_neglog_pvalue, + create_empty_column_if_not_exists, + get_struct_field_schema, order_array_of_structs_by_field, ) from gentropy.common.utils import get_logsum @@ -271,10 +273,19 @@ def validate_lead_pvalue(self: StudyLocus, pvalue_cutoff: float) -> StudyLocus: Returns: StudyLocus: Updated study locus with quality control flags. """ + df = self.df + qc_colname = StudyLocus.get_QC_column_name() + if qc_colname not in self.df.columns: + df = self.df.withColumn( + qc_colname, + create_empty_column_if_not_exists( + qc_colname, get_struct_field_schema(StudyLocus.get_schema(), qc_colname) + ), + ) return StudyLocus( _df=( - self.df.withColumn( - "qualityControls", + df.withColumn( + qc_colname, # Because this QC might already run on the dataset, the unique set of flags is generated: f.array_distinct( self._qc_subsignificant_associations( diff --git a/tests/gentropy/datasource/finngen/test_finngen_finemapping.py b/tests/gentropy/datasource/finngen/test_finngen_finemapping.py index ed0b68643..1e5d486b7 100644 --- a/tests/gentropy/datasource/finngen/test_finngen_finemapping.py +++ b/tests/gentropy/datasource/finngen/test_finngen_finemapping.py @@ -2,12 +2,16 @@ from __future__ import annotations +from pathlib import Path + import hail as hl import pytest from pyspark.sql import SparkSession +from gentropy.common.session import Session from gentropy.dataset.study_locus import StudyLocus from gentropy.datasource.finngen.finemapping import FinnGenFinemapping +from gentropy.finngen_finemapping_ingestion import FinnGenFinemappingIngestionStep @pytest.mark.parametrize( @@ -43,3 +47,39 @@ def test_finngen_finemapping_from_finngen_susie_finemapping( ), StudyLocus, ) + + +@pytest.mark.parametrize( + [ + "finngen_susie_finemapping_snp_files", + "finngen_susie_finemapping_cs_summary_files", + ], + [ + pytest.param( + "tests/gentropy/data_samples/finngen_R9_AB1_EBV.SUSIE.snp.gz", + "tests/gentropy/data_samples/finngen_credset_summary_sample.tsv", + id="non block compressed files", + ), + ], +) +@pytest.mark.step_test +def test_finngen_finemapping_ingestion_step( + session: Session, + finngen_susie_finemapping_snp_files: str, + finngen_susie_finemapping_cs_summary_files: str, + tmp_path: Path, +) -> None: + """Test finngen finemapping ingestion step.""" + output_path = tmp_path / "output" + FinnGenFinemappingIngestionStep( + session=session, + finngen_finemapping_out=str(output_path), + finngen_susie_finemapping_cs_summary_files=finngen_susie_finemapping_cs_summary_files, + finngen_susie_finemapping_snp_files=finngen_susie_finemapping_snp_files, + finngen_finemapping_lead_pvalue_threshold=1e-5, + ) + assert output_path.is_dir() + assert (output_path / "_SUCCESS").exists() + + cs = StudyLocus.from_parquet(session=session, path=str(output_path)) + assert cs.df.count() == 1 From b325eaad487ae7729db431d7314565b07e2882fa Mon Sep 17 00:00:00 2001 From: Yakov Date: Fri, 4 Oct 2024 13:46:24 +0100 Subject: [PATCH 080/188] fix: fix of type error in schema checking (#817) * fix: fix of type error in schma checking * fix: fix fix fix --- src/gentropy/method/locus_breaker_clumping.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/gentropy/method/locus_breaker_clumping.py b/src/gentropy/method/locus_breaker_clumping.py index fd7661a22..3ab1e605a 100644 --- a/src/gentropy/method/locus_breaker_clumping.py +++ b/src/gentropy/method/locus_breaker_clumping.py @@ -111,9 +111,7 @@ def locus_breaker( f.lit(None) .cast(t.ArrayType(t.StringType())) .alias("qualityControls"), - StudyLocus.assign_study_locus_id( - ["studyId", "variantId"] - ), + StudyLocus.assign_study_locus_id(["studyId", "variantId"]), ) ), _schema=StudyLocus.get_schema(), @@ -135,6 +133,7 @@ def process_locus_breaker_output( Returns: StudyLocus: clumped study loci with large loci broken by window-based clumping. """ + large_loci_size = int(large_loci_size) small_loci = lbc.filter( (f.col("locusEnd") - f.col("locusStart")) <= large_loci_size ) From 99b1d3c09c10bf753d1daf35f6eec1a12a0e576d Mon Sep 17 00:00:00 2001 From: Yakov Date: Fri, 4 Oct 2024 15:04:30 +0100 Subject: [PATCH 081/188] fix: adding studId to FM log (#816) --- src/gentropy/susie_finemapper.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/gentropy/susie_finemapper.py b/src/gentropy/susie_finemapper.py index 1379ad89b..38a621f96 100644 --- a/src/gentropy/susie_finemapper.py +++ b/src/gentropy/susie_finemapper.py @@ -590,6 +590,8 @@ def susie_finemapper_from_prepared_dataframes( log_df = pd.DataFrame( { + "studyId": studyId, + "region": region, "N_gwas_before_dedupl": N_gwas_before_dedupl, "N_gwas": N_gwas, "N_ld": N_ld, From 8b291687973d1a4c30d82958831f173d74f825e5 Mon Sep 17 00:00:00 2001 From: Tobi Alegbe Date: Mon, 7 Oct 2024 15:53:37 +0100 Subject: [PATCH 082/188] fix: biosample id duplication (#822) * fix(biosample_index): remove biosampleId column if present in validation and tests * fix(biosample index): update tests for biosample index --- src/gentropy/dataset/study_index.py | 8 +++ tests/gentropy/dataset/test_study_index.py | 83 ++++++++++++++++------ 2 files changed, 70 insertions(+), 21 deletions(-) diff --git a/src/gentropy/dataset/study_index.py b/src/gentropy/dataset/study_index.py index 143396894..e7023ee9b 100644 --- a/src/gentropy/dataset/study_index.py +++ b/src/gentropy/dataset/study_index.py @@ -421,6 +421,14 @@ def validate_biosample(self: StudyIndex, biosample_index: BiosampleIndex) -> Stu """ biosample_set = biosample_index.df.select("biosampleId", f.lit(True).alias("isIdFound")) + # If biosampleId in df, we need to drop it: + if "biosampleId" in self.df.columns: + self.df = self.df.drop("biosampleId") + + # As the biosampleFromSourceId is not a mandatory field of study index, we return if the column is not there: + if "biosampleFromSourceId" not in self.df.columns: + return self + validated_df = ( self.df.join(biosample_set, self.df.biosampleFromSourceId == biosample_set.biosampleId, how="left") .withColumn( diff --git a/tests/gentropy/dataset/test_study_index.py b/tests/gentropy/dataset/test_study_index.py index b4e092317..303642d5e 100644 --- a/tests/gentropy/dataset/test_study_index.py +++ b/tests/gentropy/dataset/test_study_index.py @@ -186,7 +186,7 @@ def create_study_index(drop_column: str) -> StudyIndex: self.study_index = create_study_index("") self.study_index_no_gene = create_study_index("geneId") - self.study_index_no_biosample_id = create_study_index("biosampleId") + self.study_index_no_biosample_id = create_study_index("biosampleFromSourceId") self.gene_index = GeneIndex( _df=spark.createDataFrame(self.GENE_DATA, self.GENE_COLUMNS), @@ -207,15 +207,13 @@ def test_biosample_validation_type(self: TestQTLValidation) -> None: validated = self.study_index.validate_biosample(self.biosample_index) assert isinstance(validated, StudyIndex) - @pytest.mark.parametrize("gene_or_biosample", ["gene", "biosample"]) - def test_qtl_validation_correctness( - self: TestQTLValidation, gene_or_biosample: str - ) -> None: + @pytest.mark.parametrize("test", ["gene", "biosample"]) + def test_qtl_validation_correctness(self: TestQTLValidation, test: str) -> None: """Testing if the QTL validation only flags the expected studies.""" - if gene_or_biosample == "gene": + if test == "gene": validated = self.study_index.validate_target(self.gene_index).persist() bad_study = "s2" - if gene_or_biosample == "biosample": + if test == "biosample": validated = self.study_index.validate_biosample( self.biosample_index ).persist() @@ -239,17 +237,35 @@ def test_biosample_validation_correctness(self: TestQTLValidation) -> None: """Testing if the biosample validation only flags the expected studies.""" self.test_qtl_validation_correctness("biosample") - @pytest.mark.parametrize("gene_or_biosample", ["gene", "biosample"]) - def test_qtl_validation_no_relevant_column( - self: TestQTLValidation, gene_or_biosample: str + @pytest.mark.parametrize( + "drop,test", + [ + ("gene", "gene"), + ("gene", "biosample"), + ("biosample", "biosample"), + ("biosample", "gene"), + ], + ) + def test_qtl_validation_drop_relevant_column( + self: TestQTLValidation, drop: str, test: str ) -> None: - """Testing what happens if no relevant column is present.""" - if gene_or_biosample == "gene": - validated = self.study_index_no_gene.validate_target(self.gene_index) - if gene_or_biosample == "biosample": - validated = self.study_index_no_biosample_id.validate_biosample( - self.biosample_index - ) + """Testing what happens if an expected column is not present.""" + if drop == "gene": + if test == "gene": + validated = self.study_index_no_gene.validate_target(self.gene_index) + if test == "biosample": + validated = self.study_index_no_gene.validate_biosample( + self.biosample_index + ) + if drop == "biosample": + if test == "gene": + validated = self.study_index_no_biosample_id.validate_target( + self.gene_index + ) + if test == "biosample": + validated = self.study_index_no_biosample_id.validate_biosample( + self.biosample_index + ) # Asserty type: assert isinstance(validated, StudyIndex) @@ -259,11 +275,36 @@ def test_qtl_validation_no_relevant_column( def test_qtl_validation_no_gene_column(self: TestQTLValidation) -> None: """Testing what happens if no gene column is present.""" - self.test_qtl_validation_no_relevant_column("gene") + self.test_qtl_validation_drop_relevant_column(test="gene", drop="gene") + + def test_qtl_validation_no_biosample_from_source_column( + self: TestQTLValidation, + ) -> None: + """Testing what happens if no biosampleFromSourceId column is present.""" + self.test_qtl_validation_drop_relevant_column( + test="biosample", drop="biosample" + ) - def test_qtl_validation_no_biosample_column(self: TestQTLValidation) -> None: - """Testing what happens if no biosample column is present.""" - self.test_qtl_validation_no_relevant_column("biosample") + def test_qtl_validation_existing_gene_column(self: TestQTLValidation) -> None: + """Testing what happens if no gene column is present.""" + self.test_qtl_validation_drop_relevant_column(test="gene", drop="biosample") + + def test_qtl_validation_existing_biosample_from_source_column( + self: TestQTLValidation, + ) -> None: + """Testing what happens if a biosampleFromSourceId column is present.""" + self.test_qtl_validation_drop_relevant_column(test="biosample", drop="gene") + + def test_qtl_validation_existing_biosample_column(self: TestQTLValidation) -> None: + """Testing what happens if a biosampleId column is present in study index as well as biosampleFromSourceId.""" + # Append a biosample column filled with null to the self.study_index then validate: + validated = StudyIndex( + _df=self.study_index.df.withColumn( + "biosampleId", f.lit(None).cast("string") + ), + _schema=StudyIndex.get_schema(), + ).validate_biosample(self.biosample_index) + assert isinstance(validated, StudyIndex) class TestUniquenessValidation: From 27d82065492e2668a537460917fc127a8cf47a19 Mon Sep 17 00:00:00 2001 From: Vivien Ho <56025826+vivienho@users.noreply.github.com> Date: Tue, 8 Oct 2024 15:18:35 +0100 Subject: [PATCH 083/188] feat: change LD annotation for PICS fine-mapping to use major ancestry (#821) * feat: add functions to get the major population and calculate r2 * refactor: remove functions not needed anymore * refactor: change r2Overall to r2Major * test: add tests for both of the added functions * test: remove tests no longer needed * revert: change r2Major back to r2Overall --- src/gentropy/method/ld.py | 114 ++++++++++--------- tests/gentropy/method/test_ld.py | 185 +++++++++++++++++++++++++++---- 2 files changed, 228 insertions(+), 71 deletions(-) diff --git a/src/gentropy/method/ld.py b/src/gentropy/method/ld.py index 68b78b103..64d47451d 100644 --- a/src/gentropy/method/ld.py +++ b/src/gentropy/method/ld.py @@ -6,6 +6,7 @@ from pyspark.sql import functions as f +from gentropy.common.spark_helpers import order_array_of_structs_by_field from gentropy.dataset.study_locus import StudyLocus, StudyLocusQualityCheck if TYPE_CHECKING: @@ -19,60 +20,64 @@ class LDAnnotator: """Class to annotate linkage disequilibrium (LD) operations from GnomAD.""" @staticmethod - def _calculate_weighted_r_overall(ld_set: Column) -> Column: - """Aggregation of weighted R information using ancestry proportions. + def _get_major_population(ordered_populations: Column) -> Column: + """Get major population based on an ldPopulationStructure array ordered by relativeSampleSize. + + If there is a tie for the major population, nfe is selected if it is one of the major populations. + The first population in the array is selected if there is no tie for the major population, or there is a tie but nfe is not one of the major populations. Args: - ld_set (Column): LD set + ordered_populations (Column): ldPopulationStructure array ordered by relativeSampleSize Returns: - Column: LD set with added 'r2Overall' field + Column: major population """ - return f.transform( - ld_set, - lambda x: f.struct( - x["tagVariantId"].alias("tagVariantId"), - # r2Overall is the accumulated sum of each r2 relative to the population size - f.aggregate( - x["rValues"], - f.lit(0.0), - lambda acc, y: acc - + f.coalesce( - f.pow(y["r"], 2) * y["relativeSampleSize"], f.lit(0.0) - ), # we use coalesce to avoid problems when r/relativeSampleSize is null - ).alias("r2Overall"), - ), + major_population_size = ordered_populations["relativeSampleSize"][0] + major_populations = f.filter( + ordered_populations, + lambda x: x["relativeSampleSize"] == major_population_size + ) + # Check if nfe (Non-Finnish European) is one of the major populations + has_nfe = f.filter( + major_populations, + lambda x: x["ldPopulation"] == "nfe" + ) + return f.when( + (f.size(major_populations) > 1) & (f.size(has_nfe) == 1), + f.lit("nfe") + ).otherwise( + ordered_populations["ldPopulation"][0] ) @staticmethod - def _add_population_size(ld_set: Column, study_populations: Column) -> Column: - """Add population size to each rValues entry in the ldSet. + def _calculate_r2_major(ld_set: Column, major_population: Column) -> Column: + """Calculate R2 using R of the major population in the study. Args: ld_set (Column): LD set - study_populations (Column): Study populations + major_population (Column): Major population of the study Returns: - Column: LD set with added 'relativeSampleSize' field + Column: LD set with added 'r2Overall' field """ - # Create a population to relativeSampleSize map from the struct - populations_map = f.map_from_arrays( - study_populations["ldPopulation"], - study_populations["relativeSampleSize"], - ) - return f.transform( + ld_set_with_major_pop = f.transform( ld_set, lambda x: f.struct( x["tagVariantId"].alias("tagVariantId"), - f.transform( + f.filter( x["rValues"], - lambda y: f.struct( - y["population"].alias("population"), - y["r"].alias("r"), - populations_map[y["population"]].alias("relativeSampleSize"), - ), - ).alias("rValues"), - ), + lambda y: y["population"] == major_population + ).alias("rValues") + ) + ) + return f.transform( + ld_set_with_major_pop, + lambda x: f.struct( + x["tagVariantId"].alias("tagVariantId"), + f.coalesce( + f.pow(x["rValues"]["r"][0], 2), f.lit(0.0) + ).alias("r2Overall") + ) ) @staticmethod @@ -126,10 +131,10 @@ def ld_annotate( """Annotate linkage disequilibrium (LD) information to a set of studyLocus. This function: - 1. Annotates study locus with population structure information from the study index + 1. Annotates study locus with population structure information ordered by relativeSampleSize from the study index 2. Joins the LD index to the StudyLocus - 3. Adds the population size of the study to each rValues entry in the ldSet - 4. Calculates the overall R weighted by the ancestry proportions in every given study. + 3. Gets the major population from the population structure + 4. Calculates R2 by using the R of the major ancestry 5. Flags associations with variants that are not found in the LD reference 6. Rescues lead variant when no LD information is available but lead variant is available @@ -150,9 +155,14 @@ def ld_annotate( associations.df # Drop ldSet column if already available .select(*[col for col in associations.df.columns if col != "ldSet"]) - # Annotate study locus with population structure from study index + # Annotate study locus with population structure ordered by relativeSampleSize from study index .join( - studies.df.select("studyId", "ldPopulationStructure"), + studies.df.select( + "studyId", + order_array_of_structs_by_field( + "ldPopulationStructure", "relativeSampleSize" + ).alias("ldPopulationStructure") + ), on="studyId", how="left", ) @@ -162,25 +172,27 @@ def ld_annotate( on=["variantId", "chromosome"], how="left", ) - # Add population size to each rValues entry in the ldSet if population structure available: + # Get major population from population structure if population structure available .withColumn( - "ldSet", + "majorPopulation", f.when( f.col("ldPopulationStructure").isNotNull(), - cls._add_population_size( - f.col("ldSet"), f.col("ldPopulationStructure") - ), - ), + cls._get_major_population( + f.col("ldPopulationStructure") + ) + ) ) - # Aggregate weighted R information using ancestry proportions + # Calculate R2 using R of the major population .withColumn( "ldSet", f.when( f.col("ldPopulationStructure").isNotNull(), - cls._calculate_weighted_r_overall(f.col("ldSet")), - ), + cls._calculate_r2_major( + f.col("ldSet"), f.col("majorPopulation") + ) + ) ) - .drop("ldPopulationStructure") + .drop("ldPopulationStructure", "majorPopulation") # Filter the LD set by the R2 threshold and set to null if no LD information passes the threshold .withColumn( "ldSet", diff --git a/tests/gentropy/method/test_ld.py b/tests/gentropy/method/test_ld.py index 8fb86ff31..7e7237ac9 100644 --- a/tests/gentropy/method/test_ld.py +++ b/tests/gentropy/method/test_ld.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Any import pyspark.sql.functions as f import pyspark.sql.types as t @@ -22,32 +22,177 @@ class TestLDAnnotator: """Test LDAnnotatorGnomad.""" - def test__add_population_size( + @pytest.mark.parametrize( + ("observed", "expected"), + [ + # no tie in relativeSampleSize + ( + # observed ldPopulationStructure + [ + Row( + ldPopulationStructure=[ + {"ldPopulation": "pop1", "relativeSampleSize": 0.5}, + {"ldPopulation": "pop2", "relativeSampleSize": 0.3}, + {"ldPopulation": "pop3", "relativeSampleSize": 0.2}, + ], + ) + ], + # expected majorPopulation + "pop1", + ), + # tie in relativeSampleSize, "nfe" is not one of the tied populations + ( + # observed ldPopulationStructure + [ + Row( + ldPopulationStructure=[ + {"ldPopulation": "pop1", "relativeSampleSize": 0.4}, + {"ldPopulation": "pop2", "relativeSampleSize": 0.4}, + {"ldPopulation": "pop3", "relativeSampleSize": 0.2}, + ], + ) + ], + # expected majorPopulation + "pop1", + ), + # tie in relativeSampleSize, "nfe" is one of the tied populations + ( + # observed ldPopulationStructure + [ + Row( + ldPopulationStructure=[ + {"ldPopulation": "pop1", "relativeSampleSize": 0.4}, + {"ldPopulation": "nfe", "relativeSampleSize": 0.4}, + {"ldPopulation": "pop3", "relativeSampleSize": 0.2}, + ], + ) + ], + # expected majorPopulation + "nfe", + ), + ], + ) + def test__get_major_population( self: TestLDAnnotator, + spark: SparkSession, + observed: list[Any], + expected: list[Any], ) -> None: - """Test _add_population_size.""" - result_df = self.observed_df.select( - LDAnnotator._add_population_size( - f.col("ldSet"), f.col("ldPopulationStructure") - ).alias("ldSet") + """Test _get_major_population.""" + schema = t.StructType( + [ + t.StructField( + "ldPopulationStructure", + t.ArrayType( + t.StructType( + [ + t.StructField("ldPopulation", t.StringType(), True), + t.StructField( + "relativeSampleSize", t.DoubleType(), True + ), + ] + ) + ), + True, + ), + ] + ) + observed_df = spark.createDataFrame(observed, schema) + result_df = observed_df.withColumn( + "majorPopulation", + LDAnnotator._get_major_population(f.col("ldPopulationStructure")), ) - expected = [0.8, None] - for i, row in enumerate(result_df.collect()): - assert row["ldSet"][0]["rValues"][i]["relativeSampleSize"] == pytest.approx( - expected[i] - ) + assert result_df.collect()[0]["majorPopulation"] == pytest.approx(expected) - def test__calculate_weighted_r_overall( + @pytest.mark.parametrize( + ("observed", "expected"), + [ + # r available for majorPopulation + ( + # observed ldSet and majorPopulation + [ + Row( + majorPopulation="pop1", + ldSet=[ + { + "tagVariantId": "tag1", + "rValues": [ + {"population": "pop1", "r": 0.5}, + {"population": "pop2", "r": 0.6}, + ], + } + ], + ) + ], + # expected r2Overall + 0.25, + ), + # r not available for majorPopulation + ( + # observed ldSet and majorPopulation + [ + Row( + majorPopulation="pop3", + ldSet=[ + { + "tagVariantId": "tag1", + "rValues": [ + {"population": "pop1", "r": 0.5}, + {"population": "pop2", "r": 0.6}, + ], + } + ], + ) + ], + # expected r2Overall + 0.0, + ), + ], + ) + def test__calculate_r2_major( self: TestLDAnnotator, + spark: SparkSession, + observed: list[Any], + expected: list[Any], ) -> None: - """Test _calculate_weighted_r_overall.""" - result_df = self.observed_df.withColumn( + """Test _calculate_r2_major.""" + schema = t.StructType( + [ + t.StructField("majorPopulation", t.StringType(), True), + t.StructField( + "ldSet", + t.ArrayType( + t.StructType( + [ + t.StructField("tagVariantId", t.StringType(), True), + t.StructField( + "rValues", + t.ArrayType( + t.StructType( + [ + t.StructField( + "population", t.StringType(), True + ), + t.StructField( + "r", t.DoubleType(), True + ), + ] + ) + ), + True, + ), + ] + ) + ), + True, + ), + ] + ) + observed_df = spark.createDataFrame(observed, schema) + result_df = observed_df.withColumn( "ldSet", - LDAnnotator._add_population_size( - f.col("ldSet"), f.col("ldPopulationStructure") - ), - ).withColumn("ldSet", LDAnnotator._calculate_weighted_r_overall(f.col("ldSet"))) - expected = 0.2 + LDAnnotator._calculate_r2_major(f.col("ldSet"), f.col("majorPopulation")), + ) assert result_df.collect()[0]["ldSet"][0]["r2Overall"] == pytest.approx( expected ) From f3490d3e28590e5c771d01bf80859427c632a381 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 8 Oct 2024 15:59:46 +0100 Subject: [PATCH 084/188] build(deps-dev): bump ipython from 8.27.0 to 8.28.0 (#819) Bumps [ipython](https://github.com/ipython/ipython) from 8.27.0 to 8.28.0. - [Release notes](https://github.com/ipython/ipython/releases) - [Commits](https://github.com/ipython/ipython/compare/8.27.0...8.28.0) --- updated-dependencies: - dependency-name: ipython dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Szymon Szyszkowski <69353402+project-defiant@users.noreply.github.com> --- poetry.lock | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/poetry.lock b/poetry.lock index bf854b313..d70e16e9f 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1899,13 +1899,13 @@ test = ["flaky", "ipyparallel", "pre-commit", "pytest (>=7.0)", "pytest-asyncio [[package]] name = "ipython" -version = "8.27.0" +version = "8.28.0" description = "IPython: Productive Interactive Computing" optional = false python-versions = ">=3.10" files = [ - {file = "ipython-8.27.0-py3-none-any.whl", hash = "sha256:f68b3cb8bde357a5d7adc9598d57e22a45dfbea19eb6b98286fa3b288c9cd55c"}, - {file = "ipython-8.27.0.tar.gz", hash = "sha256:0b99a2dc9f15fd68692e898e5568725c6d49c527d36a9fb5960ffbdeaa82ff7e"}, + {file = "ipython-8.28.0-py3-none-any.whl", hash = "sha256:530ef1e7bb693724d3cdc37287c80b07ad9b25986c007a53aa1857272dac3f35"}, + {file = "ipython-8.28.0.tar.gz", hash = "sha256:0d0d15ca1e01faeb868ef56bc7ee5a0de5bd66885735682e8a322ae289a13d1a"}, ] [package.dependencies] @@ -3952,6 +3952,7 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, From 60f6bfa25036963790d3fe64bfaed50dc9a86a38 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 9 Oct 2024 11:17:13 +0100 Subject: [PATCH 085/188] build(deps-dev): bump pre-commit from 3.8.0 to 4.0.0 (#820) Bumps [pre-commit](https://github.com/pre-commit/pre-commit) from 3.8.0 to 4.0.0. - [Release notes](https://github.com/pre-commit/pre-commit/releases) - [Changelog](https://github.com/pre-commit/pre-commit/blob/main/CHANGELOG.md) - [Commits](https://github.com/pre-commit/pre-commit/compare/v3.8.0...v4.0.0) --- updated-dependencies: - dependency-name: pre-commit dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- poetry.lock | 8 ++++---- pyproject.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/poetry.lock b/poetry.lock index d70e16e9f..9cdc7b88e 100644 --- a/poetry.lock +++ b/poetry.lock @@ -3321,13 +3321,13 @@ tests = ["pytest (>=5.4.1)", "pytest-cov (>=2.8.1)", "pytest-mypy (>=0.8.0)", "p [[package]] name = "pre-commit" -version = "3.8.0" +version = "4.0.0" description = "A framework for managing and maintaining multi-language pre-commit hooks." optional = false python-versions = ">=3.9" files = [ - {file = "pre_commit-3.8.0-py2.py3-none-any.whl", hash = "sha256:9a90a53bf82fdd8778d58085faf8d83df56e40dfe18f45b19446e26bf1b3a63f"}, - {file = "pre_commit-3.8.0.tar.gz", hash = "sha256:8bb6494d4a20423842e198980c9ecf9f96607a07ea29549e180eef9ae80fe7af"}, + {file = "pre_commit-4.0.0-py2.py3-none-any.whl", hash = "sha256:0ca2341cf94ac1865350970951e54b1a50521e57b7b500403307aed4315a1234"}, + {file = "pre_commit-4.0.0.tar.gz", hash = "sha256:5d9807162cc5537940f94f266cbe2d716a75cfad0d78a317a92cac16287cfed6"}, ] [package.dependencies] @@ -5219,4 +5219,4 @@ multidict = ">=4.0" [metadata] lock-version = "2.0" python-versions = "^3.10, <3.11" -content-hash = "50a797b217805183c5967246c1ca4b339037ce60e44a6c43b5c3fc6a9fb2832a" +content-hash = "e786d680aaa9f4a57bfc91fc2a18002199156ccc840c52e372171026506cdf04" diff --git a/pyproject.toml b/pyproject.toml index 47829ddcf..6f0e2e919 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,7 +36,7 @@ skops = ">=0.9,<0.11" google-cloud-secret-manager = "^2.20.0" [tool.poetry.dev-dependencies] -pre-commit = "^3.8.0" +pre-commit = "^4.0.0" mypy = "^1.11" pep8-naming = "^0.14.1" interrogate = "^1.7.0" From b7dce8f48cf4780ec15eb00083988e7bb3e66516 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Irene=20L=C3=B3pez=20Santiago?= <45119610+ireneisdoomed@users.noreply.github.com> Date: Wed, 9 Oct 2024 15:33:29 +0100 Subject: [PATCH 086/188] feat: decouple feature generation from L2G training step (#823) * fix: join between gold standard and credible set based on studyId and variantId * fix: minor bugs to generate the feature matrix * fix(colocalisation): safeguard existing rightStudyType when applying `append_study_metadata` * feat: add feature generation step (working interactively) * feat(l2g): remove feature generation from `LocusToGeneStep` * fix: correct feature names * feat: filter gwas credible sets in `L2GPrediction.from_credible_set` * chore: update docs * chore: pass credible set to `L2GGoldStandard.build_feature_matrix` in test * chore: uncomment code --- docs/python_api/steps/l2g.md | 4 +- src/gentropy/config.py | 60 +++++- src/gentropy/dataset/colocalisation.py | 14 +- src/gentropy/dataset/l2g_features/distance.py | 4 +- src/gentropy/dataset/l2g_gold_standard.py | 15 +- src/gentropy/dataset/l2g_prediction.py | 17 +- src/gentropy/l2g.py | 196 +++++++++--------- .../open_targets/test_l2g_gold_standard.py | 3 +- 8 files changed, 195 insertions(+), 118 deletions(-) diff --git a/docs/python_api/steps/l2g.md b/docs/python_api/steps/l2g.md index 847569e36..556e5a275 100644 --- a/docs/python_api/steps/l2g.md +++ b/docs/python_api/steps/l2g.md @@ -1,5 +1,7 @@ --- -title: locus_to_gene +title: Locus to Gene (L2G) --- +::: gentropy.l2g.LocusToGeneFeatureMatrixStep + ::: gentropy.l2g.LocusToGeneStep diff --git a/src/gentropy/config.py b/src/gentropy/config.py index 3ed439333..798a6b7bf 100644 --- a/src/gentropy/config.py +++ b/src/gentropy/config.py @@ -236,9 +236,6 @@ class LocusToGeneConfig(StepConfig): predictions_path: str = MISSING credible_set_path: str = MISSING variant_index_path: str = MISSING - colocalisation_path: str = MISSING - study_index_path: str = MISSING - gene_index_path: str = MISSING model_path: str | None = None feature_matrix_path: str | None = None gold_standard_curation_path: str | None = None @@ -282,10 +279,60 @@ class LocusToGeneConfig(StepConfig): wandb_run_name: str | None = None hf_hub_repo_id: str | None = "opentargets/locus_to_gene" download_from_hub: bool = True - write_feature_matrix: bool = True _target_: str = "gentropy.l2g.LocusToGeneStep" +@dataclass +class LocusToGeneFeatureMatrixConfig(StepConfig): + """Locus to gene feature matrix step configuration.""" + + session: Any = field( + default_factory=lambda: { + "extended_spark_conf": { + "spark.driver.memory": "48g", + "spark.executor.memory": "48g", + "spark.sql.shuffle.partitions": "800", + } + } + ) + credible_set_path: str = MISSING + variant_index_path: str | None = None + colocalisation_path: str | None = None + study_index_path: str | None = None + gene_index_path: str | None = None + feature_matrix_path: str = MISSING + features_list: list[str] = field( + default_factory=lambda: [ + # max CLPP for each (study, locus, gene) aggregating over a specific qtl type + "eQtlColocClppMaximum", + "pQtlColocClppMaximum", + "sQtlColocClppMaximum", + "tuQtlColocClppMaximum", + # max H4 for each (study, locus, gene) aggregating over a specific qtl type + "eQtlColocH4Maximum", + "pQtlColocH4Maximum", + "sQtlColocH4Maximum", + "tuQtlColocH4Maximum", + # distance to gene footprint + "distanceSentinelFootprint", + "distanceSentinelFootprintNeighbourhood", + "distanceFootprintMean", + "distanceFootprintMeanNeighbourhood", + # distance to gene tss + "distanceTssMean", + "distanceTssMeanNeighbourhood", + "distanceSentinelTss", + "distanceSentinelTssNeighbourhood", + # vep + "vepMaximum", + "vepMaximumNeighbourhood", + "vepMean", + "vepMeanNeighbourhood", + ] + ) + _target_: str = "gentropy.l2g.LocusToGeneFeatureMatrixStep" + + @dataclass class PICSConfig(StepConfig): """PICS step configuration.""" @@ -597,6 +644,11 @@ def register_config() -> None: cs.store(group="step", name="ld_based_clumping", node=LDBasedClumpingConfig) cs.store(group="step", name="ld_index", node=LDIndexConfig) cs.store(group="step", name="locus_to_gene", node=LocusToGeneConfig) + cs.store( + group="step", + name="locus_to_gene_feature_matrix", + node=LocusToGeneFeatureMatrixConfig, + ) cs.store(group="step", name="finngen_studies", node=FinngenStudiesConfig) cs.store( diff --git a/src/gentropy/dataset/colocalisation.py b/src/gentropy/dataset/colocalisation.py index c85209462..c9083f67a 100644 --- a/src/gentropy/dataset/colocalisation.py +++ b/src/gentropy/dataset/colocalisation.py @@ -60,7 +60,9 @@ def extract_maximum_coloc_probability_per_region_and_gene( """ from gentropy.colocalisation import ColocalisationStep - valid_qtls = list(EqtlCatalogueStudyIndex.method_to_study_type_mapping.values()) + valid_qtls = list( + set(EqtlCatalogueStudyIndex.method_to_study_type_mapping.values()) + ) if filter_by_qtl and filter_by_qtl not in valid_qtls: raise ValueError(f"There are no studies with QTL type {filter_by_qtl}") @@ -91,7 +93,7 @@ def extract_maximum_coloc_probability_per_region_and_gene( self.append_study_metadata( study_locus, study_index, - metadata_cols=["geneId"], + metadata_cols=["geneId", "studyType"], colocalisation_side="right", ) # it also filters based on method and qtl type @@ -147,6 +149,12 @@ def append_study_metadata( ) .distinct() ) + coloc_df = ( + # drop `rightStudyType` in case it is requested + self.df.drop("rightStudyType") + if "studyType" in metadata_cols and colocalisation_side == "right" + else self.df + ) return ( # Append that to the respective side of the colocalisation dataset study_loci_w_metadata.selectExpr( @@ -155,5 +163,5 @@ def append_study_metadata( f"{col} as {colocalisation_side}{col[0].upper() + col[1:]}" for col in metadata_cols ], - ).join(self.df, f"{colocalisation_side}StudyLocusId", "right") + ).join(coloc_df, f"{colocalisation_side}StudyLocusId", "right") ) diff --git a/src/gentropy/dataset/l2g_features/distance.py b/src/gentropy/dataset/l2g_features/distance.py index ea030108c..8d42d30ed 100644 --- a/src/gentropy/dataset/l2g_features/distance.py +++ b/src/gentropy/dataset/l2g_features/distance.py @@ -349,7 +349,7 @@ class DistanceSentinelFootprintFeature(L2GFeature): fill_na_value = 500_000 feature_dependency_type = VariantIndex - feature_name = "distanceSentinelFootprintMinimum" + feature_name = "distanceSentinelFootprint" @classmethod def compute( @@ -388,7 +388,7 @@ class DistanceSentinelFootprintNeighbourhoodFeature(L2GFeature): fill_na_value = 500_000 feature_dependency_type = VariantIndex - feature_name = "DistanceSentinelFootprintNeighbourhoodFeature" + feature_name = "distanceSentinelFootprintNeighbourhood" @classmethod def compute( diff --git a/src/gentropy/dataset/l2g_gold_standard.py b/src/gentropy/dataset/l2g_gold_standard.py index 064f6cc0e..e1083fbf0 100644 --- a/src/gentropy/dataset/l2g_gold_standard.py +++ b/src/gentropy/dataset/l2g_gold_standard.py @@ -11,6 +11,7 @@ from gentropy.common.schemas import parse_spark_schema from gentropy.common.spark_helpers import get_record_with_maximum_value from gentropy.dataset.dataset import Dataset +from gentropy.dataset.study_locus import StudyLocus if TYPE_CHECKING: from pyspark.sql import DataFrame @@ -107,11 +108,13 @@ def process_gene_interactions( def build_feature_matrix( self: L2GGoldStandard, full_feature_matrix: L2GFeatureMatrix, + credible_set: StudyLocus, ) -> L2GFeatureMatrix: """Return a feature matrix for study loci in the gold standard. Args: full_feature_matrix (L2GFeatureMatrix): Feature matrix for all study loci to join on + credible_set (StudyLocus): Full credible sets to annotate the feature matrix with variant and study IDs and perform the join Returns: L2GFeatureMatrix: Feature matrix for study loci in the gold standard @@ -120,10 +123,16 @@ def build_feature_matrix( return L2GFeatureMatrix( _df=full_feature_matrix._df.join( - f.broadcast(self.df.drop("variantId", "studyId", "sources")), - on=["studyLocusId", "geneId"], + credible_set.df.select("studyLocusId", "variantId", "studyId"), + "studyLocusId", + "left", + ) + .join( + f.broadcast(self.df.drop("studyLocusId", "sources")), + on=["studyId", "variantId", "geneId"], how="inner", - ), + ) + .distinct(), with_gold_standard=True, ) diff --git a/src/gentropy/dataset/l2g_prediction.py b/src/gentropy/dataset/l2g_prediction.py index 97e58f526..c29b359af 100644 --- a/src/gentropy/dataset/l2g_prediction.py +++ b/src/gentropy/dataset/l2g_prediction.py @@ -5,12 +5,13 @@ from dataclasses import dataclass from typing import TYPE_CHECKING, Type +import pyspark.sql.functions as f + from gentropy.common.schemas import parse_spark_schema from gentropy.common.session import Session from gentropy.dataset.dataset import Dataset from gentropy.dataset.l2g_feature_matrix import L2GFeatureMatrix from gentropy.dataset.study_locus import StudyLocus -from gentropy.method.l2g.feature_factory import L2GFeatureInputLoader from gentropy.method.l2g.model import LocusToGeneModel if TYPE_CHECKING: @@ -40,8 +41,8 @@ def from_credible_set( cls: Type[L2GPrediction], session: Session, credible_set: StudyLocus, + feature_matrix: L2GFeatureMatrix, features_list: list[str], - features_input_loader: L2GFeatureInputLoader, model_path: str | None, hf_token: str | None = None, download_from_hub: bool = True, @@ -51,8 +52,8 @@ def from_credible_set( Args: session (Session): Session object that contains the Spark session credible_set (StudyLocus): Dataset containing credible sets from GWAS only + feature_matrix (L2GFeatureMatrix): Dataset containing all credible sets and their annotations features_list (list[str]): List of features to use for the model - features_input_loader (L2GFeatureInputLoader): Loader with all feature dependencies model_path (str | None): Path to the model file. It can be either in the filesystem or the name on the Hugging Face Hub (in the form of username/repo_name). hf_token (str | None): Hugging Face token to download the model from the Hub. Only required if the model is private. download_from_hub (bool): Whether to download the model from the Hugging Face Hub. Defaults to True. @@ -70,10 +71,12 @@ def from_credible_set( # Prepare data fm = ( - L2GFeatureMatrix.from_features_list( - study_loci_to_annotate=credible_set, - features_list=features_list, - features_input_loader=features_input_loader, + L2GFeatureMatrix( + _df=( + credible_set.df.filter(f.col("studyType") == "gwas") + .select("studyLocusId") + .join(feature_matrix._df, "studyLocusId") + ) ) .fill_na() .select_features(features_list) diff --git a/src/gentropy/l2g.py b/src/gentropy/l2g.py index 7962da484..296aba3d2 100644 --- a/src/gentropy/l2g.py +++ b/src/gentropy/l2g.py @@ -24,29 +24,89 @@ from gentropy.method.l2g.trainer import LocusToGeneTrainer +class LocusToGeneFeatureMatrixStep: + """Annotate credible set with functional genomics features.""" + + def __init__( + self, + session: Session, + *, + features_list: list[str] = LocusToGeneConfig().features_list, + credible_set_path: str, + variant_index_path: str | None = None, + colocalisation_path: str | None = None, + study_index_path: str | None = None, + gene_index_path: str | None = None, + feature_matrix_path: str, + ) -> None: + """Initialise the step and run the logic based on mode. + + Args: + session (Session): Session object that contains the Spark session + features_list (list[str]): List of features to use for the model + credible_set_path (str): Path to the credible set dataset necessary to build the feature matrix + variant_index_path (str | None): Path to the variant index dataset + colocalisation_path (str | None): Path to the colocalisation dataset + study_index_path (str | None): Path to the study index dataset + gene_index_path (str | None): Path to the gene index dataset + feature_matrix_path (str): Path to the L2G feature matrix output dataset + """ + credible_set = StudyLocus.from_parquet( + session, credible_set_path, recursiveFileLookup=True + ) + studies = ( + StudyIndex.from_parquet(session, study_index_path, recursiveFileLookup=True) + if study_index_path + else None + ) + variant_index = ( + VariantIndex.from_parquet(session, variant_index_path) + if variant_index_path + else None + ) + coloc = ( + Colocalisation.from_parquet( + session, colocalisation_path, recursiveFileLookup=True + ) + if colocalisation_path + else None + ) + gene_index = ( + GeneIndex.from_parquet(session, gene_index_path, recursiveFileLookup=True) + if gene_index_path + else None + ) + features_input_loader = L2GFeatureInputLoader( + variant_index=variant_index, + colocalisation=coloc, + study_index=studies, + study_locus=credible_set, + gene_index=gene_index, + ) + + fm = credible_set.build_feature_matrix(features_list, features_input_loader) + fm._df.write.mode(session.write_mode).parquet(feature_matrix_path) + + class LocusToGeneStep: """Locus to gene step.""" def __init__( self, session: Session, - hyperparameters: dict[str, Any], + hyperparameters: dict[str, Any] = LocusToGeneConfig().hyperparameters, *, run_mode: str, - features_list: list[str], - download_from_hub: bool, + features_list: list[str] = LocusToGeneConfig().features_list, + download_from_hub: bool = LocusToGeneConfig().download_from_hub, wandb_run_name: str, model_path: str | None = None, credible_set_path: str, + feature_matrix_path: str, gold_standard_curation_path: str | None = None, variant_index_path: str | None = None, - colocalisation_path: str | None = None, - study_index_path: str | None = None, - gene_index_path: str | None = None, gene_interactions_path: str | None = None, predictions_path: str | None = None, - feature_matrix_path: str | None = None, - write_feature_matrix: bool, hf_hub_repo_id: str | None = LocusToGeneConfig().hf_hub_repo_id, ) -> None: """Initialise the step and run the logic based on mode. @@ -60,15 +120,11 @@ def __init__( wandb_run_name (str): Name of the run to track model training in Weights and Biases model_path (str | None): Path to the model. It can be either in the filesystem or the name on the Hugging Face Hub (in the form of username/repo_name). credible_set_path (str): Path to the credible set dataset necessary to build the feature matrix + feature_matrix_path (str): Path to the L2G feature matrix input dataset gold_standard_curation_path (str | None): Path to the gold standard curation file - variant_index_path (str | None): Path to the variant index dataset - colocalisation_path (str | None): Path to the colocalisation dataset - study_index_path (str | None): Path to the study index dataset - gene_index_path (str | None): Path to the gene index dataset + variant_index_path (str | None): Path to the variant index gene_interactions_path (str | None): Path to the gene interactions dataset predictions_path (str | None): Path to the L2G predictions output dataset - feature_matrix_path (str | None): Path to the L2G feature matrix output dataset - write_feature_matrix (bool): Whether to write the full feature matrix to the filesystem hf_hub_repo_id (str | None): Hugging Face Hub repository ID. If provided, the model will be uploaded to Hugging Face. Raises: @@ -85,7 +141,6 @@ def __init__( self.predictions_path = predictions_path self.features_list = list(features_list) self.hyperparameters = dict(hyperparameters) - self.feature_matrix_path = feature_matrix_path self.wandb_run_name = wandb_run_name self.hf_hub_repo_id = hf_hub_repo_id self.download_from_hub = download_from_hub @@ -93,36 +148,15 @@ def __init__( # Load common inputs self.credible_set = StudyLocus.from_parquet( session, credible_set_path, recursiveFileLookup=True - ).filter(f.col("studyType") == "gwas") - self.studies = ( - StudyIndex.from_parquet(session, study_index_path, recursiveFileLookup=True) - if study_index_path - else None + ) + self.feature_matrix = L2GFeatureMatrix( + _df=session.load_data(feature_matrix_path), features_list=self.features_list ) self.variant_index = ( VariantIndex.from_parquet(session, variant_index_path) if variant_index_path else None ) - self.coloc = ( - Colocalisation.from_parquet( - session, colocalisation_path, recursiveFileLookup=True - ) - if colocalisation_path - else None - ) - self.gene_index = ( - GeneIndex.from_parquet(session, gene_index_path, recursiveFileLookup=True) - if gene_index_path - else None - ) - self.features_input_loader = L2GFeatureInputLoader( - variant_index=self.variant_index, - coloc=self.coloc, - studies=self.studies, - study_locus=self.credible_set, - gene_index=self.gene_index, - ) if run_mode == "predict": self.run_predict() @@ -140,28 +174,21 @@ def __init__( self.run_train() def run_predict(self) -> None: - """Run the prediction step. - - Raises: - ValueError: If not all dependencies in prediction mode are set - """ - if self.studies and self.coloc: - predictions = L2GPrediction.from_credible_set( - self.session, - self.credible_set, - self.features_list, - self.features_input_loader, - model_path=self.model_path, - hf_token=access_gcp_secret("hfhub-key", "open-targets-genetics-dev"), - download_from_hub=self.download_from_hub, + """Run the prediction step.""" + predictions = L2GPrediction.from_credible_set( + self.session, + self.credible_set, + self.feature_matrix, + self.features_list, + model_path=self.model_path, + hf_token=access_gcp_secret("hfhub-key", "open-targets-genetics-dev"), + download_from_hub=self.download_from_hub, + ) + if self.predictions_path: + predictions.df.write.mode(self.session.write_mode).parquet( + self.predictions_path ) - if self.predictions_path: - predictions.df.write.mode(self.session.write_mode).parquet( - self.predictions_path - ) - self.session.logger.info(self.predictions_path) - else: - raise ValueError("Dependencies for predict mode not set.") + self.session.logger.info(self.predictions_path) def run_train(self) -> None: """Run the training step.""" @@ -170,11 +197,8 @@ def run_train(self) -> None: and self.interactions and self.wandb_run_name and self.model_path - and self.variant_index ): wandb_key = access_gcp_secret("wandb-key", "open-targets-genetics-dev") - # Process gold standard and L2G features - data = self._generate_feature_matrix(write_feature_matrix=True) # Instantiate classifier and train model l2g_model = LocusToGeneModel( @@ -183,7 +207,8 @@ def run_train(self) -> None: ) wandb_login(key=wandb_key) trained_model = LocusToGeneTrainer( - model=l2g_model, feature_matrix=data + model=l2g_model, + feature_matrix=self._annotate_gold_standards_w_feature_matrix(), ).train(self.wandb_run_name) if trained_model.training_data and trained_model.model and self.model_path: trained_model.save(self.model_path) @@ -202,46 +227,31 @@ def run_train(self) -> None: commit_message="chore: update model", ) - def _generate_feature_matrix(self, write_feature_matrix: bool) -> L2GFeatureMatrix: + def _annotate_gold_standards_w_feature_matrix(self) -> L2GFeatureMatrix: """Generate the feature matrix of annotated gold standards. - Args: - write_feature_matrix (bool): Whether to write the feature matrix for all credible sets to disk - Returns: L2GFeatureMatrix: Feature matrix with gold standards annotated with features. Raises: - ValueError: If write_feature_matrix is set to True but a path is not provided or if dependencies to build features are not set. + ValueError: Not all training dependencies are defined """ - if ( - self.gs_curation - and self.interactions - and self.studies - and self.variant_index - ): + if self.gs_curation and self.interactions and self.variant_index: study_locus_overlap = StudyLocus( _df=self.credible_set.df.join( f.broadcast( - self.gs_curation.withColumn( - "variantId", + self.gs_curation.select( f.concat_ws( "_", f.col("sentinel_variant.locus_GRCh38.chromosome"), f.col("sentinel_variant.locus_GRCh38.position"), f.col("sentinel_variant.alleles.reference"), f.col("sentinel_variant.alleles.alternative"), - ), - ).select( - StudyLocus.assign_study_locus_id( - [ - "association_info.otg_id", # studyId - "variantId", - ] - ), + ).alias("variantId"), + f.col("association_info.otg_id").alias("studyId"), ) ), - "studyLocusId", + ["studyId", "variantId"], "inner", ), _schema=StudyLocus.get_schema(), @@ -254,18 +264,10 @@ def _generate_feature_matrix(self, write_feature_matrix: bool) -> L2GFeatureMatr interactions=self.interactions, ) - fm = self.credible_set.build_feature_matrix( - self.features_list, self.features_input_loader - ) - if write_feature_matrix: - if not self.feature_matrix_path: - raise ValueError("feature_matrix_path must be set.") - fm._df.write.mode(self.session.write_mode).parquet( - self.feature_matrix_path - ) - return ( - gold_standards.build_feature_matrix(fm) + gold_standards.build_feature_matrix( + self.feature_matrix, self.credible_set + ) .fill_na() .select_features(self.features_list) ) diff --git a/tests/gentropy/datasource/open_targets/test_l2g_gold_standard.py b/tests/gentropy/datasource/open_targets/test_l2g_gold_standard.py index aa36359ca..e6afc942f 100644 --- a/tests/gentropy/datasource/open_targets/test_l2g_gold_standard.py +++ b/tests/gentropy/datasource/open_targets/test_l2g_gold_standard.py @@ -171,5 +171,6 @@ def test_build_feature_matrix( ) fm = mock_study_locus.build_feature_matrix(features_list, loader) assert isinstance( - mock_l2g_gold_standard.build_feature_matrix(fm), L2GFeatureMatrix + mock_l2g_gold_standard.build_feature_matrix(fm, mock_study_locus), + L2GFeatureMatrix, ), "Feature matrix should be of type L2GFeatureMatrix" From 9f0111cb3dd0cde70831cb658415e1bbe20ff28e Mon Sep 17 00:00:00 2001 From: David Ochoa Date: Wed, 9 Oct 2024 16:20:01 +0100 Subject: [PATCH 087/188] fix: mhc flag incorrect (#825) --- src/gentropy/dataset/study_locus.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/gentropy/dataset/study_locus.py b/src/gentropy/dataset/study_locus.py index 4d8136c8e..f03b98029 100644 --- a/src/gentropy/dataset/study_locus.py +++ b/src/gentropy/dataset/study_locus.py @@ -279,7 +279,8 @@ def validate_lead_pvalue(self: StudyLocus, pvalue_cutoff: float) -> StudyLocus: df = self.df.withColumn( qc_colname, create_empty_column_if_not_exists( - qc_colname, get_struct_field_schema(StudyLocus.get_schema(), qc_colname) + qc_colname, + get_struct_field_schema(StudyLocus.get_schema(), qc_colname), ), ) return StudyLocus( @@ -940,7 +941,7 @@ def qc_MHC_region(self: StudyLocus) -> StudyLocus: "qualityControls", self.update_quality_flag( f.col("qualityControls"), - ~( + ( (f.col("chromosome") == region.chromosome) & ( (f.col("position") <= region.end) From 31e217b7b4702fec0f91ce68cbe011c5efa78b07 Mon Sep 17 00:00:00 2001 From: David Ochoa Date: Thu, 10 Oct 2024 13:28:35 +0100 Subject: [PATCH 088/188] revert: no longer rescuing variants not in LD matrix when overlapping with SuSiE (#827) * revert: no longer rescueing variants not in LD matrix * test: update test to cover new expectation --- src/gentropy/dataset/study_locus.py | 7 +------ tests/gentropy/dataset/test_study_locus.py | 4 ++-- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/gentropy/dataset/study_locus.py b/src/gentropy/dataset/study_locus.py index f03b98029..e9be88a9d 100644 --- a/src/gentropy/dataset/study_locus.py +++ b/src/gentropy/dataset/study_locus.py @@ -1047,12 +1047,7 @@ def qc_explained_by_SuSiE(self: StudyLocus) -> StudyLocus: # credible set in SuSiE overlapping region f.col("inSuSiE") # credible set not based on SuSiE - & (f.col("finemappingMethod") != "SuSiE-inf") - # credible set not already flagged as unresolved LD - & ~f.array_contains( - f.col("qualityControls"), - StudyLocusQualityCheck.UNRESOLVED_LD.value, - ), + & (f.col("finemappingMethod") != "SuSiE-inf"), StudyLocusQualityCheck.EXPLAINED_BY_SUSIE, ), ) diff --git a/tests/gentropy/dataset/test_study_locus.py b/tests/gentropy/dataset/test_study_locus.py index 3f6cfcb59..94da005b9 100644 --- a/tests/gentropy/dataset/test_study_locus.py +++ b/tests/gentropy/dataset/test_study_locus.py @@ -985,7 +985,7 @@ class TestStudyLocusSuSiERedundancyFlagging: [{"variantId": "X_3_A_A"}, {"variantId": "X_5_A_A"}], [], ), - # NOT to be flagged (Unresolved LD) + # To be flagged (Unresolved LD flag on it) ( "5", "v5", @@ -1080,4 +1080,4 @@ def test_qc_explained_by_SuSiE_correctness( ) ) .count() - ) == 2 + ) == 3 From 58333c0296f2f923410e965124ea76ef95a4592e Mon Sep 17 00:00:00 2001 From: Daniel Suveges Date: Thu, 10 Oct 2024 13:58:06 +0100 Subject: [PATCH 089/188] fix: empty inSilicoPredictors object in GnomAD variant index (#807) * fix: empty inSilicoPredictors object in variant index * fix: object filtering expression * fix(hail): limit removed --- src/gentropy/datasource/gnomad/variants.py | 26 ++++++++++++++-------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/gentropy/datasource/gnomad/variants.py b/src/gentropy/datasource/gnomad/variants.py index fc68a3154..0575261c2 100644 --- a/src/gentropy/datasource/gnomad/variants.py +++ b/src/gentropy/datasource/gnomad/variants.py @@ -131,16 +131,24 @@ def as_variant_index(self: GnomADVariants) -> VariantIndex: .drop("locus", "alleles") .select_globals() .to_spark(flatten=False) - .withColumn( - "variantId", - VariantIndex.hash_long_variant_ids( - f.col("variantId"), - f.col("chromosome"), - f.col("position"), - self.lenght_threshold, - ), + .withColumns( + { + # Once The parsing is done, we have to drop objects with no score from inSilicoPredictors: + "inSilicoPredictors": f.filter( + f.col("inSilicoPredictors"), + lambda predictor: predictor["score"].isNotNull(), + ), + # Generate a variantId that is hashed for long variant ids: + "variantId": VariantIndex.hash_long_variant_ids( + f.col("variantId"), + f.col("chromosome"), + f.col("position"), + self.lenght_threshold, + ), + # We are not capturing the most severe consequence from GnomAD, but this column needed for the schema: + "mostSevereConsequenceId": f.lit(None).cast(t.StringType()), + } ) - .withColumn("mostSevereConsequenceId", f.lit(None).cast(t.StringType())) ), _schema=VariantIndex.get_schema(), ) From c7c602a9a784c5b19b413da0ea32261a6fbd0804 Mon Sep 17 00:00:00 2001 From: David Ochoa Date: Fri, 11 Oct 2024 07:33:16 +0100 Subject: [PATCH 090/188] fix: write mode added to validation steps (#826) --- src/gentropy/study_locus_validation.py | 12 ++++++------ src/gentropy/study_validation.py | 16 +++++++++------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/gentropy/study_locus_validation.py b/src/gentropy/study_locus_validation.py index 486b31ca5..0be046a67 100644 --- a/src/gentropy/study_locus_validation.py +++ b/src/gentropy/study_locus_validation.py @@ -51,10 +51,10 @@ def __init__( .assign_confidence() ).persist() # we will need this for 2 types of outputs - study_locus_with_qc.valid_rows( - invalid_qc_reasons, invalid=True - ).df.write.parquet(invalid_study_locus_path) + study_locus_with_qc.valid_rows(invalid_qc_reasons, invalid=True).df.write.mode( + session.write_mode + ).parquet(invalid_study_locus_path) - study_locus_with_qc.valid_rows(invalid_qc_reasons).df.write.parquet( - valid_study_locus_path - ) + study_locus_with_qc.valid_rows(invalid_qc_reasons).df.write.mode( + session.write_mode + ).parquet(valid_study_locus_path) diff --git a/src/gentropy/study_validation.py b/src/gentropy/study_validation.py index 573298757..a9bebe25e 100644 --- a/src/gentropy/study_validation.py +++ b/src/gentropy/study_validation.py @@ -66,13 +66,15 @@ def __init__( .validate_study_type() # Flagging non-supported study types. .validate_target(target_index) # Flagging QTL studies with invalid targets .validate_disease(disease_index) # Flagging invalid EFOs - .validate_biosample(biosample_index) # Flagging QTL studies with invalid biosamples + .validate_biosample( + biosample_index + ) # Flagging QTL studies with invalid biosamples ).persist() # we will need this for 2 types of outputs - study_index_with_qc.valid_rows( - invalid_qc_reasons, invalid=True - ).df.write.parquet(invalid_study_index_path) + study_index_with_qc.valid_rows(invalid_qc_reasons, invalid=True).df.write.mode( + session.write_mode + ).parquet(invalid_study_index_path) - study_index_with_qc.valid_rows(invalid_qc_reasons).df.write.parquet( - valid_study_index_path - ) + study_index_with_qc.valid_rows(invalid_qc_reasons).df.write.mode( + session.write_mode + ).parquet(valid_study_index_path) From e3d32ba1e01db3ad8a45ba40027f836703ceeff3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Irene=20L=C3=B3pez=20Santiago?= <45119610+ireneisdoomed@users.noreply.github.com> Date: Fri, 11 Oct 2024 09:52:46 +0100 Subject: [PATCH 091/188] feat(l2g): merge sQTL and tuQTL colocalisation features (#824) * feat: merge tuQTL colocalisation results into sQTL features * fix: add colocalisation neighbourhood features in the l2g default features list * fix: minor bug --- .../datasets/l2g_features/colocalisation.md | 4 - src/gentropy/config.py | 10 +- src/gentropy/dataset/colocalisation.py | 21 +- .../dataset/l2g_features/colocalisation.py | 196 ++---------------- src/gentropy/method/l2g/feature_factory.py | 8 - tests/gentropy/dataset/test_l2g_feature.py | 8 - 6 files changed, 35 insertions(+), 212 deletions(-) diff --git a/docs/python_api/datasets/l2g_features/colocalisation.md b/docs/python_api/datasets/l2g_features/colocalisation.md index a3928c4ab..c38c690d7 100644 --- a/docs/python_api/datasets/l2g_features/colocalisation.md +++ b/docs/python_api/datasets/l2g_features/colocalisation.md @@ -7,19 +7,15 @@ title: From colocalisation ::: gentropy.dataset.l2g_features.colocalisation.EQtlColocClppMaximumFeature ::: gentropy.dataset.l2g_features.colocalisation.PQtlColocClppMaximumFeature ::: gentropy.dataset.l2g_features.colocalisation.SQtlColocClppMaximumFeature -::: gentropy.dataset.l2g_features.colocalisation.TuQtlColocClppMaximumFeature ::: gentropy.dataset.l2g_features.colocalisation.EQtlColocH4MaximumFeature ::: gentropy.dataset.l2g_features.colocalisation.PQtlColocH4MaximumFeature ::: gentropy.dataset.l2g_features.colocalisation.SQtlColocH4MaximumFeature -::: gentropy.dataset.l2g_features.colocalisation.TuQtlColocH4MaximumFeature ::: gentropy.dataset.l2g_features.colocalisation.EQtlColocClppMaximumNeighbourhoodFeature ::: gentropy.dataset.l2g_features.colocalisation.PQtlColocClppMaximumNeighbourhoodFeature ::: gentropy.dataset.l2g_features.colocalisation.SQtlColocClppMaximumNeighbourhoodFeature -::: gentropy.dataset.l2g_features.colocalisation.TuQtlColocClppMaximumNeighbourhoodFeature ::: gentropy.dataset.l2g_features.colocalisation.EQtlColocH4MaximumNeighbourhoodFeature ::: gentropy.dataset.l2g_features.colocalisation.PQtlColocH4MaximumNeighbourhoodFeature ::: gentropy.dataset.l2g_features.colocalisation.SQtlColocH4MaximumNeighbourhoodFeature -::: gentropy.dataset.l2g_features.colocalisation.TuQtlColocH4MaximumNeighbourhoodFeature ## Common logic diff --git a/src/gentropy/config.py b/src/gentropy/config.py index 798a6b7bf..50eb4af72 100644 --- a/src/gentropy/config.py +++ b/src/gentropy/config.py @@ -246,12 +246,18 @@ class LocusToGeneConfig(StepConfig): "eQtlColocClppMaximum", "pQtlColocClppMaximum", "sQtlColocClppMaximum", - "tuQtlColocClppMaximum", # max H4 for each (study, locus, gene) aggregating over a specific qtl type "eQtlColocH4Maximum", "pQtlColocH4Maximum", "sQtlColocH4Maximum", - "tuQtlColocH4Maximum", + # max CLPP for each (study, locus, gene) aggregating over a specific qtl type and in relation with the mean in the vicinity + "eQtlColocClppMaximumNeighbourhood", + "pQtlColocClppMaximumNeighbourhood", + "sQtlColocClppMaximumNeighbourhood", + # max H4 for each (study, locus, gene) aggregating over a specific qtl type and in relation with the mean in the vicinity + "eQtlColocH4MaximumNeighbourhood", + "pQtlColocH4MaximumNeighbourhood", + "sQtlColocH4MaximumNeighbourhood", # distance to gene footprint "distanceSentinelFootprint", "distanceSentinelFootprintNeighbourhood", diff --git a/src/gentropy/dataset/colocalisation.py b/src/gentropy/dataset/colocalisation.py index c9083f67a..4b85b68d6 100644 --- a/src/gentropy/dataset/colocalisation.py +++ b/src/gentropy/dataset/colocalisation.py @@ -42,7 +42,7 @@ def extract_maximum_coloc_probability_per_region_and_gene( study_index: StudyIndex, *, filter_by_colocalisation_method: str, - filter_by_qtl: str | None = None, + filter_by_qtls: str | list[str] | None = None, ) -> DataFrame: """Get maximum colocalisation probability for a (studyLocus, gene) window. @@ -50,7 +50,7 @@ def extract_maximum_coloc_probability_per_region_and_gene( study_locus (StudyLocus): Dataset containing study loci to filter the colocalisation dataset on and the geneId linked to the region study_index (StudyIndex): Study index to use to get study metadata filter_by_colocalisation_method (str): optional filter to apply on the colocalisation dataset - filter_by_qtl (str | None): optional filter to apply on the colocalisation dataset + filter_by_qtls (str | list[str] | None): optional filter to apply on the colocalisation dataset Returns: DataFrame: table with the maximum colocalisation scores for the provided study loci @@ -63,8 +63,15 @@ def extract_maximum_coloc_probability_per_region_and_gene( valid_qtls = list( set(EqtlCatalogueStudyIndex.method_to_study_type_mapping.values()) ) - if filter_by_qtl and filter_by_qtl not in valid_qtls: - raise ValueError(f"There are no studies with QTL type {filter_by_qtl}") + + if filter_by_qtls: + filter_by_qtls = ( + list(map(str.lower, [filter_by_qtls])) + if isinstance(filter_by_qtls, str) + else list(map(str.lower, filter_by_qtls)) + ) + if any(qtl not in valid_qtls for qtl in filter_by_qtls): + raise ValueError(f"There are no studies with QTL type {filter_by_qtls}") if filter_by_colocalisation_method not in [ "ECaviar", @@ -82,10 +89,8 @@ def extract_maximum_coloc_probability_per_region_and_gene( f.col("rightGeneId").isNotNull(), f.lower("colocalisationMethod") == filter_by_colocalisation_method.lower(), ] - if filter_by_qtl: - coloc_filtering_expr.append( - f.lower("rightStudyType") == filter_by_qtl.lower() - ) + if filter_by_qtls: + coloc_filtering_expr.append(f.lower("rightStudyType").isin(filter_by_qtls)) filtered_colocalisation = ( # Bring rightStudyType and rightGeneId and filter by rows where the gene is null, diff --git a/src/gentropy/dataset/l2g_features/colocalisation.py b/src/gentropy/dataset/l2g_features/colocalisation.py index c44573b72..c61daa909 100644 --- a/src/gentropy/dataset/l2g_features/colocalisation.py +++ b/src/gentropy/dataset/l2g_features/colocalisation.py @@ -23,7 +23,7 @@ def common_colocalisation_feature_logic( colocalisation_method: str, colocalisation_metric: str, feature_name: str, - qtl_type: str, + qtl_types: list[str] | str, *, colocalisation: Colocalisation, study_index: StudyIndex, @@ -36,7 +36,7 @@ def common_colocalisation_feature_logic( colocalisation_method (str): The colocalisation method to filter the data by colocalisation_metric (str): The colocalisation metric to use feature_name (str): The name of the feature to create - qtl_type (str): The type of QTL to filter the data by + qtl_types (list[str] | str): The types of QTL to filter the data by colocalisation (Colocalisation): Dataset with the colocalisation results study_index (StudyIndex): Study index to fetch study type and gene study_locus (StudyLocus): Study locus to traverse between colocalisation and study index @@ -55,7 +55,7 @@ def common_colocalisation_feature_logic( study_locus, study_index, filter_by_colocalisation_method=colocalisation_method, - filter_by_qtl=qtl_type, + filter_by_qtls=qtl_types, ), on=joining_cols, ) @@ -73,7 +73,7 @@ def common_neighbourhood_colocalisation_feature_logic( colocalisation_method: str, colocalisation_metric: str, feature_name: str, - qtl_type: str, + qtl_types: list[str] | str, *, colocalisation: Colocalisation, study_index: StudyIndex, @@ -86,7 +86,7 @@ def common_neighbourhood_colocalisation_feature_logic( colocalisation_method (str): The colocalisation method to filter the data by colocalisation_metric (str): The colocalisation metric to use feature_name (str): The name of the feature to create - qtl_type (str): The type of QTL to filter the data by + qtl_types (list[str] | str): The types of QTL to filter the data by colocalisation (Colocalisation): Dataset with the colocalisation results study_index (StudyIndex): Study index to fetch study type and gene study_locus (StudyLocus): Study locus to traverse between colocalisation and study index @@ -101,7 +101,7 @@ def common_neighbourhood_colocalisation_feature_logic( colocalisation_method, colocalisation_metric, local_feature_name, - qtl_type, + qtl_types, colocalisation=colocalisation, study_index=study_index, study_locus=study_locus, @@ -310,7 +310,7 @@ def compute( """ colocalisation_method = "ECaviar" colocalisation_metric = "clpp" - qtl_type = "sqtl" + qtl_types = ["sqtl", "tuqtl"] return cls( _df=convert_from_wide_to_long( common_colocalisation_feature_logic( @@ -318,7 +318,7 @@ def compute( colocalisation_method, colocalisation_metric, cls.feature_name, - qtl_type, + qtl_types, **feature_dependency, ), id_vars=("studyLocusId", "geneId"), @@ -352,91 +352,7 @@ def compute( """ colocalisation_method = "ECaviar" colocalisation_metric = "clpp" - qtl_type = "sqtl" - return cls( - _df=convert_from_wide_to_long( - common_neighbourhood_colocalisation_feature_logic( - study_loci_to_annotate, - colocalisation_method, - colocalisation_metric, - cls.feature_name, - qtl_type, - **feature_dependency, - ), - id_vars=("studyLocusId", "geneId"), - var_name="featureName", - value_name="featureValue", - ), - _schema=cls.get_schema(), - ) - - -class TuQtlColocClppMaximumFeature(L2GFeature): - """Max CLPP for each (study, locus, gene) aggregating over all tuQTLs.""" - - feature_dependency_type = [Colocalisation, StudyIndex, StudyLocus] - feature_name = "tuQtlColocClppMaximum" - - @classmethod - def compute( - cls: type[TuQtlColocClppMaximumFeature], - study_loci_to_annotate: StudyLocus | L2GGoldStandard, - feature_dependency: dict[str, Any], - ) -> TuQtlColocClppMaximumFeature: - """Computes the feature. - - Args: - study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation - feature_dependency (dict[str, Any]): Dataset with the colocalisation results - - Returns: - TuQtlColocClppMaximumFeature: Feature dataset - """ - colocalisation_method = "ECaviar" - colocalisation_metric = "clpp" - qtl_type = "tuqtl" - return cls( - _df=convert_from_wide_to_long( - common_colocalisation_feature_logic( - study_loci_to_annotate, - colocalisation_method, - colocalisation_metric, - cls.feature_name, - qtl_type, - **feature_dependency, - ), - id_vars=("studyLocusId", "geneId"), - var_name="featureName", - value_name="featureValue", - ), - _schema=cls.get_schema(), - ) - - -class TuQtlColocClppMaximumNeighbourhoodFeature(L2GFeature): - """Max CLPP for each (study, locus) aggregating over all tuQTLs.""" - - feature_dependency_type = [Colocalisation, StudyIndex, StudyLocus] - feature_name = "tuQtlColocClppMaximumNeighbourhood" - - @classmethod - def compute( - cls: type[TuQtlColocClppMaximumNeighbourhoodFeature], - study_loci_to_annotate: StudyLocus | L2GGoldStandard, - feature_dependency: dict[str, Any], - ) -> TuQtlColocClppMaximumNeighbourhoodFeature: - """Computes the feature. - - Args: - study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation - feature_dependency (dict[str, Any]): Dataset with the colocalisation results - - Returns: - TuQtlColocClppMaximumNeighbourhoodFeature: Feature dataset - """ - colocalisation_method = "ECaviar" - colocalisation_metric = "clpp" - qtl_type = "tuqtl" + qtl_types = ["sqtl", "tuqtl"] return cls( _df=convert_from_wide_to_long( common_neighbourhood_colocalisation_feature_logic( @@ -444,7 +360,7 @@ def compute( colocalisation_method, colocalisation_metric, cls.feature_name, - qtl_type, + qtl_types, **feature_dependency, ), id_vars=("studyLocusId", "geneId"), @@ -646,7 +562,7 @@ def compute( """ colocalisation_method = "Coloc" colocalisation_metric = "h4" - qtl_type = "sqtl" + qtl_types = ["sqtl", "tuqtl"] return cls( _df=convert_from_wide_to_long( common_colocalisation_feature_logic( @@ -654,7 +570,7 @@ def compute( colocalisation_method, colocalisation_metric, cls.feature_name, - qtl_type, + qtl_types, **feature_dependency, ), id_vars=("studyLocusId", "geneId"), @@ -688,7 +604,7 @@ def compute( """ colocalisation_method = "Coloc" colocalisation_metric = "h4" - qtl_type = "sqtl" + qtl_types = ["sqtl", "tuqtl"] return cls( _df=convert_from_wide_to_long( common_neighbourhood_colocalisation_feature_logic( @@ -696,91 +612,7 @@ def compute( colocalisation_method, colocalisation_metric, cls.feature_name, - qtl_type, - **feature_dependency, - ), - id_vars=("studyLocusId", "geneId"), - var_name="featureName", - value_name="featureValue", - ), - _schema=cls.get_schema(), - ) - - -class TuQtlColocH4MaximumFeature(L2GFeature): - """Max H4 for each (study, locus, gene) aggregating over all tuQTLs.""" - - feature_dependency_type = [Colocalisation, StudyIndex, StudyLocus] - feature_name = "tuQtlColocH4Maximum" - - @classmethod - def compute( - cls: type[TuQtlColocH4MaximumFeature], - study_loci_to_annotate: StudyLocus | L2GGoldStandard, - feature_dependency: dict[str, Any], - ) -> TuQtlColocH4MaximumFeature: - """Computes the feature. - - Args: - study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation - feature_dependency (dict[str, Any]): Dataset with the colocalisation results - - Returns: - TuQtlColocH4MaximumFeature: Feature dataset - """ - colocalisation_method = "Coloc" - colocalisation_metric = "h4" - qtl_type = "tuqtl" - return cls( - _df=convert_from_wide_to_long( - common_colocalisation_feature_logic( - study_loci_to_annotate, - colocalisation_method, - colocalisation_metric, - cls.feature_name, - qtl_type, - **feature_dependency, - ), - id_vars=("studyLocusId", "geneId"), - var_name="featureName", - value_name="featureValue", - ), - _schema=cls.get_schema(), - ) - - -class TuQtlColocH4MaximumNeighbourhoodFeature(L2GFeature): - """Max H4 for each (study, locus) aggregating over all tuQTLs.""" - - feature_dependency_type = [Colocalisation, StudyIndex, StudyLocus] - feature_name = "tuQtlColocH4MaximumNeighbourhood" - - @classmethod - def compute( - cls: type[TuQtlColocH4MaximumNeighbourhoodFeature], - study_loci_to_annotate: StudyLocus | L2GGoldStandard, - feature_dependency: dict[str, Any], - ) -> TuQtlColocH4MaximumNeighbourhoodFeature: - """Computes the feature. - - Args: - study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation - feature_dependency (dict[str, Any]): Dataset with the colocalisation results - - Returns: - TuQtlColocH4MaximumNeighbourhoodFeature: Feature dataset - """ - colocalisation_method = "Coloc" - colocalisation_metric = "h4" - qtl_type = "tuqtl" - return cls( - _df=convert_from_wide_to_long( - common_colocalisation_feature_logic( - study_loci_to_annotate, - colocalisation_method, - colocalisation_metric, - cls.feature_name, - qtl_type, + qtl_types, **feature_dependency, ), id_vars=("studyLocusId", "geneId"), diff --git a/src/gentropy/method/l2g/feature_factory.py b/src/gentropy/method/l2g/feature_factory.py index 41db44806..1077fc825 100644 --- a/src/gentropy/method/l2g/feature_factory.py +++ b/src/gentropy/method/l2g/feature_factory.py @@ -17,10 +17,6 @@ SQtlColocClppMaximumNeighbourhoodFeature, SQtlColocH4MaximumFeature, SQtlColocH4MaximumNeighbourhoodFeature, - TuQtlColocClppMaximumFeature, - TuQtlColocClppMaximumNeighbourhoodFeature, - TuQtlColocH4MaximumFeature, - TuQtlColocH4MaximumNeighbourhoodFeature, ) from gentropy.dataset.l2g_features.distance import ( DistanceFootprintMeanFeature, @@ -113,16 +109,12 @@ class FeatureFactory: "pQtlColocClppMaximumNeighbourhood": PQtlColocClppMaximumNeighbourhoodFeature, "sQtlColocClppMaximum": SQtlColocClppMaximumFeature, "sQtlColocClppMaximumNeighbourhood": SQtlColocClppMaximumNeighbourhoodFeature, - "tuQtlColocClppMaximum": TuQtlColocClppMaximumFeature, - "tuQtlColocClppMaximumNeighbourhood": TuQtlColocClppMaximumNeighbourhoodFeature, "eQtlColocH4Maximum": EQtlColocH4MaximumFeature, "eQtlColocH4MaximumNeighbourhood": EQtlColocH4MaximumNeighbourhoodFeature, "pQtlColocH4Maximum": PQtlColocH4MaximumFeature, "pQtlColocH4MaximumNeighbourhood": PQtlColocH4MaximumNeighbourhoodFeature, "sQtlColocH4Maximum": SQtlColocH4MaximumFeature, "sQtlColocH4MaximumNeighbourhood": SQtlColocH4MaximumNeighbourhoodFeature, - "tuQtlColocH4Maximum": TuQtlColocH4MaximumFeature, - "tuQtlColocH4MaximumNeighbourhood": TuQtlColocH4MaximumNeighbourhoodFeature, "vepMean": VepMeanFeature, "vepMeanNeighbourhood": VepMeanNeighbourhoodFeature, "vepMaximum": VepMaximumFeature, diff --git a/tests/gentropy/dataset/test_l2g_feature.py b/tests/gentropy/dataset/test_l2g_feature.py index c674280ac..6d3b1b3af 100644 --- a/tests/gentropy/dataset/test_l2g_feature.py +++ b/tests/gentropy/dataset/test_l2g_feature.py @@ -32,10 +32,6 @@ SQtlColocClppMaximumNeighbourhoodFeature, SQtlColocH4MaximumFeature, SQtlColocH4MaximumNeighbourhoodFeature, - TuQtlColocClppMaximumFeature, - TuQtlColocClppMaximumNeighbourhoodFeature, - TuQtlColocH4MaximumFeature, - TuQtlColocH4MaximumNeighbourhoodFeature, common_colocalisation_feature_logic, common_neighbourhood_colocalisation_feature_logic, ) @@ -75,19 +71,15 @@ EQtlColocH4MaximumFeature, PQtlColocH4MaximumFeature, SQtlColocH4MaximumFeature, - TuQtlColocH4MaximumFeature, EQtlColocClppMaximumFeature, PQtlColocClppMaximumFeature, SQtlColocClppMaximumFeature, - TuQtlColocClppMaximumFeature, EQtlColocClppMaximumNeighbourhoodFeature, PQtlColocClppMaximumNeighbourhoodFeature, SQtlColocClppMaximumNeighbourhoodFeature, - TuQtlColocClppMaximumNeighbourhoodFeature, EQtlColocH4MaximumNeighbourhoodFeature, PQtlColocH4MaximumNeighbourhoodFeature, SQtlColocH4MaximumNeighbourhoodFeature, - TuQtlColocH4MaximumNeighbourhoodFeature, DistanceTssMeanFeature, DistanceTssMeanNeighbourhoodFeature, DistanceFootprintMeanFeature, From fb6111d1a69799d60ce89b8c1753681a0075f91d Mon Sep 17 00:00:00 2001 From: Daniel Suveges Date: Fri, 11 Oct 2024 15:21:09 +0100 Subject: [PATCH 092/188] fix: adding single point statistics to pics loci (#832) * fix: adding single point statistics to pics loci * fix: patching field update logic * refactor: simplifying the pics process slightly * test: for lead statistics propagation * refactor: udf as decorator * fix: removing commented rows * fix: reverting udf decorator - tests would fail otherwise --- src/gentropy/method/pics.py | 78 +++++++++++++++++++----------- tests/gentropy/method/test_pics.py | 76 ++++++++++++++++++++++++++++- 2 files changed, 124 insertions(+), 30 deletions(-) diff --git a/src/gentropy/method/pics.py b/src/gentropy/method/pics.py index 5fd084efd..b1dc46e12 100644 --- a/src/gentropy/method/pics.py +++ b/src/gentropy/method/pics.py @@ -17,6 +17,18 @@ class PICS: """Probabilistic Identification of Causal SNPs (PICS), an algorithm estimating the probability that an individual variant is causal considering the haplotype structure and observed pattern of association at the genetic locus.""" + # The fields for the picsed locus + ldSet tagVariantId is renamed to variantId: + PICSED_LOCUS_SCHEMA = t.ArrayType( + t.StructType( + [ + t.StructField("variantId", t.StringType(), True), + t.StructField("r2Overall", t.DoubleType(), True), + t.StructField("posteriorProbability", t.DoubleType(), True), + t.StructField("standardError", t.DoubleType(), True), + ] + ) + ) + @staticmethod def _pics_relative_posterior_probability( neglog_p: float, pics_snp_mu: float, pics_snp_std: float @@ -195,36 +207,24 @@ def finemap( Returns: StudyLocus: Study locus with PICS results """ - # Register UDF by defining the structure of the output locus array of structs - # it also renames tagVariantId to variantId - - picsed_ldset_schema = t.ArrayType( - t.StructType( - [ - t.StructField("tagVariantId", t.StringType(), True), - t.StructField("r2Overall", t.DoubleType(), True), - t.StructField("posteriorProbability", t.DoubleType(), True), - t.StructField("standardError", t.DoubleType(), True), - ] - ) - ) - picsed_study_locus_schema = t.ArrayType( - t.StructType( - [ - t.StructField("variantId", t.StringType(), True), - t.StructField("r2Overall", t.DoubleType(), True), - t.StructField("posteriorProbability", t.DoubleType(), True), - t.StructField("standardError", t.DoubleType(), True), - ] - ) - ) - _finemap_udf = f.udf( - lambda locus, neglog_p: PICS._finemap(locus, neglog_p, k), - picsed_ldset_schema, + # Finemapping method is an optional column: + finemapping_method_expression = ( + f.lit("pics") + if "finemappingMethod" not in associations.df.columns + else f.coalesce(f.col("finemappingMethod"), f.lit("pics")) ) + + # Flagging expression for loci that do not qualify for PICS: non_picsable_expr = ( f.size(f.filter(f.col("ldSet"), lambda x: x.r2Overall >= 0.5)) == 0 ) + + # Registering the UDF to be used in the pipeline: + finemap_udf = f.udf( + lambda ld_set, neglog_p: cls._finemap(ld_set, neglog_p, k), + cls.PICSED_LOCUS_SCHEMA, + ) + return StudyLocus( _df=( associations.df @@ -237,11 +237,31 @@ def finemap( "locus", f.when( f.col("ldSet").isNotNull(), - _finemap_udf(f.col("ldSet"), f.col("neglog_pvalue")).cast( - picsed_study_locus_schema + finemap_udf(f.col("ldSet"), f.col("neglog_pvalue")), + ), + ) + # Updating single point statistics in the locus object for the lead variant: + .withColumn( + "locus", + f.transform( + f.col("locus"), + lambda tag: f.when( + f.col("variantId") == tag["variantId"], + tag.withField("pValueMantissa", f.col("pValueMantissa")) + .withField("pValueExponent", f.col("pValueExponent")) + .withField("beta", f.col("beta")), + ).otherwise( + tag.withField( + "pValueMantissa", f.lit(None).cast(t.FloatType()) + ) + .withField( + "pValueExponent", f.lit(None).cast(t.IntegerType()) + ) + .withField("beta", f.lit(None).cast(t.DoubleType())) ), ), ) + # Flagging loci that do not qualify for PICS: .withColumn( "qualityControls", StudyLocus.update_quality_flag( @@ -252,7 +272,7 @@ def finemap( ) .withColumn( "finemappingMethod", - f.coalesce(f.col("finemappingMethod"), f.lit("pics")), + finemapping_method_expression, ) .withColumn( "studyLocusId", diff --git a/tests/gentropy/method/test_pics.py b/tests/gentropy/method/test_pics.py index ff6f115dc..3639b408f 100644 --- a/tests/gentropy/method/test_pics.py +++ b/tests/gentropy/method/test_pics.py @@ -3,7 +3,9 @@ from __future__ import annotations import pyspark.sql.functions as f -from pyspark.sql import Row +import pyspark.sql.types as t +import pytest +from pyspark.sql import Row, SparkSession from gentropy.dataset.study_locus import StudyLocus from gentropy.method.pics import PICS @@ -81,3 +83,75 @@ def test__finemap_udf() -> None: def test_finemap(mock_study_locus: StudyLocus) -> None: """Test finemap function returns study-locus.""" assert isinstance(PICS.finemap(mock_study_locus), StudyLocus) + + +class TestLeadPropagation: + """This test suite is designed to test that the statistics of the lead variant are propagated correctly.""" + + DATA = [ + ("v1", "v1", 1.0), + ("v1", "v2", 0.9), + ("v1", "v3", 0.3), + ] + + @pytest.fixture(autouse=True) + def setup(self, spark: SparkSession) -> None: + """Set up the test suite. + + Args: + spark (SparkSession): The spark session. + """ + df = ( + spark.createDataFrame(self.DATA, ["variantId", "tagVariantId", "r2Overall"]) + .groupBy("variantId") + .agg( + f.collect_list( + f.struct( + f.col("tagVariantId"), + f.col("r2Overall").cast(t.DoubleType()).alias("r2Overall"), + ) + ).alias("ldSet") + ) + .withColumns( + { + "studyLocusId": f.lit("l1"), + "studyId": f.lit("s1"), + "chromosome": f.lit("1"), + "pValueMantissa": f.lit(1.0).cast(t.FloatType()), + "pValueExponent": f.lit(-4).cast(t.IntegerType()), + "beta": f.lit(0.234).cast(t.DoubleType()), + "qualityControls": f.lit(None).cast(t.ArrayType(t.StringType())), + "ldSet": f.filter( + f.col("ldSet"), lambda x: x.tagVariantId.isNotNull() + ), + } + ) + ) + + self.study_locus = StudyLocus(_df=df, _schema=StudyLocus.get_schema()) + + def test_lead_propagation(self: TestLeadPropagation) -> None: + """Testing if all the lead variant statistics are propagated to the tag variants.""" + # Explode all the tags: + finemapped = ( + PICS.finemap(self.study_locus) + .df.select( + f.col("variantId"), + f.col("pValueMantissa"), + f.col("pValueExponent"), + f.col("beta"), + f.explode("locus").alias("locus"), + ) + .collect() + ) + + # Looping through all the tags and checking if the statistics are propagated correctly: + for row in finemapped: + if row["locus"]["variantId"] == row["variantId"]: + assert row["locus"]["pValueMantissa"] == row["pValueMantissa"] + assert row["locus"]["pValueExponent"] == row["pValueExponent"] + assert row["locus"]["beta"] == row["beta"] + else: + assert row["locus"]["pValueMantissa"] is None + assert row["locus"]["pValueExponent"] is None + assert row["locus"]["beta"] is None From 9f446e8f594ca63d359f09683933217b61446b44 Mon Sep 17 00:00:00 2001 From: Daniel Suveges Date: Fri, 11 Oct 2024 19:46:22 +0100 Subject: [PATCH 093/188] fix(find_overlap): missing right study type in output (#828) * fix: rightStudyType nulls removed * test: improve testing of peak overlap function * fix: overlap test --------- Co-authored-by: David Ochoa --- src/gentropy/dataset/study_locus.py | 3 +- tests/gentropy/conftest.py | 9 ++++ .../gentropy/data_samples/coloc_test.parquet | Bin 0 -> 15598 bytes .../dataset/test_study_locus_overlaps.py | 45 +++++++++++++++++- 4 files changed, 54 insertions(+), 3 deletions(-) create mode 100644 tests/gentropy/data_samples/coloc_test.parquet diff --git a/src/gentropy/dataset/study_locus.py b/src/gentropy/dataset/study_locus.py index e9be88a9d..b6fc7b8c9 100644 --- a/src/gentropy/dataset/study_locus.py +++ b/src/gentropy/dataset/study_locus.py @@ -412,6 +412,7 @@ def _overlapping_peaks( .select( f.col("left.studyLocusId").alias("leftStudyLocusId"), f.col("right.studyLocusId").alias("rightStudyLocusId"), + f.col("right.studyType").alias("rightStudyType"), f.col("left.chromosome").alias("chromosome"), ) .distinct() @@ -452,7 +453,6 @@ def _align_overlapping_tags( f.col("chromosome"), f.col("tagVariantId"), f.col("studyLocusId").alias("rightStudyLocusId"), - f.col("studyType").alias("rightStudyType"), *[f.col(col).alias(f"right_{col}") for col in stats_cols], ).join(peak_overlaps, on=["chromosome", "rightStudyLocusId"], how="inner") @@ -464,6 +464,7 @@ def _align_overlapping_tags( "rightStudyLocusId", "leftStudyLocusId", "tagVariantId", + "rightStudyType", ], how="outer", ).select( diff --git a/tests/gentropy/conftest.py b/tests/gentropy/conftest.py index f977e3f74..9ea31ae20 100644 --- a/tests/gentropy/conftest.py +++ b/tests/gentropy/conftest.py @@ -501,6 +501,15 @@ def sample_ukbiobank_studies(spark: SparkSession) -> DataFrame: ) +@pytest.fixture() +def study_locus_sample_for_colocalisation(spark: SparkSession) -> DataFrame: + """Sample study locus data for colocalisation.""" + return StudyLocus( + _df=spark.read.parquet("tests/gentropy/data_samples/coloc_test.parquet"), + _schema=StudyLocus.get_schema(), + ) + + @pytest.fixture() def sample_target_index(spark: SparkSession) -> DataFrame: """Sample target index sample data.""" diff --git a/tests/gentropy/data_samples/coloc_test.parquet b/tests/gentropy/data_samples/coloc_test.parquet new file mode 100644 index 0000000000000000000000000000000000000000..54cc420c45fc521ceedbcb1ba33753f1a8567ef5 GIT binary patch literal 15598 zcmd5@30zZ0x4#zx1R52Q8?5KG zDvP9YNUCV>yps-I6bmw(DKb(9X~-EkQHN zpkqO5*l2YcG>E4@r#6=@yY0qkATpR6G=pj)kxC>A3sK1Ba+#`&QmIsRapyM|z?)pE zQmUe%3mnRwT6X^X(+&}o0|n5|p18RPch;Tqq&7d>KEE+WXPLXo_A;Xrj!?mi5>Q8W z{xz2=zOmF?p_>oiW&cs03sf6R>8box6?-@gEjy-~tMNft!f?Gv6fP1eLgb+eks?SW z4smtkaG}KY!-z1cM63`8K{rGSg-C|Yw1}jZlhnrieS8MsC--`o5hc(rDkUvVo2(6r zR;L-XI$erN93l!+88TIIdd)CZvRa#=QN{F(jSIm)GO=7C4&y+xF43`ZVId(Ri8MrJ z>E7Im1I&@O^p3o?CO%(Wn3MtxB?dsgWesQc{&2j6J zi|ECj9agmSN9S*AsM_;auUtt0AT3T#F;8n>Hnwo#^;od}npo3-0Z-N(|BjMfTJ}oD~f=M{OOeP&)_9Pu4eU4;- zQ{$hhrcb=G;HFPkEnV@}O-(IdA+YWw4wb{9@~^F{agLz&l6Xy<NMfJzXdH ztLmaJJ#^caS-+p~r3V&d_6#}ZOHWJXOy2yHFTGXx^V-V?ed%9oVq%2reQE!f>=t2b zeCZMGb`*ZS#FyT^ZHrVp$Cth&?>BzMEMGcHw|DNjnZESQjXjSC=lIf_do0{qo$X5- zTK;l1d5kZ;v$ELtp3av(lopel(9xIfaA8J&(%Y9_6HCO*XZh0KQRSa{zw)8ydKAnk zeBnd4+;M2#gI|4U$2O70BaZmc#GuyOzg+4=cU$uxx^piddTZP0+%_Ni(9`*Yk9#V7 z=nK`$)^MagbaoBSRodQi>D0TC76^fL9Woa?*1>D?tK z2PKqy(~rB0KUu8srVrnZ{OU?N03_64HUYF1O#r71G;?wrhkh{b|L-76V58 z=})&f^heVXcl>FmogRxWed|w8iRyf7**bq(T#^^zz1p9a{?)mi_i}&QgZz_+3jFCa z%Qmjdp6O379raC;I>Vnn?zxrd9qLb?8b}TuSJ;| z2w(Sr)*t3~^`CP+tNZ%6_Wd^gKKA?gt^7?%JAc#f@c#Ob=j7CVEx#Ea;Wy`y|F-Mn zqgI`0``w8D#BVzjRC@D;17Vx4v$9XzA?r-n1-&wlmNnUe!h5cHadv1CnpT?mYinXL zIy2y}$$_f5X#Kj|Kd;R#L?fFv>mIC|gTCy%Gi*z@IcQm@#TR2b%t4>%CrvE8Uw}B< ze(?DIN&zCXx_uc?QGmXB;MRTAz5+C$PoC554h5+D)84neeF~5^J4Ym}%||PuI{XrJ zBp;!emxpJ3n~yfNX#YcLNj~b&9wKUu<7bUKYYPap#4AkB2dF@~N8R)>A%(%6-D>l>bkLZ3fkjT@oS57Q_z&Xw0K3u6tq`6HFrkh6cl}=XU9;%6cjnD z%cJ}ulTjyUr}(jlHlhB-&8}^`um%-)d7RoSUV^HcULw=i7NJRTAN_o#QxOvM?r`Db z(#5F9>2?`j-iy%5&&TS%-MkQOm6jIo=(G?e7G6XPSqstmPxffaN*16^-K)zs>K34z zvC|3-aSM?D#uy^Qbpc8|oHyZo&3rU{Q{k|$=gmh?{a)m)DV&e!{%gnV(alFaziEDV zqGCRZADHx$w$*&(eyUkShi3E9%pz9v&412A0?+8Sg2(faWHLoeeJ~H5T48wf^42_b zx2&q5_0RJVHEdYLu?ut2n5CzG@}63V9Bz#Z`-WYJe$VrfXIz?t_ADCHfru|a%eqcz zReUWUY45je)V?AgU6~fBnQ+mFj2Q!E>68%-xLSF)d`}+QbSS(1dQl$wC4A^#m6v9s z+q=dN^i<451LrMX`Q%v+@`_zvAUlwQUg#&dQH^s@(|xVSd{{aIrFS8w?JJp%Hnzza zUv}&(G`sKNS<7}$M23Yy?&pq=!~5rd<8+idMyi!>LC>dJ-P|fPhe$Oe$8zsp8_4;&ucZjzMHQZ%?mKQJ7Q;*}(yXd#EH# zE{hBxJVO);xvGm8QV@qILR9jVL~FSsG&B@IyEOHl%@&1)k`Y9g;4y@|JX9_Z3C9U} zs6-N_A>1WlGL=&Nkl;XoFC}{ie@DR4M-dVVQlh=j^W<`=Buv#s?n!V$L&ehYM0mns zi3|wtg;TN+r=LtId5AQUPqO4ve`Rncl!S<-krAMzR4xt;4@Bul0+^+Y6*McyLWp(07ta!^_nCMF|-rJ$`iR4gHT4PL>K%fm!uE)f?@5v>&x zxd=uI&V=6WI0{LKn0!DegMTIsB2+3;1_qCJ z;DCk0{Mo@9NH4JnLdR&OQVwmv#Gx(cL2FN`Bm~i^OI6+cXBvpKWXBLFs z_PtDdZ+HWHnX@-7;B-=ZbzK?o!AV6E&u-27_HRB<+oCf4f=hNy*LhcG6yG?sb<^{G z-$WcWj655<^yc*8ecSEVT&*by;|?AewdB)QD|&>_x;Vk}qn<7F=jMHV^L|TL)9&R+ zO?RX&KHF-DpoZevu$R2I2OsC=@XF|!x*zBk9bA-r)&sijpk~V2_05zH?Ol|4`&^YA z2TFOXx0`a}2sh=*7@l&&eV($+r-^b$H!tPLKUyd|ocB`BPTESyS8)^4S5f1j8WeZ=F&cCI2|C~U33_?zDcW$~0Y?hCBvn9C ze{A?+n>hlvL<*hn#W1alWBxB$LmZu(V)ORqxfHa{Ss9SCHDuO9I$zqmucm+VY|WX9 z^b3DZUZI$s*nd%*MP@q#(_lJ@<Mz8+RvurSMeEk)?e+cgELuk7ADc%HwscMosQF88}v2jgEXe$}97`O5`Ld9y)7VC2AhLaSQ)aC2F)Tbk)_3mFUUh z8P}sqD$$A&k48*7QHjE@Pq_TW(MmMOC%a#pVW&~lwwo7n_E(~^H1+D{fK%EjSTS`^ zC3@V2=NwpGiFSRnJS5;`CF;~;M(eTsYSeyp?dmgYD^ZQ1U{f$WyFFpcqBlUhMymvw z{X2pPS}`UqpwCG54~&mlV?z;^Dct#W>ld@udX}0?W#nQ z5xcubW>liHJqNa$GO7|S^*_j7ms*KFxFyOzp{qmz>f+m~{*}n%<3s2Fcv_7*{aNzG zw_ep~&AAD)^SIUM=-H}UT_0DW*g<`t3~pMD9<7~q!yu?eC$oPzu{RHJPQ~8~xm|^p zluygL`=SaRkC+tmB|JY&Y5yO2i)tk9xA@g(-hfw`l;D503iaS6h%`SLQ99rpDe06)zOGP-TVDMIXt}<4dQkC$cQ$odlvgmiJT%aVmhjtt^|+-Gb$!BH6y#$>yho?H z-0(7@qHlWtG05GBhWl5<1#paLdb7LE_uY(W_Se$ZvmA_Q$6eu|Wsma^@9ssP`1^Ti z;f;i4B{%a>^U3K&;ve(S0gt~{4~GEbz|+fqIlJ;uZ?fgYmk?M2&vm=)H+ksk+6P&` zmE@s5PLjt7%kogvh7$*zM(3dogF5W4Yy<&`^MPjvf1CZ^8b}zOsYTAz(e1{4a7>TK z3&3>8N7G0vJ2hQ<@tmsT4m4rz_*=ofb|CevZP(eC%Fs@g)6?XKJJ9jgoFShcEki?o z?H{z|$1-$}=kvUOU@3Y5bLg_D6lL*UTa}D2McaCQ9RI3)De}{0j$H%guCs<-em1%k zOZa1nFT}}+VGEiHJ)+T4p zJf2mGXnn=ZOJ~Z^(1{0|wuE|K!)9cyNi9X~70u5SW|yKyM@dDAsvPaCYQh;OD@P;Z ze~xgJmLuWzQDc8mL;jFOetWN%qh}E}_oNk;p^^6tOKK07qENk}r>3M7oypDotfsgW z%^9BD?$5QQC@xafn7h6d{o*QHny|PO9qM!QMdy!ppqW0gCwy|sQSvJR{v^)Nmz*s} z7%ll}ISRW|*!c9Ta^!OR*B_%VmSe9m?*Y}n)~u+r3cvdvfH&GPzHHcN3)X0t4&Sh$ z{n_nzKEO1OkZMOA`(@5yV3_R;QM0bhW!}sX;mYesYBTIf>u3I8BBU+cd)&QPGdbr0 zn^E87FOpM6Ckql%l9RNFn0b^!E@lX0Oq^qog>+2NYZA5bz%{063?>Fr02E|UN|K#| zG?dtn<#$Dfe-Ap34(>0dOpwDOx-gI++XL{_`GHf(DjTK4k8hs2Oo?q z7G~J_JQgO~8QEMjo&Gv?&gbzPpxVu(JEOJaJ=k+Tk5h*{w;OmMu&o>-09a{6Mt!#R>AWUh3a9+-psbu zuC*r*x!Q6UxKWXox~JW2xvM|0<<@*aJzW%O*Rv{`s<0ZP zDuzn3pgihhuYPHuy-M+5YJjE6q#@KLQ%e|}+MuqSv{beJ3sqXeaJUnrq;P-Z@4(}v z;p?&<__nNDqCe5Y3x>{A;A$#}8@ z7GcSZ$xKa2)+8IuHGMTnNty(MQm51CG@bRDQR%QlkLe65#-^m}695l`H%c?8lM~hY z#2CFkMQ>KISz3C$X?gCXNlVacQ?c?EePs^3CZp2TI;~+$bV{;8pQ1~Hi)`l}5nwPG zi^tMw(+m_a&Df|eAa^9F!|ZBP>s_QadDtf!xQnz|8~4NA8Y#qT4Be6wHJN4|Js8=# zlwqQfsLtjBPHMUyH2FlMPVOT%XMJGF(wcHGsGI2$G}fTjgJDbqV#wD zriIC(Eg=)AV$Th$lZ!{s3Cv+Nh9~%$L8I5E=zHl?;??n5JV<6WUF-Sl+q=?h&iJ~& z;9^E+O;&NU2ZWZf=d$=-{Myz+xaQ^XWzKBad+JO%%7M$`ZYR0BNFh5yP6WI$=4&`u zgyj|@R~S~fD6Q2~T<#?mEVzVlKWUe1pV20vL%8u!jAdGaMxH5#WFi%$0n*i>l$a0} z!?zQx9k3hK1Y{(+*(6lJPz{Baw%yNm#mkhjE{)=G7pSR3LRbTL%~%GD&F3+e6qArt zZYGoqOB}s$Xo`QiM1Unl@B=ZmgJ&P+%CHUgV$EySl#mdvhWlp+i|K7Ek_odrw`vCz5c8KI2BcT{es}mIS-Y2kTO3yNY^uq~M5jao{oXOlQ)-$cl zCfQxNJ)k7Q9)j3YT!#Q#U}Dc@!WS99lGhTcNJ6+7riB&Vve?^3W-}Y`t)aR-h4Jg> zGV!-!{9+BpuLXRzMf=zG51X7?kYkGbd8R`E_5geeFuyTz4`SRa8tegw;7d4GpL%Tz zvf&g||+?z!C z5W>>{Xf<%%1v9ZI zGz{xnV*>GaCisficUsf#YTJSwxX#?^4%}P^Xc8fJ2zc|!i1&VnE@p4Hr^BS!F^oC{ zlj071an3p?>+kEP&L(k3Ks7u!&BrgsiHwPQ1b076ONA4{9Qfi9_9?vj)e8qqm^!Wj zY6+_vdzp`L=1=Tc_&{fVYhW$Bf@SR1V*fe}GOX^GJrb->VZ!Hrs)jGvmFdU zR0Fxp{yf97ZfUVkY;d>BsuQl5q~Nu8gF8sE9wqH5?0NNbnNo}yAZ5b{EafRf3Nr$- z33-ZzSP!K36c$oHmnoze3%O*mQzpa{3`9m~XTrqm#0ihr=H4~jc8U(q zJ!3QM(Rl84HHU$9W*mnZ?3wWN;EKj(5%stB`Z=Jx_4sQG0P5Fb_UR?oYq^dZLI|@w zu@n8BUiR?Iq!jktEKjrNg7e-(_TxVuZpeBqmnpPxGzfjE!#-65LJ6x-9KY5v#_Lfk zh(1Sh_1p|-7Xds1k0fB8n4V1h4H$pdNXm~8R>2oq{~4bd@7nRJC^J5s=}h==h_^5L zdolh66Mj}Jv(Z?1Fze}Wj-1V?M;dc4G!|yH5+31t*{KemjsL(C-b#Sja~oJ=PLGDw zaZ<9$dZK@l-e9cGRHjBGEb#|rti%e>#gP6~%pI)EZj&-ak!HVc*c5dFSs27y z6n7~{SQIJDk$TAqo7>u08=KqOsGSC+XJ>-++GOm#Rnd4m_jhhsdi{U|RJg|CK4C#a z;W`>tdCUp%Oau{kNC4xl0kKQ5*fS}3X{n0AOUoO?T93?T+b=MMu2nI@r7<8Db57>i z1&g)6H6V6-Cb-@7R4n#UpMM&7Yw!qtG<)5nKEmCdVW6!n7SBd);eoE7+ko)HxX;^D zvDaN1_)o&?g+8FgGZ$_S8`=qr`hphrP{+!kLDw6|Z9t1FSc^v{Es6)5wJJtgdt;b&yd_pB-FqmMgx4@`%!yL zJqpG^w@!?rHo$szV;GkuWOJ)j@bwygAdi=#9~P`mRRfb0Y$BC{;l!T?TnW!f5)A(c zUfX&#(njfmfqw!n#t^Je867+lSe`_+LCyP)JI>DlG?QPrUz$Omo?!3`^h?rebctzx z;RDC{C96l8i|jNNRIoPyItAX7({(yET(tOw1B52f&x-CBK5oK(2 z5O%ig{V}Z6njJx#Y|sqT=po}RjbWza>;Pc>cQmR2;wSXWa!%sUUq8%Rq#@;fS6hvu}SysNnzU`Fj=@9H|Q5vevH z+e)C;>(yf*+d`z8rmSgwFncJ_YzDP9Ijtv5d-If^@YVxXkB7BM$Lr5K%>V{FYa(s! zNbfxQ3@8iHYX^JRp<;5w{~86;$?p$hXQ1sE?`#|E>F8fT*qQEs0b=6EZSDWrS8b*L zu%|IkRW{gnc0wE9Zijd~hZziW=HE;t)3Dft+B)3e)U}oVgE?Mf|82;A@hK@fxafe4 zw_K9}iFtzh7f7aC27CLrGps${Xy{_%{n7pxLXZEpP4C}@0RKx{+yC1Pvfmcjo#O5G zpurOeUUy449W+ueu*Ba2QLsoHEEWXBr)zbIg3wTnBqTu*5+;!-CLj@PV|7ZV+d>?}71%K)MKjC|sG5`Po literal 0 HcmV?d00001 diff --git a/tests/gentropy/dataset/test_study_locus_overlaps.py b/tests/gentropy/dataset/test_study_locus_overlaps.py index 58dc95039..669af476f 100644 --- a/tests/gentropy/dataset/test_study_locus_overlaps.py +++ b/tests/gentropy/dataset/test_study_locus_overlaps.py @@ -4,6 +4,7 @@ from typing import TYPE_CHECKING, Any +import pyspark.sql.functions as f import pyspark.sql.types as t import pytest @@ -59,7 +60,12 @@ def test_study_locus_overlap_from_associations(mock_study_locus: StudyLocus) -> False, # expected - output DataFrame with overlapping signals [ - {"leftStudyLocusId": "1", "rightStudyLocusId": "2", "chromosome": "1"}, + { + "leftStudyLocusId": "1", + "rightStudyLocusId": "2", + "rightStudyType": "eqtl", + "chromosome": "1", + }, ], ), ( @@ -93,7 +99,14 @@ def test_study_locus_overlap_from_associations(mock_study_locus: StudyLocus) -> # intrastudy - bool of whether or not to use inter-study or intra-study logic True, # expected - output DataFrame with overlapping signals - [{"leftStudyLocusId": "2", "rightStudyLocusId": "1", "chromosome": "1"}], + [ + { + "leftStudyLocusId": "2", + "rightStudyLocusId": "1", + "rightStudyType": "gwas", + "chromosome": "1", + } + ], ), ], ) @@ -118,6 +131,7 @@ def test_overlapping_peaks( [ t.StructField("leftStudyLocusId", t.StringType()), t.StructField("rightStudyLocusId", t.StringType()), + t.StructField("rightStudyType", t.StringType()), t.StructField("chromosome", t.StringType()), ] ) @@ -125,3 +139,30 @@ def test_overlapping_peaks( result_df = StudyLocus._overlapping_peaks(observed_df, intrastudy) expected_df = spark.createDataFrame(expected, expected_schema) assert result_df.collect() == expected_df.collect() + + +class TestStudyLocusOverlap: + """Test the overlapping of StudyLocus dataset.""" + + @pytest.fixture(autouse=True) + def setup( + self: TestStudyLocusOverlap, study_locus_sample_for_colocalisation: StudyLocus + ) -> None: + """Get sample dataset.""" + # Store imput dataset: + self.study_locus = study_locus_sample_for_colocalisation + + # Call locus overlap: + self.overlaps = study_locus_sample_for_colocalisation.find_overlaps() + + def test_coloc_return_type(self: TestStudyLocusOverlap) -> None: + """Test get_schema.""" + assert isinstance(self.overlaps, StudyLocusOverlap) + + def test_coloc_not_null(self: TestStudyLocusOverlap) -> None: + """Test get_schema.""" + assert self.overlaps.df.count() != 0 + + def test_coloc_study_type_not_null(self: TestStudyLocusOverlap) -> None: + """Test get_schema.""" + assert self.overlaps.filter(f.col("rightStudyType").isNull()).df.count() == 0 From c4520aa31a524034475c4630c311d1b0f4053088 Mon Sep 17 00:00:00 2001 From: David Ochoa Date: Sat, 12 Oct 2024 14:02:08 +0100 Subject: [PATCH 094/188] feat: enhance variant index partitioning (#834) --- src/gentropy/variant_index.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/gentropy/variant_index.py b/src/gentropy/variant_index.py index f6d555f07..dba087c79 100644 --- a/src/gentropy/variant_index.py +++ b/src/gentropy/variant_index.py @@ -59,8 +59,9 @@ def __init__( col("variantId"), col("chromosome"), col("position") ), ) - .write.partitionBy("chromosome") - .mode(session.write_mode) + .repartitionByRange("chromosome", "position") + .sortWithinPartitions("chromosome", "position") + .write.mode(session.write_mode) .parquet(variant_index_path) ) From e77abf499bc4a4b9cdb77cbe962423563fcd5828 Mon Sep 17 00:00:00 2001 From: Yakov Date: Mon, 14 Oct 2024 13:44:52 +0100 Subject: [PATCH 095/188] feat: adding new LD interface (#759) * feat: adding new LD interface * fix: adding ld_index * fix: adding csa * fix: adding fucntion in init * chore: temporary commit to build the Docker image * chore: revert temporary GitHub Actions configuration * chore: committing some restructuring * chore: committing some changes * chore: tweaking variable names * fix: fixing locus index boundaries * docs: documenting where gnomad ht were sourced from * fix: adding afr ancestry to panUKBB interface * fix: fixing arguments for susie_finemapper * fix: removing unneeded code from panukbb ld * feat: ancestry mapping * fix: remove chr from chromosome column + some other bugs * fix: removing duplicated variants & resolving flipped indels * chore: committing changes * Update src/gentropy/datasource/pan_ukbb_ld/ld.py Co-authored-by: Daniel Suveges * Update src/gentropy/method/ld_matrix_interface.py Co-authored-by: Daniel Suveges * Update colocalisation.py * fix: rightStudyType nulls removed * test: improve testing of peak overlap function * fix: overlap test * fix: changes suggested by ds review * chore: removing unneeded variants.py --------- Co-authored-by: Kirill Tsukanov Co-authored-by: Daniel Considine Co-authored-by: Daniel-Considine <113430683+Daniel-Considine@users.noreply.github.com> Co-authored-by: Daniel Suveges --- src/gentropy/config.py | 23 ++ .../datasource/pan_ukbb_ld/__init__.py | 3 + src/gentropy/datasource/pan_ukbb_ld/ld.py | 214 ++++++++++++++++ src/gentropy/method/ld_matrix_interface.py | 101 ++++++++ src/gentropy/susie_finemapper.py | 230 ++++++++++++++++++ 5 files changed, 571 insertions(+) create mode 100644 src/gentropy/datasource/pan_ukbb_ld/__init__.py create mode 100644 src/gentropy/datasource/pan_ukbb_ld/ld.py create mode 100644 src/gentropy/method/ld_matrix_interface.py diff --git a/src/gentropy/config.py b/src/gentropy/config.py index 50eb4af72..464861803 100644 --- a/src/gentropy/config.py +++ b/src/gentropy/config.py @@ -403,6 +403,29 @@ class GnomadVariantConfig(StepConfig): _target_: str = "gentropy.gnomad_ingestion.GnomadVariantIndexStep" +@dataclass +class PanUKBBConfig(StepConfig): + """Pan UKB variant ingestion step configuration.""" + + session: Any = field( + default_factory=lambda: { + "start_hail": True, + } + ) + pan_ukbb_ht_path: str = "gs://panukbb-ld-matrixes/ukb-diverse-pops-public-build-38/UKBB.{POP}.ldadj.variant.b38" + pan_ukbb_bm_path: str = "gs://panukbb-ld-matrixes/UKBB.{POP}.ldadj" + ukbb_annotation_path: str = "gs://panukbb-ld-matrixes/UKBB.{POP}.aligned.parquet" + pan_ukbb_pops: list[str] = field( + default_factory=lambda: [ + "AFR", # African + "CSA", # Central/South Asian + "EUR", # European + ] + ) + use_version_from_input: bool = False + _target_: str = "gentropy.pan_ukb_ingestion.PanUKBBVariantIndexStep" + + @dataclass class VariantIndexConfig(StepConfig): """Variant index step configuration.""" diff --git a/src/gentropy/datasource/pan_ukbb_ld/__init__.py b/src/gentropy/datasource/pan_ukbb_ld/__init__.py new file mode 100644 index 000000000..dc57b8db8 --- /dev/null +++ b/src/gentropy/datasource/pan_ukbb_ld/__init__.py @@ -0,0 +1,3 @@ +"""Pan UKBB Data Source.""" + +from __future__ import annotations diff --git a/src/gentropy/datasource/pan_ukbb_ld/ld.py b/src/gentropy/datasource/pan_ukbb_ld/ld.py new file mode 100644 index 000000000..1926ddc9c --- /dev/null +++ b/src/gentropy/datasource/pan_ukbb_ld/ld.py @@ -0,0 +1,214 @@ +"""Step to import filtered version of a LD matrix (block matrix).""" + +from __future__ import annotations + +from typing import TYPE_CHECKING + +import hail as hl +import numpy as np +import pyspark.sql.functions as f +from hail.linalg import BlockMatrix +from pyspark.sql.window import Window + +from gentropy.common.session import Session +from gentropy.config import PanUKBBConfig + +if TYPE_CHECKING: + from pyspark.sql import DataFrame, Row + + +class PanUKBBLDMatrix: + """Toolset to work with Pan UKBB LD matrices.""" + + def __init__( + self, + pan_ukbb_ht_path: str = PanUKBBConfig().pan_ukbb_ht_path, + pan_ukbb_bm_path: str = PanUKBBConfig().pan_ukbb_bm_path, + ld_populations: list[str] = PanUKBBConfig().pan_ukbb_pops, + ukbb_annotation_path: str = PanUKBBConfig().ukbb_annotation_path, + ): + """Initialize. + + Datasets are in hail native format. + + Args: + pan_ukbb_ht_path (str): Path to hail table, source: gs://ukb-diverse-pops-public/ld_release + pan_ukbb_bm_path (str): Path to hail block matrix + ld_populations (list[str]): List of populations + ukbb_annotation_path (str): Path to pan-ukbb variant LD index with alleles flipped to match the order in OT variant annotation + Default values are set in PanUKBBConfig. + """ + self.pan_ukbb_ht_path = pan_ukbb_ht_path + self.pan_ukbb_bm_path = pan_ukbb_bm_path + self.ld_populations = ld_populations + self.ukbb_annotation_output_path = ukbb_annotation_path + + def align_ld_index_alleles( + self, + variant_annotation: DataFrame, + population: str, + hail_table_path: str = PanUKBBConfig.pan_ukbb_ht_path, + hail_table_output: str = PanUKBBConfig.ukbb_annotation_path, + ) -> None: + """Align Pan-UKBB variant LD index alleles with the Open Targets variant annotation. + + Args: + variant_annotation (DataFrame): Open Targets variant annotation DataFrame + population (str): Population label + hail_table_path (str): Path to hail table with Pan-UKBB variant LD index + hail_table_output (str): Path to output the aligned Pan-UKBB variant LD index with alleles in the correct order + """ + ht = hl.read_table(hail_table_path.format(POP=population)) + ht = ( + ht.to_spark() + .select( + "`locus.contig`", + "`locus.position`", + "`alleles`", + "`idx`", + ) + .withColumns( + { + "chromosome": f.split("`locus.contig`", "chr")[1], + "position": f.col("`locus.position`"), + "referenceAllele": f.element_at("`alleles`", 1), + "alternateAllele": f.element_at("`alleles`", 2), + } + ) + .drop("locus.contig", "locus.position", "alleles") + .dropDuplicates( + ["chromosome", "position", "referenceAllele", "alternateAllele"] + ) + ) + ht_va = ( + ht.alias("ukbb") + .join( + variant_annotation.select( + "chromosome", + "position", + f.col("referenceAllele").alias("va_ref"), + f.col("alternateAllele").alias("va_alt"), + ).dropDuplicates(["chromosome", "position", "va_ref", "va_alt"]), + on=["chromosome", "position"], + how="left", + ) + .filter( + ( + (f.col("referenceAllele") == f.col("va_ref")) + & (f.col("alternateAllele") == f.col("va_alt")) + ) + | ( + (f.col("referenceAllele") == f.col("va_alt")) + & (f.col("alternateAllele") == f.col("va_ref")) + ) + | (f.col("va_ref").isNull() | f.col("va_alt").isNull()) + ) + .withColumns( + { + "alleleOrder": f.when( + (f.col("referenceAllele") == f.col("va_alt")) + & (f.col("alternateAllele") == f.col("va_ref")), + -1, + ).otherwise(1), + "new_referenceAllele": f.when( + (f.col("referenceAllele") == f.col("va_alt")) + & (f.col("alternateAllele") == f.col("va_ref")), + f.col("va_ref"), + ).otherwise(f.col("referenceAllele")), + "new_alternateAllele": f.when( + (f.col("alternateAllele") == f.col("va_ref")) + & (f.col("referenceAllele") == f.col("va_alt")), + f.col("va_alt"), + ).otherwise(f.col("alternateAllele")), + } + ) + .select( + f.concat_ws( + "_", + "chromosome", + "position", + "new_referenceAllele", + "new_alternateAllele", + ).alias("variantId"), + "chromosome", + "position", + f.col("new_referenceAllele").alias("referenceAllele"), + f.col("new_alternateAllele").alias("alternateAllele"), + "alleleOrder", + "idx", + ) + ) + window_spec = Window.partitionBy("idx").orderBy(f.col("alleleOrder").desc()) + ht_va = ( + ht_va.withColumn("rank", f.rank().over(window_spec)) + .filter(f.col("rank") == 1) + .drop("rank") + ) + ht_va.write.mode("overwrite").parquet(hail_table_output.format(POP=population)) + + def get_numpy_matrix( + self: PanUKBBLDMatrix, + locus_index: DataFrame, + ancestry: str, + ) -> np.ndarray: + """Extract the LD block matrix for a locus. + + Args: + locus_index (DataFrame): hail matrix variant index table + ancestry (str): Ancestry label + + Returns: + np.ndarray: LD block matrix for the locus + """ + idx = [row["idx"] for row in locus_index.select("idx").collect()] + + half_matrix = ( + BlockMatrix.read(self.pan_ukbb_bm_path.format(POP=ancestry)) + .filter(idx, idx) + .to_numpy() + ) + + alleleOrder = [ + row["alleleOrder"] for row in locus_index.select("alleleOrder").collect() + ] + outer_allele_order = np.outer(alleleOrder, alleleOrder) + np.fill_diagonal(outer_allele_order, 1) + + ld_matrix = (half_matrix + half_matrix.T) - np.diag(np.diag(half_matrix)) + ld_matrix = ld_matrix * outer_allele_order + np.fill_diagonal(ld_matrix, 1) + + return ld_matrix + + def get_locus_index_boundaries( + self, + session: Session, + study_locus_row: Row, + ancestry: str = "EUR", + ) -> DataFrame: + """Extract hail matrix index from StudyLocus rows. + + Args: + session (Session): Session object + study_locus_row (Row): Study-locus row + ancestry (str): Major population, default is "EUR" + + Returns: + DataFrame: Returns the index of the pan-ukbb matrix for the locus + + """ + chromosome = str(study_locus_row["chromosome"]) + start = int(study_locus_row["locusStart"]) + end = int(study_locus_row["locusEnd"]) + + index_file = session.spark.read.parquet( + self.ukbb_annotation_output_path.format(POP=ancestry) + ) + + index_file = index_file.filter( + (f.col("chromosome") == chromosome) + & (f.col("position") >= start) + & (f.col("position") <= end) + ).sort("idx") + + return index_file diff --git a/src/gentropy/method/ld_matrix_interface.py b/src/gentropy/method/ld_matrix_interface.py new file mode 100644 index 000000000..d0051101b --- /dev/null +++ b/src/gentropy/method/ld_matrix_interface.py @@ -0,0 +1,101 @@ +"""Step to import filtered version of a LD matrix (block matrix).""" + +from __future__ import annotations + +from typing import TYPE_CHECKING + +import numpy as np +import pyspark.sql.functions as f + +from gentropy.common.session import Session +from gentropy.datasource.gnomad.ld import GnomADLDMatrix +from gentropy.datasource.pan_ukbb_ld.ld import PanUKBBLDMatrix + +if TYPE_CHECKING: + from pyspark.sql import DataFrame, Row + + +class LDMatrixInterface: + """Toolset to interact with LD matrices.""" + + ancestry_map = { + "nfe": "EUR", + "csa": "CSA", + "afr": "AFR", + } + + @staticmethod + def get_locus_index_boundaries( + session: Session, + study_locus_row: Row, + ancestry: str = "nfe", + ) -> DataFrame: + """Extract hail matrix index from StudyLocus rows. + + Args: + session (Session): Session object + study_locus_row (Row): Study-locus row + ancestry (str): Major population to extract from gnomad matrix, default is "nfe" + + Returns: + DataFrame: Returns the index of the gnomad matrix for the locus + + """ + if ancestry in ("nfe", "csa", "afr"): + joined_index = PanUKBBLDMatrix().get_locus_index_boundaries( + session=session, + study_locus_row=study_locus_row, + ancestry=LDMatrixInterface.ancestry_map.get(ancestry, ancestry), + ) + else: + joined_index = ( + GnomADLDMatrix() + .get_locus_index_boundaries( + study_locus_row=study_locus_row, + major_population=ancestry, + ) + .withColumn( + "variantId", + f.concat( + f.regexp_replace(f.col("`locus.contig`"), "chr", ""), + f.lit("_"), + f.col("`locus.position`"), + f.lit("_"), + f.col("alleles").getItem(0), + f.lit("_"), + f.col("alleles").getItem(1), + ).cast("string"), + ) + ) + + return joined_index + + @staticmethod + def get_numpy_matrix( + locus_index: DataFrame, + ancestry: str = "nfe", + ) -> np.ndarray: + """Extract the LD block matrix for a locus. + + Args: + locus_index (DataFrame): hail matrix variant index table + ancestry (str): major ancestry label eg. `nfe` + + Returns: + np.ndarray: LD block matrix for the locus + """ + if ancestry in ( + "afr", + "csa", + "nfe", + ): + block_matrix = PanUKBBLDMatrix().get_numpy_matrix( + locus_index=locus_index, + ancestry=LDMatrixInterface.ancestry_map.get(ancestry, ancestry), + ) + else: + block_matrix = GnomADLDMatrix.get_numpy_matrix( + locus_index=locus_index, gnomad_ancestry=ancestry + ) + + return block_matrix diff --git a/src/gentropy/susie_finemapper.py b/src/gentropy/susie_finemapper.py index 38a621f96..7d04b5763 100644 --- a/src/gentropy/susie_finemapper.py +++ b/src/gentropy/susie_finemapper.py @@ -29,6 +29,7 @@ from gentropy.dataset.study_locus import StudyLocus from gentropy.datasource.gnomad.ld import GnomADLDMatrix from gentropy.method.carma import CARMA +from gentropy.method.ld_matrix_interface import LDMatrixInterface from gentropy.method.sumstat_imputation import SummaryStatisticsImputation from gentropy.method.susie_inf import SUSIE_inf @@ -855,3 +856,232 @@ def susie_finemapper_one_sl_row_v4_ss_gathered_boundaries( ) return out + + @staticmethod + def susie_finemapper_one_sl_row_v4_ss_gathered_boundaries_ldinterface( # noqa: C901 + session: Session, + study_locus_row: Row, + study_index: StudyIndex, + max_causal_snps: int = 10, + susie_est_tausq: bool = False, + run_carma: bool = False, + run_sumstat_imputation: bool = False, + carma_time_limit: int = 600, + carma_tau: float = 0.04, + imputed_r2_threshold: float = 0.9, + ld_score_threshold: float = 5, + sum_pips: float = 0.99, + lead_pval_threshold: float = 1e-5, + purity_mean_r2_threshold: float = 0, + purity_min_r2_threshold: float = 0.25, + cs_lbf_thr: float = 2, + ) -> dict[str, Any] | None: + """Susie fine-mapper function that uses study-locus row with collected locus, chromosome and position as inputs. + + Args: + session (Session): Spark session + study_locus_row (Row): StudyLocus row with collected locus + study_index (StudyIndex): StudyIndex object + max_causal_snps (int): maximum number of causal variants + susie_est_tausq (bool): estimate tau squared, default is False + run_carma (bool): run CARMA, default is False + run_sumstat_imputation (bool): run summary statistics imputation, default is False + carma_time_limit (int): CARMA time limit, default is 600 seconds + carma_tau (float): CARMA tau, shrinkage parameter + imputed_r2_threshold (float): imputed R2 threshold, default is 0.8 + ld_score_threshold (float): LD score threshold ofr imputation, default is 4 + sum_pips (float): the expected sum of posterior probabilities in the locus, default is 0.99 (99% credible set) + lead_pval_threshold (float): p-value threshold for the lead variant from CS, default is 1e-5 + purity_mean_r2_threshold (float): thrshold for purity mean r2 qc metrics for filtering credible sets + purity_min_r2_threshold (float): thrshold for purity min r2 qc metrics for filtering credible sets + cs_lbf_thr (float): credible set logBF threshold for filtering credible sets, default is 2 + + Returns: + dict[str, Any] | None: dictionary with study locus, number of GWAS variants, number of LD variants, number of variants after merge, number of outliers, number of imputed variants, number of variants to fine-map, or None + """ + # PLEASE DO NOT REMOVE THIS LINE + pd.DataFrame.iteritems = pd.DataFrame.items + + chromosome = study_locus_row["chromosome"] + studyId = study_locus_row["studyId"] + locusStart = study_locus_row["locusStart"] + locusEnd = study_locus_row["locusEnd"] + + study_index_df = study_index._df + study_index_df = study_index_df.filter(f.col("studyId") == studyId) + major_population = study_index_df.select( + "studyId", + order_array_of_structs_by_field( + "ldPopulationStructure", "relativeSampleSize" + )[0]["ldPopulation"].alias("majorPopulation"), + ).collect()[0]["majorPopulation"] + + region = chromosome + ":" + str(int(locusStart)) + "-" + str(int(locusEnd)) + + schema = StudyLocus.get_schema() + gwas_df = session.spark.createDataFrame([study_locus_row], schema=schema) + exploded_df = gwas_df.select(f.explode("locus").alias("locus")) + + result_df = exploded_df.select( + "locus.variantId", "locus.beta", "locus.standardError" + ) + gwas_df = ( + result_df.withColumn("z", f.col("beta") / f.col("standardError")) + .withColumn( + "chromosome", f.split(f.col("variantId"), "_")[0].cast("string") + ) + .withColumn("position", f.split(f.col("variantId"), "_")[1].cast("int")) + .filter(f.col("chromosome") == chromosome) + .filter(f.col("position") >= int(locusStart)) + .filter(f.col("position") <= int(locusEnd)) + .filter(f.col("z").isNotNull()) + ) + + # Remove ALL duplicated variants from GWAS DataFrame - we don't know which is correct + variant_counts = gwas_df.groupBy("variantId").count() + unique_variants = variant_counts.filter(f.col("count") == 1) + gwas_df = gwas_df.join(unique_variants, on="variantId", how="left_semi") + + ld_index = LDMatrixInterface.get_locus_index_boundaries( + study_locus_row=study_locus_row, ancestry=major_population, session=session + ) + + # Remove ALL duplicated variants from ld_index DataFrame - we don't know which is correct + variant_counts = ld_index.groupBy("variantId").count() + unique_variants = variant_counts.filter(f.col("count") == 1) + ld_index = ld_index.join(unique_variants, on="variantId", how="left_semi").sort( + "idx" + ) + if "alleleOrder" not in ld_index.columns: + ld_index = ld_index.withColumn("alleleOrder", f.lit(1)) + + if not run_sumstat_imputation: + # Filtering out the variants that are not in the LD matrix, we don't need them + gwas_index = gwas_df.join( + ld_index.select("variantId", "idx", "alleleOrder"), on="variantId" + ).sort("idx") + gwas_df = gwas_index.select( + "variantId", + "z", + "chromosome", + "position", + "beta", + "StandardError", + ) + gwas_index = gwas_index.drop( + "z", "chromosome", "position", "beta", "StandardError" + ) + if gwas_index.rdd.isEmpty(): + logging.warning("No overlapping variants in the LD Index") + return None + gnomad_ld = LDMatrixInterface.get_numpy_matrix( + gwas_index, ancestry=major_population + ) + + # Module to remove NANs from the LD matrix + if sum(sum(np.isnan(gnomad_ld))) > 0: + gwas_index = gwas_index.toPandas() + + # First round of filtering out the variants with NANs + nan_count = 1 - (sum(np.isnan(gnomad_ld)) / len(gnomad_ld)) + indices = np.where(nan_count >= 0.98) + indices = indices[0] + gnomad_ld = gnomad_ld[indices][:, indices] + + gwas_index = gwas_index.iloc[indices, :] + + if len(gwas_index) == 0: + logging.warning("No overlapping variants in the LD Index") + return None + + # Second round of filtering out the variants with NANs + nan_count = sum(np.isnan(gnomad_ld)) + indices = np.where(nan_count == 0) + indices = indices[0] + + gnomad_ld = gnomad_ld[indices][:, indices] + gwas_index = gwas_index.iloc[indices, :] + + if len(gwas_index) == 0: + logging.warning("No overlapping variants in the LD Index") + return None + + gwas_index = session.spark.createDataFrame(gwas_index) + + else: + gwas_index = gwas_df.join( + ld_index.select("variantId", "idx", "alleleOrder"), on="variantId" + ).sort("idx") + if gwas_index.rdd.isEmpty(): + logging.warning("No overlapping variants in the LD Index") + return None + gwas_index = ld_index + gnomad_ld = LDMatrixInterface.get_numpy_matrix( + gwas_index, ancestry=major_population + ) + + # Module to remove NANs from the LD matrix + if sum(sum(np.isnan(gnomad_ld))) > 0: + gwas_index = gwas_index.toPandas() + + # First round of filtering out the variants with NANs + nan_count = 1 - (sum(np.isnan(gnomad_ld)) / len(gnomad_ld)) + indices = np.where(nan_count >= 0.98) + indices = indices[0] + gnomad_ld = gnomad_ld[indices][:, indices] + + gwas_index = gwas_index.iloc[indices, :] + + if len(gwas_index) == 0: + logging.warning("No overlapping variants in the LD Index") + return None + + # Second round of filtering out the variants with NANs + nan_count = sum(np.isnan(gnomad_ld)) + indices = np.where(nan_count == 0) + indices = indices[0] + + gnomad_ld = gnomad_ld[indices][:, indices] + gwas_index = gwas_index.iloc[indices, :] + + if len(gwas_index) == 0: + logging.warning("No overlapping variants in the LD Index") + return None + + gwas_index = session.spark.createDataFrame(gwas_index) + + # sanity filters on LD matrix + np.fill_diagonal(gnomad_ld, 1) + gnomad_ld[gnomad_ld > 1] = 1 + gnomad_ld[gnomad_ld < -1] = -1 + upper_triangle = np.triu(gnomad_ld) + gnomad_ld = ( + upper_triangle + upper_triangle.T - np.diag(upper_triangle.diagonal()) + ) + np.fill_diagonal(gnomad_ld, 1) + + out = SusieFineMapperStep.susie_finemapper_from_prepared_dataframes( + GWAS_df=gwas_df, + ld_index=gwas_index, + gnomad_ld=gnomad_ld, + L=max_causal_snps, + session=session, + studyId=studyId, + region=region, + locusStart=locusStart, + locusEnd=locusEnd, + susie_est_tausq=susie_est_tausq, + run_carma=run_carma, + run_sumstat_imputation=run_sumstat_imputation, + carma_time_limit=carma_time_limit, + carma_tau=carma_tau, + imputed_r2_threshold=imputed_r2_threshold, + ld_score_threshold=ld_score_threshold, + sum_pips=sum_pips, + lead_pval_threshold=lead_pval_threshold, + purity_mean_r2_threshold=purity_mean_r2_threshold, + purity_min_r2_threshold=purity_min_r2_threshold, + cs_lbf_thr=cs_lbf_thr, + ) + + return out From 38d4cb5a07a32463102764c1991c28cd4391f563 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Irene=20L=C3=B3pez=20Santiago?= <45119610+ireneisdoomed@users.noreply.github.com> Date: Mon, 14 Oct 2024 15:16:58 +0100 Subject: [PATCH 096/188] ci: configure java v8 (#840) --- .github/workflows/pr.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index 5fb541572..f27ae499e 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -17,6 +17,11 @@ jobs: uses: actions/setup-python@v5 with: python-version: 3.10.8 + - name: Set up Java + uses: actions/setup-java@v4 + with: + java-version: "8" + distribution: "temurin" - name: Install and configure Poetry uses: snok/install-poetry@v1 with: From d461e38173d11250df0557d1d52285c4f0097d01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Irene=20L=C3=B3pez=20Santiago?= <45119610+ireneisdoomed@users.noreply.github.com> Date: Mon, 14 Oct 2024 16:11:34 +0100 Subject: [PATCH 097/188] fix(trainer): drop `studyLocusId` from training sets (#837) --- src/gentropy/method/l2g/trainer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gentropy/method/l2g/trainer.py b/src/gentropy/method/l2g/trainer.py index 69dfb24ff..1c4088462 100644 --- a/src/gentropy/method/l2g/trainer.py +++ b/src/gentropy/method/l2g/trainer.py @@ -155,14 +155,14 @@ def train( Returns: LocusToGeneModel: Fitted model """ - data_df = self.feature_matrix._df.drop("geneId").toPandas() + data_df = self.feature_matrix._df.drop("geneId", "studyLocusId").toPandas() # Encode labels in `goldStandardSet` to a numeric value data_df["goldStandardSet"] = data_df["goldStandardSet"].map( self.model.label_encoder ) - # Convert all columns to numeric and split + # Ensure all columns are numeric and split data_df = data_df.apply(pd.to_numeric) self.feature_cols = [ col From 6817aadcc0ffe2baf53909cba9a05a3f57a10d64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Irene=20L=C3=B3pez=20Santiago?= <45119610+ireneisdoomed@users.noreply.github.com> Date: Mon, 14 Oct 2024 16:18:08 +0100 Subject: [PATCH 098/188] fix(l2g): remove custom session params + other fixes (#841) * chore: delete l2g custom spark session * fix: add neighbourhood features in `LocusToGeneFeatureMatrixConfig` * fix(feature_matrix): use right config for default values --- src/gentropy/config.py | 21 +++++++++------------ src/gentropy/l2g.py | 4 ++-- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/gentropy/config.py b/src/gentropy/config.py index 464861803..83a578ab8 100644 --- a/src/gentropy/config.py +++ b/src/gentropy/config.py @@ -222,16 +222,7 @@ class LDBasedClumpingConfig(StepConfig): class LocusToGeneConfig(StepConfig): """Locus to gene step configuration.""" - session: Any = field( - default_factory=lambda: { - "extended_spark_conf": { - "spark.dynamicAllocation.enabled": "false", - "spark.driver.memory": "48g", - "spark.executor.memory": "48g", - "spark.sql.shuffle.partitions": "800", - } - } - ) + session: Any = field(default_factory=lambda: {"extended_spark_conf": None}) run_mode: str = MISSING predictions_path: str = MISSING credible_set_path: str = MISSING @@ -313,12 +304,18 @@ class LocusToGeneFeatureMatrixConfig(StepConfig): "eQtlColocClppMaximum", "pQtlColocClppMaximum", "sQtlColocClppMaximum", - "tuQtlColocClppMaximum", # max H4 for each (study, locus, gene) aggregating over a specific qtl type "eQtlColocH4Maximum", "pQtlColocH4Maximum", "sQtlColocH4Maximum", - "tuQtlColocH4Maximum", + # max CLPP for each (study, locus, gene) aggregating over a specific qtl type and in relation with the mean in the vicinity + "eQtlColocClppMaximumNeighbourhood", + "pQtlColocClppMaximumNeighbourhood", + "sQtlColocClppMaximumNeighbourhood", + # max H4 for each (study, locus, gene) aggregating over a specific qtl type and in relation with the mean in the vicinity + "eQtlColocH4MaximumNeighbourhood", + "pQtlColocH4MaximumNeighbourhood", + "sQtlColocH4MaximumNeighbourhood", # distance to gene footprint "distanceSentinelFootprint", "distanceSentinelFootprintNeighbourhood", diff --git a/src/gentropy/l2g.py b/src/gentropy/l2g.py index 296aba3d2..8ff41d09b 100644 --- a/src/gentropy/l2g.py +++ b/src/gentropy/l2g.py @@ -10,7 +10,7 @@ from gentropy.common.session import Session from gentropy.common.utils import access_gcp_secret -from gentropy.config import LocusToGeneConfig +from gentropy.config import LocusToGeneConfig, LocusToGeneFeatureMatrixConfig from gentropy.dataset.colocalisation import Colocalisation from gentropy.dataset.gene_index import GeneIndex from gentropy.dataset.l2g_feature_matrix import L2GFeatureMatrix @@ -31,7 +31,7 @@ def __init__( self, session: Session, *, - features_list: list[str] = LocusToGeneConfig().features_list, + features_list: list[str] = LocusToGeneFeatureMatrixConfig().features_list, credible_set_path: str, variant_index_path: str | None = None, colocalisation_path: str | None = None, From 44f05c438f16266f64a8f45889de875e31bd4a57 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Oct 2024 16:26:00 +0100 Subject: [PATCH 099/188] build(deps-dev): bump pymdown-extensions from 10.10.1 to 10.11.2 (#815) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [pymdown-extensions](https://github.com/facelessuser/pymdown-extensions) from 10.10.1 to 10.11.2. - [Release notes](https://github.com/facelessuser/pymdown-extensions/releases) - [Commits](https://github.com/facelessuser/pymdown-extensions/compare/10.10.1...10.11.2) --- updated-dependencies: - dependency-name: pymdown-extensions dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Irene López Santiago <45119610+ireneisdoomed@users.noreply.github.com> --- poetry.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/poetry.lock b/poetry.lock index 9cdc7b88e..083f524f9 100644 --- a/poetry.lock +++ b/poetry.lock @@ -3740,13 +3740,13 @@ files = [ [[package]] name = "pymdown-extensions" -version = "10.10.1" +version = "10.11.2" description = "Extension pack for Python Markdown." optional = false python-versions = ">=3.8" files = [ - {file = "pymdown_extensions-10.10.1-py3-none-any.whl", hash = "sha256:6c74ea6c2e2285186a241417480fc2d3cc52941b3ec2dced4014c84dc78c5493"}, - {file = "pymdown_extensions-10.10.1.tar.gz", hash = "sha256:ad277ee4739ced051c3b6328d22ce782358a3bec39bc6ca52815ccbf44f7acdc"}, + {file = "pymdown_extensions-10.11.2-py3-none-any.whl", hash = "sha256:41cdde0a77290e480cf53892f5c5e50921a7ee3e5cd60ba91bf19837b33badcf"}, + {file = "pymdown_extensions-10.11.2.tar.gz", hash = "sha256:bc8847ecc9e784a098efd35e20cba772bc5a1b529dfcef9dc1972db9021a1049"}, ] [package.dependencies] From 7fa85b22a0ec07137df56b0771fc3b9b84d3161d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Oct 2024 16:34:02 +0100 Subject: [PATCH 100/188] build(deps-dev): bump mkdocs-git-committers-plugin-2 from 2.3.0 to 2.4.1 (#818) Bumps [mkdocs-git-committers-plugin-2](https://github.com/ojacques/mkdocs-git-committers-plugin-2) from 2.3.0 to 2.4.1. - [Release notes](https://github.com/ojacques/mkdocs-git-committers-plugin-2/releases) - [Commits](https://github.com/ojacques/mkdocs-git-committers-plugin-2/compare/2.3.0...2.4.1) --- updated-dependencies: - dependency-name: mkdocs-git-committers-plugin-2 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- poetry.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/poetry.lock b/poetry.lock index 083f524f9..2d49d84ac 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2472,13 +2472,13 @@ pyyaml = ">=5.1" [[package]] name = "mkdocs-git-committers-plugin-2" -version = "2.3.0" +version = "2.4.1" description = "An MkDocs plugin to create a list of contributors on the page. The git-committers plugin will seed the template context with a list of GitHub or GitLab committers and other useful GIT info such as last modified date" optional = false -python-versions = ">=3.8,<4" +python-versions = "<4,>=3.8" files = [ - {file = "mkdocs-git-committers-plugin-2-2.3.0.tar.gz", hash = "sha256:d6baca1ae04db8120640038eda8142f2d081c27b53f3b566c83c75717e4ed81a"}, - {file = "mkdocs_git_committers_plugin_2-2.3.0-py3-none-any.whl", hash = "sha256:7b3434af3be525c12858eb3b44b4c6b695b7c7b7760482ea8de1c6e292e84f0f"}, + {file = "mkdocs_git_committers_plugin_2-2.4.1-py3-none-any.whl", hash = "sha256:ec9c1d81445606c471337d1c4a1782c643b7377077b545279dc18b86b7362c6d"}, + {file = "mkdocs_git_committers_plugin_2-2.4.1.tar.gz", hash = "sha256:ea1f80a79cedc42289e0b8e973276df04fb94f56e0ae3efc5385fb28547cf5cb"}, ] [package.dependencies] From c50f660880d5ecc817a9cd9ca29f36e3b5ec28ef Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Oct 2024 16:46:26 +0100 Subject: [PATCH 101/188] build(deps-dev): bump pyparsing from 3.1.2 to 3.2.0 (#836) Bumps [pyparsing](https://github.com/pyparsing/pyparsing) from 3.1.2 to 3.2.0. - [Release notes](https://github.com/pyparsing/pyparsing/releases) - [Changelog](https://github.com/pyparsing/pyparsing/blob/master/CHANGES) - [Commits](https://github.com/pyparsing/pyparsing/compare/pyparsing_3.1.2...3.2.0) --- updated-dependencies: - dependency-name: pyparsing dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- poetry.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/poetry.lock b/poetry.lock index 2d49d84ac..8c18cf5af 100644 --- a/poetry.lock +++ b/poetry.lock @@ -3758,13 +3758,13 @@ extra = ["pygments (>=2.12)"] [[package]] name = "pyparsing" -version = "3.1.2" +version = "3.2.0" description = "pyparsing module - Classes and methods to define and execute parsing grammars" optional = false -python-versions = ">=3.6.8" +python-versions = ">=3.9" files = [ - {file = "pyparsing-3.1.2-py3-none-any.whl", hash = "sha256:f9db75911801ed778fe61bb643079ff86601aca99fcae6345aa67292038fb742"}, - {file = "pyparsing-3.1.2.tar.gz", hash = "sha256:a1bac0ce561155ecc3ed78ca94d3c9378656ad4c94c1270de543f621420f94ad"}, + {file = "pyparsing-3.2.0-py3-none-any.whl", hash = "sha256:93d9577b88da0bbea8cc8334ee8b918ed014968fd2ec383e868fb8afb1ccef84"}, + {file = "pyparsing-3.2.0.tar.gz", hash = "sha256:cbf74e27246d595d9a74b186b810f6fbb86726dbf3b9532efb343f6d7294fe9c"}, ] [package.extras] From 6da92cedd1714237f097b1a7d1d84096b025d9c8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Oct 2024 16:56:02 +0100 Subject: [PATCH 102/188] build(deps-dev): bump mkdocstrings-python from 1.11.1 to 1.12.1 (#842) Bumps [mkdocstrings-python](https://github.com/mkdocstrings/python) from 1.11.1 to 1.12.1. - [Release notes](https://github.com/mkdocstrings/python/releases) - [Changelog](https://github.com/mkdocstrings/python/blob/main/CHANGELOG.md) - [Commits](https://github.com/mkdocstrings/python/compare/1.11.1...1.12.1) --- updated-dependencies: - dependency-name: mkdocstrings-python dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- poetry.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/poetry.lock b/poetry.lock index 8c18cf5af..254c05a75 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2585,13 +2585,13 @@ python-legacy = ["mkdocstrings-python-legacy (>=0.2.1)"] [[package]] name = "mkdocstrings-python" -version = "1.11.1" +version = "1.12.1" description = "A Python handler for mkdocstrings." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "mkdocstrings_python-1.11.1-py3-none-any.whl", hash = "sha256:a21a1c05acef129a618517bb5aae3e33114f569b11588b1e7af3e9d4061a71af"}, - {file = "mkdocstrings_python-1.11.1.tar.gz", hash = "sha256:8824b115c5359304ab0b5378a91f6202324a849e1da907a3485b59208b797322"}, + {file = "mkdocstrings_python-1.12.1-py3-none-any.whl", hash = "sha256:205244488199c9aa2a39787ad6a0c862d39b74078ea9aa2be817bc972399563f"}, + {file = "mkdocstrings_python-1.12.1.tar.gz", hash = "sha256:60d6a5ca912c9af4ad431db6d0111ce9f79c6c48d33377dde6a05a8f5f48d792"}, ] [package.dependencies] From e34e0c978acdf69df382cb5cfa7c9d0a25292622 Mon Sep 17 00:00:00 2001 From: Yakov Date: Tue, 15 Oct 2024 10:47:53 +0100 Subject: [PATCH 103/188] chore: adding priors to coloc step (#830) * chore: adding priors to step * fix: making specifying the priors optional * fix: revert optional --------- Co-authored-by: Daniel Considine Co-authored-by: Szymon Szyszkowski <69353402+project-defiant@users.noreply.github.com> --- src/gentropy/colocalisation.py | 10 +++++++++- src/gentropy/config.py | 3 +++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/gentropy/colocalisation.py b/src/gentropy/colocalisation.py index 0dcdff206..6c2aa3467 100644 --- a/src/gentropy/colocalisation.py +++ b/src/gentropy/colocalisation.py @@ -24,6 +24,9 @@ def __init__( credible_set_path: str, coloc_path: str, colocalisation_method: str, + priorc1: float = 1e-4, + priorc2: float = 1e-4, + priorc12: float = 1e-5, ) -> None: """Run Colocalisation step. @@ -32,6 +35,9 @@ def __init__( credible_set_path (str): Input credible sets path. coloc_path (str): Output Colocalisation path. colocalisation_method (str): Colocalisation method. + priorc1 (float): Prior on variant being causal for trait 1. Defaults to 1e-4. + priorc2 (float): Prior on variant being causal for trait 2. Defaults to 1e-4. + priorc12 (float): Prior on variant being causal for both traits. Defaults to 1e-5. """ colocalisation_class = self._get_colocalisation_class(colocalisation_method) # Extract @@ -47,7 +53,9 @@ def __init__( # Transform overlaps = credible_set.find_overlaps() - colocalisation_results = colocalisation_class.colocalise(overlaps) # type: ignore + colocalisation_results = colocalisation_class.colocalise( # type: ignore + overlaps, priorc1=priorc1, priorc2=priorc2, priorc12=priorc12 + ) # Load colocalisation_results.df.write.mode(session.write_mode).parquet( diff --git a/src/gentropy/config.py b/src/gentropy/config.py index 83a578ab8..d7d12df21 100644 --- a/src/gentropy/config.py +++ b/src/gentropy/config.py @@ -38,6 +38,9 @@ class ColocalisationConfig(StepConfig): credible_set_path: str = MISSING coloc_path: str = MISSING colocalisation_method: str = MISSING + priorc1: float = MISSING + priorc2: float = MISSING + priorc12: float = MISSING _target_: str = "gentropy.colocalisation.ColocalisationStep" From 0a6d57b1fcb59ffc9ca71f6c4ea2f7ceaa07df49 Mon Sep 17 00:00:00 2001 From: Yakov Date: Tue, 15 Oct 2024 13:14:47 +0100 Subject: [PATCH 104/188] fix: fix ukbppp studindex (#839) * fix: fix ukbppp studindex * fix: review --------- Co-authored-by: Szymon Szyszkowski <69353402+project-defiant@users.noreply.github.com> --- .../datasource/ukb_ppp_eur/study_index.py | 26 +++++++++++-------- .../ukb_ppp_eur_sumstat_preprocess.py | 26 ++++++++++++++----- 2 files changed, 35 insertions(+), 17 deletions(-) diff --git a/src/gentropy/datasource/ukb_ppp_eur/study_index.py b/src/gentropy/datasource/ukb_ppp_eur/study_index.py index 8a3105f5d..890630e54 100644 --- a/src/gentropy/datasource/ukb_ppp_eur/study_index.py +++ b/src/gentropy/datasource/ukb_ppp_eur/study_index.py @@ -52,17 +52,21 @@ def from_source( .join(num_of_samples, "studyId", "inner") ) # Add population structure. - study_index_df = study_index_df.withColumn( - "discoverySamples", - f.array( - f.struct( - f.col("nSamples").cast("integer").alias("sampleSize"), - f.lit("European").alias("ancestry"), - ) - ), - ).withColumn( - "ldPopulationStructure", - cls.aggregate_and_map_ancestries(f.col("discoverySamples")), + study_index_df = ( + study_index_df.withColumn( + "discoverySamples", + f.array( + f.struct( + f.col("nSamples").cast("integer").alias("sampleSize"), + f.lit("European").alias("ancestry"), + ) + ), + ) + .withColumn( + "ldPopulationStructure", + cls.aggregate_and_map_ancestries(f.col("discoverySamples")), + ) + .withColumn("biosampleFromSourceId", f.lit("UBERON_0001969")) ) return StudyIndex( diff --git a/src/gentropy/ukb_ppp_eur_sumstat_preprocess.py b/src/gentropy/ukb_ppp_eur_sumstat_preprocess.py index 3cee45c6a..8f0f3eef2 100644 --- a/src/gentropy/ukb_ppp_eur_sumstat_preprocess.py +++ b/src/gentropy/ukb_ppp_eur_sumstat_preprocess.py @@ -15,7 +15,14 @@ class UkbPppEurStep: """UKB PPP (EUR) data ingestion and harmonisation.""" def __init__( - self, session: Session, raw_study_index_path_from_tsv: str, raw_summary_stats_path: str, variant_annotation_path: str, tmp_variant_annotation_path: str, study_index_output_path: str, summary_stats_output_path: str + self, + session: Session, + raw_study_index_path_from_tsv: str, + raw_summary_stats_path: str, + variant_annotation_path: str, + tmp_variant_annotation_path: str, + study_index_output_path: str, + summary_stats_output_path: str, ) -> None: """Run UKB PPP (EUR) data ingestion and harmonisation step. @@ -28,7 +35,9 @@ def __init__( study_index_output_path (str): Study index output path. summary_stats_output_path (str): Summary stats output path. """ - session.logger.info("Pre-compute the direct and flipped variant annotation dataset.") + session.logger.info( + "Pre-compute the direct and flipped variant annotation dataset." + ) prepare_va(session, variant_annotation_path, tmp_variant_annotation_path) session.logger.info("Process study index.") @@ -38,11 +47,16 @@ def __init__( raw_study_index_path_from_tsv=raw_study_index_path_from_tsv, raw_summary_stats_path=raw_summary_stats_path, ) - .df - .write - .mode("overwrite") + .df.write.mode("overwrite") .parquet(study_index_output_path) ) session.logger.info("Process and harmonise summary stats.") - process_summary_stats_per_chromosome(session, UkbPppEurSummaryStats, raw_summary_stats_path, tmp_variant_annotation_path, summary_stats_output_path, study_index_output_path) + process_summary_stats_per_chromosome( + session, + UkbPppEurSummaryStats, + raw_summary_stats_path, + tmp_variant_annotation_path, + summary_stats_output_path, + study_index_output_path, + ) From 84a7a0d85a0652dbc895b3c3309cdff77ad23fe2 Mon Sep 17 00:00:00 2001 From: David Ochoa Date: Tue, 15 Oct 2024 16:26:21 +0100 Subject: [PATCH 105/188] fix: l2g fixes (#844) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: unnecessary session object * fix: circular dependency * revert: broadcast * fix: join * feat(l2g): persist feature matrix in l2g training plan (#843) * fix(gold_standard): remove extra columns in `build_feature_matrix` * fix: uncomment filter overlaps * feat(feature_matrix): `select_features` returns a new instance * fix(overlaps): add missing columns in `_convert_to_square_matrix` * fix(l2g): set `variant_index_path` as optional in step config * fix(l2g): set `feature_matrix_path` as mandatory in step config * fix(l2g): set `predictions_path` as optional in step config * chore(feature_matrix): remove `features_list` default from step * chore: fix `test_filter_unique_associations` toy data * chore: fix `test_filter_unique_associations` toy data --------- Co-authored-by: Irene López Santiago <45119610+ireneisdoomed@users.noreply.github.com> Co-authored-by: Irene López --- src/gentropy/config.py | 7 +-- src/gentropy/dataset/l2g_feature_matrix.py | 33 +++++++--- src/gentropy/dataset/l2g_gold_standard.py | 3 +- src/gentropy/dataset/study_locus_overlap.py | 3 + src/gentropy/l2g.py | 60 ++++++++++--------- tests/gentropy/conftest.py | 8 +-- tests/gentropy/dataset/test_l2g.py | 7 ++- .../dataset/test_l2g_feature_matrix.py | 20 ++++--- .../dataset/test_study_locus_overlap.py | 10 ++-- 9 files changed, 92 insertions(+), 59 deletions(-) diff --git a/src/gentropy/config.py b/src/gentropy/config.py index d7d12df21..a05ba3258 100644 --- a/src/gentropy/config.py +++ b/src/gentropy/config.py @@ -225,13 +225,12 @@ class LDBasedClumpingConfig(StepConfig): class LocusToGeneConfig(StepConfig): """Locus to gene step configuration.""" - session: Any = field(default_factory=lambda: {"extended_spark_conf": None}) run_mode: str = MISSING - predictions_path: str = MISSING credible_set_path: str = MISSING - variant_index_path: str = MISSING + feature_matrix_path: str = MISSING + predictions_path: str | None = None + variant_index_path: str | None = None model_path: str | None = None - feature_matrix_path: str | None = None gold_standard_curation_path: str | None = None gene_interactions_path: str | None = None features_list: list[str] = field( diff --git a/src/gentropy/dataset/l2g_feature_matrix.py b/src/gentropy/dataset/l2g_feature_matrix.py index b4893a785..bb4942312 100644 --- a/src/gentropy/dataset/l2g_feature_matrix.py +++ b/src/gentropy/dataset/l2g_feature_matrix.py @@ -5,6 +5,8 @@ from functools import reduce from typing import TYPE_CHECKING, Type +from typing_extensions import Self + from gentropy.common.spark_helpers import convert_from_long_to_wide from gentropy.dataset.l2g_gold_standard import L2GGoldStandard from gentropy.method.l2g.feature_factory import FeatureFactory, L2GFeatureInputLoader @@ -31,8 +33,9 @@ def __init__( features_list (list[str] | None): List of features to use. If None, all possible features are used. with_gold_standard (bool): Whether to include the gold standard set in the feature matrix. """ + self.with_gold_standard = with_gold_standard self.fixed_cols = ["studyLocusId", "geneId"] - if with_gold_standard: + if self.with_gold_standard: self.fixed_cols.append("goldStandardSet") self.features_list = features_list or [ @@ -143,7 +146,7 @@ def select_features( self: L2GFeatureMatrix, features_list: list[str] | None, ) -> L2GFeatureMatrix: - """Select a subset of features from the feature matrix. + """Returns a new object with a subset of features from the original feature matrix. Args: features_list (list[str] | None): List of features to select @@ -156,12 +159,24 @@ def select_features( """ if features_list := features_list or self.features_list: # cast to float every feature in the features_list - self._df = self._df.selectExpr( - self.fixed_cols - + [ - f"CAST({feature} AS FLOAT) AS {feature}" - for feature in features_list - ] + return L2GFeatureMatrix( + _df=self._df.selectExpr( + self.fixed_cols + + [ + f"CAST({feature} AS FLOAT) AS {feature}" + for feature in features_list + ] + ), + features_list=features_list, + with_gold_standard=self.with_gold_standard, ) - return self raise ValueError("features_list cannot be None") + + def persist(self: Self) -> Self: + """Persist the feature matrix in memory. + + Returns: + Self: Persisted Dataset + """ + self._df = self._df.persist() + return self diff --git a/src/gentropy/dataset/l2g_gold_standard.py b/src/gentropy/dataset/l2g_gold_standard.py index e1083fbf0..f1df3a700 100644 --- a/src/gentropy/dataset/l2g_gold_standard.py +++ b/src/gentropy/dataset/l2g_gold_standard.py @@ -59,7 +59,7 @@ def from_otg_curation( OpenTargetsL2GGoldStandard.as_l2g_gold_standard( gold_standard_curation, variant_index ) - # .filter_unique_associations(study_locus_overlap) + .filter_unique_associations(study_locus_overlap) .remove_false_negatives(interactions_df) ) @@ -132,6 +132,7 @@ def build_feature_matrix( on=["studyId", "variantId", "geneId"], how="inner", ) + .drop("studyId", "variantId") .distinct(), with_gold_standard=True, ) diff --git a/src/gentropy/dataset/study_locus_overlap.py b/src/gentropy/dataset/study_locus_overlap.py index d14a2da96..a6288a5e8 100644 --- a/src/gentropy/dataset/study_locus_overlap.py +++ b/src/gentropy/dataset/study_locus_overlap.py @@ -1,4 +1,5 @@ """Study locus overlap index dataset.""" + from __future__ import annotations from dataclasses import dataclass @@ -60,6 +61,8 @@ def _convert_to_square_matrix(self: StudyLocusOverlap) -> StudyLocusOverlap: "rightStudyLocusId as leftStudyLocusId", "rightStudyType", "tagVariantId", + "chromosome", + "statistics", ) ).distinct(), _schema=self.get_schema(), diff --git a/src/gentropy/l2g.py b/src/gentropy/l2g.py index 8ff41d09b..1a5037bb2 100644 --- a/src/gentropy/l2g.py +++ b/src/gentropy/l2g.py @@ -10,7 +10,6 @@ from gentropy.common.session import Session from gentropy.common.utils import access_gcp_secret -from gentropy.config import LocusToGeneConfig, LocusToGeneFeatureMatrixConfig from gentropy.dataset.colocalisation import Colocalisation from gentropy.dataset.gene_index import GeneIndex from gentropy.dataset.l2g_feature_matrix import L2GFeatureMatrix @@ -31,7 +30,7 @@ def __init__( self, session: Session, *, - features_list: list[str] = LocusToGeneFeatureMatrixConfig().features_list, + features_list: list[str], credible_set_path: str, variant_index_path: str | None = None, colocalisation_path: str | None = None, @@ -94,20 +93,20 @@ class LocusToGeneStep: def __init__( self, session: Session, - hyperparameters: dict[str, Any] = LocusToGeneConfig().hyperparameters, + hyperparameters: dict[str, Any], *, run_mode: str, - features_list: list[str] = LocusToGeneConfig().features_list, - download_from_hub: bool = LocusToGeneConfig().download_from_hub, + features_list: list[str], + download_from_hub: bool, wandb_run_name: str, - model_path: str | None = None, credible_set_path: str, feature_matrix_path: str, + model_path: str | None = None, gold_standard_curation_path: str | None = None, variant_index_path: str | None = None, gene_interactions_path: str | None = None, predictions_path: str | None = None, - hf_hub_repo_id: str | None = LocusToGeneConfig().hf_hub_repo_id, + hf_hub_repo_id: str | None, ) -> None: """Initialise the step and run the logic based on mode. @@ -118,9 +117,9 @@ def __init__( features_list (list[str]): List of features to use for the model download_from_hub (bool): Whether to download the model from Hugging Face Hub wandb_run_name (str): Name of the run to track model training in Weights and Biases - model_path (str | None): Path to the model. It can be either in the filesystem or the name on the Hugging Face Hub (in the form of username/repo_name). credible_set_path (str): Path to the credible set dataset necessary to build the feature matrix feature_matrix_path (str): Path to the L2G feature matrix input dataset + model_path (str | None): Path to the model. It can be either in the filesystem or the name on the Hugging Face Hub (in the form of username/repo_name). gold_standard_curation_path (str | None): Path to the gold standard curation file variant_index_path (str | None): Path to the variant index gene_interactions_path (str | None): Path to the gene interactions dataset @@ -174,7 +173,13 @@ def __init__( self.run_train() def run_predict(self) -> None: - """Run the prediction step.""" + """Run the prediction step. + + Raises: + ValueError: If predictions_path is not provided for prediction mode + """ + if not self.predictions_path: + raise ValueError("predictions_path must be provided for prediction mode") predictions = L2GPrediction.from_credible_set( self.session, self.credible_set, @@ -184,11 +189,10 @@ def run_predict(self) -> None: hf_token=access_gcp_secret("hfhub-key", "open-targets-genetics-dev"), download_from_hub=self.download_from_hub, ) - if self.predictions_path: - predictions.df.write.mode(self.session.write_mode).parquet( - self.predictions_path - ) - self.session.logger.info(self.predictions_path) + predictions.df.write.mode(self.session.write_mode).parquet( + self.predictions_path + ) + self.session.logger.info("L2G predictions saved successfully.") def run_train(self) -> None: """Run the training step.""" @@ -239,20 +243,21 @@ def _annotate_gold_standards_w_feature_matrix(self) -> L2GFeatureMatrix: if self.gs_curation and self.interactions and self.variant_index: study_locus_overlap = StudyLocus( _df=self.credible_set.df.join( - f.broadcast( - self.gs_curation.select( - f.concat_ws( - "_", - f.col("sentinel_variant.locus_GRCh38.chromosome"), - f.col("sentinel_variant.locus_GRCh38.position"), - f.col("sentinel_variant.alleles.reference"), - f.col("sentinel_variant.alleles.alternative"), - ).alias("variantId"), - f.col("association_info.otg_id").alias("studyId"), - ) + self.gs_curation.select( + f.concat_ws( + "_", + f.col("sentinel_variant.locus_GRCh38.chromosome"), + f.col("sentinel_variant.locus_GRCh38.position"), + f.col("sentinel_variant.alleles.reference"), + f.col("sentinel_variant.alleles.alternative"), + ).alias("variantId"), + f.col("association_info.otg_id").alias("studyId"), ), - ["studyId", "variantId"], - "inner", + on=[ + "studyId", + "variantId", + ], + how="inner", ), _schema=StudyLocus.get_schema(), ).find_overlaps() @@ -270,5 +275,6 @@ def _annotate_gold_standards_w_feature_matrix(self) -> L2GFeatureMatrix: ) .fill_na() .select_features(self.features_list) + .persist() ) raise ValueError("Dependencies for train mode not set.") diff --git a/tests/gentropy/conftest.py b/tests/gentropy/conftest.py index 9ea31ae20..81a378ee2 100644 --- a/tests/gentropy/conftest.py +++ b/tests/gentropy/conftest.py @@ -600,12 +600,12 @@ def mock_l2g_feature_matrix(spark: SparkSession) -> L2GFeatureMatrix: return L2GFeatureMatrix( _df=spark.createDataFrame( [ - ("1", "gene1", 100.0, None), - ("2", "gene2", 1000.0, 0.0), + ("1", "gene1", 100.0, None, True), + ("2", "gene2", 1000.0, 0.0, False), ], - "studyLocusId STRING, geneId STRING, distanceTssMean FLOAT, distanceSentinelTssMinimum FLOAT", + "studyLocusId STRING, geneId STRING, distanceTssMean FLOAT, distanceSentinelTssMinimum FLOAT, goldStandardSet BOOLEAN", ), - with_gold_standard=False, + with_gold_standard=True, ) diff --git a/tests/gentropy/dataset/test_l2g.py b/tests/gentropy/dataset/test_l2g.py index f73b6f7c2..293735edd 100644 --- a/tests/gentropy/dataset/test_l2g.py +++ b/tests/gentropy/dataset/test_l2g.py @@ -70,8 +70,11 @@ def test_filter_unique_associations(spark: SparkSession) -> None: ) mock_sl_overlap_df = spark.createDataFrame( - [("1", "2", "eqtl", "variant2"), ("1", "4", "eqtl", "variant4")], - "leftStudyLocusId STRING, rightStudyLocusId STRING, rightStudyType STRING, tagVariantId STRING", + [ + ("1", "2", "eqtl", "CHROM1", "variant2", None), + ("1", "4", "eqtl", "CHROM1", "variant4", None), + ], + StudyLocusOverlap.get_schema(), ) expected_df = spark.createDataFrame( diff --git a/tests/gentropy/dataset/test_l2g_feature_matrix.py b/tests/gentropy/dataset/test_l2g_feature_matrix.py index b74b6330a..f4859844a 100644 --- a/tests/gentropy/dataset/test_l2g_feature_matrix.py +++ b/tests/gentropy/dataset/test_l2g_feature_matrix.py @@ -5,13 +5,7 @@ from typing import TYPE_CHECKING import pytest -from pyspark.sql.types import ( - ArrayType, - DoubleType, - StringType, - StructField, - StructType, -) +from pyspark.sql.types import ArrayType, DoubleType, StringType, StructField, StructType from gentropy.dataset.colocalisation import Colocalisation from gentropy.dataset.l2g_feature_matrix import L2GFeatureMatrix @@ -24,6 +18,18 @@ from pyspark.sql import SparkSession +def test_select_features_inheritance( + spark: SparkSession, mock_l2g_feature_matrix: L2GFeatureMatrix +) -> None: + """Test L2GFeatureMatrix.select_features method inherits the instance attributes in the new instance.""" + new_instance = mock_l2g_feature_matrix.select_features( + features_list=["distanceTssMean"] + ) + assert new_instance.features_list == ["distanceTssMean"] + # Because the feature matrix contains the gold standard flag information, the new fixed colums should be the same + assert "goldStandardSet" in new_instance.fixed_cols + + class TestFromFeaturesList: """Test L2GFeatureMatrix.from_features_list method. diff --git a/tests/gentropy/dataset/test_study_locus_overlap.py b/tests/gentropy/dataset/test_study_locus_overlap.py index 5dcba19c9..c517c023d 100644 --- a/tests/gentropy/dataset/test_study_locus_overlap.py +++ b/tests/gentropy/dataset/test_study_locus_overlap.py @@ -19,19 +19,19 @@ def test_convert_to_square_matrix(spark: SparkSession) -> None: mock_sl_overlap = StudyLocusOverlap( _df=spark.createDataFrame( [ - ("1", "2", "eqtl", "variant2"), + ("1", "2", "eqtl", "CHROM1", "variant2", None), ], - "leftStudyLocusId STRING, rightStudyLocusId STRING, rightStudyType STRING, tagVariantId STRING", + StudyLocusOverlap.get_schema(), ), _schema=StudyLocusOverlap.get_schema(), ) expected_df = spark.createDataFrame( [ - ("1", "2", "eqtl", "variant2"), - ("2", "1", "eqtl", "variant2"), + ("1", "2", "eqtl", "CHROM1", "variant2", None), + ("2", "1", "eqtl", "CHROM1", "variant2", None), ], - "leftStudyLocusId STRING, rightStudyLocusId STRING, rightStudyType STRING, tagVariantId STRING", + StudyLocusOverlap.get_schema(), ) observed_df = mock_sl_overlap._convert_to_square_matrix().df From 172cedfedfc336dbd6277286bae736eb2b9504f9 Mon Sep 17 00:00:00 2001 From: Yakov Date: Tue, 15 Oct 2024 16:47:41 +0100 Subject: [PATCH 106/188] chore: remove h4/h3 ratio (#829) * chore: remove h3/h4 ratiob * fix: remove it from schema * fix: conftest * fix: h3h4 --- src/gentropy/assets/schemas/colocalisation.json | 6 ------ src/gentropy/method/colocalisation.py | 17 ++++++++++++----- tests/gentropy/conftest.py | 1 - 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/gentropy/assets/schemas/colocalisation.json b/src/gentropy/assets/schemas/colocalisation.json index 7d05c849a..0bfb66816 100644 --- a/src/gentropy/assets/schemas/colocalisation.json +++ b/src/gentropy/assets/schemas/colocalisation.json @@ -67,12 +67,6 @@ "nullable": true, "metadata": {} }, - { - "name": "log2h4h3", - "type": "double", - "nullable": true, - "metadata": {} - }, { "name": "clpp", "type": "double", diff --git a/src/gentropy/method/colocalisation.py b/src/gentropy/method/colocalisation.py index 7a3a0d9c5..7d711d9a3 100644 --- a/src/gentropy/method/colocalisation.py +++ b/src/gentropy/method/colocalisation.py @@ -79,7 +79,12 @@ def colocalise( f.col("statistics.right_posteriorProbability"), ), ) - .groupBy("leftStudyLocusId", "rightStudyLocusId", "rightStudyType", "chromosome") + .groupBy( + "leftStudyLocusId", + "rightStudyLocusId", + "rightStudyType", + "chromosome", + ) .agg( f.count("*").alias("numberColocalisingVariants"), f.sum(f.col("clpp")).alias("clpp"), @@ -168,7 +173,12 @@ def colocalise( f.col("left_logBF") + f.col("right_logBF"), ) # Group by overlapping peak and generating dense vectors of log_BF: - .groupBy("chromosome", "leftStudyLocusId", "rightStudyLocusId", "rightStudyType") + .groupBy( + "chromosome", + "leftStudyLocusId", + "rightStudyLocusId", + "rightStudyType", + ) .agg( f.count("*").alias("numberColocalisingVariants"), fml.array_to_vector(f.collect_list(f.col("left_logBF"))).alias( @@ -245,13 +255,10 @@ def colocalise( .withColumn("h2", f.col("posteriors").getItem(2)) .withColumn("h3", f.col("posteriors").getItem(3)) .withColumn("h4", f.col("posteriors").getItem(4)) - .withColumn("h4h3", f.col("h4") / f.col("h3")) - .withColumn("log2h4h3", f.log2(f.col("h4h3"))) # clean up .drop( "posteriors", "allBF", - "h4h3", "lH0bf", "lH1bf", "lH2bf", diff --git a/tests/gentropy/conftest.py b/tests/gentropy/conftest.py index 81a378ee2..b1fc5ef90 100644 --- a/tests/gentropy/conftest.py +++ b/tests/gentropy/conftest.py @@ -81,7 +81,6 @@ def mock_colocalisation(spark: SparkSession) -> Colocalisation: .withColumnSpec("h2", percentNulls=0.1) .withColumnSpec("h3", percentNulls=0.1) .withColumnSpec("h4", percentNulls=0.1) - .withColumnSpec("log2h4h3", percentNulls=0.1) .withColumnSpec("clpp", percentNulls=0.1) .withColumnSpec( "colocalisationMethod", From 97a8873a34621eb7ef3e74e34b7426bc54c0e501 Mon Sep 17 00:00:00 2001 From: Daniel-Considine <113430683+Daniel-Considine@users.noreply.github.com> Date: Wed, 16 Oct 2024 17:11:15 +0100 Subject: [PATCH 107/188] fix: updating the susie_finemapper init (#846) * fix: updating the susie_finemapper init * fix: more fixes * fix: v2 * fix: v2 --------- Co-authored-by: Yakov Tsepilov --- src/gentropy/susie_finemapper.py | 276 +++---------------------------- 1 file changed, 25 insertions(+), 251 deletions(-) diff --git a/src/gentropy/susie_finemapper.py b/src/gentropy/susie_finemapper.py index 7d04b5763..25adbccbe 100644 --- a/src/gentropy/susie_finemapper.py +++ b/src/gentropy/susie_finemapper.py @@ -26,8 +26,7 @@ order_array_of_structs_by_field, ) from gentropy.dataset.study_index import StudyIndex -from gentropy.dataset.study_locus import StudyLocus -from gentropy.datasource.gnomad.ld import GnomADLDMatrix +from gentropy.dataset.study_locus import StudyLocus, StudyLocusQualityCheck from gentropy.method.carma import CARMA from gentropy.method.ld_matrix_interface import LDMatrixInterface from gentropy.method.sumstat_imputation import SummaryStatisticsImputation @@ -104,7 +103,7 @@ def __init__( study_index = StudyIndex.from_parquet(session, study_index_path) # Run fine-mapping - result_logging = self.susie_finemapper_one_sl_row_v4_ss_gathered_boundaries( + result_logging = self.susie_finemapper_one_sl_row_gathered_boundaries( session=session, study_locus_row=study_locus, study_index=study_index, @@ -127,9 +126,19 @@ def __init__( if result_logging is not None: if result_logging["study_locus"] is not None: # Write result - result_logging["study_locus"].df.write.mode(session.write_mode).parquet( - study_locus_output + df = result_logging["study_locus"].df + + df = df.withColumn("qualityControls", f.lit(None)) + df = df.withColumn( + "qualityControls", + StudyLocus.update_quality_flag( + f.col("qualityControls"), + f.lit(True), + StudyLocusQualityCheck.OUT_OF_SAMPLE_LD, + ), ) + + df.write.mode(session.write_mode).parquet(study_locus_output) # Write log result_logging["log"].to_parquet( study_locus_output + ".log", @@ -426,6 +435,7 @@ def susie_finemapper_from_prepared_dataframes( purity_min_r2_threshold: float = 0.25, cs_lbf_thr: float = 2, ld_min_r2: float = 0.9, + N_total: int = 100_000, ) -> dict[str, Any] | None: """Susie fine-mapper function that uses LD, z-scores, variant info and other options for Fine-Mapping. @@ -452,6 +462,7 @@ def susie_finemapper_from_prepared_dataframes( purity_min_r2_threshold (float): thrshold for purity min r2 qc metrics for filtering credible sets cs_lbf_thr (float): credible set logBF threshold for filtering credible sets, default is 2 ld_min_r2 (float): Threshold to fillter CS by leads in high LD, default is 0.9 + N_total (int): total number of samples, default is 100_000 Returns: dict[str, Any] | None: dictionary with study locus, number of GWAS variants, number of LD variants, number of variants after merge, number of outliers, number of imputed variants, number of variants to fine-map @@ -550,7 +561,7 @@ def susie_finemapper_from_prepared_dataframes( N_imputed = 0 susie_output = SUSIE_inf.susie_inf( - z=z_to_fm, LD=ld_to_fm, L=L, est_tausq=susie_est_tausq + z=z_to_fm, LD=ld_to_fm, L=L, est_tausq=susie_est_tausq, n=N_total ) schema = StructType( @@ -613,7 +624,7 @@ def susie_finemapper_from_prepared_dataframes( } @staticmethod - def susie_finemapper_one_sl_row_v4_ss_gathered_boundaries( + def susie_finemapper_one_sl_row_gathered_boundaries( # noqa: C901 session: Session, study_locus_row: Row, study_index: StudyIndex, @@ -673,248 +684,9 @@ def susie_finemapper_one_sl_row_v4_ss_gathered_boundaries( )[0]["ldPopulation"].alias("majorPopulation"), ).collect()[0]["majorPopulation"] - region = chromosome + ":" + str(int(locusStart)) + "-" + str(int(locusEnd)) - - schema = StudyLocus.get_schema() - gwas_df = session.spark.createDataFrame([study_locus_row], schema=schema) - exploded_df = gwas_df.select(f.explode("locus").alias("locus")) - - result_df = exploded_df.select( - "locus.variantId", "locus.beta", "locus.standardError" - ) - gwas_df = ( - result_df.withColumn("z", f.col("beta") / f.col("standardError")) - .withColumn( - "chromosome", f.split(f.col("variantId"), "_")[0].cast("string") - ) - .withColumn("position", f.split(f.col("variantId"), "_")[1].cast("int")) - .filter(f.col("chromosome") == chromosome) - .filter(f.col("position") >= int(locusStart)) - .filter(f.col("position") <= int(locusEnd)) - .filter(f.col("z").isNotNull()) - ) - - # Remove ALL duplicated variants from GWAS DataFrame - we don't know which is correct - variant_counts = gwas_df.groupBy("variantId").count() - unique_variants = variant_counts.filter(f.col("count") == 1) - gwas_df = gwas_df.join(unique_variants, on="variantId", how="left_semi") - - ld_index = ( - GnomADLDMatrix() - .get_locus_index_boundaries( - study_locus_row=study_locus_row, - major_population=major_population, - ) - .withColumn( - "variantId", - f.concat( - f.lit(chromosome), - f.lit("_"), - f.col("`locus.position`"), - f.lit("_"), - f.col("alleles").getItem(0), - f.lit("_"), - f.col("alleles").getItem(1), - ).cast("string"), - ) - ) - # Remove ALL duplicated variants from ld_index DataFrame - we don't know which is correct - variant_counts = ld_index.groupBy("variantId").count() - unique_variants = variant_counts.filter(f.col("count") == 1) - ld_index = ld_index.join(unique_variants, on="variantId", how="left_semi").sort( - "idx" - ) - - if not run_sumstat_imputation: - # Filtering out the variants that are not in the LD matrix, we don't need them - gwas_index = gwas_df.join( - ld_index.select("variantId", "alleles", "idx"), on="variantId" - ).sort("idx") - gwas_df = gwas_index.select( - "variantId", - "z", - "chromosome", - "position", - "beta", - "StandardError", - ) - gwas_index = gwas_index.drop( - "z", "chromosome", "position", "beta", "StandardError" - ) - if gwas_index.rdd.isEmpty(): - logging.warning("No overlapping variants in the LD Index") - return None - gnomad_ld = GnomADLDMatrix.get_numpy_matrix( - gwas_index, gnomad_ancestry=major_population - ) - - # Module to remove NANs from the LD matrix - if sum(sum(np.isnan(gnomad_ld))) > 0: - gwas_index = gwas_index.toPandas() - - # First round of filtering out the variants with NANs - nan_count = 1 - (sum(np.isnan(gnomad_ld)) / len(gnomad_ld)) - indices = np.where(nan_count >= 0.98) - indices = indices[0] - gnomad_ld = gnomad_ld[indices][:, indices] - - gwas_index = gwas_index.iloc[indices, :] - - if len(gwas_index) == 0: - logging.warning("No overlapping variants in the LD Index") - return None - - # Second round of filtering out the variants with NANs - nan_count = sum(np.isnan(gnomad_ld)) - indices = np.where(nan_count == 0) - indices = indices[0] - - gnomad_ld = gnomad_ld[indices][:, indices] - gwas_index = gwas_index.iloc[indices, :] - - if len(gwas_index) == 0: - logging.warning("No overlapping variants in the LD Index") - return None - - gwas_index = session.spark.createDataFrame(gwas_index) - - else: - gwas_index = gwas_df.join( - ld_index.select("variantId", "alleles", "idx"), on="variantId" - ).sort("idx") - if gwas_index.rdd.isEmpty(): - logging.warning("No overlapping variants in the LD Index") - return None - gwas_index = ld_index - gnomad_ld = GnomADLDMatrix.get_numpy_matrix( - gwas_index, gnomad_ancestry=major_population - ) - - # Module to remove NANs from the LD matrix - if sum(sum(np.isnan(gnomad_ld))) > 0: - gwas_index = gwas_index.toPandas() - - # First round of filtering out the variants with NANs - nan_count = 1 - (sum(np.isnan(gnomad_ld)) / len(gnomad_ld)) - indices = np.where(nan_count >= 0.98) - indices = indices[0] - gnomad_ld = gnomad_ld[indices][:, indices] - - gwas_index = gwas_index.iloc[indices, :] - - if len(gwas_index) == 0: - logging.warning("No overlapping variants in the LD Index") - return None - - # Second round of filtering out the variants with NANs - nan_count = sum(np.isnan(gnomad_ld)) - indices = np.where(nan_count == 0) - indices = indices[0] - - gnomad_ld = gnomad_ld[indices][:, indices] - gwas_index = gwas_index.iloc[indices, :] - - if len(gwas_index) == 0: - logging.warning("No overlapping variants in the LD Index") - return None - - gwas_index = session.spark.createDataFrame(gwas_index) - - # sanity filters on LD matrix - np.fill_diagonal(gnomad_ld, 1) - gnomad_ld[gnomad_ld > 1] = 1 - gnomad_ld[gnomad_ld < -1] = -1 - upper_triangle = np.triu(gnomad_ld) - gnomad_ld = ( - upper_triangle + upper_triangle.T - np.diag(upper_triangle.diagonal()) - ) - np.fill_diagonal(gnomad_ld, 1) - - out = SusieFineMapperStep.susie_finemapper_from_prepared_dataframes( - GWAS_df=gwas_df, - ld_index=gwas_index, - gnomad_ld=gnomad_ld, - L=max_causal_snps, - session=session, - studyId=studyId, - region=region, - locusStart=int(locusStart), - locusEnd=int(locusEnd), - susie_est_tausq=susie_est_tausq, - run_carma=run_carma, - run_sumstat_imputation=run_sumstat_imputation, - carma_time_limit=carma_time_limit, - carma_tau=carma_tau, - imputed_r2_threshold=imputed_r2_threshold, - ld_score_threshold=ld_score_threshold, - sum_pips=sum_pips, - lead_pval_threshold=lead_pval_threshold, - purity_mean_r2_threshold=purity_mean_r2_threshold, - purity_min_r2_threshold=purity_min_r2_threshold, - cs_lbf_thr=cs_lbf_thr, - ld_min_r2=ld_min_r2, - ) - - return out - - @staticmethod - def susie_finemapper_one_sl_row_v4_ss_gathered_boundaries_ldinterface( # noqa: C901 - session: Session, - study_locus_row: Row, - study_index: StudyIndex, - max_causal_snps: int = 10, - susie_est_tausq: bool = False, - run_carma: bool = False, - run_sumstat_imputation: bool = False, - carma_time_limit: int = 600, - carma_tau: float = 0.04, - imputed_r2_threshold: float = 0.9, - ld_score_threshold: float = 5, - sum_pips: float = 0.99, - lead_pval_threshold: float = 1e-5, - purity_mean_r2_threshold: float = 0, - purity_min_r2_threshold: float = 0.25, - cs_lbf_thr: float = 2, - ) -> dict[str, Any] | None: - """Susie fine-mapper function that uses study-locus row with collected locus, chromosome and position as inputs. - - Args: - session (Session): Spark session - study_locus_row (Row): StudyLocus row with collected locus - study_index (StudyIndex): StudyIndex object - max_causal_snps (int): maximum number of causal variants - susie_est_tausq (bool): estimate tau squared, default is False - run_carma (bool): run CARMA, default is False - run_sumstat_imputation (bool): run summary statistics imputation, default is False - carma_time_limit (int): CARMA time limit, default is 600 seconds - carma_tau (float): CARMA tau, shrinkage parameter - imputed_r2_threshold (float): imputed R2 threshold, default is 0.8 - ld_score_threshold (float): LD score threshold ofr imputation, default is 4 - sum_pips (float): the expected sum of posterior probabilities in the locus, default is 0.99 (99% credible set) - lead_pval_threshold (float): p-value threshold for the lead variant from CS, default is 1e-5 - purity_mean_r2_threshold (float): thrshold for purity mean r2 qc metrics for filtering credible sets - purity_min_r2_threshold (float): thrshold for purity min r2 qc metrics for filtering credible sets - cs_lbf_thr (float): credible set logBF threshold for filtering credible sets, default is 2 - - Returns: - dict[str, Any] | None: dictionary with study locus, number of GWAS variants, number of LD variants, number of variants after merge, number of outliers, number of imputed variants, number of variants to fine-map, or None - """ - # PLEASE DO NOT REMOVE THIS LINE - pd.DataFrame.iteritems = pd.DataFrame.items - - chromosome = study_locus_row["chromosome"] - studyId = study_locus_row["studyId"] - locusStart = study_locus_row["locusStart"] - locusEnd = study_locus_row["locusEnd"] - - study_index_df = study_index._df - study_index_df = study_index_df.filter(f.col("studyId") == studyId) - major_population = study_index_df.select( - "studyId", - order_array_of_structs_by_field( - "ldPopulationStructure", "relativeSampleSize" - )[0]["ldPopulation"].alias("majorPopulation"), - ).collect()[0]["majorPopulation"] + N_total = int(study_index_df.select("nSamples").collect()[0]["nSamples"]) + if N_total is None: + N_total = 100_000 region = chromosome + ":" + str(int(locusStart)) + "-" + str(int(locusEnd)) @@ -1068,8 +840,8 @@ def susie_finemapper_one_sl_row_v4_ss_gathered_boundaries_ldinterface( # noqa: session=session, studyId=studyId, region=region, - locusStart=locusStart, - locusEnd=locusEnd, + locusStart=int(locusStart), + locusEnd=int(locusEnd), susie_est_tausq=susie_est_tausq, run_carma=run_carma, run_sumstat_imputation=run_sumstat_imputation, @@ -1082,6 +854,8 @@ def susie_finemapper_one_sl_row_v4_ss_gathered_boundaries_ldinterface( # noqa: purity_mean_r2_threshold=purity_mean_r2_threshold, purity_min_r2_threshold=purity_min_r2_threshold, cs_lbf_thr=cs_lbf_thr, + ld_min_r2=ld_min_r2, + N_total=N_total, ) return out From 6a059d0f4d25e3b6ed1fe506ddffd344dc77bd43 Mon Sep 17 00:00:00 2001 From: Szymon Szyszkowski <69353402+project-defiant@users.noreply.github.com> Date: Thu, 17 Oct 2024 11:39:13 +0200 Subject: [PATCH 108/188] feat(coloc): step refactoring (#845) * feat: prior fix * refactor: coloc step * fix: subclasss colocalisation methods on interface * fix: failing coloc step * chore(coloc): step tests * chore: restore old script --------- Co-authored-by: Szymon Szyszkowski Co-authored-by: project-defiant --- src/gentropy/colocalisation.py | 73 +++-- src/gentropy/config.py | 4 +- src/gentropy/dataset/colocalisation.py | 2 +- src/gentropy/method/colocalisation.py | 59 +++- tests/gentropy/dataset/test_study_index.py | 1 - .../method/test_colocalisation_method.py | 6 + .../gentropy/step/test_colocalisation_step.py | 293 ++++++++++++++++++ 7 files changed, 392 insertions(+), 46 deletions(-) create mode 100644 tests/gentropy/step/test_colocalisation_step.py diff --git a/src/gentropy/colocalisation.py b/src/gentropy/colocalisation.py index 6c2aa3467..a45a9a6a1 100644 --- a/src/gentropy/colocalisation.py +++ b/src/gentropy/colocalisation.py @@ -2,14 +2,14 @@ from __future__ import annotations -import inspect -from importlib import import_module +from functools import partial +from typing import Any, Type from pyspark.sql.functions import col from gentropy.common.session import Session from gentropy.dataset.study_locus import StudyLocus -from gentropy.method.colocalisation import Coloc +from gentropy.method.colocalisation import Coloc, ColocalisationMethodInterface class ColocalisationStep: @@ -18,59 +18,71 @@ class ColocalisationStep: This workflow runs colocalisation analyses that assess the degree to which independent signals of the association share the same causal variant in a region of the genome, typically limited by linkage disequilibrium (LD). """ + __coloc_methods__ = { + method.METHOD_NAME.lower(): method + for method in ColocalisationMethodInterface.__subclasses__() + } + def __init__( self, session: Session, credible_set_path: str, coloc_path: str, colocalisation_method: str, - priorc1: float = 1e-4, - priorc2: float = 1e-4, - priorc12: float = 1e-5, + colocalisation_method_params: dict[str, Any] | None = None, ) -> None: """Run Colocalisation step. + This step allows for running two colocalisation methods: ecaviar and coloc. + Args: session (Session): Session object. credible_set_path (str): Input credible sets path. coloc_path (str): Output Colocalisation path. colocalisation_method (str): Colocalisation method. - priorc1 (float): Prior on variant being causal for trait 1. Defaults to 1e-4. - priorc2 (float): Prior on variant being causal for trait 2. Defaults to 1e-4. - priorc12 (float): Prior on variant being causal for both traits. Defaults to 1e-5. + colocalisation_method_params (dict[str, Any] | None): Keyword arguments passed to the colocalise method of Colocalisation class. Defaults to None + + Keyword Args: + priorc1 (float): Prior on variant being causal for trait 1. Defaults to 1e-4. For coloc method only. + priorc2 (float): Prior on variant being causal for trait 2. Defaults to 1e-4. For coloc method only. + priorc12 (float): Prior on variant being causal for both traits. Defaults to 1e-5. For coloc method only. """ + colocalisation_method = colocalisation_method.lower() colocalisation_class = self._get_colocalisation_class(colocalisation_method) + # Extract - credible_set = ( - StudyLocus.from_parquet( - session, credible_set_path, recursiveFileLookup=True - ).filter(col("finemappingMethod").isin("SuSie", "SuSiE-inf")) - if colocalisation_class is Coloc - else StudyLocus.from_parquet( - session, credible_set_path, recursiveFileLookup=True - ) + credible_set = StudyLocus.from_parquet( + session, credible_set_path, recusiveFileLookup=True ) + if colocalisation_method == Coloc.METHOD_NAME.lower(): + credible_set = credible_set.filter( + col("finemappingMethod").isin("SuSie", "SuSiE-inf") + ) # Transform overlaps = credible_set.find_overlaps() - colocalisation_results = colocalisation_class.colocalise( # type: ignore - overlaps, priorc1=priorc1, priorc2=priorc2, priorc12=priorc12 - ) + # Make a partial caller to ensure that colocalisation_method_params are added to the call only when dict is not empty + coloc = colocalisation_class.colocalise + if colocalisation_method_params: + coloc = partial(coloc, **colocalisation_method_params) + colocalisation_results = coloc(overlaps) # Load colocalisation_results.df.write.mode(session.write_mode).parquet( f"{coloc_path}/{colocalisation_method.lower()}" ) @classmethod - def _get_colocalisation_class(cls: type[ColocalisationStep], method: str) -> type: + def _get_colocalisation_class( + cls, method: str + ) -> Type[ColocalisationMethodInterface]: """Get colocalisation class. Args: method (str): Colocalisation method. Returns: - type: Colocalisation class. + Type[ColocalisationMethodInterface]: Class that implements the ColocalisationMethodInterface. Raises: ValueError: if method not available. @@ -79,15 +91,8 @@ def _get_colocalisation_class(cls: type[ColocalisationStep], method: str) -> typ >>> ColocalisationStep._get_colocalisation_class("ECaviar") """ - module_name = "gentropy.method.colocalisation" - module = import_module(module_name) - - available_methods = [] - for class_name, class_obj in inspect.getmembers(module, inspect.isclass): - if class_obj.__module__ == module_name: - available_methods.append(class_name) - if class_name == method: - return class_obj - raise ValueError( - f"Method {method} is not supported. Available: {(', ').join(available_methods)}" - ) + method = method.lower() + if method not in cls.__coloc_methods__: + raise ValueError(f"Colocalisation method {method} not available.") + coloc_method = cls.__coloc_methods__[method] + return coloc_method diff --git a/src/gentropy/config.py b/src/gentropy/config.py index a05ba3258..ad941f5e0 100644 --- a/src/gentropy/config.py +++ b/src/gentropy/config.py @@ -38,9 +38,7 @@ class ColocalisationConfig(StepConfig): credible_set_path: str = MISSING coloc_path: str = MISSING colocalisation_method: str = MISSING - priorc1: float = MISSING - priorc2: float = MISSING - priorc12: float = MISSING + colocalisation_method_params: dict[str, Any] = field(default_factory=dict[str, Any]) _target_: str = "gentropy.colocalisation.ColocalisationStep" diff --git a/src/gentropy/dataset/colocalisation.py b/src/gentropy/dataset/colocalisation.py index 4b85b68d6..568b46007 100644 --- a/src/gentropy/dataset/colocalisation.py +++ b/src/gentropy/dataset/colocalisation.py @@ -83,7 +83,7 @@ def extract_maximum_coloc_probability_per_region_and_gene( method_colocalisation_metric = ColocalisationStep._get_colocalisation_class( filter_by_colocalisation_method - ).METHOD_METRIC # type: ignore + ).METHOD_METRIC coloc_filtering_expr = [ f.col("rightGeneId").isNotNull(), diff --git a/src/gentropy/method/colocalisation.py b/src/gentropy/method/colocalisation.py index 7d711d9a3..37ca7b0d7 100644 --- a/src/gentropy/method/colocalisation.py +++ b/src/gentropy/method/colocalisation.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Protocol import numpy as np import pyspark.ml.functions as fml @@ -14,13 +14,41 @@ from gentropy.dataset.colocalisation import Colocalisation if TYPE_CHECKING: + from typing import Any + from numpy.typing import NDArray from pyspark.sql import Column from gentropy.dataset.study_locus_overlap import StudyLocusOverlap -class ECaviar: +class ColocalisationMethodInterface(Protocol): + """Colocalisation method interface.""" + + METHOD_NAME: str + METHOD_METRIC: str + + @classmethod + def colocalise( + cls, overlapping_signals: StudyLocusOverlap, **kwargs: Any + ) -> Colocalisation: + """Method to generate the colocalisation. + + Args: + overlapping_signals (StudyLocusOverlap): Overlapping study loci. + **kwargs (Any): Additional keyword arguments to the colocalise method. + + + Returns: + Colocalisation: loci colocalisation + + Raises: + NotImplementedError: Implement in derivative classes. + """ + raise NotImplementedError("Implement in derivative classes.") + + +class ECaviar(ColocalisationMethodInterface): """ECaviar-based colocalisation analysis. It extends [CAVIAR](https://www.ncbi.nlm.nih.gov/pmc/articles/PMC5142122/#bib18) framework to explicitly estimate the posterior probability that the same variant is causal in 2 studies while accounting for the uncertainty of LD. eCAVIAR computes the colocalization posterior probability (**CLPP**) by utilizing the marginal posterior probabilities. This framework allows for **multiple variants to be causal** in a single locus. @@ -60,12 +88,15 @@ def _get_clpp(left_pp: Column, right_pp: Column) -> Column: @classmethod def colocalise( - cls: type[ECaviar], overlapping_signals: StudyLocusOverlap + cls: type[ECaviar], + overlapping_signals: StudyLocusOverlap, + **kwargs: Any, ) -> Colocalisation: """Calculate bayesian colocalisation based on overlapping signals. Args: overlapping_signals (StudyLocusOverlap): overlapping signals. + **kwargs (Any): Additional parameters passed to the colocalise method. Returns: Colocalisation: colocalisation results based on eCAVIAR. @@ -95,7 +126,7 @@ def colocalise( ) -class Coloc: +class Coloc(ColocalisationMethodInterface): """Calculate bayesian colocalisation based on overlapping signals from credible sets. Based on the [R COLOC package](https://github.com/chr1swallace/coloc/blob/main/R/claudia.R), which uses the Bayes factors from the credible set to estimate the posterior probability of colocalisation. This method makes the simplifying assumption that **only one single causal variant** exists for any given trait in any genomic region. @@ -143,22 +174,36 @@ def _get_posteriors(all_bfs: NDArray[np.float64]) -> DenseVector: def colocalise( cls: type[Coloc], overlapping_signals: StudyLocusOverlap, - priorc1: float = 1e-4, - priorc2: float = 1e-4, - priorc12: float = 1e-5, + **kwargs: float, ) -> Colocalisation: """Calculate bayesian colocalisation based on overlapping signals. Args: overlapping_signals (StudyLocusOverlap): overlapping peaks + **kwargs (float): Additional parameters passed to the colocalise method. + Keyword Args: priorc1 (float): Prior on variant being causal for trait 1. Defaults to 1e-4. priorc2 (float): Prior on variant being causal for trait 2. Defaults to 1e-4. priorc12 (float): Prior on variant being causal for traits 1 and 2. Defaults to 1e-5. Returns: Colocalisation: Colocalisation results + + Raises: + TypeError: When passed incorrect prior argument types. """ + # Ensure priors are always present, even if not passed + priorc1 = kwargs.get("priorc1") or 1e-4 + priorc2 = kwargs.get("priorc2") or 1e-4 + priorc12 = kwargs.get("priorc12") or 1e-5 + priors = [priorc1, priorc2, priorc12] + if any(not isinstance(prior, float) for prior in priors): + raise TypeError( + "Passed incorrect type(s) for prior parameters. got %s", + {type(p): p for p in priors}, + ) + # register udfs logsum = f.udf(get_logsum, DoubleType()) posteriors = f.udf(Coloc._get_posteriors, VectorUDT()) diff --git a/tests/gentropy/dataset/test_study_index.py b/tests/gentropy/dataset/test_study_index.py index 303642d5e..4bfede7d9 100644 --- a/tests/gentropy/dataset/test_study_index.py +++ b/tests/gentropy/dataset/test_study_index.py @@ -444,7 +444,6 @@ def _setup(self: TestDiseaseValidation, spark: SparkSession) -> None: "backgroundTraitFromSourceMappedIds", f.array().cast("array") ) ) - study_df.show() # Mock study index: self.study_index = StudyIndex( _df=study_df, diff --git a/tests/gentropy/method/test_colocalisation_method.py b/tests/gentropy/method/test_colocalisation_method.py index 1d788eb1f..c9a99d16f 100644 --- a/tests/gentropy/method/test_colocalisation_method.py +++ b/tests/gentropy/method/test_colocalisation_method.py @@ -17,6 +17,12 @@ def test_coloc(mock_study_locus_overlap: StudyLocusOverlap) -> None: """Test coloc.""" assert isinstance(Coloc.colocalise(mock_study_locus_overlap), Colocalisation) + assert isinstance( + Coloc.colocalise( + mock_study_locus_overlap, priorc1=1e-4, priorc2=1e-4, priorc12=1e-5 + ), + Colocalisation, + ) @pytest.mark.parametrize( diff --git a/tests/gentropy/step/test_colocalisation_step.py b/tests/gentropy/step/test_colocalisation_step.py new file mode 100644 index 000000000..e74dee234 --- /dev/null +++ b/tests/gentropy/step/test_colocalisation_step.py @@ -0,0 +1,293 @@ +"""Test colocalisation step.""" + +from pathlib import Path +from typing import Type + +import pytest + +from gentropy.colocalisation import ColocalisationStep +from gentropy.common.session import Session +from gentropy.dataset.colocalisation import Colocalisation +from gentropy.dataset.study_locus import StudyLocus +from gentropy.method.colocalisation import Coloc, ColocalisationMethodInterface, ECaviar + + +@pytest.mark.step_test +class TestColocalisationStep: + """Test colocalisation steps.""" + + @pytest.fixture(autouse=True) + def _setup(self, session: Session, tmp_path: Path) -> None: + """Setup StudyLocus for testing.""" + credible_set_data = [ + ( + "-1299941111165481046", + "gwas", + "1_62634374_G_GA", + "1", + 62634374, + "1:62116600-63176657", + "GCST90269661", + None, + -18.026562155233105, + 8.294741, + -72, + None, + None, + None, + [ + "Variant not found in LD reference, Study locus finemapped without in-sample LD reference" + ], + "SuSiE-inf", + 2, + 128.08235878972883, + 1.0, + 1.0, + 62116600, + 63176657, + None, + [("1_62634374_G_GA", 1.0)], + [ + ( + True, + True, + 303.2017476882394, + 1.0, + "1_62634374_G_GA", + None, + None, + -0.07779708137213309, + None, + None, + ) + ], + "SuSiE fine-mapped credible set with out-of-sample LD", + ), + ( + "-1245591334543437941", + "gwas", + "1_62725906_C_A", + "1", + 62725906, + "1:62275115-62861709", + "GCST90024601", + None, + 6.818181818181818, + 1.0845997, + -12, + None, + None, + None, + [ + "Variant not found in LD reference, Study locus finemapped without in-sample LD reference" + ], + "SuSiE-inf", + 3, + 903.4374513916813, + 1.0, + 1.0, + 62275115, + 62861709, + None, + [("1_62725906_C_A", 1.0)], + [ + ( + True, + True, + 2087.4457573345685, + 0.9999999999381545, + "1_62725906_C_A", + None, + None, + 0.20241232721094407, + None, + None, + ) + ], + "SuSiE fine-mapped credible set with out-of-sample LD", + ), + ( + "-0.20241232721094407", + "gwas", + "1_62725906_C_A", + "1", + 62725906, + "1:62335572-62883302", + "GCST90025461", + None, + 6.363636363636364, + 5.0753098, + -10, + None, + None, + None, + [ + "Variant not found in LD reference, Study locus finemapped without in-sample LD reference" + ], + "SuSiE-inf", + 2, + 912.1598183692258, + 1.0, + 1.0, + 62335572, + 62883302, + None, + [("1_62725906_C_A", 1.0)], + [ + ( + True, + True, + 2107.38950418228, + 0.9999999999454303, + "1_62725906_C_A", + None, + None, + 0.20330391077149534, + None, + None, + ) + ], + "SuSiE fine-mapped credible set with out-of-sample LD", + ), + ( + "-2271857845883525223", + "gwas", + "1_62634374_G_GA", + "1", + 62634374, + "1:62192511-63034021", + "GCST90269580", + None, + -15.43232373355239, + 1.0077391, + -54, + None, + None, + None, + [ + "Variant not found in LD reference, Study locus finemapped without in-sample LD reference" + ], + "SuSiE-inf", + 2, + 104.77639852123883, + 1.0, + 1.0, + 62192511, + 63034021, + None, + [("1_62634374_G_GA", 1.0)], + [ + ( + True, + True, + 249.20354469210795, + 1.0, + "1_62634374_G_GA", + None, + None, + -0.07071263272378725, + None, + None, + ) + ], + "SuSiE fine-mapped credible set with out-of-sample LD", + ), + ] + self.credible_set_path = str(tmp_path / "credible_set_datasets") + session.spark.createDataFrame( + credible_set_data, schema=StudyLocus.get_schema() + ).write.parquet(self.credible_set_path) + self.coloc_path = str(tmp_path / "colocalisation") + + @pytest.mark.parametrize( + ["label", "expected_method"], + [ + pytest.param("coloc", Coloc, id="coloc method"), + pytest.param("ecaviar", ECaviar, id="ecaviar method"), + pytest.param("ECaviar", ECaviar, id="uppercase label"), + ], + ) + def test_get_colocalisation_class( + self, label: str, expected_method: Type[ColocalisationMethodInterface] + ) -> None: + """Test _get_colocalisation_class method on ColocalisationStep.""" + method = ColocalisationStep._get_colocalisation_class(label) + assert ( + method is expected_method + ), "Incorrect colocalisation class returned by ColocalisationStep._get_colocalisation_class(label)" + + def test_label_with_invalid_method(self) -> None: + """Test what happens when invalid method_label is passed to the _get_colocalisation_class.""" + with pytest.raises(ValueError): + ColocalisationStep._get_colocalisation_class("NewMethod") + + @pytest.mark.parametrize( + ["coloc_method", "expected_data"], + [ + pytest.param( + "ecaviar", + { + "clpp": [1.0, 1.0], + "colocalisationMethod": ["eCAVIAR", "eCAVIAR"], + "leftStudyLocusId": [ + "-1245591334543437941", + "-2271857845883525223", + ], + "rightStudyLocusId": [ + "-0.20241232721094407", + "-1299941111165481046", + ], + }, + id="ecaviar", + ), + pytest.param( + "coloc", + { + "h4": [1.0, 1.0], + "h3": [0.0, 0.0], + "h2": [0.0, 0.0], + "h1": [0.0, 0.0], + "h0": [0.0, 0.0], + "colocalisationMethod": ["COLOC", "COLOC"], + "leftStudyLocusId": [ + "-1245591334543437941", + "-2271857845883525223", + ], + "rightStudyLocusId": [ + "-0.20241232721094407", + "-1299941111165481046", + ], + }, + id="coloc", + ), + ], + ) + def test_colocalise( + self, + coloc_method: str, + expected_data: dict[str, list[float] | list[str]], + session: Session, + ) -> None: + """Test colocalise method.""" + ColocalisationStep( + session=session, + credible_set_path=self.credible_set_path, + coloc_path=self.coloc_path, + colocalisation_method=coloc_method, + ) + + coloc_dataset = Colocalisation.from_parquet( + session, self.coloc_path, recursiveFileLookup=True + ) + for column in expected_data: + values = [c[column] for c in coloc_dataset.df.collect()] + expected_values = expected_data[column] + for v, e in zip(values, expected_values): + if isinstance(e, float): + assert ( + e == pytest.approx(v, 1e-1) + ), f"Incorrect value {v} at {column} found in {coloc_method}, expected {e}" + else: + assert ( + e == v + ), f"Incorrect value {v} at {column} found in {coloc_method}, expected {e}" From 9bbbc02681ae4ac2b137522aff29e4d946f047d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Irene=20L=C3=B3pez=20Santiago?= <45119610+ireneisdoomed@users.noreply.github.com> Date: Thu, 17 Oct 2024 11:32:01 +0100 Subject: [PATCH 109/188] test: skip `fetch_coordinates_from_rsids` (#850) --- src/gentropy/datasource/ensembl/api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gentropy/datasource/ensembl/api.py b/src/gentropy/datasource/ensembl/api.py index 2a767610f..eb42b3166 100644 --- a/src/gentropy/datasource/ensembl/api.py +++ b/src/gentropy/datasource/ensembl/api.py @@ -20,7 +20,7 @@ def fetch_coordinates_from_rsids( Exception: If an error occurs while processing the batches. Example: - >>> fetch_coordinates_from_rsids(["rs75493593"]) + >>> fetch_coordinates_from_rsids(["rs75493593"]) # doctest: +SKIP {'rs75493593': ['17_7041768_G_C', '17_7041768_G_T']} """ From 5cbf5ed793d3a131495cdf70330ee720102544ae Mon Sep 17 00:00:00 2001 From: Daniel Suveges Date: Thu, 17 Oct 2024 11:41:02 +0100 Subject: [PATCH 110/188] fix(eqtl): deduplicating credible set loci (#849) * fix(eqtl): deduplicating credible set loci * fix: removing --- .../datasource/eqtl_catalogue/finemapping.py | 60 ++-- tests/gentropy/conftest.py | 18 +- .../data_samples/QTD000584.lbf_variable.txt | 292 ++++++------------ .../eqtl_catalogue/test_eqtl_catalogue.py | 28 +- 4 files changed, 156 insertions(+), 242 deletions(-) diff --git a/src/gentropy/datasource/eqtl_catalogue/finemapping.py b/src/gentropy/datasource/eqtl_catalogue/finemapping.py index 0808b7016..ea46359df 100644 --- a/src/gentropy/datasource/eqtl_catalogue/finemapping.py +++ b/src/gentropy/datasource/eqtl_catalogue/finemapping.py @@ -136,22 +136,8 @@ def parse_susie_results( """ ss_ftp_path_template = "https://ftp.ebi.ac.uk/pub/databases/spot/eQTL/sumstats" return ( - lbf.withColumn( - "dataset_id", - cls._extract_dataset_id_from_file_path(f.input_file_name()), - ) - .join( - ( - credible_sets.withColumn( - "dataset_id", - cls._extract_dataset_id_from_file_path(f.input_file_name()), - ) - .withColumn( - "credibleSetIndex", - cls._extract_credible_set_index(f.col("cs_id")), - ) - .join(f.broadcast(studies_metadata), on="dataset_id") - ), + lbf.join( + credible_sets.join(f.broadcast(studies_metadata), on="dataset_id"), on=["molecular_trait_id", "region", "variant", "dataset_id"], how="inner", ) @@ -285,11 +271,26 @@ def read_credible_set_from_source( Returns: DataFrame: Credible sets DataFrame. """ - return session.spark.read.csv( - credible_set_path, - sep="\t", - header=True, - schema=cls.raw_credible_set_schema, + return ( + session.spark.read.csv( + credible_set_path, + sep="\t", + header=True, + schema=cls.raw_credible_set_schema, + ) + .withColumns( + { + # Adding dataset id based on the input file name: + "dataset_id": cls._extract_dataset_id_from_file_path( + f.input_file_name() + ), + # Parsing credible set index from the cs_id: + "credibleSetIndex": cls._extract_credible_set_index(f.col("cs_id")), + } + ) + # Remove duplicates caused by explosion of single variants to multiple rsid-s: + .drop("rsid") + .distinct() ) @classmethod @@ -307,9 +308,16 @@ def read_lbf_from_source( Returns: DataFrame: Log Bayes Factors DataFrame. """ - return session.spark.read.csv( - lbf_path, - sep="\t", - header=True, - schema=cls.raw_lbf_schema, + return ( + session.spark.read.csv( + lbf_path, + sep="\t", + header=True, + schema=cls.raw_lbf_schema, + ) + .withColumn( + "dataset_id", + cls._extract_dataset_id_from_file_path(f.input_file_name()), + ) + .distinct() ) diff --git a/tests/gentropy/conftest.py b/tests/gentropy/conftest.py index b1fc5ef90..10298205d 100644 --- a/tests/gentropy/conftest.py +++ b/tests/gentropy/conftest.py @@ -459,22 +459,20 @@ def sample_finngen_studies(spark: SparkSession) -> DataFrame: @pytest.fixture() -def sample_eqtl_catalogue_finemapping_credible_sets(spark: SparkSession) -> DataFrame: +def sample_eqtl_catalogue_finemapping_credible_sets(session: Session) -> DataFrame: """Sample raw eQTL Catalogue credible sets outputted by SuSIE.""" - return spark.read.option("delimiter", "\t").csv( - "tests/gentropy/data_samples/QTD000584.credible_sets.tsv", - header=True, - schema=EqtlCatalogueFinemapping.raw_credible_set_schema, + return EqtlCatalogueFinemapping.read_credible_set_from_source( + session, + credible_set_path=["tests/gentropy/data_samples/QTD000584.credible_sets.tsv"], ) @pytest.fixture() -def sample_eqtl_catalogue_finemapping_lbf(spark: SparkSession) -> DataFrame: +def sample_eqtl_catalogue_finemapping_lbf(session: Session) -> DataFrame: """Sample raw eQTL Catalogue table with logBayesFactors outputted by SuSIE.""" - return spark.read.option("delimiter", "\t").csv( - "tests/gentropy/data_samples/QTD000584.lbf_variable.txt", - header=True, - schema=EqtlCatalogueFinemapping.raw_lbf_schema, + return EqtlCatalogueFinemapping.read_lbf_from_source( + session, + lbf_path=["tests/gentropy/data_samples/QTD000584.lbf_variable.txt"], ) diff --git a/tests/gentropy/data_samples/QTD000584.lbf_variable.txt b/tests/gentropy/data_samples/QTD000584.lbf_variable.txt index 47023f5b6..2e5f080b7 100644 --- a/tests/gentropy/data_samples/QTD000584.lbf_variable.txt +++ b/tests/gentropy/data_samples/QTD000584.lbf_variable.txt @@ -1,201 +1,93 @@ molecular_trait_id region variant chromosome position lbf_variable1 lbf_variable2 lbf_variable3 lbf_variable4 lbf_variable5 lbf_variable6 lbf_variable7 lbf_variable8 lbf_variable9 lbf_variable10 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124823679_A_C 10 124823679 -1.26935233091278 0.00552916857251828 0.00670686749504501 0.00684844231246418 0.00642940186674279 0.00573212028335401 0.0049294931404007 0.00412586958588079 0.00338040036796583 0.00272239661658613 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124823817_T_C 10 124823817 -2.25582222123641 -0.00208125858550989 -0.00256052488318437 -0.00261904135127056 -0.00244640743271951 -0.00216292043253841 -0.00184233048896054 -0.00152734817415645 -0.00124041502049366 -0.000991265768420568 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124824245_G_A 10 124824245 -2.25249260789328 -0.00197882128489812 -0.00243573380317663 -0.00249154951399166 -0.00232690101650856 -0.00205664557252794 -0.00175120086684633 -0.00145129303789115 -0.00117826513141051 -0.00094132823193549 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124824364_C_A 10 124824364 -2.25582222123641 -0.00208125858550989 -0.00256052488318437 -0.00261904135127056 -0.00244640743271951 -0.00216292043253841 -0.00184233048896054 -0.00152734817415645 -0.00124041502049366 -0.000991265768420568 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124824534_C_CA 10 124824534 -2.26318575514626 -0.00759055742912418 -0.00927290986259788 -0.00947680517976357 -0.00887433723066655 -0.00787871618900615 -0.00674313127256188 -0.00561710571236462 -0.00458216509091836 -0.00367617563083877 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124825317_C_CA 10 124825317 -0.577170243131913 0.0161425873788299 0.0196348326829869 0.0200560085606836 0.0188102366798635 0.0167429348752397 0.0143719021033193 0.0120069483938527 0.00982103212513996 0.00789777641993306 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124825317_C_CAA 10 124825317 -1.93134671459752 0.00808255585983675 0.00982087088974337 0.0100302701012764 0.00941074157608668 0.00838160756220585 0.00719967534544841 0.0060190946946368 0.00492641412078276 0.00396386932238579 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124825317_CA_C 10 124825317 -0.532610050446922 0.0206967338320014 0.0251845551687073 0.0257260629026321 0.0241245358917253 0.0214679440558103 0.0184226737957691 0.015386928044514 0.0125825075687986 0.0101162494818747 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124825356_A_G 10 124825356 -0.698810919271326 0.0188588353573147 0.0229460465266103 0.0234391645719034 0.0219807191027961 0.0195612559074494 0.0167874827544021 0.0140220418245414 0.0114670266520394 0.00921986192434243 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124826915_CA_C 10 124826915 -2.31321458683551 -0.00840871648295538 -0.0102690109215051 -0.0104943894955198 -0.00982839321766171 -0.00872744617829202 -0.00747120691421399 -0.00622499048851344 -0.00507909365762194 -0.00407558751563553 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124826959_TG_T 10 124826959 -0.724597943609362 0.0182366191848016 0.0221881319406165 0.0226648572108372 0.021254882010378 0.0189157406366314 0.0162339191520751 0.0135600139674978 0.0110894466434504 0.00891645807503716 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124827162_AT_A 10 124827162 -2.21496848857903 -0.000625904251086329 -0.000787481469924689 -0.00080761257734574 -0.000748472679356293 -0.000653030232775187 -0.000547665274479137 -0.000446885348123871 -0.000357525256686309 -0.000281883923476833 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124827532_A_G 10 124827532 -2.4239637525357 -0.0102023448081918 -0.0124549417313204 -0.0127277408296163 -0.0119215488382096 -0.0105883972157388 -0.00906651295314331 -0.00755604216127681 -0.00616651788850042 -0.00494914623184917 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124827750_CA_C 10 124827750 -2.19705303485449 -0.00537724863697608 -0.00657770507775179 -0.00672340680485517 -0.00629302312399416 -0.00558265410110481 -0.00477375066817576 -0.00397306111913664 -0.003238379074328 -0.00259621529903864 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124828361_A_G 10 124828361 -2.25588888031751 -0.00208224488191977 -0.00256172645601493 -0.00262026893494349 -0.00244755811013109 -0.00216394368366934 -0.00184320789165371 -0.00152808041788477 -0.00124101337164051 -0.000991746533507865 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124828519_C_T 10 124828519 -2.25588888031751 -0.00208224488191977 -0.00256172645601493 -0.00262026893494349 -0.00244755811013109 -0.00216394368366934 -0.00184320789165371 -0.00152808041788477 -0.00124101337164051 -0.000991746533507865 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124828674_C_CT 10 124828674 -2.2667244433029 -0.00233277556838196 -0.00286698520973738 -0.0029321414787975 -0.00273987673260034 -0.00242386800603445 -0.00206606181755742 -0.00171404672221032 -0.00139296162534341 -0.00111382485843814 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124829420_G_A 10 124829420 -0.773523247901995 0.015053028496554 0.0183075326479205 0.0186999848913336 0.0175391396825431 0.0156125614034157 0.0134026087571608 0.0111979862234701 0.00915996807566311 0.00736660676212342 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124829573_A_G 10 124829573 -2.25249260789328 -0.00197882128489812 -0.00243573380317663 -0.00249154951399166 -0.00232690101650856 -0.00205664557252794 -0.00175120086684633 -0.00145129303789115 -0.00117826513141051 -0.00094132823193549 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124830088_A_G 10 124830088 -2.25249260789328 -0.00197882128489812 -0.00243573380317663 -0.00249154951399166 -0.00232690101650856 -0.00205664557252794 -0.00175120086684633 -0.00145129303789115 -0.00117826513141051 -0.00094132823193549 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124831282_G_T 10 124831282 -2.4051241801424 -0.010194429812052 -0.0124453571870049 -0.0127179559473882 -0.0119123569954724 -0.0105801942745289 -0.00905945119390417 -0.0075501258083901 -0.00616166635223259 -0.00494523626616372 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124831283_C_T 10 124831283 -2.25249260789328 -0.00197882128489812 -0.00243573380317663 -0.00249154951399166 -0.00232690101650856 -0.00205664557252794 -0.00175120086684633 -0.00145129303789115 -0.00117826513141051 -0.00094132823193549 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124831840_GTC_G 10 124831840 -1.20159579152222 0.0109045402639332 0.01325692516841 0.0135404689032392 0.012701693318911 0.0113090986301061 0.00971086161782742 0.00811562554315026 0.0066401903543869 0.00534128287561808 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124831844_T_A 10 124831844 -1.34658243357735 0.00835723769649288 0.0101540220853651 0.0103704459305436 0.00973012977614873 0.00866640295231225 0.00744464090993979 0.00622416647313395 0.00509446481102227 0.004099230894131 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124831872_T_A 10 124831872 -2.34625212779857 -0.00968803683158015 -0.0118285437848731 -0.0120878037141861 -0.0113216450523219 -0.0100548425007685 -0.00860892613410691 -0.00717409193702956 -0.00585435801725565 -0.00469829595754456 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124832027_A_AT 10 124832027 -2.25588888031751 -0.00208224488191977 -0.00256172645601493 -0.00262026893494349 -0.00244755811013109 -0.00216394368366934 -0.00184320789165371 -0.00152808041788477 -0.00124101337164051 -0.000991746533507865 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124833145_C_CA 10 124833145 -2.28283780570513 -0.00698556273488071 -0.00853682247273824 -0.00872490334208464 -0.00816921247013314 -0.00725119755438497 -0.00620459080659508 -0.00516728131637656 -0.00421430872952477 -0.00338041150034485 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124833253_G_A 10 124833253 -2.40657832584665 -0.010203516950968 -0.0124564268860818 -0.0127292651718496 -0.0119229580124944 -0.0105896217621688 -0.00906753535325366 -0.00755687284647166 -0.00616717992570104 -0.00494966650181938 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124833306_C_CA 10 124833306 -0.718119334208785 0.0204411095129298 0.0248729799428951 0.0254077221671682 0.0238261920838805 0.0212027184080621 0.0181953299954114 0.0151972610715623 0.0124275702368206 0.00999179406236905 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124833440_G_A 10 124833440 -2.41814339171232 -0.0098327631078603 -0.0120047960981764 -0.0122678640335487 -0.0114904461724898 -0.0102049807281643 -0.00873769306515593 -0.00728157837374699 -0.00594220704109105 -0.00476889267550984 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124835036_G_T 10 124835036 -2.25249260789328 -0.00197882128489812 -0.00243573380317663 -0.00249154951399166 -0.00232690101650856 -0.00205664557252794 -0.00175120086684633 -0.00145129303789115 -0.00117826513141051 -0.00094132823193549 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124835477_A_G 10 124835477 -2.26357089726545 -0.00222271066466995 -0.00273289892174455 -0.00279515289447785 -0.00261146945343693 -0.00230967927981629 -0.00196814756905628 -0.00163233041593891 -0.0013261864531442 -0.00106017148459969 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124837161_C_T 10 124837161 -2.25249260789328 -0.00197882128489812 -0.00243573380317663 -0.00249154951399166 -0.00232690101650856 -0.00205664557252794 -0.00175120086684633 -0.00145129303789115 -0.00117826513141051 -0.00094132823193549 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124838416_A_G 10 124838416 -2.25101211104246 -0.0019007294594231 -0.0023406051271837 -0.00239436257681014 -0.00223579989727307 -0.00197562888849667 -0.00168172781245923 -0.00139331039268331 -0.00113088226397506 -0.000903255146583959 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124838524_C_CA 10 124838524 -2.19483311051505 -0.00073611609891211 -0.000923663761242199 -0.000946982114754746 -0.000878450889030269 -0.000767649297590989 -0.000645009776721217 -0.000527355321968237 -0.000422707491994689 -0.000333856132527011 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124839146_G_A 10 124839146 -2.41082375945296 -0.0099006577745171 -0.0120875311249189 -0.0123523927681961 -0.0115696724236227 -0.0102754235108065 -0.00879808585381836 -0.00733197202772651 -0.00598338047337421 -0.00480197096266988 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124839225_GT_G 10 124839225 -2.2547600983747 -0.00180979521534308 -0.00222990403800383 -0.00228127539590872 -0.00212976945205723 -0.00188129907636458 -0.00160080305748656 -0.00132574085524739 -0.00107564323783382 -0.00085885419282361 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124839264_G_A 10 124839264 -2.25101211104246 -0.0019007294594231 -0.0023406051271837 -0.00239436257681014 -0.00223579989727307 -0.00197562888849667 -0.00168172781245923 -0.00139331039268331 -0.00113088226397506 -0.000903255146583959 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124840199_T_C 10 124840199 -2.39506056143101 -0.0100551588919027 -0.0122757056966614 -0.0125446341421811 -0.0117498873604074 -0.0104357075330044 -0.00893554999762491 -0.00744671581526868 -0.00607715974785661 -0.00487733286532199 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124840467_G_C 10 124840467 -2.1955186516612 -0.00526044141737181 -0.00643541330403563 -0.00657803613453112 -0.00615675597566279 -0.00546147170434175 -0.00466983553727074 -0.00388633342336675 -0.00316750640982066 -0.00253926795723158 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124840650_A_T 10 124840650 -0.374919234825047 0.0248189202763704 0.0302058642972165 0.0308559915029942 0.0289332976481971 0.0257445014718507 0.0220899879909635 0.0184477751553693 0.0150838660999502 0.0121261860282771 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124841158_G_A 10 124841158 -2.25719025489475 -0.00373076326931709 -0.00456968145801628 -0.00467164556865285 -0.0043705450008793 -0.00387415552450276 -0.0033098215585956 -0.00275218677675948 -0.00224138417213471 -0.00179559257569517 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124841267_C_CA 10 124841267 -0.65796727446411 0.0189073654131953 0.0230050128069865 0.0234993877730809 0.0220372234211639 0.0196115820169309 0.0168307125669158 0.0140581828413753 0.0114966063532012 0.00924366168201773 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124841437_A_T 10 124841437 -2.29495240097472 -0.00291412074261821 -0.00357511775813135 -0.00365559041324737 -0.00341803791169371 -0.0030269813358732 -0.00258326144869336 -0.00214572179889183 -0.00174573513882059 -0.00139729438053715 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124841469_C_T 10 124841469 -2.25101211104246 -0.0019007294594231 -0.0023406051271837 -0.00239436257681014 -0.00223579989727307 -0.00197562888849667 -0.00168172781245923 -0.00139331039268331 -0.00113088226397506 -0.000903255146583959 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124841584_A_ATT 10 124841584 -2.25101211104246 -0.0019007294594231 -0.0023406051271837 -0.00239436257681014 -0.00223579989727307 -0.00197562888849667 -0.00168172781245923 -0.00139331039268331 -0.00113088226397506 -0.000903255146583959 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124842626_A_G 10 124842626 -2.41287094557869 -0.0100150766337816 -0.0122271638344906 -0.0124950780441044 -0.0117033357201128 -0.0103941634812945 -0.00889978325271024 -0.00741674739941001 -0.0060525820624826 -0.00485752266582073 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124843625_T_C 10 124843625 -0.391278428517821 0.024561707548254 0.0298925376811181 0.0305358856678355 0.0286332362714949 0.0254776545317208 0.0218611616603241 0.0182567943647096 0.0149277976644338 0.0120007813442671 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124843786_G_T 10 124843786 -1.33271204361954 0.00441986373065539 0.00535558969393302 0.00546793225278286 0.00513532497097469 0.00458127002409814 0.00394260008157588 0.0033021845256247 0.00270727904679813 0.00218152035234276 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124843824_A_T 10 124843824 -0.808644938623694 0.016697723696264 0.0203135002655714 0.0207496644093359 0.019459618318773 0.017319203250421 0.014864862658424 0.0124173893985442 0.0101557032279578 0.00816617525578556 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124844385_G_T 10 124844385 -2.02426977742932 -0.00213689943378714 -0.0026291399548195 -0.00268924500523449 -0.00251192446234683 -0.00222075929825616 -0.00189151365654316 -0.00156805551923922 -0.00127342581869971 -0.00101761227868069 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124844711_C_CT 10 124844711 -2.01503820789279 -0.0031535461822334 -0.00386680125593264 -0.00395359058961686 -0.00369735935604076 -0.00327534683315944 -0.00279619439061829 -0.00232339410815152 -0.00189089116750285 -0.00151390251550865 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124844711_CT_C 10 124844711 -1.25199277177365 0.00564134730161303 0.00684346544685388 0.00698798899544517 0.00656022898481989 0.00584849311572233 0.00502931156001063 0.00420920084715881 0.00344851446769701 0.00277713927604362 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124844888_T_A 10 124844888 -0.375732324632437 0.0248049403934418 0.0301888353436373 0.0308385942069993 0.0289169894669477 0.0257299980795658 0.0220775506700184 0.0184373945242706 0.015075382871137 0.0121193693891644 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124845303_A_G 10 124845303 -0.556302344385712 0.0212121522157274 0.0258124212515813 0.02636751383189 0.0247258183214765 0.0220026662019812 0.0188812049933484 0.015769620000925 0.0128952390237536 0.0103675349386072 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124845846_A_C 10 124845846 -0.884014411763964 0.0151661909799317 0.0184479377895981 0.0188437496976177 0.0176730174456483 0.0157303195339376 0.0135023205298919 0.0112801617152996 0.00922634025881797 0.00741939137745495 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124846286_G_A 10 124846286 -1.37561849919552 0.00360869729913871 0.0043675560701204 0.00445853364713455 0.00418909939642553 0.00373973471157552 0.00322091938858371 0.0026998228571804 0.00221500290375154 0.0017859441489021 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124846582_A_T 10 124846582 -2.26188014201847 -0.00224770286182485 -0.00276329511473161 -0.00282620056778216 -0.00264058969506387 -0.00233560082750373 -0.00199039993220795 -0.00165092240380105 -0.00134139465236771 -0.00107240210186754 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124847850_CA_C 10 124847850 -2.28281655421035 -0.00654849040547711 -0.00800445581757403 -0.00818102594238379 -0.00765937146285545 -0.00679776151501077 -0.00581573061622098 -0.00484270944668097 -0.00394905137158963 -0.00316725747826574 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124847866_A_C 10 124847866 -2.26188014201847 -0.00224770286182485 -0.00276329511473161 -0.00282620056778216 -0.00264058969506387 -0.00233560082750373 -0.00199039993220795 -0.00165092240380105 -0.00134139465236771 -0.00107240210186754 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124848040_G_C 10 124848040 -0.481683170797529 0.0227445034177043 0.0276790136989811 0.0282744849293763 0.0265133981797634 0.0235924041188884 0.0202444637162862 0.0169074327419207 0.0138250704192542 0.0111146884616717 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124848431_G_T 10 124848431 -2.38994467621248 -0.0102487196804901 -0.0125114761704976 -0.0127855037145341 -0.011975680154201 -0.010636515414411 -0.00910775469932679 -0.00759044613753002 -0.00619462013039795 -0.00497171833825583 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124849256_C_T 10 124849256 -1.38512306922568 0.00339803602645494 0.00411095135359352 0.00419637882777657 0.00394335521202338 0.00352118509595067 0.00303350175896622 0.00254339629742217 0.00208716759899241 0.00168322238442897 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124850331_AT_A 10 124850331 -1.14789963673752 0.00996659050391013 0.012113906167416 0.0123726636984429 0.0116071677113001 0.010335953372294 0.00887658967490967 0.00741951332525836 0.00607146531596081 0.00488439246519556 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124850332_T_A 10 124850332 -1.01054912426359 0.0121087994910529 0.0147233008992642 0.0150384958619871 0.0141061253366908 0.012558376242287 0.0107824370924039 0.00901021637326727 0.00737142598287832 0.00592897437797379 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124850559_T_G 10 124850559 -1.13119431454808 0.0077316812330781 0.00938960202083639 0.00958918572989953 0.0089986189143505 0.00801708156622638 0.00688902193433982 0.00576141878737957 0.00471704068319001 0.0037964732754765 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124850734_G_C 10 124850734 -2.37281216720148 -0.00849915332668516 -0.0103805678343534 -0.0106085343587341 -0.00993490934488417 -0.00882146614210955 -0.00755114392486167 -0.00629114155199195 -0.00513272999375847 -0.00411839045022067 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124850745_T_G 10 124850745 -2.34013210285488 -0.00969765122941624 -0.0118403812180796 -0.0120999132441537 -0.0113329522913554 -0.0100648328471036 -0.00861742889999473 -0.00718113521053709 -0.00586007372556985 -0.00470286051065205 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124851010_CA_C 10 124851010 -2.24645897725556 -0.00235531432211511 -0.00289433135303696 -0.00296006531160753 -0.00276608972863635 -0.00244723489208853 -0.00208615341038509 -0.00173085986078103 -0.00140673445268824 -0.00112491489425048 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124851270_A_G 10 124851270 -1.61315974418337 -0.000695769921655209 -0.000875665552248162 -0.000898092069163692 -0.000832212088537787 -0.000725915764403062 -0.000608615379035893 -0.000496473023891664 -0.000397087102147253 -0.000312998377002049 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124851579_G_GTA 10 124851579 -1.59727070433974 -0.00061750007360839 -0.000780342350705343 -0.000800709184291648 -0.000740919496504233 -0.000644717347988877 -0.000538975306584533 -0.00043834176227886 -0.000349575886498421 -0.00027481732563972 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124851849_C_G 10 124851849 -2.20172963397072 0.000344256327158732 0.00039415271008636 0.000399565593268481 0.00038317481379968 0.000353440956338602 0.00031548803148862 0.000273580693262776 0.000231287096364774 0.000191276585144617 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124852104_G_GT 10 124852104 -2.2142673807444 -4.62757645354195e-05 -8.15929161559481e-05 -8.64752302738303e-05 -7.24257501500958e-05 -5.1720342387096e-05 -3.19376801352078e-05 -1.63778023014594e-05 -5.66040100657972e-06 8.87177957320517e-07 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124852520_C_T 10 124852520 -2.20172963397072 0.000344256327158732 0.00039415271008636 0.000399565593268481 0.00038317481379968 0.000353440956338602 0.00031548803148862 0.000273580693262776 0.000231287096364774 0.000191276585144617 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124853121_T_C 10 124853121 -2.08205539936493 -0.00420301069672924 -0.00514722500754417 -0.00526196779568089 -0.00492312010183538 -0.00436442249759983 -0.00372912664544867 -0.00310123401735352 -0.00252594669318995 -0.00202377282313959 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124853579_T_TAC 10 124853579 -1.61585361789647 -0.000345258762839418 -0.000448720538141156 -0.000461913934652891 -0.000423335086342291 -0.000362281274423282 -0.000296775425316476 -0.000236194720025562 -0.000184379079970931 -0.000142075434924838 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124853751_G_GTAAA 10 124853751 -2.20977800042084 3.70890256058409e-05 1.99281102375437e-05 1.72385022576549e-05 2.48041614621108e-05 3.47623586063328e-05 4.22377673410246e-05 4.55419703824234e-05 4.49491512908295e-05 4.1559466096075e-05 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124853754_A_AATAC 10 124853754 -2.42310750391642 -0.00816288430775636 -0.00997028315492132 -0.0101892914486599 -0.00954214613878657 -0.0084725115638733 -0.00725223239856909 -0.00604193309195722 -0.00492927684208899 -0.00395504989832229 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124853754_AATAC_A 10 124853754 -2.23742763746063 -0.00309302891731633 -0.00379548670270724 -0.0038810337245434 -0.00362852200688257 -0.00321292741721368 -0.00274150469795131 -0.00227679631973965 -0.00185210290683546 -0.00148224109781347 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124854823_C_CT 10 124854823 -1.86484506952777 0.00383919706239855 0.00464862332681681 0.00474571721880057 0.00445820147131881 0.00397890418358582 0.003425869817268 0.00287075923259517 0.00235460317835168 0.00189805451313596 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124855424_T_C 10 124855424 -1.0689563395791 0.0141172757206536 0.0171696302035032 0.0175377135128474 0.016448956230227 0.0146420365699691 0.0125693744018558 0.010501743789741 0.00859039221974855 0.00690851161051054 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124855907_G_C 10 124855907 -2.20172963397072 0.000344256327158732 0.00039415271008636 0.000399565593268481 0.00038317481379968 0.000353440956338602 0.00031548803148862 0.000273580693262776 0.000231287096364774 0.000191276585144617 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124855998_G_A 10 124855998 -2.37932547905698 -0.00861996285577771 -0.0105277396098318 -0.0107588911543872 -0.0100758489045782 -0.00894680165723827 -0.00765861847467741 -0.00638083841970261 -0.00520602792366454 -0.0041772857839284 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124856077_A_T 10 124856077 -1.16017327403508 0.00801496109916755 0.0097347198991069 0.00994177515210781 0.00932911690801985 0.00831097738559849 0.00714102523529814 0.00597172866494144 0.0048888938827627 0.00393455384169439 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124856078_A_T 10 124856078 -2.14546465344517 -0.00264064646411999 -0.0032489631421706 -0.0033232551150908 -0.00310409717180971 -0.0027442463684717 -0.00233735805750968 -0.00193764577601785 -0.00157357336004704 -0.00125747255615627 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124856242_A_T 10 124856242 -2.18709076006587 -0.00538453181998921 -0.0065864650294607 -0.00673234219202712 -0.00630143767333413 -0.0055901939405385 -0.00478027140120796 -0.0039785487658075 -0.0032428974093639 -0.00259986956338309 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124856370_C_A 10 124856370 -1.11015451493385 0.0118067214251947 0.0143554458513271 0.0146626971213943 0.0137538153112589 0.0122450014223734 0.0105136514942097 0.00878583544447276 0.00718802616565428 0.00578158250360916 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124856452_T_G 10 124856452 -2.20172963397072 0.000344256327158732 0.00039415271008636 0.000399565593268481 0.00038317481379968 0.000353440956338602 0.00031548803148862 0.000273580693262776 0.000231287096364774 0.000191276585144617 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124856781_C_A 10 124856781 -2.36227386231629 -0.00816558116262867 -0.00997388799706478 -0.010193013635666 -0.00954552323386615 -0.00847535078454831 -0.00725450724893095 -0.00604370003366839 -0.00493062235971653 -0.00395606214243127 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124857129_C_CT 10 124857129 -0.628128352211606 0.0177862952187477 0.021636776894546 0.0221012213611553 0.0207275049713487 0.0184481586819056 0.0158343421387213 0.0132276629929318 0.0108187035753233 0.00869950642747908 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124857129_C_CTT 10 124857129 -2.42446482948922 -0.00926366137701251 -0.0113108456281656 -0.0115588116243739 -0.0108260353360889 -0.00961447205302912 -0.00823167021258353 -0.00685953560296149 -0.00559753276883068 -0.00449209086004476 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124857210_G_C 10 124857210 -0.306771195812222 0.0286652508914989 0.0348902182491391 0.0356415588328018 0.033419575533935 0.0297347307371907 0.0255122158064474 0.0213044359671573 0.0174186366462514 0.0140024549121831 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124857357_T_TC 10 124857357 -0.74774913506455 0.0214291612881903 0.0260762148754976 0.0266369431252684 0.024978567685662 0.0222277202792651 0.0190744684515596 0.0159311466000784 0.013027407337197 0.0104738541329716 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124858183_C_CA 10 124858183 -2.36528455141954 -0.00827051004109691 -0.010102092818042 -0.0103240404132974 -0.00966821288590625 -0.00858426591431449 -0.00734771591222039 -0.00612133846652974 -0.00499395294071414 -0.00400686936803973 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124858338_C_CA 10 124858338 -0.773298686997732 0.0194937265888591 0.023718843168909 0.0242286059761128 0.0227209306438221 0.0202198272743854 0.0173525046840579 0.0144938466078139 0.0118527543759659 0.00952992235737105 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124858870_A_G 10 124858870 -1.99595508079809 -0.0030426223995299 -0.00373368189427925 -0.00381784076000002 -0.00356942264728266 -0.00316056964121536 -0.00269680051078636 -0.00223964438309876 -0.00182186054527822 -0.00145802291673025 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124859522_G_A 10 124859522 -2.365157793514 -0.00827230048391048 -0.0101042706382657 -0.0103262649462352 -0.009670299249668 -0.00858612299682049 -0.00734931002308947 -0.00612267027291802 -0.00499504229370284 -0.00400774539649795 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124859964_G_C 10 124859964 -1.97405365708197 -0.000543187217329155 -0.000689424284475049 -0.000707774278422058 -0.000653946936808758 -0.000567586561615485 -0.000473047903800872 -0.000383497516525999 -0.000304893758784175 -0.000239010868388512 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124860024_G_A 10 124860024 -2.36198869204334 -0.00818237968679414 -0.00999474923050592 -0.0102143760096149 -0.00956541085758689 -0.00849283648263688 -0.00726930683032956 -0.00605589201100054 -0.00494046640365386 -0.00396388882906162 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124861026_G_A 10 124861026 -0.29067413452153 0.0292743585012767 0.0356323821717037 0.0363998018739244 0.0341302799222793 0.0303666802517433 0.0260540420335156 0.021756582282018 0.0177880781062152 0.0142992751009148 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124861051_C_CA 10 124861051 -2.03795344804845 0.00555943061560837 0.00674735090256284 0.00689025720990388 0.00646733396331989 0.00576398883266815 0.00495499615532724 0.00414564596221378 0.00339543051932356 0.00273367987436712 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124861242_G_A 10 124861242 -2.20538965904691 0.000288868708465007 0.000326679151345655 0.000330631833028505 0.000318558453802353 0.000295978460458812 0.000266214181689595 0.000232457354235382 0.000197682182137449 0.000164274842282541 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124861453_TAA_T 10 124861453 -2.00910553493323 -0.00182619854521437 -0.00225222279478343 -0.00230437118373716 -0.0021506075147375 -0.0018986367507523 -0.0016145052431189 -0.00133621578900422 -0.0010834843115779 -0.000864650898003028 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124861546_CT_C 10 124861546 -0.299575679675067 0.0293182633765765 0.0356858057176668 0.0364543738184406 0.0341814550444037 0.0304122204168675 0.026093122370122 0.0217892226905265 0.0178147691794286 0.0143207342160045 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124861678_T_C 10 124861678 -2.20538965904691 0.000288868708465007 0.000326679151345655 0.000330631833028505 0.000318558453802353 0.000295978460458812 0.000266214181689595 0.000232457354235382 0.000197682182137449 0.000164274842282541 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124861767_AAC_A 10 124861767 -2.365157793514 -0.00827230048391048 -0.0101042706382657 -0.0103262649462352 -0.009670299249668 -0.00858612299682049 -0.00734931002308947 -0.00612267027291802 -0.00499504229370284 -0.00400774539649795 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124861896_C_CT 10 124861896 -2.34361530890309 -0.00980634181046591 -0.011972669645862 -0.0122350494284547 -0.0114596665769731 -0.0101775802247421 -0.0087141702195348 -0.00726192484030941 -0.00592613088375993 -0.00475596454737515 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124861896_CT_C 10 124861896 -2.11354144863348 -0.00409914225762442 -0.00502058249042037 -0.00513257112179355 -0.00480186548615391 -0.00425664741908793 -0.00363676336165764 -0.00302419255784248 -0.0024630230271776 -0.00197323604012922 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124862342_G_GTTTC 10 124862342 -0.864289568967809 0.0117991261534693 0.0143437545655223 0.0146504461140693 0.01374317670312 0.0122367825312009 0.0105078147886846 0.00878196212628257 0.00718560700752313 0.00578016109837343 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124862342_GTTTC_G 10 124862342 -2.07217144588303 -0.00258142782033044 -0.00317205002266618 -0.00324407967452078 -0.00303152917706973 -0.00268212882431484 -0.00228644336901063 -0.00189708658195631 -0.00154187258018723 -0.00123300999567011 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124862659_C_T 10 124862659 -2.00640662063191 -0.0015945570639424 -0.00197002543164304 -0.00201606566951762 -0.00188036208133902 -0.0016583151324463 -0.0014084341022178 -0.00116423409372279 -0.000942947211313605 -0.000751729697384906 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124863331_C_A 10 124863331 -1.22981344082261 0.00648215511408479 0.00786783716180706 0.00803454041488383 0.00754119935295261 0.00672080692922439 0.00577726742646778 0.00483339430462681 0.00395855802165279 0.00318694041292122 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124863667_C_T 10 124863667 -2.3114541036934 -0.00829396163175478 -0.0101306759535689 -0.0103532432628235 -0.00969558317750518 -0.008608602562032 -0.00736858267875284 -0.00613875319919099 -0.0050081841819436 -0.0040183049156246 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124863792_G_A 10 124863792 -2.41338949335586 -0.0102158448242644 -0.0124713467902331 -0.0127444957394616 -0.0119372685587149 -0.0106023974915321 -0.00907853859404728 -0.00756609550762599 -0.00617474587064493 -0.00495576633282546 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124863826_G_A 10 124863826 -2.41855974376777 -0.0101440851973633 -0.0123838778534062 -0.0126551275127089 -0.0118535151938319 -0.0105279425574754 -0.00901471897582562 -0.00751285317703587 -0.00613125311405538 -0.00492083048354353 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124863850_G_GC 10 124863850 -2.41352642132538 -0.0102144621698033 -0.012469660943899 -0.0127427732232159 -0.0119356544404736 -0.0106009628320707 -0.00907730911471605 -0.00756507000458795 -0.00617390830827391 -0.00495509366272406 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124863879_T_C 10 124863879 -2.41268773268103 -0.0102220363045333 -0.0124788964814622 -0.0127522097145749 -0.0119444969101368 -0.0106088219217635 -0.00908404396312212 -0.00757068729584676 -0.0061784959761586 -0.0049587780367748 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124864887_G_C 10 124864887 -2.41381085358942 -0.0102111816273278 -0.0124656612846996 -0.0127386865962063 -0.0119318248998526 -0.0105975589377953 -0.00907439191290926 -0.00756263668078105 -0.00617192085803975 -0.00495349743346196 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124864962_G_A 10 124864962 -2.36296427035108 -0.00948256910029599 -0.0115783613765692 -0.0118322222259506 -0.0110820300565244 -0.00984169616350661 -0.00842609600830224 -0.00702145659546582 -0.00572959297396114 -0.00459802178713353 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124864997_C_T 10 124864997 -2.14306511331013 -0.000260582271575327 -0.000344678931059939 -0.000355510086136768 -0.000323907281513769 -0.000274320602060119 -0.000221798724961975 -0.000173991441501986 -0.000133826557028982 -0.00010165157100106 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124865002_G_A 10 124865002 -2.41251023227331 -0.0102177237552032 -0.0124736416121158 -0.0127468409641547 -0.0119394648622468 -0.0106043476515545 -0.00908020794689834 -0.00756748634465332 -0.00617588064852326 -0.00495667689130519 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124865704_C_T 10 124865704 -2.356457849256 -0.00810041343117263 -0.00989494605377494 -0.0101124190637973 -0.00946982283804632 -0.00840780679078579 -0.00719637044055998 -0.00599500068627545 -0.00489069306086476 -0.00392388550016687 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124866001_C_T 10 124866001 -2.41724916412078 -0.0101958677186325 -0.0124469888190628 -0.012719607906591 -0.011913947000719 -0.0105816689704175 -0.00906077472772004 -0.00755127886086404 -0.0061626447093448 -0.00494604760820128 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124866099_A_G 10 124866099 -2.35790509730176 -0.00943119364994427 -0.0115157563517401 -0.0117682599888602 -0.0110220803751888 -0.0097883931689875 -0.00838039806867608 -0.00698332514382205 -0.00569843849875928 -0.00457299284562085 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124866319_G_A 10 124866319 -2.18814687053492 0.00103374299003889 0.00123404983497233 0.00125763382490041 0.00118751492896596 0.00106875046180654 0.000928882685671262 0.000785528494525511 0.000649649603641667 0.000527441820001417 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124867389_CA_C 10 124867389 -2.42439460706178 -0.0101842635723424 -0.0124330062519746 -0.0127053421280041 -0.0119005213782186 -0.0105696512953779 -0.00905039308598443 -0.00754255137385229 -0.00615546565041747 -0.00494024614327948 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124867437_G_A 10 124867437 -2.42181542402192 -0.0101066826092229 -0.0123382838178938 -0.0126085430100131 -0.0118098586950279 -0.0104891346011668 -0.00898145612081969 -0.00748510459873053 -0.00610858680202764 -0.00490262433592559 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124867446_C_G 10 124867446 -1.85215232914845 -0.00219644256812179 -0.00270409053415355 -0.00276612269390064 -0.00258314719750308 -0.0022828582301293 -0.00194355207155761 -0.00161048553124532 -0.00130734889056683 -0.00104434379659546 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124867617_A_G 10 124867617 0.0880066890301177 0.0386184419415754 0.0470141016771235 0.0480276683821961 0.0450303335243802 0.0400606280284359 0.0343672187321142 0.0286951992821192 0.0234585417857001 0.018855811854865 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124868004_G_T 10 124868004 -2.19059206540259 0.000953096955157218 0.00113580654021028 0.00115726448532039 0.00109343176676324 0.000985083395587338 0.00085713839380297 0.000725651487846868 0.000600719590937437 0.000488126203770367 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124868077_G_GTGA 10 124868077 -2.41899105915463 -0.0101780617338392 -0.0124252775963898 -0.0126974243405238 -0.011893159682852 -0.0105631931415644 -0.00904494157493074 -0.00753807276433704 -0.00615185904515902 -0.00493738546844558 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124868108_C_T 10 124868108 -2.14137376350746 0.00264440227928109 0.00319616521047505 0.00326221109855407 0.00306654318791511 0.00273974650405817 0.00236175554929829 0.0019813871070169 0.00162687466035072 0.00131264841277945 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124868637_C_T 10 124868637 -2.35102908566065 -0.00780264455196455 -0.00953175666351491 -0.0097413143052516 -0.00912211407945041 -0.00809881776910881 -0.00693163082493786 -0.00577423046153225 -0.00471041807656247 -0.00377912609346032 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124868925_C_T 10 124868925 -2.42306586227239 -0.0100929881505887 -0.0123215899667151 -0.0125914864714836 -0.0117938742724766 -0.0104749255068342 -0.00896927737872755 -0.00747494489504685 -0.00610028793409745 -0.00489595850814961 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124869257_C_A 10 124869257 -2.40674804533862 -0.0101603128281558 -0.0124038473720414 -0.0126755543259103 -0.0118725933059327 -0.0105448069896554 -0.00902908155322146 -0.00752475900861693 -0.00614092186447524 -0.00492855719484586 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124870301_A_T 10 124870301 -2.42454937630958 -0.00974110134836925 -0.0118928028542493 -0.0121534054533319 -0.0113832711043136 -0.0101098404746653 -0.0086562759604818 -0.0072137650952655 -0.00588689393417718 -0.00472451987113187 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124870342_G_A 10 124870342 -2.24254240705457 -0.00155228805833918 -0.001918805622525 -0.0019637739393592 -0.0018312471997417 -0.0016144878414015 -0.00137070144089391 -0.00113261520680918 -0.000917011551710978 -0.000730820734208049 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124870593_C_T 10 124870593 -2.28037853045056 -0.00134568315480665 -0.00166453583354098 -0.00170367426888918 -0.00158833865386798 -0.00139980328914646 -0.00118791410601071 -0.000981141917813844 -0.000794040732649215 -0.000632581205984195 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124870765_G_A 10 124870765 -2.34195939181553 -0.00902961921251144 -0.0110268481587883 -0.0112688079747527 -0.0105538087631345 -0.00937181748354243 -0.00802304244203489 -0.00668496244615779 -0.00545453617141289 -0.00437695428784401 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124870937_A_AAG 10 124870937 -2.37230685613492 -0.0093384519906885 -0.0114030468423576 -0.0116531449753792 -0.0109140826757277 -0.00969221702959722 -0.00829779624754634 -0.00691427904751718 -0.0056419356567381 -0.00452753650781235 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124871088_G_A 10 124871088 -2.26562276538336 -0.00537848873693392 -0.00657950314815325 -0.00672528021667285 -0.00629467842352716 -0.0055839768997612 -0.00477473843442233 -0.00397376401807215 -0.00323886218870451 -0.0025965392986782 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124871508_C_A 10 124871508 -2.41297959802709 -0.0101947873312165 -0.0124456400135347 -0.0127182258369429 -0.011912662783883 -0.0105805434293291 -0.00905982558303986 -0.00755049984142708 -0.00616201788623894 -0.00494555077041792 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124871651_C_T 10 124871651 -2.3623966394335 -0.00830651776258673 -0.0101460758460079 -0.0103689899794577 -0.00971030666917239 -0.00862164030402823 -0.00737970712410219 -0.00614799112696929 -0.0050156980025875 -0.00402431740164788 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124871717_A_G 10 124871717 -2.4120830893663 -0.0102036150574341 -0.0124564046810671 -0.0127292247990596 -0.0119229691746092 -0.0105897033553912 -0.00906767491220384 -0.00755704645855548 -0.00616736437406873 -0.0049498444409326 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124872065_T_A 10 124872065 -2.30465233503976 -0.00365486539906623 -0.00447767922271014 -0.00457770666273749 -0.00428233826081614 -0.00379550118031746 -0.00324217557751449 -0.00269557085906413 -0.00219500349589508 -0.00175824653571421 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124872284_G_T 10 124872284 -2.30348823457678 -0.00361587902324656 -0.0044301847211381 -0.0045291842032591 -0.00423685518766437 -0.00375505420705258 -0.00320749298886014 -0.0026666256327994 -0.00217135053572592 -0.00173924146888726 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124872559_C_T 10 124872559 -2.35818431673202 -0.00824558293686994 -0.0100718622175235 -0.0102931724982511 -0.00963923160842528 -0.0085584251654911 -0.00732549161127682 -0.00610273627658842 -0.00497871148928031 -0.00399459471276487 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124872986_C_A 10 124872986 -0.923706737356496 0.0113315790353465 0.0137774642370032 0.0140723123671753 0.0132001198497949 0.0117521885172498 0.010090661306521 0.00843248146293307 0.0068990280585175 0.00554919908147644 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124872994_G_A 10 124872994 -2.02341254613387 -0.00305117962125623 -0.0037442032562236 -0.0038286019425362 -0.00357947548896753 -0.00316945864580731 -0.00270437280105584 -0.00224592262039458 -0.0018269597359315 -0.00146209816974752 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124874052_A_T 10 124874052 -2.38693357409243 -0.00857135685344668 -0.0104677043984567 -0.0106974530085249 -0.0100185440549705 -0.00889626085821815 -0.00761568940437174 -0.00634534793821828 -0.00517727850068006 -0.00415436230611821 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124874155_T_G 10 124874155 -2.39775412364336 -0.0095381309483078 -0.0116458920824067 -0.0119011954574866 -0.0111467353237535 -0.00989931199233807 -0.00847557202956661 -0.00706280566807305 -0.00576342417034059 -0.00462523416929539 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124874233_C_T 10 124874233 -2.3657502195825 -0.00819925708227709 -0.0100143852244652 -0.0102343204824731 -0.0095844263876832 -0.00851021757446402 -0.00728467031510993 -0.0060690927664635 -0.00495153679656823 -0.00397298222001563 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124874407_G_A 10 124874407 -2.26168534408016 -0.00422404575473223 -0.00517125252840644 -0.00528631338163388 -0.00494649756284593 -0.0043860331397263 -0.0037484614709502 -0.00311803508838837 -0.00254017415289898 -0.0020355542196957 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124874580_T_C 10 124874580 -1.19481654392163 0.0101655306157933 0.0123577032463165 0.0126219163375412 0.0118403142047154 0.0105425674085526 0.00905306449880472 0.00756622814239627 0.00619093445407781 0.0049800925341712 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124874628_C_CT 10 124874628 -2.21762065241773 -0.0068649175779858 -0.00838864786078775 -0.00857336997435709 -0.00802758682496441 -0.00712586538941729 -0.00609771797206493 -0.00507858055624455 -0.00414219430208052 -0.00332272602368633 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124874628_C_CTT 10 124874628 -2.41714408502127 -0.00800738758039721 -0.00978066315042758 -0.00999554192893104 -0.00936060032146635 -0.00831117033048256 -0.0071139884713225 -0.00592664550866528 -0.00483513478250375 -0.00387945455836292 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124874628_CT_C 10 124874628 -2.32866712978018 -0.00982315867274641 -0.0119934445874148 -0.0122563103102897 -0.0114794955938891 -0.0101950662573653 -0.00872902015657351 -0.00727419931742856 -0.00593607209606306 -0.00476388984716758 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124875024_TG_T 10 124875024 -2.42452927878212 -0.00995743974258767 -0.0121564186176411 -0.0124227350109321 -0.0116357077968465 -0.0103342934182642 -0.00884870870390708 -0.00737433855345104 -0.00601808911237178 -0.0048299211207814 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124875025_G_T 10 124875025 -2.4074340910167 -0.0100566566558609 -0.0122776043978226 -0.0125465832484069 -0.0117516889421418 -0.0104372724088253 -0.00893685570121816 -0.00744777584257594 -0.00607800384572599 -0.00487799564911295 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124875780_A_C 10 124875780 -2.38071407300441 -0.00964567364203406 -0.0117770634939354 -0.0120352252895088 -0.0112723161652171 -0.0100109112755642 -0.00857119345630197 -0.00714254995264962 -0.00582854491132201 -0.00467752856522763 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124875816_T_G 10 124875816 -2.27825848629036 -0.00467085688263058 -0.00571556438176835 -0.00584240515522705 -0.00546775928303234 -0.00484958240206401 -0.00414595096883952 -0.00344977312729711 -0.00281126046625824 -0.00225337270792991 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124875879_A_G 10 124875879 -2.28786347712826 -0.00487631012383982 -0.00596584354113627 -0.00609809996602451 -0.00570744142188451 -0.00506273121830825 -0.00432872766074865 -0.00360231827681012 -0.00293591784287139 -0.00235353665601723 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124875900_C_T 10 124875900 -2.27825848629036 -0.00467085688263058 -0.00571556438176835 -0.00584240515522705 -0.00546775928303234 -0.00484958240206401 -0.00414595096883952 -0.00344977312729711 -0.00281126046625824 -0.00225337270792991 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124876023_T_C 10 124876023 -2.27825848629036 -0.00467085688263058 -0.00571556438176835 -0.00584240515522705 -0.00546775928303234 -0.00484958240206401 -0.00414595096883952 -0.00344977312729711 -0.00281126046625824 -0.00225337270792991 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124876126_G_C 10 124876126 -2.42442534698811 -0.00996620261597592 -0.0121671208762901 -0.0124336722754026 -0.0116459506476527 -0.0103433885272244 -0.00885649441035641 -0.00738082549002339 -0.00602338193984098 -0.00483416826723149 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124876310_G_A 10 124876310 -2.27825848629036 -0.00467085688263058 -0.00571556438176835 -0.00584240515522705 -0.00546775928303234 -0.00484958240206401 -0.00414595096883952 -0.00344977312729711 -0.00281126046625824 -0.00225337270792991 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124876408_T_A 10 124876408 -2.27825848629036 -0.00467085688263058 -0.00571556438176835 -0.00584240515522705 -0.00546775928303234 -0.00484958240206401 -0.00414595096883952 -0.00344977312729711 -0.00281126046625824 -0.00225337270792991 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124876535_G_C 10 124876535 -2.27829632805935 -0.0046719314900967 -0.00571687347664041 -0.00584374258032572 -0.00546901294301305 -0.00485069726480258 -0.00414690695804953 -0.00345057098314872 -0.00281191245252588 -0.00225389658222452 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124876564_C_CAAATAAATTAAATAAAT 10 124876564 -2.12942475684804 -0.00158894226318473 -0.00196172235023306 -0.00200739705782738 -0.00187274792744985 -0.00165230120068705 -0.00140402024302455 -0.00116116606062144 -0.000940902542695632 -0.000750411885188207 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124876568_C_CAAAT 10 124876568 -2.36215716918498 -0.00930963241113991 -0.0113680331574431 -0.0116173857781154 -0.0108805285028986 -0.00966232519673138 -0.00827211136925454 -0.00689279817253707 -0.00562434798885292 -0.00451338044114014 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124876568_C_CAAATAAAT 10 124876568 -0.648929701322621 0.0308435023885512 0.037538910758864 0.0383469638093343 0.0359572174258802 0.0319938803026778 0.0274518144402669 0.0229251617514246 0.0187445132080155 0.0150688257769223 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124876568_C_T 10 124876568 -2.18052202855304 -0.0025014134292598 -0.00307281178678309 -0.00314247042041149 -0.00293689828122723 -0.00259888188556445 -0.00221594741345088 -0.00183898574125596 -0.00149494453347643 -0.00119568940126769 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124876568_CAAATAAATAAAT_C 10 124876568 -2.39512978852103 -0.00966641362165488 -0.0118020856746277 -0.0120607589826016 -0.0112963335514102 -0.0100323896310339 -0.00858972654791046 -0.00715811151822665 -0.00584133104862161 -0.00468785065644051 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124876675_A_G 10 124876675 -2.18052202855304 -0.0025014134292598 -0.00307281178678309 -0.00314247042041149 -0.00293689828122723 -0.00259888188556445 -0.00221594741345088 -0.00183898574125596 -0.00149494453347643 -0.00119568940126769 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124876737_A_G 10 124876737 -2.18052202855304 -0.0025014134292598 -0.00307281178678309 -0.00314247042041149 -0.00293689828122723 -0.00259888188556445 -0.00221594741345088 -0.00183898574125596 -0.00149494453347643 -0.00119568940126769 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124876844_A_AT 10 124876844 -2.18052202855304 -0.0025014134292598 -0.00307281178678309 -0.00314247042041149 -0.00293689828122723 -0.00259888188556445 -0.00221594741345088 -0.00183898574125596 -0.00149494453347643 -0.00119568940126769 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124876970_G_T 10 124876970 -2.19095558457118 -0.0026607600886992 -0.0032669188210912 -0.00334077688664092 -0.00312278806469335 -0.00276419634652525 -0.0023577087879838 -0.00195730204120537 -0.0015916325090366 -0.00127338083983242 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124877181_G_A 10 124877181 -2.14942874363679 -0.00173198752737358 -0.00213550753494474 -0.0021848838874825 -0.00203928133960396 -0.00180063515418505 -0.00153144685282891 -0.00126770412651389 -0.00102810371357176 -0.00082057698983995 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124877742_C_A 10 124877742 -2.06789359669105 0.00262987934722991 0.00317820519682677 0.00324382912345111 0.00304940571873802 0.00272464288181862 0.00234893708859962 0.00197079826345536 0.00161830332058033 0.00130581835814692 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124877843_A_G 10 124877843 -2.11433783846441 -0.00499598240766241 -0.00611346990748007 -0.00624915308189644 -0.00584839244132107 -0.00518713173971674 -0.00443447616285741 -0.00368981097672227 -0.00300684247595751 -0.00241012368287175 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124879093_T_C 10 124879093 -2.14290127114632 -0.00384406929353576 -0.0047133166240183 -0.00481908880636928 -0.00450682075191633 -0.00399251706057679 -0.00340857100185765 -0.00283234773866159 -0.00230520965746672 -0.0018457033228696 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124879923_G_C 10 124879923 -2.40574668912287 -0.0102621202589086 -0.0125278272947424 -0.0128022120185198 -0.0119913327898047 -0.0106504215446259 -0.00911966590142299 -0.00760037614135145 -0.00620272648010101 -0.00497822609501108 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124880248_C_T 10 124880248 -1.75985774107497 -0.000877998601555241 -0.00109773845343986 -0.00112497966076397 -0.00104486327676945 -0.000914988452652477 -0.000770712572622845 -0.000631732887391045 -0.000507600807614583 -0.000401785470919513 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124880294_G_A 10 124880294 -1.9302822333851 -0.00663373426827363 -0.00810982892571577 -0.0082888702952415 -0.00775992850902441 -0.00688640253167883 -0.00589097568227137 -0.00490487765349767 -0.00399938193617988 -0.00320736784692865 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124880336_T_C 10 124880336 -2.3971867783626 -0.00536784219154596 -0.00656538312311383 -0.00671071122189026 -0.006281419100306 -0.0055727663806806 -0.00476568956506807 -0.00396667520303096 -0.00323341469103466 -0.00259240340282307 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124880404_C_CA 10 124880404 -1.12033853837012 0.0244027604505059 0.0296972495055932 0.0303361632276444 0.0284465890882575 0.0253124981487161 0.0217203410918638 0.0181399226250618 0.0148327803451616 0.0119247739464381 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124880404_CA_C 10 124880404 -2.1183672853477 -0.00473362071415639 -0.00579071933489494 -0.00591902499045105 -0.00554002302072565 -0.00491448643477943 -0.00420222218601563 -0.00349723797950663 -0.00285041846016343 -0.00228509379823727 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124880634_A_G 10 124880634 -2.42263994346138 -0.00980890127822365 -0.0119749417421993 -0.0122372647243512 -0.011462035241383 -0.0101801143860145 -0.00871675898083257 -0.0072644269715183 -0.00592843026074208 -0.00475799007795086 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124880658_C_G 10 124880658 -1.54338394539326 0.0054732181143331 0.006636598101601 0.00677638902011513 0.00636258344555207 0.00567375159401484 0.00488046004011222 0.0040857800176437 0.00334825903324143 0.00269700196257672 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124880660_C_G 10 124880660 -2.42416829065956 -0.00990841040868284 -0.0120961267053583 -0.0123610679168187 -0.0115780975040773 -0.0102833454460893 -0.00880529657188056 -0.0073383332879815 -0.00598883475236445 -0.00480653243049112 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124880710_T_C 10 124880710 -2.40511428331389 -0.0101195205057487 -0.0123543389114853 -0.01262499780101 -0.0118251391319895 -0.0105025123221472 -0.00899272201284296 -0.00749433786698495 -0.00611600569828985 -0.00490849710312347 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124881424_C_T 10 124881424 -1.36919701492274 0.00999673883925034 0.0121489779011763 0.0124082824073661 0.0116411348917662 0.0103670205340629 0.00890407623996703 0.00744315622964464 0.00609131454102307 0.00490071372014 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124882052_C_T 10 124882052 -1.82420838934042 0.0022928177461039 0.0027633036003798 0.00281940697305805 0.00265306005708954 0.00237438141671209 0.00205074471555555 0.00172371164138019 0.00141772511562177 0.00114558890483929 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124883060_G_A 10 124883060 -1.90172214488359 0.000577834630465457 0.000674749179790268 0.000685735811911226 0.000652797970321473 0.000595242745631719 0.000524817245715514 0.00044992479634498 0.000376620248644155 0.000308915212811733 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124883112_C_G 10 124883112 -1.89887216225045 0.000537991937034743 0.000626233357059025 0.000636172694886472 0.000606331851326747 0.000553910421083437 0.000489364593859509 0.000420327911155205 0.000352428055699683 0.00028947216448838 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124883394_T_TATTC 10 124883394 -2.38825389806601 -0.00878270817768545 -0.0107237598647796 -0.0109588724170124 -0.0102640787576536 -0.00911532698727369 -0.00780423307672162 -0.00650327561321129 -0.00530675905511302 -0.00425869852260474 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124883535_T_A 10 124883535 -2.38883035182704 -0.00876769840310532 -0.0107054703526681 -0.01094018654477 -0.0102465647594068 -0.009099754282758 -0.00779088174651577 -0.00649213456308928 -0.00529765622368883 -0.00425138528198943 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124883669_A_G 10 124883669 -2.02483811858609 0.00281448798610162 0.00340305047823719 0.0034735314263088 0.00326474527569998 0.00291618593853871 0.00251323571720308 0.00210796785899481 0.00173043429351782 0.00139594610687688 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124883741_G_T 10 124883741 -1.90172214488359 0.000577834630465457 0.000674749179790268 0.000685735811911226 0.000652797970321473 0.000595242745631719 0.000524817245715514 0.00044992479634498 0.000376620248644155 0.000308915212811733 -UROS.11248.43.3..1 chr10:124823285-126823285 chr10_124883757_G_T 10 124883757 -2.23798452352228 -0.00323497440754217 -0.00396937981280354 -0.00405881135783215 -0.00379482448051105 -0.00336031726431107 -0.00286740186100642 -0.00238146493585711 -0.00193733324513268 -0.00155051237063519 +ISG15.14148.2.3..1 chr1:1138-2001138 chr1_1004625_A_G 1 1004625 31.6611029091783 -0.202959075620786 -0.202130730314703 -0.20961965656411 -0.220935552186467 -0.231637998079872 -0.238725148211663 -0.24082771183179 -0.237793637394013 -0.230147752064775 +ISG15.14148.2.3..1 chr1:1138-2001138 chr1_1005429_C_CA 1 1005429 32.221487936929 -0.195965362215776 -0.195159905703761 -0.202442615288331 -0.213450908310367 -0.223867149857143 -0.230767346101171 -0.232814731479065 -0.229859524607447 -0.222413891866702 +ISG15.14148.2.3..1 chr1:1138-2001138 chr1_1005429_C_CA 1 1005429 32.221487936929 -0.195965362215776 -0.195159905703761 -0.202442615288331 -0.213450908310367 -0.223867149857143 -0.230767346101171 -0.232814731479065 -0.229859524607447 -0.222413891866702 +ISG15.14148.2.3..1 chr1:1138-2001138 chr1_1005904_C_T 1 1005904 32.2201611534391 -0.195991762843284 -0.195186220371416 -0.202469703004364 -0.213479148809414 -0.223896462401234 -0.230797358533138 -0.232844950282998 -0.229889448070568 -0.222443065660339 +ISG15.14148.2.3..1 chr1:1138-2001138 chr1_1005954_G_A 1 1005954 32.2307888818185 -0.19578105619256 -0.19497623026446 -0.202253251284341 -0.213253021383546 -0.223661291151955 -0.230556257657266 -0.232602096369102 -0.229649101642647 -0.222209070783182 +ISG15.14148.2.3..1 chr1:1138-2001138 chr1_1006159_C_T 1 1006159 31.136467292701 -0.209990149528141 -0.209138719976353 -0.216835315041259 -0.228461477008492 -0.239453018312253 -0.246729173853613 -0.248887512499901 -0.245773726161243 -0.237925750736744 +ISG15.14148.2.3..1 chr1:1138-2001138 chr1_1007746_CTTTTTTTTTTTTTT_C 1 1007746 32.9559850984322 -0.038316648883864 -0.0380238494960996 -0.0406893282630594 -0.0448305028253735 -0.04887519730207 -0.051621545891178 -0.0524445636406954 -0.0512453110009252 -0.0482663766774842 +ISG15.14148.2.3..1 chr1:1138-2001138 chr1_1008088_T_C 1 1008088 1.37412874657265 0.327702121948042 0.326632473445201 0.336381513669191 0.350847368073308 0.364259715641688 0.373012957292964 0.375606404726796 0.37190257498043 0.362433775328293 +ISG15.14148.2.3..1 chr1:1138-2001138 chr1_1008307_G_C 1 1008307 32.5456111578158 -0.194700204398019 -0.193898250606131 -0.201149852637882 -0.212113006036389 -0.222488569395536 -0.229362885636536 -0.231402755433439 -0.228458430823835 -0.22104090567139 +ISG15.14148.2.3..1 chr1:1138-2001138 chr1_1008307_G_C 1 1008307 32.5456111578158 -0.194700204398019 -0.193898250606131 -0.201149852637882 -0.212113006036389 -0.222488569395536 -0.229362885636536 -0.231402755433439 -0.228458430823835 -0.22104090567139 +ISG15.14148.2.3..1 chr1:1138-2001138 chr1_1009184_T_C 1 1009184 32.5611388775887 -0.194290897321716 -0.193490230314105 -0.200730245427149 -0.211676195244074 -0.222035837874369 -0.228899799643638 -0.230936619539856 -0.227996653323558 -0.220590227413268 +ISG15.14148.2.3..1 chr1:1138-2001138 chr1_1009184_T_C 1 1009184 32.5611388775887 -0.194290897321716 -0.193490230314105 -0.200730245427149 -0.211676195244074 -0.222035837874369 -0.228899799643638 -0.230936619539856 -0.227996653323558 -0.220590227413268 +ISG15.14148.2.3..1 chr1:1138-2001138 chr1_1009716_C_T 1 1009716 2.71104079064173 0.494816635254447 0.493192703993635 0.50794034053314 0.529835423625354 0.550140638470176 0.563389361772642 0.567308216212787 0.561697932338878 0.547375550942794 +ISG15.14148.2.3..1 chr1:1138-2001138 chr1_1009731_C_T 1 1009731 2.82150405521786 0.540342129323484 0.538562825668397 0.554719332306166 0.57871213290032 0.600969016749107 0.615494215722806 0.619790737162891 0.61363890191046 0.597937184159163 +ISG15.14148.2.3..1 chr1:1138-2001138 chr1_1010094_C_T 1 1010094 2.24493920482519 0.411968335337582 0.41061718608088 0.422907017935993 0.441149233643318 0.458066284407125 0.469106147268475 0.472374152232941 0.467700270944111 0.455760977707615 +ISG15.14148.2.3..1 chr1:1138-2001138 chr1_1010232_C_T 1 1010232 1.91202916188143 0.359803709417789 0.358629772331635 0.36932105260348 0.385180619164498 0.399879856468536 0.409469520222412 0.41230946464606 0.408251380242343 0.397876921424855 +ISG15.14148.2.3..1 chr1:1138-2001138 chr1_1010481_ATTAT_A 1 1010481 1.77173807821859 0.32367057938181 0.322617627724349 0.332215602605901 0.34644932972347 0.359638760397212 0.368242813192753 0.370791808350112 0.367151750023736 0.357841775774211 +ISG15.14148.2.3..1 chr1:1138-2001138 chr1_1010481_ATTAT_A 1 1010481 1.77173807821859 0.32367057938181 0.322617627724349 0.332215602605901 0.34644932972347 0.359638760397212 0.368242813192753 0.370791808350112 0.367151750023736 0.357841775774211 +ISG15.14148.2.3..1 chr1:1138-2001138 chr1_1010481_ATTAT_A 1 1010481 1.77173807821859 0.32367057938181 0.322617627724349 0.332215602605901 0.34644932972347 0.359638760397212 0.368242813192753 0.370791808350112 0.367151750023736 0.357841775774211 +ISG15.14148.2.3..1 chr1:1138-2001138 chr1_1010747_GT_G 1 1010747 1.75810715157238 0.324689439194826 0.323633006588353 0.33326218961169 0.347542511100306 0.360775365411779 0.369407817534277 0.371965166683577 0.368313013217345 0.358972409164632 +ISG15.14148.2.3..1 chr1:1138-2001138 chr1_1010755_T_G 1 1010755 1.75810715157238 0.324689439194826 0.323633006588353 0.33326218961169 0.347542511100306 0.360775365411779 0.369407817534277 0.371965166683577 0.368313013217345 0.358972409164632 +ISG15.14148.2.3..1 chr1:1138-2001138 chr1_1011654_G_A 1 1011654 2.12169251532154 0.366460361798816 0.365265937516033 0.376141030220329 0.392271491754132 0.407219493507684 0.416970000694678 0.419857141457765 0.415731154253511 0.40518294886129 +ISG15.14148.2.3..1 chr1:1138-2001138 chr1_1013041_A_AAAC 1 1013041 2.00781021970105 0.362130484724756 0.360948644878316 0.371710067829663 0.387674855396944 0.402472485475907 0.412126585625301 0.414985420016895 0.410899869364181 0.400456289240032 +ISG15.14148.2.3..1 chr1:1138-2001138 chr1_1013312_G_A 1 1013312 2.389285291571 0.421166743866767 0.419791984834859 0.432290918596263 0.450834183229199 0.468019640467544 0.479228539567116 0.482545253802808 0.477800748778892 0.465678374403175 +ISG15.14148.2.3..1 chr1:1138-2001138 chr1_1013490_C_G 1 1013490 1.89538630594497 0.353868820883007 0.352714933468769 0.363225203506876 0.378815233728964 0.393263825335052 0.402689707855315 0.405481310490667 0.40149274816844 0.39129510202527 +ISG15.14148.2.3..1 chr1:1138-2001138 chr1_1013541_T_C 1 1013541 1.89945161357021 0.354469519574711 0.353313593450461 0.363842259202563 0.379459698800289 0.393933795126526 0.40337635110558 0.40617287510971 0.402177232445623 0.391961588903811 +ISG15.14148.2.3..1 chr1:1138-2001138 chr1_1013855_G_A 1 1013855 1.89454057580979 0.354052298424014 0.352897840814967 0.363413213754561 0.379010797399775 0.393466353945608 0.402896750555113 0.405689674590678 0.401699201839202 0.391496694616208 +ISG15.14148.2.3..1 chr1:1138-2001138 chr1_1014228_G_A 1 1014228 32.6418654124405 -0.180802804248279 -0.180043852226177 -0.186910406121919 -0.197302938239478 -0.207151747100776 -0.213684283615382 -0.215623798363078 -0.212823520223575 -0.205772783096275 +ISG15.14148.2.3..1 chr1:1138-2001138 chr1_1014228_G_A 1 1014228 32.6418654124405 -0.180802804248279 -0.180043852226177 -0.186910406121919 -0.197302938239478 -0.207151747100776 -0.213684283615382 -0.215623798363078 -0.212823520223575 -0.205772783096275 +ISG15.14148.2.3..1 chr1:1138-2001138 chr1_1014545_C_T 1 1014545 1.20281022405445 0.267916639443903 0.267054936386071 0.274920572041875 0.286572348338058 0.297357277091691 0.304387754403386 0.306471311531062 0.303499065561979 0.295888238410321 +ISG15.14148.2.3..1 chr1:1138-2001138 chr1_1014863_A_C 1 1014863 30.7102047260281 -0.214696165616663 -0.213828713720751 -0.221669131092052 -0.233511900561953 -0.244706884587611 -0.252116790069818 -0.254314638616173 -0.251144400637229 -0.243154229162276 +ISG15.14148.2.3..1 chr1:1138-2001138 chr1_1014863_A_C 1 1014863 30.7102047260281 -0.214696165616663 -0.213828713720751 -0.221669131092052 -0.233511900561953 -0.244706884587611 -0.252116790069818 -0.254314638616173 -0.251144400637229 -0.243154229162276 +ISG15.14148.2.3..1 chr1:1138-2001138 chr1_1015336_A_T 1 1015336 1.73768783536195 0.324567751473565 0.323512736755249 0.33312889658469 0.347388308919715 0.360600087747298 0.369217920528146 0.371770851149316 0.368125094883084 0.3588001019182 +ISG15.14148.2.3..1 chr1:1138-2001138 chr1_1015925_A_ATT 1 1015925 31.1469863801803 -0.208655966377409 -0.207808108361277 -0.215472257639861 -0.227051979795868 -0.238002207875466 -0.245252278704403 -0.247402975301871 -0.244300066522567 -0.236480736750293 +ISG15.14148.2.3..1 chr1:1138-2001138 chr1_1015925_A_ATT 1 1015925 31.1469863801803 -0.208655966377409 -0.207808108361277 -0.215472257639861 -0.227051979795868 -0.238002207875466 -0.245252278704403 -0.247402975301871 -0.244300066522567 -0.236480736750293 +ISG15.14148.2.3..1 chr1:1138-2001138 chr1_1015925_A_ATT 1 1015925 31.1469863801803 -0.208655966377409 -0.207808108361277 -0.215472257639861 -0.227051979795868 -0.238002207875466 -0.245252278704403 -0.247402975301871 -0.244300066522567 -0.236480736750293 +ISG15.14148.2.3..1 chr1:1138-2001138 chr1_1015925_A_ATT 1 1015925 31.1469863801803 -0.208655966377409 -0.207808108361277 -0.215472257639861 -0.227051979795868 -0.238002207875466 -0.245252278704403 -0.247402975301871 -0.244300066522567 -0.236480736750293 +ISG15.14148.2.3..1 chr1:1138-2001138 chr1_1015925_A_ATT 1 1015925 31.1469863801803 -0.208655966377409 -0.207808108361277 -0.215472257639861 -0.227051979795868 -0.238002207875466 -0.245252278704403 -0.247402975301871 -0.244300066522567 -0.236480736750293 +ISG15.14148.2.3..1 chr1:1138-2001138 chr1_1015925_A_ATT 1 1015925 31.1469863801803 -0.208655966377409 -0.207808108361277 -0.215472257639861 -0.227051979795868 -0.238002207875466 -0.245252278704403 -0.247402975301871 -0.244300066522567 -0.236480736750293 +ISG15.14148.2.3..1 chr1:1138-2001138 chr1_1015950_G_A 1 1015950 0.884176683134713 0.195840705162238 0.195221010473166 0.200903976121869 0.209307445943998 0.217074019195252 0.222133581488668 0.223635775784243 0.221499942951625 0.216016641813618 +ISG15.14148.2.3..1 chr1:1138-2001138 chr1_1016623_G_A 1 1016623 30.9861128754779 -0.210464865129048 -0.209610975855757 -0.217329439548726 -0.22899041237872 -0.240016470987136 -0.247316190638715 -0.249481554483427 -0.246357691513044 -0.23848526219243 +ISG15.14148.2.3..1 chr1:1138-2001138 chr1_1017114_A_AT 1 1017114 31.024532551894 -0.210241815843817 -0.209388737406676 -0.217099878090532 -0.228749800882685 -0.239765441432763 -0.247058283430011 -0.249221606899604 -0.246100659800412 -0.238235582934101 +ISG15.14148.2.3..1 chr1:1138-2001138 chr1_1017114_A_AT 1 1017114 31.024532551894 -0.210241815843817 -0.209388737406676 -0.217099878090532 -0.228749800882685 -0.239765441432763 -0.247058283430011 -0.249221606899604 -0.246100659800412 -0.238235582934101 +ISG15.14148.2.3..1 chr1:1138-2001138 chr1_1017114_A_AT 1 1017114 31.024532551894 -0.210241815843817 -0.209388737406676 -0.217099878090532 -0.228749800882685 -0.239765441432763 -0.247058283430011 -0.249221606899604 -0.246100659800412 -0.238235582934101 +ISG15.14148.2.3..1 chr1:1138-2001138 chr1_1017114_A_AT 1 1017114 31.024532551894 -0.210241815843817 -0.209388737406676 -0.217099878090532 -0.228749800882685 -0.239765441432763 -0.247058283430011 -0.249221606899604 -0.246100659800412 -0.238235582934101 +ISG15.14148.2.3..1 chr1:1138-2001138 chr1_1022518_G_T 1 1022518 31.2281969352636 0.0634418252095963 0.0633989654806943 0.0637694407831844 0.0641436052558637 0.0642910202108671 0.0642800157751431 0.0642644363690663 0.0643069267573702 0.0643407268154315 +ISG15.14151.4.3..1 chr1:1138-2001138 chr1_1004625_A_G 1 1004625 60.3575665524951 -1.78394536462074 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +ISG15.14151.4.3..1 chr1:1138-2001138 chr1_1005429_C_CA 1 1005429 61.024165250281 -1.73525144796326 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +ISG15.14151.4.3..1 chr1:1138-2001138 chr1_1005429_C_CA 1 1005429 61.024165250281 -1.73525144796326 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +ISG15.14151.4.3..1 chr1:1138-2001138 chr1_1005904_C_T 1 1005904 61.0221011561896 -1.73539907793572 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +ISG15.14151.4.3..1 chr1:1138-2001138 chr1_1005954_G_A 1 1005954 60.9716665050324 -1.73683060605725 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +ISG15.14151.4.3..1 chr1:1138-2001138 chr1_1006159_C_T 1 1006159 59.9874687452069 -1.78614534920697 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +ISG15.14151.4.3..1 chr1:1138-2001138 chr1_1007746_CTTTTTTTTTTTTTT_C 1 1007746 56.5256228788874 -1.19720405745599 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +ISG15.14151.4.3..1 chr1:1138-2001138 chr1_1008088_T_C 1 1008088 -0.907129234395213 25.243875269357 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +ISG15.14151.4.3..1 chr1:1138-2001138 chr1_1008307_G_C 1 1008307 65.6918304267104 -1.45884813824405 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +ISG15.14151.4.3..1 chr1:1138-2001138 chr1_1008307_G_C 1 1008307 65.6918304267104 -1.45884813824405 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +ISG15.14151.4.3..1 chr1:1138-2001138 chr1_1009184_T_C 1 1009184 65.771960163951 -1.44456525071005 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +ISG15.14151.4.3..1 chr1:1138-2001138 chr1_1009184_T_C 1 1009184 65.771960163951 -1.44456525071005 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +ISG15.14151.4.3..1 chr1:1138-2001138 chr1_1009716_C_T 1 1009716 -0.447856745307585 25.2017785595101 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +ISG15.14151.4.3..1 chr1:1138-2001138 chr1_1009731_C_T 1 1009731 -0.445841857837749 25.4269874827134 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +ISG15.14151.4.3..1 chr1:1138-2001138 chr1_1010094_C_T 1 1010094 -0.649054852993949 25.4428175271184 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +ISG15.14151.4.3..1 chr1:1138-2001138 chr1_1010232_C_T 1 1010232 -0.829276587086672 25.6799899493842 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +ISG15.14151.4.3..1 chr1:1138-2001138 chr1_1010481_ATTAT_A 1 1010481 -0.836262770837368 25.4389216459073 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +ISG15.14151.4.3..1 chr1:1138-2001138 chr1_1010481_ATTAT_A 1 1010481 -0.836262770837368 25.4389216459073 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +ISG15.14151.4.3..1 chr1:1138-2001138 chr1_1010481_ATTAT_A 1 1010481 -0.836262770837368 25.4389216459073 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +ISG15.14151.4.3..1 chr1:1138-2001138 chr1_1010747_GT_G 1 1010747 -0.826170274979466 25.5495904572018 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +ISG15.14151.4.3..1 chr1:1138-2001138 chr1_1010755_T_G 1 1010755 -0.826170274979466 25.5495904572018 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +ISG15.14151.4.3..1 chr1:1138-2001138 chr1_1011654_G_A 1 1011654 -0.721925093708164 25.2119185314773 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +ISG15.14151.4.3..1 chr1:1138-2001138 chr1_1013041_A_AAAC 1 1013041 -0.683178587820276 25.4495400510799 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +ISG15.14151.4.3..1 chr1:1138-2001138 chr1_1013312_G_A 1 1013312 -0.646682543118569 25.7383508815934 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +ISG15.14151.4.3..1 chr1:1138-2001138 chr1_1013490_C_G 1 1013490 -0.830608796417208 25.621658716628 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +ISG15.14151.4.3..1 chr1:1138-2001138 chr1_1013541_T_C 1 1013541 -0.836649880908032 25.5935368859696 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +ISG15.14151.4.3..1 chr1:1138-2001138 chr1_1013855_G_A 1 1013855 -0.833887346945684 25.6126978286785 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +ISG15.14151.4.3..1 chr1:1138-2001138 chr1_1014228_G_A 1 1014228 68.87357824629 -1.44285040965178 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +ISG15.14151.4.3..1 chr1:1138-2001138 chr1_1014228_G_A 1 1014228 68.87357824629 -1.44285040965178 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +ISG15.14151.4.3..1 chr1:1138-2001138 chr1_1014545_C_T 1 1014545 -1.01063070074985 26.0676629268844 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +ISG15.14151.4.3..1 chr1:1138-2001138 chr1_1014863_A_C 1 1014863 65.3967593369157 -1.45885206221497 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +ISG15.14151.4.3..1 chr1:1138-2001138 chr1_1014863_A_C 1 1014863 65.3967593369157 -1.45885206221497 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +ISG15.14151.4.3..1 chr1:1138-2001138 chr1_1015336_A_T 1 1015336 -0.739349906651994 25.7895461533593 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +ISG15.14151.4.3..1 chr1:1138-2001138 chr1_1015925_A_ATT 1 1015925 65.2749061618345 -1.41461869181183 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +ISG15.14151.4.3..1 chr1:1138-2001138 chr1_1015925_A_ATT 1 1015925 65.2749061618345 -1.41461869181183 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +ISG15.14151.4.3..1 chr1:1138-2001138 chr1_1015925_A_ATT 1 1015925 65.2749061618345 -1.41461869181183 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +ISG15.14151.4.3..1 chr1:1138-2001138 chr1_1015925_A_ATT 1 1015925 65.2749061618345 -1.41461869181183 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +ISG15.14151.4.3..1 chr1:1138-2001138 chr1_1015925_A_ATT 1 1015925 65.2749061618345 -1.41461869181183 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +ISG15.14151.4.3..1 chr1:1138-2001138 chr1_1015925_A_ATT 1 1015925 65.2749061618345 -1.41461869181183 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +ISG15.14151.4.3..1 chr1:1138-2001138 chr1_1015950_G_A 1 1015950 -1.01506118885836 25.5809772743873 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +ISG15.14151.4.3..1 chr1:1138-2001138 chr1_1016623_G_A 1 1016623 65.0485663530216 -1.4274791103387 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +ISG15.14151.4.3..1 chr1:1138-2001138 chr1_1017114_A_AT 1 1017114 65.3771920394664 -1.39957248113441 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +ISG15.14151.4.3..1 chr1:1138-2001138 chr1_1017114_A_AT 1 1017114 65.3771920394664 -1.39957248113441 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +ISG15.14151.4.3..1 chr1:1138-2001138 chr1_1017114_A_AT 1 1017114 65.3771920394664 -1.39957248113441 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +ISG15.14151.4.3..1 chr1:1138-2001138 chr1_1017114_A_AT 1 1017114 65.3771920394664 -1.39957248113441 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +ISG15.14151.4.3..1 chr1:1138-2001138 chr1_1022518_G_T 1 1022518 59.6277992377165 -0.0390342701330888 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 diff --git a/tests/gentropy/datasource/eqtl_catalogue/test_eqtl_catalogue.py b/tests/gentropy/datasource/eqtl_catalogue/test_eqtl_catalogue.py index ce892128a..4e7a87cc4 100644 --- a/tests/gentropy/datasource/eqtl_catalogue/test_eqtl_catalogue.py +++ b/tests/gentropy/datasource/eqtl_catalogue/test_eqtl_catalogue.py @@ -4,6 +4,7 @@ import pytest from pyspark.sql import DataFrame +from pyspark.sql import functions as f from gentropy.dataset.study_index import StudyIndex from gentropy.dataset.study_locus import StudyLocus @@ -41,12 +42,27 @@ def test_parse_susie_results( ) -def test_credsets_from_susie_results(processed_finemapping_df: DataFrame) -> None: - """Test creating a study locus from SuSIE results.""" - assert isinstance( - EqtlCatalogueFinemapping.from_susie_results(processed_finemapping_df), - StudyLocus, - ) +class TestEqtlCatalogueStudyLocus: + """Test the correctness of the study locus dataset from eQTL Catalogue.""" + + @pytest.fixture(autouse=True) + def _setup(self, processed_finemapping_df: DataFrame) -> DataFrame: + """Set up the test.""" + self.study_locus = EqtlCatalogueFinemapping.from_susie_results( + processed_finemapping_df + ) + + def test_credsets_from_susie_results(self: TestEqtlCatalogueStudyLocus) -> None: + """Test creating a study locus from SuSIE results.""" + assert isinstance(self.study_locus, StudyLocus) + + def test_locus_uniqueness(self: TestEqtlCatalogueStudyLocus) -> None: + """Test the uniqueness of the locus.""" + find_discrepancies = self.study_locus.df.select( + f.size("locus").alias("locus_size"), + f.size(f.array_distinct("locus")).alias("locus_distinct_size"), + ).filter(f.col("locus_size") != f.col("locus_distinct_size")) + assert find_discrepancies.count() == 0 def test_studies_from_susie_results(processed_finemapping_df: DataFrame) -> None: From 3ef43a9998534b0656af64cf4f5e560a40799346 Mon Sep 17 00:00:00 2001 From: Yakov Date: Thu, 17 Oct 2024 12:27:10 +0100 Subject: [PATCH 111/188] chore: adding logging even when no CS in locus (#848) * chore: adding logging even when no CS in locus * fix: addin CS count to log --- src/gentropy/susie_finemapper.py | 52 +++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/src/gentropy/susie_finemapper.py b/src/gentropy/susie_finemapper.py index 25adbccbe..5ec347e6a 100644 --- a/src/gentropy/susie_finemapper.py +++ b/src/gentropy/susie_finemapper.py @@ -127,7 +127,6 @@ def __init__( if result_logging["study_locus"] is not None: # Write result df = result_logging["study_locus"].df - df = df.withColumn("qualityControls", f.lit(None)) df = df.withColumn( "qualityControls", @@ -137,8 +136,8 @@ def __init__( StudyLocusQualityCheck.OUT_OF_SAMPLE_LD, ), ) - df.write.mode(session.write_mode).parquet(study_locus_output) + if result_logging["log"] is not None: # Write log result_logging["log"].to_parquet( study_locus_output + ".log", @@ -600,21 +599,40 @@ def susie_finemapper_from_prepared_dataframes( end_time = time.time() - log_df = pd.DataFrame( - { - "studyId": studyId, - "region": region, - "N_gwas_before_dedupl": N_gwas_before_dedupl, - "N_gwas": N_gwas, - "N_ld": N_ld, - "N_overlap": N_after_merge, - "N_outliers": N_outliers, - "N_imputed": N_imputed, - "N_final_to_fm": len(ld_to_fm), - "elapsed_time": end_time - start_time, - }, - index=[0], - ) + if study_locus is not None: + log_df = pd.DataFrame( + { + "studyId": studyId, + "region": region, + "N_gwas_before_dedupl": N_gwas_before_dedupl, + "N_gwas": N_gwas, + "N_ld": N_ld, + "N_overlap": N_after_merge, + "N_outliers": N_outliers, + "N_imputed": N_imputed, + "N_final_to_fm": len(ld_to_fm), + "elapsed_time": end_time - start_time, + "number_of_CS": study_locus.df.count(), + }, + index=[0], + ) + else: + log_df = pd.DataFrame( + { + "studyId": studyId, + "region": region, + "N_gwas_before_dedupl": N_gwas_before_dedupl, + "N_gwas": N_gwas, + "N_ld": N_ld, + "N_overlap": N_after_merge, + "N_outliers": N_outliers, + "N_imputed": N_imputed, + "N_final_to_fm": len(ld_to_fm), + "elapsed_time": end_time - start_time, + "number_of_CS": 0, + }, + index=[0], + ) return { "study_locus": study_locus, From d33f66a91a950b029078d15de905b770db07042d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Irene=20L=C3=B3pez=20Santiago?= <45119610+ireneisdoomed@users.noreply.github.com> Date: Thu, 17 Oct 2024 13:52:04 +0100 Subject: [PATCH 112/188] feat(l2g): limit colocalisation neighbourhood to protein coding genes (#847) * feat(l2g): wip - limit colocalisation neighbourhood to protein coding genes * feat: adjust logic in `common_neighbourhood_colocalisation_feature_logic` * fix: correct logic in `common_neighbourhood_vep_feature_logic` * chore: adjust tests --- .../dataset/l2g_features/colocalisation.py | 34 +++++--- src/gentropy/dataset/l2g_features/vep.py | 36 ++++---- tests/gentropy/dataset/test_l2g_feature.py | 82 +++++++++---------- 3 files changed, 76 insertions(+), 76 deletions(-) diff --git a/src/gentropy/dataset/l2g_features/colocalisation.py b/src/gentropy/dataset/l2g_features/colocalisation.py index c61daa909..319a128da 100644 --- a/src/gentropy/dataset/l2g_features/colocalisation.py +++ b/src/gentropy/dataset/l2g_features/colocalisation.py @@ -5,10 +5,10 @@ from typing import TYPE_CHECKING, Any import pyspark.sql.functions as f -from pyspark.sql import Window from gentropy.common.spark_helpers import convert_from_wide_to_long from gentropy.dataset.colocalisation import Colocalisation +from gentropy.dataset.gene_index import GeneIndex from gentropy.dataset.l2g_features.l2g_feature import L2GFeature from gentropy.dataset.l2g_gold_standard import L2GGoldStandard from gentropy.dataset.study_index import StudyIndex @@ -77,6 +77,7 @@ def common_neighbourhood_colocalisation_feature_logic( *, colocalisation: Colocalisation, study_index: StudyIndex, + gene_index: GeneIndex, study_locus: StudyLocus, ) -> DataFrame: """Wrapper to call the logic that creates a type of colocalisation features. @@ -89,6 +90,7 @@ def common_neighbourhood_colocalisation_feature_logic( qtl_types (list[str] | str): The types of QTL to filter the data by colocalisation (Colocalisation): Dataset with the colocalisation results study_index (StudyIndex): Study index to fetch study type and gene + gene_index (GeneIndex): Gene index to add gene type study_locus (StudyLocus): Study locus to traverse between colocalisation and study index Returns: @@ -105,15 +107,21 @@ def common_neighbourhood_colocalisation_feature_logic( colocalisation=colocalisation, study_index=study_index, study_locus=study_locus, + ).join(gene_index.df.select("geneId", "biotype"), "geneId", "left") + # Compute average score in the vicinity (feature will be the same for any gene associated with a studyLocus) + # (non protein coding genes in the vicinity are excluded see #3552) + regional_mean_per_study_locus = ( + local_max.filter(f.col("biotype") == "protein_coding") + .groupBy("studyLocusId") + .agg(f.mean(local_feature_name).alias("regional_mean")) ) return ( - # Then compute maximum score in the vicinity (feature will be the same for any gene associated with a studyLocus) - local_max.withColumn( - "regional_maximum", - f.max(local_feature_name).over(Window.partitionBy("studyLocusId")), + local_max.join(regional_mean_per_study_locus, "studyLocusId", "left") + .withColumn( + feature_name, + f.col(local_feature_name) - f.coalesce(f.col("regional_mean"), f.lit(0.0)), ) - .withColumn(feature_name, f.col("regional_maximum") - f.col(local_feature_name)) - .drop("regional_maximum", local_feature_name) + .drop("regional_mean", local_feature_name, "biotype") ) @@ -163,7 +171,7 @@ def compute( class EQtlColocClppMaximumNeighbourhoodFeature(L2GFeature): """Max CLPP for each (study, locus) aggregating over all eQTLs.""" - feature_dependency_type = [Colocalisation, StudyIndex, StudyLocus] + feature_dependency_type = [Colocalisation, StudyIndex, GeneIndex, StudyLocus] feature_name = "eQtlColocClppMaximumNeighbourhood" @classmethod @@ -248,7 +256,7 @@ def compute( class PQtlColocClppMaximumNeighbourhoodFeature(L2GFeature): """Max CLPP for each (study, locus, gene) aggregating over all pQTLs.""" - feature_dependency_type = [Colocalisation, StudyIndex, StudyLocus] + feature_dependency_type = [Colocalisation, StudyIndex, GeneIndex, StudyLocus] feature_name = "pQtlColocClppMaximumNeighbourhood" @classmethod @@ -332,7 +340,7 @@ def compute( class SQtlColocClppMaximumNeighbourhoodFeature(L2GFeature): """Max CLPP for each (study, locus, gene) aggregating over all sQTLs.""" - feature_dependency_type = [Colocalisation, StudyIndex, StudyLocus] + feature_dependency_type = [Colocalisation, StudyIndex, GeneIndex, StudyLocus] feature_name = "sQtlColocClppMaximumNeighbourhood" @classmethod @@ -416,7 +424,7 @@ def compute( class EQtlColocH4MaximumNeighbourhoodFeature(L2GFeature): """Max H4 for each (study, locus) aggregating over all eQTLs.""" - feature_dependency_type = [Colocalisation, StudyIndex, StudyLocus] + feature_dependency_type = [Colocalisation, StudyIndex, GeneIndex, StudyLocus] feature_name = "eQtlColocH4MaximumNeighbourhood" @classmethod @@ -500,7 +508,7 @@ def compute( class PQtlColocH4MaximumNeighbourhoodFeature(L2GFeature): """Max H4 for each (study, locus) aggregating over all pQTLs.""" - feature_dependency_type = [Colocalisation, StudyIndex, StudyLocus] + feature_dependency_type = [Colocalisation, StudyIndex, GeneIndex, StudyLocus] feature_name = "pQtlColocH4MaximumNeighbourhood" @classmethod @@ -584,7 +592,7 @@ def compute( class SQtlColocH4MaximumNeighbourhoodFeature(L2GFeature): """Max H4 for each (study, locus) aggregating over all sQTLs.""" - feature_dependency_type = [Colocalisation, StudyIndex, StudyLocus] + feature_dependency_type = [Colocalisation, StudyIndex, GeneIndex, StudyLocus] feature_name = "sQtlColocH4MaximumNeighbourhood" @classmethod diff --git a/src/gentropy/dataset/l2g_features/vep.py b/src/gentropy/dataset/l2g_features/vep.py index 13ac05f91..557d9a509 100644 --- a/src/gentropy/dataset/l2g_features/vep.py +++ b/src/gentropy/dataset/l2g_features/vep.py @@ -5,7 +5,6 @@ from typing import TYPE_CHECKING, Any import pyspark.sql.functions as f -from pyspark.sql import Window from gentropy.common.spark_helpers import convert_from_wide_to_long from gentropy.dataset.gene_index import GeneIndex @@ -92,34 +91,29 @@ def common_neighbourhood_vep_feature_logic( DataFrame: Feature dataset """ local_feature_name = feature_name.replace("Neighbourhood", "") - # First compute mean distances to a gene local_metric = common_vep_feature_logic( study_loci_to_annotate, feature_name=local_feature_name, variant_index=variant_index, + ).join( + # Bring gene classification + gene_index.df.select("geneId", "biotype"), + "geneId", + "inner", + ) + # Compute average score in the vicinity (feature will be the same for any gene associated with a studyLocus) + # (non protein coding genes in the vicinity are excluded see #3552) + regional_mean_per_study_locus = ( + local_metric.filter(f.col("biotype") == "protein_coding") + .groupBy("studyLocusId") + .agg(f.mean(local_feature_name).alias("regional_mean")) ) return ( - # Then compute mean distance in the vicinity (feature will be the same for any gene associated with a studyLocus) - local_metric.join( - # Bring gene classification - gene_index.df.select("geneId", "biotype"), - "geneId", - "inner", - ) + local_metric.join(regional_mean_per_study_locus, "studyLocusId", "left") .withColumn( - "regional_metric", - f.coalesce( - # Calculate mean based on protein coding genes - f.mean( - f.when( - f.col("biotype") == "protein_coding", f.col(local_feature_name) - ) - ).over(Window.partitionBy("studyLocusId")), - # Default to 0 if there are no protein coding genes - f.lit(0), - ), + feature_name, + f.col(local_feature_name) - f.coalesce(f.col("regional_mean"), f.lit(0.0)), ) - .withColumn(feature_name, f.col(local_feature_name) - f.col("regional_metric")) .drop("regional_metric", local_feature_name, "biotype") ) diff --git a/tests/gentropy/dataset/test_l2g_feature.py b/tests/gentropy/dataset/test_l2g_feature.py index 6d3b1b3af..bd6fca97c 100644 --- a/tests/gentropy/dataset/test_l2g_feature.py +++ b/tests/gentropy/dataset/test_l2g_feature.py @@ -119,6 +119,29 @@ def test_feature_factory_return_type( assert isinstance(feature_dataset, L2GFeature) +@pytest.fixture(scope="module") +def sample_gene_index(spark: SparkSession) -> GeneIndex: + """Create a sample gene index for testing.""" + return GeneIndex( + _df=spark.createDataFrame( + [ + { + "geneId": "gene1", + "biotype": "protein_coding", + "chromosome": "1", + }, + { + "geneId": "gene2", + "biotype": "lncRNA", + "chromosome": "1", + }, + ], + GeneIndex.get_schema(), + ), + _schema=GeneIndex.get_schema(), + ) + + class TestCommonColocalisationFeatureLogic: """Test the common logic of the colocalisation features.""" @@ -161,7 +184,9 @@ def test__common_colocalisation_feature_logic( ), "The feature values are not as expected." def test__common_neighbourhood_colocalisation_feature_logic( - self: TestCommonColocalisationFeatureLogic, spark: SparkSession + self: TestCommonColocalisationFeatureLogic, + spark: SparkSession, + sample_gene_index: GeneIndex, ) -> None: """Test the common logic of the neighbourhood colocalisation features.""" feature_name = "eQtlColocH4MaximumNeighbourhood" @@ -174,18 +199,20 @@ def test__common_neighbourhood_colocalisation_feature_logic( colocalisation=self.sample_colocalisation, study_index=self.sample_studies, study_locus=self.sample_study_locus, - ) + gene_index=sample_gene_index, + ).withColumn(feature_name, f.round(f.col(feature_name), 2)) + # expected average is (0.81)/1 = 0.81 expected_df = spark.createDataFrame( [ { "studyLocusId": "1", "geneId": "gene1", - "eQtlColocH4MaximumNeighbourhood": 0.08999999999999997, + "eQtlColocH4MaximumNeighbourhood": 0.0, # 0.81 - 0.81 }, { "studyLocusId": "1", "geneId": "gene2", - "eQtlColocH4MaximumNeighbourhood": 0.0, + "eQtlColocH4MaximumNeighbourhood": 0.09, # 0.9 - 0.81 }, ], ).select("studyLocusId", "geneId", "eQtlColocH4MaximumNeighbourhood") @@ -213,6 +240,7 @@ def _setup(self: TestCommonColocalisationFeatureLogic, spark: SparkSession) -> N ), _schema=StudyLocus.get_schema(), ) + self.sample_colocalisation = Colocalisation( _df=spark.createDataFrame( [ @@ -378,7 +406,7 @@ def test_common_distance_feature_logic( observed_df.collect() == expected_df.collect() ), f"Expected and observed dataframes are not equal for feature {feature_name}." - def test_common_neighbourhood_colocalisation_feature_logic( + def test_common_neighbourhood_distance_feature_logic( self: TestCommonDistanceFeatureLogic, spark: SparkSession, ) -> None: @@ -564,30 +592,13 @@ def test_common_vep_feature_logic( def test_common_neighbourhood_vep_feature_logic_no_protein_coding( self: TestCommonVepFeatureLogic, spark: SparkSession, + sample_gene_index: GeneIndex, ) -> None: """Test the logic of the function that extracts the maximum severity score for a gene given the average of the maximum scores for all protein coding genes in the vicinity. Because the genes in the vicinity are all non coding, the neighbourhood features should equal the local ones. """ feature_name = "vepMaximumNeighbourhood" - sample_gene_index = GeneIndex( - _df=spark.createDataFrame( - [ - { - "geneId": "gene1", - "biotype": "lncRNA", - "chromosome": "1", - }, - { - "geneId": "gene2", - "biotype": "lncRNA", - "chromosome": "1", - }, - ], - GeneIndex.get_schema(), - ), - _schema=GeneIndex.get_schema(), - ) observed_df = ( common_neighbourhood_vep_feature_logic( self.sample_study_locus, @@ -601,7 +612,11 @@ def test_common_neighbourhood_vep_feature_logic_no_protein_coding( ) expected_df = ( spark.createDataFrame( - (["1", "gene1", 0.66], ["1", "gene2", 1.0]), + # regional mean is 0.66 + ( + ["1", "gene1", 0.0], + ["1", "gene2", 0.34], + ), # (0.66-0.66) and (1.0 -0.66) ["studyLocusId", "geneId", feature_name], ) .orderBy(feature_name) @@ -614,27 +629,10 @@ def test_common_neighbourhood_vep_feature_logic_no_protein_coding( def test_common_neighbourhood_vep_feature_logic( self: TestCommonVepFeatureLogic, spark: SparkSession, + sample_gene_index: GeneIndex, ) -> None: """Test the logic of the function that extracts the maximum severity score for a gene given the average of the maximum scores for all protein coding genes in the vicinity.""" feature_name = "vepMaximumNeighbourhood" - sample_gene_index = GeneIndex( - _df=spark.createDataFrame( - [ - { - "geneId": "gene1", - "biotype": "protein_coding", - "chromosome": "1", - }, - { - "geneId": "gene2", - "biotype": "lncRNA", - "chromosome": "1", - }, - ], - GeneIndex.get_schema(), - ), - _schema=GeneIndex.get_schema(), - ) observed_df = ( common_neighbourhood_vep_feature_logic( self.sample_study_locus, From 9c523972ad374e2ed990ace5fc197062099b8095 Mon Sep 17 00:00:00 2001 From: Yakov Date: Thu, 17 Oct 2024 15:02:45 +0100 Subject: [PATCH 113/188] fix: filter nan in CSs (#855) * fix: filter nan in CSs * fix: fix v1 --- src/gentropy/susie_finemapper.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/gentropy/susie_finemapper.py b/src/gentropy/susie_finemapper.py index 5ec347e6a..a5087e0d2 100644 --- a/src/gentropy/susie_finemapper.py +++ b/src/gentropy/susie_finemapper.py @@ -324,8 +324,8 @@ def susie_inf_to_studylocus( # noqa: C901 df = pd.DataFrame( { "credibleSetIndex": cred_set_index, - "purityMeanR2": purity_mean_r2, - "purityMinR2": purity_min_r2, + "purityMeanR2": list_purity_mean_r2, + "purityMinR2": list_purity_min_r2, "zScore": z_values, "neglogpval": neglogpval, } @@ -357,6 +357,7 @@ def susie_inf_to_studylocus( # noqa: C901 cred_sets = cred_sets.filter( (f.col("neglogpval") >= -np.log10(lead_pval_threshold)) & (f.col("credibleSetlog10BF") >= cs_lbf_thr * 0.4342944819) + & (~f.isnan(f.col("credibleSetlog10BF"))) & (f.col("purityMinR2") >= purity_min_r2_threshold) & (f.col("purityMeanR2") >= purity_mean_r2_threshold) ) From c68a1444a4e739d6e689f11e0aeb3976b97d641b Mon Sep 17 00:00:00 2001 From: Szymon Szyszkowski <69353402+project-defiant@users.noreply.github.com> Date: Thu, 17 Oct 2024 21:27:44 +0200 Subject: [PATCH 114/188] revert(finngen): restore the studyId prefix in finngen cs and si (#856) --- src/gentropy/config.py | 5 +- .../datasource/finngen/finemapping.py | 11 ++- .../datasource/finngen/study_index.py | 76 ++++++++++++++---- .../finngen_ukb_meta/study_index.py | 62 ++++++++------- src/gentropy/finngen_finemapping_ingestion.py | 8 +- src/gentropy/finngen_studies.py | 24 +++--- .../finngen/test_finngen_finemapping.py | 4 + .../finngen/test_finngen_study_index.py | 77 ++++++++++++++++--- 8 files changed, 194 insertions(+), 73 deletions(-) diff --git a/src/gentropy/config.py b/src/gentropy/config.py index ad941f5e0..39ed62f9e 100644 --- a/src/gentropy/config.py +++ b/src/gentropy/config.py @@ -169,13 +169,14 @@ class FinngenFinemappingConfig(StepConfig): "gs://finngen-public-data-r11/finemap/full/susie/*.snp.bgz" ) finngen_susie_finemapping_cs_summary_files: str = ( - "gs://finngen-public-data-r11/finemap/summary/*.cred.summary.tsv" + "gs://finngen-public-data-r11/finemap/summary/*SUSIE.cred.summary.tsv" ) finngen_finemapping_out: str = MISSING + finngen_finemapping_lead_pvalue_threshold: float = 1e-5 + finngen_release_prefix: str = "FINNGEN_R11" _target_: str = ( "gentropy.finngen_finemapping_ingestion.FinnGenFinemappingIngestionStep" ) - finngen_finemapping_lead_pvalue_threshold: float = 1e-5 @dataclass diff --git a/src/gentropy/datasource/finngen/finemapping.py b/src/gentropy/datasource/finngen/finemapping.py index 3c83ba8ff..5b8d21864 100644 --- a/src/gentropy/datasource/finngen/finemapping.py +++ b/src/gentropy/datasource/finngen/finemapping.py @@ -206,6 +206,7 @@ def from_finngen_susie_finemapping( spark: SparkSession, finngen_susie_finemapping_snp_files: (str | list[str]), finngen_susie_finemapping_cs_summary_files: (str | list[str]), + finngen_release_prefix: str, credset_lbf_threshold: float = 0.8685889638065036, ) -> StudyLocus: """Process the SuSIE finemapping output for FinnGen studies. @@ -261,6 +262,7 @@ def from_finngen_susie_finemapping( spark (SparkSession): SparkSession object. finngen_susie_finemapping_snp_files (str | list[str]): SuSIE finemapping output filename(s). finngen_susie_finemapping_cs_summary_files (str | list[str]): filename of SuSIE finemapping credible set summaries. + finngen_release_prefix (str): Finngen project release prefix. Should look like FINNGEN_R*. credset_lbf_threshold (float, optional): Filter out credible sets below, Default 0.8685889638065036 == np.log10(np.exp(2)), this is threshold from publication. Returns: @@ -295,7 +297,9 @@ def from_finngen_susie_finemapping( .filter(f.col("cs").cast(t.IntegerType()) > 0) .select( # Add study idenfitier. - f.col("trait").cast(t.StringType()).alias("studyId"), + f.concat_ws("_", f.lit(finngen_release_prefix), f.col("trait")) + .cast(t.StringType()) + .alias("studyId"), f.col("region"), # Add variant information. f.regexp_replace(f.col("v"), ":", "_").alias("variantId"), @@ -408,7 +412,10 @@ def from_finngen_susie_finemapping( (f.col("credibleSetlog10BF") > credset_lbf_threshold) | (f.col("credibleSetIndex") == 1) ) - .withColumn("studyId", f.col("trait")) + .withColumn( + "studyId", + f.concat_ws("_", f.lit(finngen_release_prefix), f.col("trait")), + ) ) processed_finngen_finemapping_df = processed_finngen_finemapping_df.join( diff --git a/src/gentropy/datasource/finngen/study_index.py b/src/gentropy/datasource/finngen/study_index.py index 3946323f4..dc0389aa1 100644 --- a/src/gentropy/datasource/finngen/study_index.py +++ b/src/gentropy/datasource/finngen/study_index.py @@ -3,6 +3,7 @@ from __future__ import annotations import re +from typing import TypedDict from urllib.request import urlopen import pyspark.sql.functions as f @@ -11,6 +12,13 @@ from gentropy.dataset.study_index import StudyIndex +class FinngenPrefixMatch(TypedDict): + """Class to store the output of the validate_release_prefix.""" + + prefix: str + release: str + + class FinnGenStudyIndex: """Study index dataset from FinnGen. @@ -25,11 +33,57 @@ class FinnGenStudyIndex: Some fields are also populated as constants, such as study type and the initial sample size. """ + @staticmethod + def validate_release_prefix(release_prefix: str) -> FinngenPrefixMatch: + """Validate release prefix passed to finngen StudyIndex. + + Args: + release_prefix (str): Finngen release prefix, should be a string like FINNGEN_R*. + + Returns: + FinngenPrefixMatch: Object containing valid prefix and release strings. + + Raises: + ValueError: when incorrect release prefix is provided. + + This method ensures that the trailing underscore is removed from prefix. + """ + pattern = re.compile(r"FINNGEN_(?PR\d+){1}_?") + pattern_match = pattern.match(release_prefix) + if not pattern_match: + raise ValueError( + f"Invalid FinnGen release prefix: {release_prefix}, use the format FINNGEN_R*" + ) + release = pattern_match.group("release").upper() + if release_prefix.endswith("_"): + release_prefix = release_prefix[:-1] + return FinngenPrefixMatch(prefix=release_prefix, release=release) + + @staticmethod + def read_efo_curation(session: SparkSession, url: str) -> DataFrame: + """Read efo curation from provided url. + + Args: + session (SparkSession): Session to use when reading the mapping file. + url (str): Url to the mapping file. The file provided should be a tsv file. + + Returns: + DataFrame: DataFrame with EFO mappings. + + Example of the file can be found in https://raw.githubusercontent.com/opentargets/curation/refs/heads/master/mappings/disease/manual_string.tsv. + """ + csv_data = urlopen(url).readlines() + csv_rows = [row.decode("utf8") for row in csv_data] + rdd = session.sparkContext.parallelize(csv_rows) + # NOTE: type annotations for spark.read.csv miss the fact that the first param can be [RDD[str]] + efo_curation_mapping_df = session.read.csv(rdd, header=True, sep="\t") + return efo_curation_mapping_df + @staticmethod def join_efo_mapping( study_index: StudyIndex, efo_curation_mapping: DataFrame, - finngen_release_prefix: str, + finngen_release: str, ) -> StudyIndex: """Add EFO mapping to the Finngen study index table. @@ -44,24 +98,11 @@ def join_efo_mapping( Args: study_index (StudyIndex): Study index table. efo_curation_mapping (DataFrame): Dataframe with EFO mappings. - finngen_release_prefix (str): FinnGen release prefix. + finngen_release (str): FinnGen release. Returns: StudyIndex: Study index table with added EFO mappings. - - Raises: - ValueError: when incorrect release prefix is provided. """ - finngen_release_prefix_regex = re.compile(r"FINNGEN_(?PR\d+){1}_?") - finngen_release_prefix_match = finngen_release_prefix_regex.match( - finngen_release_prefix - ) - if not finngen_release_prefix_match: - raise ValueError( - f"Invalid FinnGen release prefix: {finngen_release_prefix}, use the format FINNGEN_R*" - ) - finngen_release = finngen_release_prefix_match.group("release").upper() - efo_mappings = ( efo_curation_mapping.withColumn("STUDY", f.upper(f.col("STUDY"))) .filter(f.col("STUDY").contains("FINNGEN")) @@ -109,9 +150,12 @@ def from_source( json_data = urlopen(finngen_phenotype_table_url).read().decode("utf-8") rdd = spark.sparkContext.parallelize([json_data]) raw_df = spark.read.json(rdd) + return StudyIndex( _df=raw_df.select( - f.concat(f.col("phenocode")).alias("studyId"), + f.concat( + f.concat_ws("_", f.lit(finngen_release_prefix), f.col("phenocode")) + ).alias("studyId"), f.col("phenostring").alias("traitFromSource"), f.col("num_cases").cast("integer").alias("nCases"), f.col("num_controls").cast("integer").alias("nControls"), diff --git a/src/gentropy/datasource/finngen_ukb_meta/study_index.py b/src/gentropy/datasource/finngen_ukb_meta/study_index.py index fe6c74beb..eefb2da7c 100644 --- a/src/gentropy/datasource/finngen_ukb_meta/study_index.py +++ b/src/gentropy/datasource/finngen_ukb_meta/study_index.py @@ -1,4 +1,5 @@ """Study Index for Finngen data source.""" + from __future__ import annotations from urllib.request import urlopen @@ -32,35 +33,42 @@ def from_source( StudyIndex: Parsed and annotated FinnGen UKB meta-analysis study table. """ # Read the raw study index and process. - study_index_df = ( - spark.read.csv(raw_study_index_path_from_tsv, sep="\t", header=True) - .select( - f.lit("gwas").alias("studyType"), - f.lit("FINNGEN_R11_UKB_META").alias("projectId"), - f.col("_gentropy_study_id").alias("studyId"), - f.col("name").alias("traitFromSource"), - f.lit(True).alias("hasSumstats"), - f.col("_gentropy_summary_stats_link").alias("summarystatsLocation"), - (f.col("fg_n_cases") + f.col("ukbb_n_cases") + f.col("fg_n_controls") + f.col("ukbb_n_controls")).cast("integer").alias("nSamples"), - f.array( - f.struct( - (f.col("fg_n_cases") + f.col("fg_n_controls")).cast("integer").alias("sampleSize"), - f.lit("Finnish").alias("ancestry"), - ), - f.struct( - (f.col("ukbb_n_cases") + f.col("ukbb_n_controls")).cast("integer").alias("sampleSize"), - f.lit("European").alias("ancestry"), - ), - ).alias("discoverySamples"), + study_index_df = spark.read.csv( + raw_study_index_path_from_tsv, sep="\t", header=True + ).select( + f.lit("gwas").alias("studyType"), + f.lit("FINNGEN_R11_UKB_META").alias("projectId"), + f.col("_gentropy_study_id").alias("studyId"), + f.col("name").alias("traitFromSource"), + f.lit(True).alias("hasSumstats"), + f.col("_gentropy_summary_stats_link").alias("summarystatsLocation"), + ( + f.col("fg_n_cases") + + f.col("ukbb_n_cases") + + f.col("fg_n_controls") + + f.col("ukbb_n_controls") ) + .cast("integer") + .alias("nSamples"), + f.array( + f.struct( + (f.col("fg_n_cases") + f.col("fg_n_controls")) + .cast("integer") + .alias("sampleSize"), + f.lit("Finnish").alias("ancestry"), + ), + f.struct( + (f.col("ukbb_n_cases") + f.col("ukbb_n_controls")) + .cast("integer") + .alias("sampleSize"), + f.lit("European").alias("ancestry"), + ), + ).alias("discoverySamples"), ) # Add population structure. - study_index_df = ( - study_index_df - .withColumn( - "ldPopulationStructure", - cls.aggregate_and_map_ancestries(f.col("discoverySamples")), - ) + study_index_df = study_index_df.withColumn( + "ldPopulationStructure", + cls.aggregate_and_map_ancestries(f.col("discoverySamples")), ) # Create study index. study_index = StudyIndex( @@ -75,6 +83,6 @@ def from_source( study_index = FinnGenStudyIndex.join_efo_mapping( study_index, efo_curation_mapping, - finngen_release_prefix="FINNGEN_R11", + finngen_release="R11", ) return study_index diff --git a/src/gentropy/finngen_finemapping_ingestion.py b/src/gentropy/finngen_finemapping_ingestion.py index ca5ca1656..c093bdb3d 100644 --- a/src/gentropy/finngen_finemapping_ingestion.py +++ b/src/gentropy/finngen_finemapping_ingestion.py @@ -8,6 +8,7 @@ from gentropy.common.session import Session from gentropy.config import FinngenFinemappingConfig from gentropy.datasource.finngen.finemapping import FinnGenFinemapping +from gentropy.datasource.finngen.study_index import FinnGenStudyIndex @dataclass @@ -21,6 +22,7 @@ def __init__( finngen_susie_finemapping_snp_files: str = FinngenFinemappingConfig().finngen_susie_finemapping_snp_files, finngen_susie_finemapping_cs_summary_files: str = FinngenFinemappingConfig().finngen_susie_finemapping_cs_summary_files, finngen_finemapping_lead_pvalue_threshold: float = FinngenFinemappingConfig().finngen_finemapping_lead_pvalue_threshold, + finngen_release_prefix: str = FinngenFinemappingConfig().finngen_release_prefix, ) -> None: """Run FinnGen finemapping ingestion step. @@ -30,14 +32,18 @@ def __init__( finngen_susie_finemapping_snp_files(str): Path to the FinnGen SuSIE finemapping results. finngen_susie_finemapping_cs_summary_files (str): FinnGen SuSIE summaries for CS filters(LBF>2). finngen_finemapping_lead_pvalue_threshold (float): Lead p-value threshold. + finngen_release_prefix (str): Finngen project release prefix. Should look like FINNGEN_R*. """ # Read finemapping outputs from the input paths. - + finngen_release_prefix = FinnGenStudyIndex.validate_release_prefix( + finngen_release_prefix + )["prefix"] ( FinnGenFinemapping.from_finngen_susie_finemapping( spark=session.spark, finngen_susie_finemapping_snp_files=finngen_susie_finemapping_snp_files, finngen_susie_finemapping_cs_summary_files=finngen_susie_finemapping_cs_summary_files, + finngen_release_prefix=finngen_release_prefix, ) # Flagging sub-significnat loci: .validate_lead_pvalue( diff --git a/src/gentropy/finngen_studies.py b/src/gentropy/finngen_studies.py index 80866ac99..d7fd558ef 100644 --- a/src/gentropy/finngen_studies.py +++ b/src/gentropy/finngen_studies.py @@ -2,8 +2,6 @@ from __future__ import annotations -from urllib.request import urlopen - from gentropy.common.session import Session from gentropy.config import FinngenStudiesConfig from gentropy.datasource.finngen.study_index import FinnGenStudyIndex @@ -35,26 +33,26 @@ def __init__( efo_curation_mapping_url (str): URL to the EFO curation mapping file sample_size (int): Number of individuals that participated in sample collection, derived from finngen release metadata. """ + _match = FinnGenStudyIndex.validate_release_prefix(finngen_release_prefix) + release_prefix = _match["prefix"] + release = _match["release"] + + efo_curation_df = FinnGenStudyIndex.read_efo_curation( + session.spark, + efo_curation_mapping_url, + ) study_index = FinnGenStudyIndex.from_source( session.spark, finngen_phenotype_table_url, - finngen_release_prefix, + release_prefix, finngen_summary_stats_url_prefix, finngen_summary_stats_url_suffix, sample_size, ) - - # NOTE: hack to allow spark to read directly from the URL. - csv_data = urlopen(efo_curation_mapping_url).readlines() - csv_rows = [row.decode("utf8") for row in csv_data] - rdd = session.spark.sparkContext.parallelize(csv_rows) - # NOTE: type annotations for spark.read.csv miss the fact that the first param can be [RDD[str]] - efo_curation_mapping = session.spark.read.csv(rdd, header=True, sep="\t") - study_index_with_efo = FinnGenStudyIndex.join_efo_mapping( study_index, - efo_curation_mapping, - finngen_release_prefix, + efo_curation_df, + release, ) study_index_with_efo.df.write.mode(session.write_mode).parquet( finngen_study_index_out diff --git a/tests/gentropy/datasource/finngen/test_finngen_finemapping.py b/tests/gentropy/datasource/finngen/test_finngen_finemapping.py index 1e5d486b7..4c7e12bf5 100644 --- a/tests/gentropy/datasource/finngen/test_finngen_finemapping.py +++ b/tests/gentropy/datasource/finngen/test_finngen_finemapping.py @@ -44,6 +44,7 @@ def test_finngen_finemapping_from_finngen_susie_finemapping( spark=spark, finngen_susie_finemapping_snp_files=finngen_susie_finemapping_snp_files, finngen_susie_finemapping_cs_summary_files=finngen_susie_finemapping_cs_summary_files, + finngen_release_prefix="FINNGEN_R11", ), StudyLocus, ) @@ -77,9 +78,12 @@ def test_finngen_finemapping_ingestion_step( finngen_susie_finemapping_cs_summary_files=finngen_susie_finemapping_cs_summary_files, finngen_susie_finemapping_snp_files=finngen_susie_finemapping_snp_files, finngen_finemapping_lead_pvalue_threshold=1e-5, + finngen_release_prefix="FINNGEN_R11", ) assert output_path.is_dir() assert (output_path / "_SUCCESS").exists() cs = StudyLocus.from_parquet(session=session, path=str(output_path)) assert cs.df.count() == 1 + study_id: str = cs.df.select("studyId").collect()[0]["studyId"] + assert study_id.startswith("FINNGEN_R11_") diff --git a/tests/gentropy/datasource/finngen/test_finngen_study_index.py b/tests/gentropy/datasource/finngen/test_finngen_study_index.py index 07d014d13..0d0537413 100644 --- a/tests/gentropy/datasource/finngen/test_finngen_study_index.py +++ b/tests/gentropy/datasource/finngen/test_finngen_study_index.py @@ -7,17 +7,21 @@ from unittest.mock import MagicMock import pytest +from pyspark.sql import DataFrame from pyspark.sql import types as T from gentropy.dataset.study_index import StudyIndex -from gentropy.datasource.finngen.study_index import FinnGenStudyIndex +from gentropy.datasource.finngen.study_index import ( + FinngenPrefixMatch, + FinnGenStudyIndex, +) from gentropy.finngen_studies import FinnGenStudiesStep if TYPE_CHECKING: from pathlib import Path from typing import Callable - from pyspark.sql import DataFrame, SparkSession + from pyspark.sql import SparkSession from gentropy.common.session import Session @@ -28,21 +32,21 @@ def finngen_study_index_mock(spark: SparkSession) -> StudyIndex: data = [ # NOTE: Study maps to a single EFO trait ( - "STUDY_1", + "FINNGEN_R11_STUDY_1", "Actinomycosis", "FINNGEN_R11", "gwas", ), # NOTE: Study does not map to EFO traits ( - "STUDY_2", + "FINNGEN_R11_STUDY_2", "Some other trait", "FINNGEN_R11", "gwas", ), # NOTE: Study maps to two EFO traits ( - "STUDY_3", + "FINNGEN_R11_STUDY_3", "Glucose", "FINNGEN_R11", "gwas", @@ -197,7 +201,7 @@ def mock_response(url: str) -> MagicMock: case "https://finngen_phenotypes": value = finngen_phenotype_table_mock case "https://efo_mappings": - value = "\n".join(["\t".join(row) + "\n" for row in efo_mappings_mock]) + value = "\n".join(["\t".join(row) for row in efo_mappings_mock]) case _: value = "" mock_open = MagicMock() @@ -235,7 +239,6 @@ def test_finngen_study_index_step( """ with monkeypatch.context() as m: m.setattr("gentropy.datasource.finngen.study_index.urlopen", urlopen_mock) - m.setattr("gentropy.finngen_studies.urlopen", urlopen_mock) output_path = str(tmp_path / "study_index") FinnGenStudiesStep( session=session, @@ -254,6 +257,20 @@ def test_finngen_study_index_step( # fmt: on +def test_finngen_study_index_read_efo_curation( + monkeypatch: pytest.MonkeyPatch, + spark: SparkSession, + urlopen_mock: Callable[[str], MagicMock], +) -> None: + """Test reading efo curation.""" + with monkeypatch.context() as m: + m.setattr("gentropy.datasource.finngen.study_index.urlopen", urlopen_mock) + efo_df = FinnGenStudyIndex.read_efo_curation(spark, "https://efo_mappings") + assert isinstance(efo_df, DataFrame) + efo_df.show() + assert efo_df.count() == 5 + + def test_finngen_study_index_from_source( monkeypatch: pytest.MonkeyPatch, spark: SparkSession, @@ -280,7 +297,7 @@ def test_finngen_study_index_from_source( assert study_index.df.count() == 3, "Expect two rows at the study_index, as in the input." rows = study_index.df.collect() - expected_study_ids = ["AB1_ACTINOMYCOSIS", "GLUCOSE", "SOME_OTHER_TRAIT"] + expected_study_ids = ["FINNGEN_R11_AB1_ACTINOMYCOSIS", "FINNGEN_R11_GLUCOSE", "FINNGEN_R11_SOME_OTHER_TRAIT"] assert "studyId" in study_index.df.columns, "Expect that studyId column exists." assert sorted([v["studyId"] for v in rows]) == expected_study_ids, "Expect that studyIds are populated from input." @@ -309,6 +326,42 @@ def test_finngen_study_index_from_source( # fmt: on +@pytest.mark.parametrize( + ["prefix", "expected_output", "xfail"], + [ + pytest.param( + "FINNGEN_R11", + FinngenPrefixMatch(prefix="FINNGEN_R11", release="R11"), + False, + id="Correct prefix passed.", + ), + pytest.param( + "FINNGEN_R11_", + FinngenPrefixMatch(prefix="FINNGEN_R11", release="R11"), + False, + id="Underscore is removed from the prefix.", + ), + pytest.param( + "R11", + FinngenPrefixMatch(prefix="FINNGEN_R11", release="R11"), + True, + id="Incorrect prefix raises ValueError.", + ), + ], +) +def test_finngen_validate_release_prefix( + prefix: str, expected_output: FinngenPrefixMatch, xfail: bool +) -> None: + """Test validate_release_prefix.""" + if not xfail: + assert ( + FinnGenStudyIndex.validate_release_prefix(prefix) == expected_output + ), "Incorrect match object" + else: + with pytest.raises(ValueError): + FinnGenStudyIndex.validate_release_prefix(prefix) + + def test_finngen_study_index_add_efos( finngen_study_index_mock: StudyIndex, efo_mappings_df_mock: DataFrame, @@ -319,7 +372,7 @@ def test_finngen_study_index_add_efos( assert efo_column_name not in finngen_study_index_mock.df.columns study_index = FinnGenStudyIndex.join_efo_mapping( finngen_study_index_mock, - finngen_release_prefix="FINNGEN_R11_", + finngen_release="R11", efo_curation_mapping=efo_mappings_df_mock, ) # fmt: off @@ -332,8 +385,8 @@ def test_finngen_study_index_add_efos( for row in study_index.df.select(efo_column_name, "studyId").collect() } expected_efos = { - "STUDY_1": ["EFO_0007128"], - "STUDY_2": [], - "STUDY_3": ["EFO_0002571", "EFO_0004468"], + "FINNGEN_R11_STUDY_1": ["EFO_0007128"], + "FINNGEN_R11_STUDY_2": [], + "FINNGEN_R11_STUDY_3": ["EFO_0002571", "EFO_0004468"], } assert expected_efos == efos, "Expect that EFOs are correctly assigned." From d650a293c2f7fac02dda381ec5ea501e9b56e948 Mon Sep 17 00:00:00 2001 From: Szymon Szyszkowski <69353402+project-defiant@users.noreply.github.com> Date: Fri, 18 Oct 2024 10:53:58 +0200 Subject: [PATCH 115/188] feat(susie_finemapper): allow for extraction of the log file from manifest (#859) * feat(susie_finemapper): allow for extraction of the log file from manifest * fix: add missing extension to the log file * fix: row istead of column --------- Co-authored-by: Szymon Szyszkowski --- src/gentropy/susie_finemapper.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/gentropy/susie_finemapper.py b/src/gentropy/susie_finemapper.py index a5087e0d2..c58f968cb 100644 --- a/src/gentropy/susie_finemapper.py +++ b/src/gentropy/susie_finemapper.py @@ -63,6 +63,12 @@ def __init__( ) -> None: """Run fine-mapping on a studyLocusId from a collected studyLocus table. + Method require a `study_locus_manifest_path` file that will contain ["study_locus_input", "study_locus_output", "log_file"]. `log_file` + is optional parameter to the manifest. In case it does not exist, the logs from the finemapper are saved under the same directory + as the `study_locus_output` with `.log` suffix. + Each execution of the method will only evaluate a single row from the `study_locus_manifest` that is inferred from the `study_locus_index` + variable. + Args: session (Session): Spark session study_index_path (str): path to the study index @@ -70,8 +76,8 @@ def __init__( study_locus_index (int): Index (0-based) of the locus in the manifest to process in this call max_causal_snps (int): Maximum number of causal variants in locus, default is 10 lead_pval_threshold (float): p-value threshold for the lead variant from CS, default is 1e-5 - purity_mean_r2_threshold (float): thrshold for purity mean r2 qc metrics for filtering credible sets, default is 0 - purity_min_r2_threshold (float): thrshold for purity min r2 qc metrics for filtering credible sets, default is 0.25 + purity_mean_r2_threshold (float): threshold for purity mean r2 qc metrics for filtering credible sets, default is 0 + purity_min_r2_threshold (float): threshold for purity min r2 qc metrics for filtering credible sets, default is 0.25 cs_lbf_thr (float): credible set logBF threshold for filtering credible sets, default is 2 sum_pips (float): the expected sum of posterior probabilities in the locus, default is 0.99 (99% credible set) susie_est_tausq (bool): estimate tau squared, default is False @@ -88,6 +94,9 @@ def __init__( row = study_locus_manifest.loc[study_locus_index] study_locus_input = row["study_locus_input"] study_locus_output = row["study_locus_output"] + log_output = study_locus_output + ".log" + if "log_output" in study_locus_manifest.columns: + log_output = row["log_output"] + ".log" # Read studyLocus study_locus = ( @@ -140,7 +149,7 @@ def __init__( if result_logging["log"] is not None: # Write log result_logging["log"].to_parquet( - study_locus_output + ".log", + log_output, engine="pyarrow", index=False, ) From 333facb6d0d81e82ec4e42d6c450968be9697020 Mon Sep 17 00:00:00 2001 From: Daniel Suveges Date: Fri, 18 Oct 2024 11:30:57 +0100 Subject: [PATCH 116/188] chore(coloc): changing the content of `numberColocalisingVariants` field (#857) * chore(coloc): chaning the content of numberColocalisingVariants * chore: pre-commit auto fixes [...] * fix: adjuting for schema and tests * fix(pics): ensuring locus has variantId * fix: pics udf test * fix: udf keys --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- src/gentropy/method/colocalisation.py | 86 +++++++++++++++++-- src/gentropy/method/pics.py | 4 + .../method/test_colocalisation_method.py | 8 ++ tests/gentropy/method/test_pics.py | 4 +- 4 files changed, 91 insertions(+), 11 deletions(-) diff --git a/src/gentropy/method/colocalisation.py b/src/gentropy/method/colocalisation.py index 37ca7b0d7..2867e700c 100644 --- a/src/gentropy/method/colocalisation.py +++ b/src/gentropy/method/colocalisation.py @@ -7,6 +7,7 @@ import numpy as np import pyspark.ml.functions as fml import pyspark.sql.functions as f +import pyspark.sql.types as t from pyspark.ml.linalg import DenseVector, Vectors, VectorUDT from pyspark.sql.types import DoubleType @@ -22,6 +23,53 @@ from gentropy.dataset.study_locus_overlap import StudyLocusOverlap +def get_tag_variant_source(statistics: Column) -> Column: + """Get the source of the tag variant for a locus-overlap row. + + Args: + statistics (Column): statistics column + + Returns: + Column: source of the tag variant + + Examples: + >>> data = [('a', 'b'),(None, 'b'),('a', None),] + >>> ( + ... spark.createDataFrame(data, ['a', 'b']) + ... .select( + ... 'a', 'b', + ... get_tag_variant_source( + ... f.struct( + ... f.col('a').alias('left_posteriorProbability'), + ... f.col('b').alias('right_posteriorProbability'), + ... ) + ... ).alias('source') + ... ) + ... .show() + ... ) + +----+----+------+ + | a| b|source| + +----+----+------+ + | a| b| both| + |null| b| right| + | a|null| left| + +----+----+------+ + + """ + return ( + # Both posterior probabilities are not null: + f.when( + statistics.left_posteriorProbability.isNotNull() + & statistics.right_posteriorProbability.isNotNull(), + f.lit("both"), + ) + # Only the left posterior probability is not null: + .when(statistics.left_posteriorProbability.isNotNull(), f.lit("left")) + # It must be right only: + .otherwise(f.lit("right")) + ) + + class ColocalisationMethodInterface(Protocol): """Colocalisation method interface.""" @@ -103,12 +151,14 @@ def colocalise( """ return Colocalisation( _df=( - overlapping_signals.df.withColumn( - "clpp", - ECaviar._get_clpp( - f.col("statistics.left_posteriorProbability"), - f.col("statistics.right_posteriorProbability"), - ), + overlapping_signals.df.withColumns( + { + "clpp": ECaviar._get_clpp( + f.col("statistics.left_posteriorProbability"), + f.col("statistics.right_posteriorProbability"), + ), + "tagVariantSource": get_tag_variant_source(f.col("statistics")), + } ) .groupBy( "leftStudyLocusId", @@ -117,7 +167,15 @@ def colocalise( "chromosome", ) .agg( - f.count("*").alias("numberColocalisingVariants"), + # Count the number of tag variants that can be found in both loci: + f.size( + f.filter( + f.collect_list(f.col("tagVariantSource")), + lambda x: x == "both", + ) + ) + .cast(t.LongType()) + .alias("numberColocalisingVariants"), f.sum(f.col("clpp")).alias("clpp"), ) .withColumn("colocalisationMethod", f.lit(cls.METHOD_NAME)) @@ -209,7 +267,10 @@ def colocalise( posteriors = f.udf(Coloc._get_posteriors, VectorUDT()) return Colocalisation( _df=( - overlapping_signals.df.select("*", "statistics.*") + overlapping_signals.df.withColumn( + "tagVariantSource", get_tag_variant_source(f.col("statistics")) + ) + .select("*", "statistics.*") # Before summing log_BF columns nulls need to be filled with 0: .fillna(0, subset=["left_logBF", "right_logBF"]) # Sum of log_BFs for each pair of signals @@ -225,7 +286,14 @@ def colocalise( "rightStudyType", ) .agg( - f.count("*").alias("numberColocalisingVariants"), + f.size( + f.filter( + f.collect_list(f.col("tagVariantSource")), + lambda x: x == "both", + ) + ) + .cast(t.LongType()) + .alias("numberColocalisingVariants"), fml.array_to_vector(f.collect_list(f.col("left_logBF"))).alias( "left_logBF" ), diff --git a/src/gentropy/method/pics.py b/src/gentropy/method/pics.py index b1dc46e12..918850527 100644 --- a/src/gentropy/method/pics.py +++ b/src/gentropy/method/pics.py @@ -160,6 +160,10 @@ def _finemap( # If PICS cannot be calculated, we drop the variant from the credible set continue + # Chaing chema: + if "tagVariantId" in tag_dict: + tag_dict["variantId"] = tag_dict.pop("tagVariantId") + pics_snp_mu = PICS._pics_mu(lead_neglog_p, tag_dict["r2Overall"]) pics_snp_std = PICS._pics_standard_deviation( lead_neglog_p, tag_dict["r2Overall"], k diff --git a/tests/gentropy/method/test_colocalisation_method.py b/tests/gentropy/method/test_colocalisation_method.py index c9a99d16f..d44652fbb 100644 --- a/tests/gentropy/method/test_colocalisation_method.py +++ b/tests/gentropy/method/test_colocalisation_method.py @@ -134,6 +134,8 @@ def test_coloc_no_logbf( "statistics": { "left_logBF": None, "right_logBF": None, + "left_posteriorProbability": None, + "right_posteriorProbability": None, }, # irrelevant for COLOC } ], @@ -150,6 +152,12 @@ def test_coloc_no_logbf( [ StructField("left_logBF", DoubleType(), True), StructField("right_logBF", DoubleType(), True), + StructField( + "left_posteriorProbability", DoubleType(), True + ), + StructField( + "right_posteriorProbability", DoubleType(), True + ), ] ), ), diff --git a/tests/gentropy/method/test_pics.py b/tests/gentropy/method/test_pics.py index 3639b408f..d5a8eb5d0 100644 --- a/tests/gentropy/method/test_pics.py +++ b/tests/gentropy/method/test_pics.py @@ -57,8 +57,8 @@ def test_finemap_quality_control( def test__finemap_udf() -> None: """Test the _finemap UDF with a simple case.""" ld_set = [ - Row(variantId="var1", r2Overall=0.8), - Row(variantId="var2", r2Overall=1), + Row(tagVariantId="var1", r2Overall=0.8), + Row(tagVariantId="var2", r2Overall=1), ] result = PICS._finemap(ld_set, lead_neglog_p=10.0, k=6.4) expected = [ From f93a9d353c7596cda7b209349e1d2a325f328c90 Mon Sep 17 00:00:00 2001 From: David Ochoa Date: Fri, 18 Oct 2024 16:24:59 +0100 Subject: [PATCH 117/188] fix: susie credible sets with unknown confidence (#862) --- src/gentropy/dataset/study_locus.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gentropy/dataset/study_locus.py b/src/gentropy/dataset/study_locus.py index b6fc7b8c9..eaec9672b 100644 --- a/src/gentropy/dataset/study_locus.py +++ b/src/gentropy/dataset/study_locus.py @@ -1175,7 +1175,7 @@ def assign_confidence(self: StudyLocus) -> StudyLocus: df = self.df.withColumn( "confidence", f.when( - (f.col("finemappingMethod") == "SuSiE-inf") + (f.col("finemappingMethod").isin(["SuSiE-inf", "SuSie"])) & ( ~f.array_contains( f.col("qualityControls"), @@ -1185,7 +1185,7 @@ def assign_confidence(self: StudyLocus) -> StudyLocus: CredibleSetConfidenceClasses.FINEMAPPED_IN_SAMPLE_LD.value, ) .when( - (f.col("finemappingMethod") == "SuSiE-inf") + (f.col("finemappingMethod").isin(["SuSiE-inf", "SuSie"])) & ( f.array_contains( f.col("qualityControls"), From 40a582c66ff3d02cc3c691b82cbaf07aa55afe14 Mon Sep 17 00:00:00 2001 From: Yakov Date: Mon, 21 Oct 2024 09:40:50 +0100 Subject: [PATCH 118/188] fix: adding beta for lead variant (#863) * fix: adding beta for lead variant * fix: v1 --- src/gentropy/susie_finemapper.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/gentropy/susie_finemapper.py b/src/gentropy/susie_finemapper.py index c58f968cb..d0759f565 100644 --- a/src/gentropy/susie_finemapper.py +++ b/src/gentropy/susie_finemapper.py @@ -415,6 +415,13 @@ def susie_inf_to_studylocus( # noqa: C901 cred_sets = cred_sets.withColumn("locusStart", f.lit(locusStart)) cred_sets = cred_sets.withColumn("locusEnd", f.lit(locusEnd)) + cred_sets = cred_sets.drop("beta").withColumn( + "beta", + f.expr(""" + filter(locus, x -> x.variantId = variantId)[0].beta + """), + ) + return StudyLocus( _df=cred_sets, _schema=StudyLocus.get_schema(), @@ -716,6 +723,8 @@ def susie_finemapper_one_sl_row_gathered_boundaries( # noqa: C901 if N_total is None: N_total = 100_000 + locusStart = max(locusStart, 0) + region = chromosome + ":" + str(int(locusStart)) + "-" + str(int(locusEnd)) schema = StudyLocus.get_schema() @@ -860,6 +869,14 @@ def susie_finemapper_one_sl_row_gathered_boundaries( # noqa: C901 ) np.fill_diagonal(gnomad_ld, 1) + # Desision tree - number of variants + if gwas_index.count() < 100: + logging.warning("Less than 100 variants after joining GWAS and LD index") + return None + elif gwas_index.count() >= 15_000: + logging.warning("More than 15000 variants after joining GWAS and LD index") + return None + out = SusieFineMapperStep.susie_finemapper_from_prepared_dataframes( GWAS_df=gwas_df, ld_index=gwas_index, From 13c2040bf5b3368225178c7405f448ced194682e Mon Sep 17 00:00:00 2001 From: Tobi Alegbe Date: Mon, 21 Oct 2024 14:33:53 +0200 Subject: [PATCH 119/188] fix: biosample index add efo cell types (#853) * feat(biosample_index_add_efo): update regex to allow removal of multiple biosample id url prefixes * feat(biosample_index_add_efo): add a dummy dataset for efo biosample id, created by copy-pasting nodes and edges from full json * feat(biosample_index_add_efo): add efo (cell info) to biosample index * feat(biosample_index_add_efo): add biosample index efo tests * chore: pre-commit auto fixes [...] * chore: remove redundant tests --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Daniel Suveges --- src/gentropy/biosample_index.py | 5 +- src/gentropy/config.py | 1 + src/gentropy/dataset/biosample_index.py | 22 + .../datasource/biosample_ontologies/utils.py | 18 +- .../data_samples/efo_biosample_sample.json | 1424 +++++++++++++++++ .../test_biosample_ontology.py | 22 +- 6 files changed, 1479 insertions(+), 13 deletions(-) create mode 100644 tests/gentropy/data_samples/efo_biosample_sample.json diff --git a/src/gentropy/biosample_index.py b/src/gentropy/biosample_index.py index e85c2e135..e0b5e9b10 100644 --- a/src/gentropy/biosample_index.py +++ b/src/gentropy/biosample_index.py @@ -16,6 +16,7 @@ def __init__( session: Session, cell_ontology_input_path: str, uberon_input_path: str, + efo_input_path: str, biosample_index_path: str, ) -> None: """Run Biosample index generation step. @@ -24,11 +25,13 @@ def __init__( session (Session): Session object. cell_ontology_input_path (str): Input cell ontology dataset path. uberon_input_path (str): Input uberon dataset path. + efo_input_path (str): Input efo dataset path. biosample_index_path (str): Output gene index dataset path. """ cell_ontology_index = extract_ontology_from_json(cell_ontology_input_path, session.spark) uberon_index = extract_ontology_from_json(uberon_input_path, session.spark) + efo_index = extract_ontology_from_json(efo_input_path, session.spark).retain_rows_with_ancestor_id(["CL_0000000"]) - biosample_index = cell_ontology_index.merge_indices([uberon_index]) + biosample_index = cell_ontology_index.merge_indices([uberon_index, efo_index]) biosample_index.df.write.mode(session.write_mode).parquet(biosample_index_path) diff --git a/src/gentropy/config.py b/src/gentropy/config.py index 39ed62f9e..26c676e9b 100644 --- a/src/gentropy/config.py +++ b/src/gentropy/config.py @@ -57,6 +57,7 @@ class BiosampleIndexConfig(StepConfig): cell_ontology_input_path: str = MISSING uberon_input_path: str = MISSING + efo_input_path: str = MISSING biosample_index_path: str = MISSING _target_: str = "gentropy.biosample_index.BiosampleIndexStep" diff --git a/src/gentropy/dataset/biosample_index.py b/src/gentropy/dataset/biosample_index.py index 39c597142..bae3c0a4f 100644 --- a/src/gentropy/dataset/biosample_index.py +++ b/src/gentropy/dataset/biosample_index.py @@ -70,3 +70,25 @@ def merge_indices( _df=aggregated_df, _schema=BiosampleIndex.get_schema() ) + + def retain_rows_with_ancestor_id( + self: BiosampleIndex, + ancestor_ids : list[str] + ) -> BiosampleIndex: + """Filter the biosample index to retain only rows with the given ancestor IDs. + + Args: + ancestor_ids (list[str]): Ancestor IDs to filter on. + + Returns: + BiosampleIndex: Filtered biosample index. + """ + # Create a Spark array of ancestor IDs prior to filtering + ancestor_ids_array = f.array(*[f.lit(id) for id in ancestor_ids]) + + return BiosampleIndex( + _df=self.df.filter( + f.size(f.array_intersect(f.col("ancestors"), ancestor_ids_array)) > 0 + ), + _schema=BiosampleIndex.get_schema() + ) diff --git a/src/gentropy/datasource/biosample_ontologies/utils.py b/src/gentropy/datasource/biosample_ontologies/utils.py index 3ef1747ee..2d9bb6bc4 100644 --- a/src/gentropy/datasource/biosample_ontologies/utils.py +++ b/src/gentropy/datasource/biosample_ontologies/utils.py @@ -1,4 +1,6 @@ """Utility functions for Biosample ontology processing.""" +import re + from pyspark.sql import DataFrame, SparkSession from pyspark.sql import functions as f from pyspark.sql.types import ArrayType, StringType @@ -92,12 +94,22 @@ def get_relationships( f.col("edge.pred").alias("predicate"), f.col("edge.obj").alias("object") ) - df_edges = df_edges.withColumn("subject", f.regexp_replace(f.col("subject"), "http://purl.obolibrary.org/obo/", "")) - df_edges = df_edges.withColumn("object", f.regexp_replace(f.col("object"), "http://purl.obolibrary.org/obo/", "")) + + # Remove certain URL prefixes from IDs + urls_to_remove = [ + "http://purl.obolibrary.org/obo/", + "http://www.ebi.ac.uk/efo/" + ] + # Create a regex pattern that matches any of the URLs + escaped_urls_pattern = "|".join([re.escape(url) for url in urls_to_remove]) + + + df_edges = df_edges.withColumn("subject", f.regexp_replace(f.col("subject"), escaped_urls_pattern, "")) + df_edges = df_edges.withColumn("object", f.regexp_replace(f.col("object"), escaped_urls_pattern, "")) # Extract the relevant information from the nodes transformed_df = df_nodes.select( - f.regexp_replace(f.col("node.id"), "http://purl.obolibrary.org/obo/", "").alias("biosampleId"), + f.regexp_replace(f.col("node.id"), escaped_urls_pattern, "").alias("biosampleId"), f.coalesce(f.col("node.lbl"), f.col("node.id")).alias("biosampleName"), f.col("node.meta.definition.val").alias("description"), f.collect_set(f.col("node.meta.xrefs.val")).over(Window.partitionBy("node.id")).getItem(0).alias("xrefs"), diff --git a/tests/gentropy/data_samples/efo_biosample_sample.json b/tests/gentropy/data_samples/efo_biosample_sample.json new file mode 100644 index 000000000..ebe979721 --- /dev/null +++ b/tests/gentropy/data_samples/efo_biosample_sample.json @@ -0,0 +1,1424 @@ +{ + "graphs": [ + { + "id": "http://www.ebi.ac.uk/efo/efo.owl", + "meta": { + "basicPropertyValues": [ + { + "pred": "http://purl.obolibrary.org/obo/format-version", + "val": "1.4" + }, + { + "pred": "http://purl.org/dc/elements/1.1/creator", + "val": "Catherine Leroy" + }, + { + "pred": "http://purl.org/dc/elements/1.1/creator", + "val": "Dani Welter" + }, + { + "pred": "http://purl.org/dc/elements/1.1/creator", + "val": "Drashtti Vasant" + }, + { + "pred": "http://purl.org/dc/elements/1.1/creator", + "val": "Ele Holloway" + }, + { + "pred": "http://purl.org/dc/elements/1.1/creator", + "val": "Eleanor Williams" + }, + { + "pred": "http://purl.org/dc/elements/1.1/creator", + "val": "Emma Kate Hastings" + }, + { + "pred": "http://purl.org/dc/elements/1.1/creator", + "val": "Gautier Koscielny" + }, + { + "pred": "http://purl.org/dc/elements/1.1/creator", + "val": "Helen Parkinson" + }, + { + "pred": "http://purl.org/dc/elements/1.1/creator", + "val": "James Malone" + }, + { + "pred": "http://purl.org/dc/elements/1.1/creator", + "val": "Jon Ison" + }, + { + "pred": "http://purl.org/dc/elements/1.1/creator", + "val": "Laura Huerta Martinez" + }, + { + "pred": "http://purl.org/dc/elements/1.1/creator", + "val": "Natalja Kurbatova" + }, + { + "pred": "http://purl.org/dc/elements/1.1/creator", + "val": "Olamidipupo Ajigboye" + }, + { + "pred": "http://purl.org/dc/elements/1.1/creator", + "val": "Paola Roncaglia" + }, + { + "pred": "http://purl.org/dc/elements/1.1/creator", + "val": "Simon Jupp" + }, + { + "pred": "http://purl.org/dc/elements/1.1/creator", + "val": "Sirarat Sarntivijai" + }, + { + "pred": "http://purl.org/dc/elements/1.1/creator", + "val": "Tomasz Adamusiak" + }, + { + "pred": "http://purl.org/dc/elements/1.1/creator", + "val": "Trish Whetzel" + }, + { + "pred": "http://purl.org/dc/elements/1.1/creator", + "val": "Zoe May Pendlington" + }, + { + "pred": "http://purl.org/dc/elements/1.1/rights", + "val": "Copyright [2014] EMBL - European Bioinformatics Institute\nLicensed under the Apache License, Version 2.0 (the \"License\"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the\nLicense. " + }, + { + "pred": "http://purl.org/dc/terms/license", + "val": "www.apache.org/licenses/LICENSE-2.0" + }, + { + "pred": "http://www.w3.org/2000/01/rdf-schema#comment", + "val": "2024-10-15" + }, + { + "pred": "http://www.w3.org/2002/07/owl#versionInfo", + "val": "3.71.0" + } + ], + "version": "http://www.ebi.ac.uk/efo/releases/v3.71.0/efo.owl" + }, + "nodes": [ + { + "id": "http://dbpedia.org/resource/China", + "lbl": "China", + "type": "CLASS", + "meta": { + "xrefs": [ + { + "val": "GAZ:00002845" + } + ] + } + }, + { + "id": "http://dbpedia.org/resource/India", + "lbl": "India", + "type": "CLASS", + "meta": { + "xrefs": [ + { + "val": "GAZ:00002839" + } + ] + } + }, + { + "id": "http://dbpedia.org/resource/Iran", + "lbl": "Iran", + "type": "CLASS", + "meta": { + "synonyms": [ + { + "pred": "hasExactSynonym", + "val": "Iran (Islamic Republic of)" + }, + { + "pred": "hasExactSynonym", + "val": "Iran (Islamic Republic of)" + } + ], + "xrefs": [ + { + "val": "GAZ:00004474" + } + ] + } + }, + { + "id": "http://dbpedia.org/resource/Japan", + "lbl": "Japan", + "type": "CLASS", + "meta": { + "xrefs": [ + { + "val": "GAZ:00002747" + } + ] + } + }, + { + "id": "http://dbpedia.org/resource/North_Korea", + "lbl": "North Korea", + "type": "CLASS", + "meta": { + "synonyms": [ + { + "pred": "hasExactSynonym", + "val": "Democratic People's Republic of Korea" + } + ], + "xrefs": [ + { + "val": "GAZ:00002801" + } + ] + } + }, + { + "id": "http://dbpedia.org/resource/Philippines", + "lbl": "Philippines", + "type": "CLASS", + "meta": { + "xrefs": [ + { + "val": "GAZ:00004525" + } + ], + "basicPropertyValues": [ + { + "pred": "http://purl.obolibrary.org/obo/IAO_0000118", + "val": "The Philippines" + } + ] + } + }, + { + "id": "http://purl.obolibrary.org/obo/CLO_0036460", + "lbl": "GM06944", + "type": "CLASS", + "meta": { + "definition": { + "val": "TRANSLOCATED CHROMOSOME" + }, + "synonyms": [ + { + "pred": "hasExactSynonym", + "val": "GM06944 cell" + } + ] + } + }, + { + "id": "http://purl.obolibrary.org/obo/CLO_0036870", + "lbl": "GM07029", + "type": "CLASS", + "meta": { + "definition": { + "val": "INTERNATIONAL HAPMAP PROJECT - CEPH (PLATE I) [UTAH RESIDENTS WITH ANCESTRY FROM NORTHERN AND WESTERN EUROPE] CEPH/UTAH PEDIGREE 1340 CYTOCHROME P450, SUBFAMILY IIC, POLYPEPTIDE 19; CYP2C19" + }, + "synonyms": [ + { + "pred": "hasExactSynonym", + "val": "GM07029 cell" + } + ] + } + }, + { + "id": "http://purl.obolibrary.org/obo/CL_0000000", + "lbl": "cell", + "type": "CLASS", + "meta": { + "definition": { + "val": "A material entity of anatomical origin (part of or deriving from an organism) that has as its parts a maximally connected cell compartment surrounded by a plasma membrane.", + "xrefs": ["CARO:mah"] + }, + "comments": [ + "The definition of cell is intended to represent all cells, and thus a cell is defined as a material entity and not an anatomical structure, which implies that it is part of an organism (or the entirety of one)." + ], + "subsets": [ + "http://purl.obolibrary.org/obo/cl#cellxgene_subset", + "http://purl.obolibrary.org/obo/ubprop#_upper_level" + ], + "xrefs": [ + { + "val": "CALOHA:TS-2035" + }, + { + "val": "CALOHA:TS-2035\n" + }, + { + "val": "FBbt:00007002" + }, + { + "val": "FMA:68646" + }, + { + "val": "FMA:68646\n " + }, + { + "val": "GO:0005623" + }, + { + "val": "GO:0005623\n" + }, + { + "val": "KUPO:0000002" + }, + { + "val": "KUPO:0000002\n\n" + }, + { + "val": "MESH:D002477" + }, + { + "val": "NCIt:C12508" + }, + { + "val": "NCIt:C48694" + }, + { + "val": "VHOG:0001533" + }, + { + "val": "VHOG:0001533\n\n" + }, + { + "val": "WBbt:0004017" + }, + { + "val": "WBbt:0004017\n" + }, + { + "val": "XAO:0003012" + }, + { + "val": "XAO:0003012\n\n" + }, + { + "val": "ZFA:0009000" + } + ] + } + }, + { + "id": "http://purl.obolibrary.org/obo/CL_0000002", + "lbl": "obsolete immortal cell line cell", + "type": "CLASS", + "meta": { + "definition": { + "val": "OBSOLETE: A cell line cell that is expected to be capable of an unlimited number of divisions, and is thus able to support indefinite growth/propagation in vitro as part of a immortal cell line.", + "xrefs": ["ReO:mhb"] + }, + "comments": [ + "Obsoleted in July 2013 and replaced by the CLO 'immortal cell line cell' class, as a result of CLO-OBI-CL alignment efforts.\n\nCovers cells actively being cultured or stored in a quiescent state for future use." + ], + "synonyms": [ + { + "pred": "hasExactSynonym", + "val": "continuous cell line cell" + }, + { + "pred": "hasExactSynonym", + "val": "permanent cell line cell" + } + ], + "basicPropertyValues": [ + { + "pred": "http://purl.obolibrary.org/obo/IAO_0100001", + "val": "http://purl.obolibrary.org/obo/CLO_0000019" + }, + { + "pred": "http://purl.obolibrary.org/obo/IAO_0100001", + "val": "http://purl.obolibrary.org/obo/CLO_0000019" + }, + { + "pred": "http://www.ebi.ac.uk/efo/obsoleted_in_version", + "val": "3.16.0" + }, + { + "pred": "http://www.ebi.ac.uk/efo/reason_for_obsolescence", + "val": "Use http://purl.obolibrary.org/obo/CLO_0000019" + } + ], + "deprecated": true + } + }, + { + "id": "http://purl.obolibrary.org/obo/CL_0000007", + "lbl": "early embryonic cell (metazoa)", + "type": "CLASS", + "meta": { + "definition": { + "val": "A cell found in the embryo before the formation of all the gem layers is complete.", + "xrefs": ["GOC:tfm"] + }, + "xrefs": [ + { + "val": "ZFA:0009002" + } + ] + } + }, + { + "id": "http://purl.obolibrary.org/obo/CL_0000010", + "lbl": "cultured cell", + "type": "CLASS", + "meta": { + "definition": { + "val": "A cell in vitro that is or has been maintained or propagated as part of a cell culture.", + "xrefs": ["ReO:mhb"] + }, + "comments": [ + "Note that this class was re-labeled to 'cultured cell' instead of 'cell line cell', as it intent was clarified to cover any cultured cells of multicellular and unicellular organisms. This includes cells actively being cultured, or cells that have been cultured but are stored in a quiescent state for future use. In having been cultured, cells must establish homeostasis and often replicate in a foreign environment. Accomodation of this stress initiates a selection of cells fit for such challenges, wherein necessary adaptive biochemical and.or genetic changes can occur. These changes can set them apart from the in vivo cells from which they derive, and such changes will typically accumulate and change over increasing time in culture." + ], + "xrefs": [ + { + "val": "MESH:D002478" + }, + { + "val": "MO:562" + }, + { + "val": "MeSH:D002460" + }, + { + "val": "NCIt:C16403" + } + ] + } + }, + { + "id": "http://purl.obolibrary.org/obo/CL_0000015", + "lbl": "male germ cell", + "type": "CLASS", + "meta": { + "definition": { + "val": "A germ cell that supports male gamete production. In some species, non-germ cells known as Sertoli cells also play a role in spermatogenesis.", + "xrefs": [ + "PMID:29462262", + "https://orcid.org/0000-0001-5208-3432" + ] + }, + "subsets": ["http://purl.obolibrary.org/obo/cl#cellxgene_subset"], + "xrefs": [ + { + "val": "FMA:72290" + }, + { + "val": "MA:0002765" + }, + { + "val": "VHOG:0001531" + }, + { + "val": "ncithesaurus:Spermatogenic_Cell" + } + ], + "basicPropertyValues": [ + { + "pred": "http://www.w3.org/2000/01/rdf-schema#seeAlso", + "val": "https://github.com/obophenotype/cell-ontology/issues/574" + } + ] + } + }, + { + "id": "http://purl.obolibrary.org/obo/CL_0000019", + "lbl": "sperm", + "type": "CLASS", + "meta": { + "definition": { + "val": "A mature male germ cell that develops from a spermatid.", + "xrefs": ["GOC:tfm", "MESH:D013094"] + }, + "subsets": ["http://purl.obolibrary.org/obo/cl#cellxgene_subset"], + "synonyms": [ + { + "pred": "hasExactSynonym", + "val": "sperm cell" + }, + { + "pred": "hasExactSynonym", + "val": "spermatozoid" + }, + { + "pred": "hasExactSynonym", + "val": "spermatozoon" + } + ], + "xrefs": [ + { + "val": "BTO:0001277" + }, + { + "val": "BTO:0002046" + }, + { + "val": "CALOHA:TS-0949" + }, + { + "val": "FBbt:00004954" + }, + { + "val": "FMA:67338" + }, + { + "val": "MA:0002765" + }, + { + "val": "MAT:0000131" + }, + { + "val": "MeSH:D012661" + }, + { + "val": "NCIt:C12602" + }, + { + "val": "NCIt:C13277" + }, + { + "val": "SAEL:93" + }, + { + "val": "WBbt:0005321" + }, + { + "val": "WBbt:0006798" + }, + { + "val": "ZFA:0009006" + } + ] + } + }, + { + "id": "http://purl.obolibrary.org/obo/CL_0000023", + "lbl": "oocyte", + "type": "CLASS", + "meta": { + "definition": { + "val": "A female germ cell that has entered meiosis.", + "xrefs": ["GOC:tfm", "ISBN:0721662544"] + }, + "subsets": ["http://purl.obolibrary.org/obo/cl#cellxgene_subset"], + "synonyms": [ + { + "pred": "hasRelatedSynonym", + "val": "oogonium" + } + ], + "xrefs": [ + { + "val": "BTO:0000964" + }, + { + "val": "CALOHA:TS-0711" + }, + { + "val": "FBbt:00004886" + }, + { + "val": "FMA:18644" + }, + { + "val": "MESH:D009865" + }, + { + "val": "NCIt:C12598" + }, + { + "val": "SNOMEDCT:86082002" + }, + { + "val": "WBbt:0006797" + }, + { + "val": "ZFA:0001109" + }, + { + "val": "ZFA:0009008" + } + ] + } + }, + { + "id": "http://purl.obolibrary.org/obo/CL_0000025", + "lbl": "egg cell", + "type": "CLASS", + "meta": { + "definition": { + "val": "A female gamete where meiosis has progressed to metaphase II and is able to participate in fertilization.", + "xrefs": ["GOC:tfm", "ISBN:0721662544"] + }, + "synonyms": [ + { + "pred": "hasExactSynonym", + "val": "mature oocyte" + }, + { + "pred": "hasExactSynonym", + "val": "ovum" + } + ], + "xrefs": [ + { + "val": "BTO:0000369" + }, + { + "val": "BTO:0003801" + }, + { + "val": "CALOHA:TS-2191" + }, + { + "val": "FBbt:00057012" + }, + { + "val": "FMA:67343" + }, + { + "val": "MAT:0000213" + }, + { + "val": "MESH:D010063" + }, + { + "val": "MeSH:D010063" + }, + { + "val": "PO:0020094" + }, + { + "val": "SNOMEDCT:73153001" + }, + { + "val": "ZFA:0001570" + } + ], + "basicPropertyValues": [ + { + "pred": "http://xmlns.com/foaf/0.1/depiction", + "val": "https://www.swissbiopics.org/api/image/Egg_cell.svg" + } + ] + } + }, + { + "id": "http://purl.obolibrary.org/obo/CL_0000031", + "lbl": "neuroblast (sensu Vertebrata)", + "type": "CLASS", + "meta": { + "definition": { + "val": "A cell that will develop into a neuron often after a migration phase.", + "xrefs": ["GOC:NV", "http://en.wikipedia.org/wiki/Neuroblast"] + }, + "subsets": ["http://purl.obolibrary.org/obo/cl#cellxgene_subset"], + "synonyms": [ + { + "pred": "hasExactSynonym", + "val": "neuroblast" + } + ], + "xrefs": [ + { + "val": "BTO:0000930" + }, + { + "val": "FMA:70563" + }, + { + "val": "ZFA:0009011" + } + ] + } + }, + { + "id": "http://purl.obolibrary.org/obo/CL_0000034", + "lbl": "stem cell", + "type": "CLASS", + "meta": { + "definition": { + "val": "A relatively undifferentiated cell that retains the ability to divide and proliferate throughout life to provide progenitor cells that can differentiate into specialized cells.", + "xrefs": ["GOC:tfm", "MESH:D013234"] + }, + "comments": [ + "This term applies to metazoan. For plant stem cells, consider using PO:0004011 ‘initial cell’ or its parent PO:0004010 ‘meristematic cell’." + ], + "subsets": [ + "http://purl.obolibrary.org/obo/cl#cellxgene_subset", + "http://purl.obolibrary.org/obo/cl#general_cell_types_upper_slim", + "http://purl.obolibrary.org/obo/uberon/core#human_reference_atlas" + ], + "synonyms": [ + { + "pred": "hasExactSynonym", + "val": "animal stem cell" + } + ], + "xrefs": [ + { + "val": "CALOHA:TS-2086" + }, + { + "val": "FMA:63368" + }, + { + "val": "NCIt:C12662" + }, + { + "val": "SNOMEDCT:419758009" + }, + { + "val": "ZFA:0005957" + } + ], + "basicPropertyValues": [ + { + "pred": "http://purl.obolibrary.org/obo/RO_0002175", + "val": "http://purl.obolibrary.org/obo/NCBITaxon_9606" + } + ] + } + }, + { + "id": "http://purl.obolibrary.org/obo/CL_0000037", + "lbl": "hematopoietic stem cell", + "type": "CLASS", + "meta": { + "definition": { + "val": "A stem cell from which all cells of the lymphoid and myeloid lineages develop, including blood cells and cells of the immune system. Hematopoietic stem cells lack cell markers of effector cells (lin-negative). Lin-negative is defined by lacking one or more of the following cell surface markers: CD2, CD3 epsilon, CD4, CD5 ,CD8 alpha chain, CD11b, CD14, CD19, CD20, CD56, ly6G, ter119.", + "xrefs": [ + "GOC:add", + "GOC:dsd", + "GOC:tfm", + "PMID:19022770", + "http://en.wikipedia.org/wiki/Hematopoietic_stem_cell" + ] + }, + "comments": [ + "Markers differ between species, and two sets of markers have been described for mice. HSCs are reportedly CD34-positive, CD45-positive, CD48-negative, CD150-positive, CD133-positive, and CD244-negative." + ], + "subsets": [ + "http://purl.obolibrary.org/obo/cl#blood_and_immune_upper_slim", + "http://purl.obolibrary.org/obo/cl#cellxgene_subset", + "http://purl.obolibrary.org/obo/uberon/core#human_reference_atlas" + ], + "synonyms": [ + { + "pred": "hasExactSynonym", + "val": "blood forming stem cell" + }, + { + "pred": "hasExactSynonym", + "val": "hemopoietic stem cell" + }, + { + "synonymType": "http://purl.obolibrary.org/obo/OMO_0003000", + "pred": "hasRelatedSynonym", + "val": "HSC" + }, + { + "pred": "hasRelatedSynonym", + "val": "colony forming unit hematopoietic" + } + ], + "xrefs": [ + { + "val": "BTO:0000725" + }, + { + "val": "CALOHA:TS-0448" + }, + { + "val": "FMA:86475" + }, + { + "val": "MESH:D006412" + }, + { + "val": "NCIt:C12551" + }, + { + "val": "SNOMEDCT:418318001" + }, + { + "val": "VHOG:0001485" + }, + { + "val": "ZFA:0009014" + } + ], + "basicPropertyValues": [ + { + "pred": "http://purl.obolibrary.org/obo/RO_0002175", + "val": "http://purl.obolibrary.org/obo/NCBITaxon_9606" + } + ] + } + }, + { + "id": "http://purl.obolibrary.org/obo/CL_0000038", + "lbl": "erythroid progenitor cell", + "type": "CLASS", + "meta": { + "definition": { + "val": "A progenitor cell committed to the erythroid lineage.", + "xrefs": ["GOC:add", "ISBN:0721601464"] + }, + "subsets": [ + "http://purl.obolibrary.org/obo/cl#blood_and_immune_upper_slim", + "http://purl.obolibrary.org/obo/cl#cellxgene_subset" + ], + "synonyms": [ + { + "synonymType": "http://purl.obolibrary.org/obo/OMO_0003000", + "pred": "hasRelatedSynonym", + "val": "BFU-E" + }, + { + "synonymType": "http://purl.obolibrary.org/obo/OMO_0003000", + "pred": "hasRelatedSynonym", + "val": "CFU-E" + }, + { + "pred": "hasRelatedSynonym", + "val": "blast forming unit erythroid" + }, + { + "pred": "hasRelatedSynonym", + "val": "burst forming unit erythroid" + }, + { + "pred": "hasRelatedSynonym", + "val": "colony forming unit erythroid" + }, + { + "pred": "hasRelatedSynonym", + "val": "erythroid stem cell" + } + ], + "xrefs": [ + { + "val": "BTO:0004911" + }, + { + "val": "NCIt:C12526" + }, + { + "val": "ZFA:0009015" + } + ] + } + }, + { + "id": "http://purl.obolibrary.org/obo/CL_0000040", + "lbl": "monoblast", + "type": "CLASS", + "meta": { + "definition": { + "val": "A myeloid progenitor cell committed to the monocyte lineage. This cell is CD11b-positive, has basophilic cytoplasm, euchromatin, and the presence of a nucleolus.", + "xrefs": [ + "GOC:add", + "PMID:1104740", + "http://en.wikipedia.org/wiki/Monoblast", + "http://www.copewithcytokines.de" + ] + }, + "comments": [ + "Morphology: mononuclear cell, diameter 12-20 _M, non-granular, N/C ratio 3/1 - 4/1; markers: CD11b (shared with many other myeloid cells); location: Adult: bone marrow; fetal: liver, Yolk Sac; role or process: hematopoiesis, monocyte development; lineage: hematopoietic, myeloid." + ], + "synonyms": [ + { + "synonymType": "http://purl.obolibrary.org/obo/OMO_0003000", + "pred": "hasRelatedSynonym", + "val": "CFU-M" + }, + { + "pred": "hasRelatedSynonym", + "val": "colony forming unit macrophage" + }, + { + "pred": "hasRelatedSynonym", + "val": "colony forming unit monocyte" + }, + { + "pred": "hasRelatedSynonym", + "val": "monocyte stem cell" + } + ], + "xrefs": [ + { + "val": "CALOHA:TS-1195" + }, + { + "val": "FMA:83553" + }, + { + "val": "NCIt:C13014" + }, + { + "val": "SNOMEDCT:53945006" + }, + { + "val": "ZFA:0009017" + } + ] + } + }, + { + "id": "http://purl.obolibrary.org/obo/CL_0000041", + "lbl": "mature eosinophil", + "type": "CLASS", + "meta": { + "definition": { + "val": "A fully differentiated eosinophil, a granular leukocyte with a nucleus that usually has two lobes connected by one or more slender threads, and cytoplasm containing coarse, round granules that are uniform in size and which can be stained by the dye eosin. Cells are also differentiated from other granulocytes by a small nuclear-to-cytoplasm ratio (1:3). This cell type is CD49d-positive.", + "xrefs": [ + "GOC:add", + "GOC:dsd", + "GOC:tfm", + "ISBN:0721601464", + "http://www.cap.org" + ] + }, + "comments": [ + "Eosinophils are CD125-positive (IL-5R), GM-CSFR-positive, IL-3R-positive, VLA4-positive. They can also express MHC Class I & II, CD4, CD9, CD11a, CD11b, CD11c, CD13, CD15, CD16, CD17, CD18, CD24, CD25,CD28, CD29, CD32, CD33, CD35, CD37, CD39, CD43, CD44, CD45, CD45RB, CD45RO, CD46, CD47, CD48, CD49d, CD49f, CD50, CD52, CD53, CD54, CD55, CD58, CD59, CD62L, CD63, CD65, CD66, CD69, CD71, CD76, CD80, CD81, CD82, CD86, CD87, CD88, CD89, CD92, CD95, CD97, CD98, CD99, CD100, CD101, CD116, CD117, CD119, CD120, CD123, CD124, CD125, CD131, CD137, CD139, CD148, CD149, CD151, CD153, CD156, CD162, CD161, CD162, CD165, CD174, CD182, CD183, CD191, CD192, CD193, CD196, CD213, IL9R, ad integrin, beta-7 integrin, FceRI, IL13Ra1, TGFbR, PAFR, LTB4R, C3aR, CystLT1R, CystLT2R, fMLPR, CRTH2 (PGD2 receptor), histamine 4R, IDO, KYN, PAR-2, Siglec-8, Siglec-10, LIR1, LIR2, LIR3, LIR7, TLR7, TLR8, and VLA-4. Eosinophils can also secrete CXCL1, eotaxin-1, GM-CSF, IL-2, IL-3, IL-4, IL-5, IL-6, IL-8, IL-10, IL-12, IL-13, IL-16, IL-18, IFN-gamma, LTC4, MIP-1alpha, NGF, PAF, RANTES, substance P, TGF-alpha, TGF-beta, TNF-alpha, and VIP." + ], + "subsets": [ + "http://purl.obolibrary.org/obo/uberon/core#human_reference_atlas" + ], + "synonyms": [ + { + "pred": "hasBroadSynonym", + "val": "polymorphonuclear leucocyte" + }, + { + "pred": "hasBroadSynonym", + "val": "polymorphonuclear leukocyte" + }, + { + "pred": "hasExactSynonym", + "val": "mature eosinocyte" + }, + { + "pred": "hasExactSynonym", + "val": "mature eosinophil leucocyte" + }, + { + "pred": "hasExactSynonym", + "val": "mature eosinophil leukocyte" + } + ], + "basicPropertyValues": [ + { + "pred": "http://purl.obolibrary.org/obo/IAO_0000116", + "val": "The status of eosinophils as true professional antigen presenting cells is unclear, despite their ability to present exogenous peptides and peptides processed from exogenous proteins (in certain studies) via MHC Class II and activate T cells. Per the equivalence axioms, 'eosinophil' is reasoned to be a subclass of 'professional antigen presenting cell', though the role of eosinophils as such in the body may be limited." + }, + { + "pred": "http://purl.obolibrary.org/obo/RO_0002175", + "val": "http://purl.obolibrary.org/obo/NCBITaxon_9606" + } + ] + } + }, + { + "id": "http://purl.obolibrary.org/obo/CL_0000042", + "lbl": "neutrophilic myeloblast", + "type": "CLASS", + "meta": { + "definition": { + "val": "A myeloblast committed to the neutrophil lineage. This cell type is GATA-1 positive, C/EBPa-positive, AML-1-positive, c-myb-positive and has low expression of PU.1 transcription factor.", + "xrefs": [ + "GOC:add", + "ISBN:0721601464", + "PMID:12560239", + "PMID:15514007" + ] + }, + "comments": [ + "These cells are CD11b-negative, CD15-negative, CD16-negative, CD35-negative, CD49d-positive, CD68-positive, lactotransferrin-negative, and fMLP receptor-negative. They are found in the Band 3 fraction." + ], + "synonyms": [ + { + "pred": "hasRelatedSynonym", + "val": "neutrophilic granuloblast" + } + ], + "xrefs": [ + { + "val": "ZFA:0009018" + } + ] + } + }, + { + "id": "http://purl.obolibrary.org/obo/CL_0000043", + "lbl": "mature basophil", + "type": "CLASS", + "meta": { + "definition": { + "val": "A fully differentiated basophil, a granular leukocyte with an irregularly shaped, pale-staining nucleus that is partially constricted into two lobes, and with cytoplasm that contains coarse granules of variable size. Basophils contain vasoactive amines such as histamine and serotonin, which are released on appropriate stimulation.", + "xrefs": [ + "GOC:add", + "GOC:dsd", + "GOC:tfm", + "ISBN:0721601464", + "PMID:18466030", + "PMID:19231594", + "PMID:20837449", + "http://www.cap.org" + ] + }, + "comments": [ + "Mature basophils are also capable of producing IL-3, IL-5, IL-6, IL-8, IL-13, IL-25, CCL22, tslp, vegf, and LTC4." + ], + "synonyms": [ + { + "pred": "hasBroadSynonym", + "val": "polymorphonuclear leucocyte" + }, + { + "pred": "hasBroadSynonym", + "val": "polymorphonuclear leukocyte" + }, + { + "pred": "hasExactSynonym", + "val": "mature basophil leucocyte" + }, + { + "pred": "hasExactSynonym", + "val": "mature basophil leukocyte" + } + ], + "xrefs": [ + { + "val": "BTO:0001026" + }, + { + "val": "CALOHA:TS-0688" + } + ] + } + }, + { + "id": "http://purl.obolibrary.org/obo/CL_0000047", + "lbl": "neural stem cell", + "type": "CLASS", + "meta": { + "definition": { + "val": "An undifferentiated neural cell that originates from the neuroectoderm and has the capacity both to perpetually self-renew without differentiating and to generate multiple central nervous system neuronal and glial cell types.", + "xrefs": ["PMID:30639325"] + }, + "subsets": ["http://purl.obolibrary.org/obo/cl#cellxgene_subset"], + "synonyms": [ + { + "pred": "hasExactSynonym", + "val": "NSC" + }, + { + "pred": "hasExactSynonym", + "val": "neuronal stem cell", + "xrefs": ["PMID:16305818"] + } + ], + "xrefs": [ + { + "val": "BTO:0002881" + }, + { + "val": "CALOHA:TS-2360" + }, + { + "val": "FMA:86684" + }, + { + "val": "NCIt:C12985" + }, + { + "val": "ZFA:0009019" + } + ] + } + }, + { + "id": "http://purl.obolibrary.org/obo/CL_0000048", + "lbl": "multi fate stem cell", + "type": "CLASS", + "meta": { + "definition": { + "val": "A stem cell that can give rise to multiple lineages of cells.", + "xrefs": ["GOC:add"] + }, + "synonyms": [ + { + "pred": "hasExactSynonym", + "val": "multi-fate stem cell" + }, + { + "pred": "hasExactSynonym", + "val": "multifate stem cell" + }, + { + "pred": "hasExactSynonym", + "val": "multipotent cell" + }, + { + "pred": "hasExactSynonym", + "val": "multipotent stem cell" + } + ], + "xrefs": [ + { + "val": "FMA:84789" + }, + { + "val": "ZFA:0009020" + } + ] + } + }, + { + "id": "http://purl.obolibrary.org/obo/CL_0000049", + "lbl": "common myeloid progenitor", + "type": "CLASS", + "meta": { + "definition": { + "val": "A progenitor cell committed to myeloid lineage, including the megakaryocyte and erythroid lineages.", + "xrefs": ["GOC:add", "ISBN:0878932437", "MESH:D023461"] + }, + "comments": [ + "This cell type is intended to be compatible with any vertebrate common myeloid progenitor. For mammalian CMP known to be CD34-positive, please use the term 'common myeloid progenitor, CD34-positive' (CL_0001059)." + ], + "subsets": [ + "http://purl.obolibrary.org/obo/cl#cellxgene_subset", + "http://purl.obolibrary.org/obo/uberon/core#human_reference_atlas" + ], + "synonyms": [ + { + "pred": "hasExactSynonym", + "val": "common myeloid precursor" + }, + { + "synonymType": "http://purl.obolibrary.org/obo/OMO_0003000", + "pred": "hasRelatedSynonym", + "val": "CFU-GEMM", + "xrefs": ["ISBN:0878932437"] + }, + { + "synonymType": "http://purl.obolibrary.org/obo/OMO_0003000", + "pred": "hasRelatedSynonym", + "val": "CFU-S", + "xrefs": ["ISBN:0878932437"] + }, + { + "synonymType": "http://purl.obolibrary.org/obo/OMO_0003000", + "pred": "hasRelatedSynonym", + "val": "CMP", + "xrefs": ["ISBN:0878932437"] + }, + { + "pred": "hasRelatedSynonym", + "val": "colony forming unit granulocyte, erythrocyte, macrophage, and megakaryocyte", + "xrefs": ["ISBN:0878932437"] + }, + { + "pred": "hasRelatedSynonym", + "val": "multipotential myeloid stem cell", + "xrefs": ["ISBN:0878932437"] + }, + { + "pred": "hasRelatedSynonym", + "val": "myeloid stem cell", + "xrefs": ["ISBN:0878932437"] + }, + { + "pred": "hasRelatedSynonym", + "val": "pluripotent stem cell (bone marrow)", + "xrefs": ["ISBN:0878932437"] + } + ], + "xrefs": [ + { + "val": "BTO:0004730" + }, + { + "val": "ZFA:0009021" + } + ], + "basicPropertyValues": [ + { + "pred": "http://purl.obolibrary.org/obo/RO_0002175", + "val": "http://purl.obolibrary.org/obo/NCBITaxon_9606" + } + ] + } + }, + { + "id": "http://purl.obolibrary.org/obo/CL_0000050", + "lbl": "megakaryocyte-erythroid progenitor cell", + "type": "CLASS", + "meta": { + "definition": { + "val": "A progenitor cell committed to the megakaryocyte and erythroid lineages.", + "xrefs": [ + "GOC:add", + "GOC:dsd", + "GOC:tfm", + "MESH:D055015", + "PMID:16647566", + "http://en.wikipedia.org/wiki/Megakaryocyte-erythroid_progenitor_cell" + ] + }, + "comments": [ + "MEPs are reportedly CD19-negative, CD34-negative, CD45RA-negative, CD110-positive, CD117-positive, and SCA1-negative and reportedly express the transcription factors GATA-1 and NF-E2." + ], + "subsets": [ + "http://purl.obolibrary.org/obo/cl#cellxgene_subset", + "http://purl.obolibrary.org/obo/uberon/core#human_reference_atlas" + ], + "synonyms": [ + { + "pred": "hasExactSynonym", + "val": "CFU-EM" + }, + { + "pred": "hasExactSynonym", + "val": "CFU-MegE" + }, + { + "pred": "hasExactSynonym", + "val": "MEP" + }, + { + "pred": "hasExactSynonym", + "val": "Meg/E progenitor" + }, + { + "pred": "hasExactSynonym", + "val": "colony forming unit erythroid megakaryocyte" + }, + { + "pred": "hasExactSynonym", + "val": "megakaryocyte/erythrocyte progenitor" + }, + { + "pred": "hasExactSynonym", + "val": "megakaryocyte/erythroid progenitor cell" + } + ], + "xrefs": [ + { + "val": "ZFA:0009022" + } + ], + "basicPropertyValues": [ + { + "pred": "http://purl.obolibrary.org/obo/RO_0002175", + "val": "http://purl.obolibrary.org/obo/NCBITaxon_9606" + } + ] + } + } + ], + "edges": [ + { + "sub": "http://dbpedia.org/resource/China", + "pred": "is_a", + "obj": "http://purl.obolibrary.org/obo/NCIT_C25464" + }, + { + "sub": "http://dbpedia.org/resource/India", + "pred": "is_a", + "obj": "http://purl.obolibrary.org/obo/NCIT_C25464" + }, + { + "sub": "http://dbpedia.org/resource/Iran", + "pred": "is_a", + "obj": "http://purl.obolibrary.org/obo/NCIT_C25464" + }, + { + "sub": "http://dbpedia.org/resource/Japan", + "pred": "is_a", + "obj": "http://purl.obolibrary.org/obo/NCIT_C25464" + }, + { + "sub": "http://dbpedia.org/resource/North_Korea", + "pred": "is_a", + "obj": "http://purl.obolibrary.org/obo/NCIT_C25464" + }, + { + "sub": "http://purl.obolibrary.org/obo/CL_0000000", + "pred": "is_a", + "obj": "http://purl.obolibrary.org/obo/GO_0005575" + }, + { + "sub": "http://purl.obolibrary.org/obo/CL_0000002", + "pred": "is_a", + "obj": "http://www.w3.org/2002/07/owl#Thing" + }, + { + "sub": "http://purl.obolibrary.org/obo/CL_0000007", + "pred": "is_a", + "obj": "http://purl.obolibrary.org/obo/CL_0002321" + }, + { + "sub": "http://purl.obolibrary.org/obo/CL_0000010", + "pred": "is_a", + "obj": "http://purl.obolibrary.org/obo/CL_0000000" + }, + { + "sub": "http://purl.obolibrary.org/obo/CL_0000010", + "pred": "http://purl.obolibrary.org/obo/RO_0000056", + "obj": "http://www.ebi.ac.uk/efo/EFO_0002694" + }, + { + "sub": "http://purl.obolibrary.org/obo/CL_0000015", + "pred": "is_a", + "obj": "http://purl.obolibrary.org/obo/CL_0000586" + }, + { + "sub": "http://purl.obolibrary.org/obo/CL_0000019", + "pred": "is_a", + "obj": "http://purl.obolibrary.org/obo/CL_0000015" + }, + { + "sub": "http://purl.obolibrary.org/obo/CL_0000019", + "pred": "is_a", + "obj": "http://purl.obolibrary.org/obo/UBERON_0000061" + }, + { + "sub": "http://purl.obolibrary.org/obo/CL_0000019", + "pred": "http://purl.obolibrary.org/obo/BFO_0000050", + "obj": "http://purl.obolibrary.org/obo/UBERON_0000079" + }, + { + "sub": "http://purl.obolibrary.org/obo/CL_0000023", + "pred": "is_a", + "obj": "http://purl.obolibrary.org/obo/CL_0000586" + }, + { + "sub": "http://purl.obolibrary.org/obo/CL_0000023", + "pred": "http://purl.obolibrary.org/obo/BFO_0000050", + "obj": "http://purl.obolibrary.org/obo/UBERON_0000474" + }, + { + "sub": "http://purl.obolibrary.org/obo/CL_0000025", + "pred": "is_a", + "obj": "http://purl.obolibrary.org/obo/CL_0000586" + }, + { + "sub": "http://purl.obolibrary.org/obo/CL_0000025", + "pred": "is_a", + "obj": "http://www.ebi.ac.uk/efo/EFO_0000988" + }, + { + "sub": "http://purl.obolibrary.org/obo/CL_0000031", + "pred": "is_a", + "obj": "http://purl.obolibrary.org/obo/CL_0000055" + }, + { + "sub": "http://purl.obolibrary.org/obo/CL_0000034", + "pred": "is_a", + "obj": "http://purl.obolibrary.org/obo/CL_0000000" + }, + { + "sub": "http://purl.obolibrary.org/obo/CL_1000497", + "pred": "is_a", + "obj": "http://purl.obolibrary.org/obo/CL_0000000" + }, + { + "sub": "http://purl.obolibrary.org/obo/CL_0008019", + "pred": "is_a", + "obj": "http://purl.obolibrary.org/obo/CL_0000000" + }, + { + "sub": "http://purl.obolibrary.org/obo/CL_0002494", + "pred": "is_a", + "obj": "http://purl.obolibrary.org/obo/CL_0000000" + }, + { + "sub": "http://purl.obolibrary.org/obo/CL_0002351", + "pred": "is_a", + "obj": "http://purl.obolibrary.org/obo/CL_0000000" + }, + { + "sub": "http://purl.obolibrary.org/obo/CL_0002319", + "pred": "is_a", + "obj": "http://purl.obolibrary.org/obo/CL_0000000" + }, + { + "sub": "http://purl.obolibrary.org/obo/CL_0002319", + "pred": "is_a", + "obj": "http://www.ebi.ac.uk/efo/EFO_0002963" + }, + { + "sub": "http://purl.obolibrary.org/obo/CL_0002319", + "pred": "http://purl.obolibrary.org/obo/RO_0001025", + "obj": "http://purl.obolibrary.org/obo/UBERON_0001016" + }, + { + "sub": "http://purl.obolibrary.org/obo/CL_0002321", + "pred": "is_a", + "obj": "http://purl.obolibrary.org/obo/CL_0000000" + }, + { + "sub": "http://purl.obolibrary.org/obo/CL_0002092", + "pred": "is_a", + "obj": "http://purl.obolibrary.org/obo/CL_0000000" + }, + { + "sub": "http://purl.obolibrary.org/obo/CL_0001063", + "pred": "is_a", + "obj": "http://purl.obolibrary.org/obo/CL_0000000" + }, + { + "sub": "http://purl.obolibrary.org/obo/CL_0000988", + "pred": "is_a", + "obj": "http://purl.obolibrary.org/obo/CL_0000000" + }, + { + "sub": "http://purl.obolibrary.org/obo/CL_0000670", + "pred": "is_a", + "obj": "http://purl.obolibrary.org/obo/CL_0000000" + }, + { + "sub": "http://purl.obolibrary.org/obo/CL_0000628", + "pred": "is_a", + "obj": "http://purl.obolibrary.org/obo/CL_0000000" + }, + { + "sub": "http://purl.obolibrary.org/obo/CL_0000586", + "pred": "is_a", + "obj": "http://purl.obolibrary.org/obo/CL_0000000" + }, + { + "sub": "http://purl.obolibrary.org/obo/CL_0000520", + "pred": "is_a", + "obj": "http://purl.obolibrary.org/obo/CL_0000000" + }, + { + "sub": "http://purl.obolibrary.org/obo/CL_0000520", + "pred": "is_a", + "obj": "http://www.ebi.ac.uk/efo/EFO_0000324" + }, + { + "sub": "http://purl.obolibrary.org/obo/CL_0000521", + "pred": "is_a", + "obj": "http://purl.obolibrary.org/obo/CL_0000000" + }, + { + "sub": "http://purl.obolibrary.org/obo/CL_0000521", + "pred": "is_a", + "obj": "http://www.ebi.ac.uk/efo/EFO_0000324" + } + ] + } + ] +} diff --git a/tests/gentropy/datasource/biosample_ontologies/test_biosample_ontology.py b/tests/gentropy/datasource/biosample_ontologies/test_biosample_ontology.py index b88623b0d..a9099048c 100644 --- a/tests/gentropy/datasource/biosample_ontologies/test_biosample_ontology.py +++ b/tests/gentropy/datasource/biosample_ontologies/test_biosample_ontology.py @@ -16,24 +16,27 @@ class TestOntologyParger: SAMPLE_CELL_ONTOLOGY_PATH = "tests/gentropy/data_samples/cell_ontology_sample.json" SAMPLE_UBERON_PATH = "tests/gentropy/data_samples/uberon_sample.json" + SAMPLE_EFO_PATH = "tests/gentropy/data_samples/efo_biosample_sample.json" - def test_cell_ontology_parser( - self: TestOntologyParger, spark: SparkSession - ) -> None: - """Test cell ontology parser.""" + def test_ontology_parser(self: TestOntologyParger, spark: SparkSession) -> None: + """Test all ontology parsers.""" cell_ontology = extract_ontology_from_json( self.SAMPLE_CELL_ONTOLOGY_PATH, spark ) + uberon = extract_ontology_from_json(self.SAMPLE_UBERON_PATH, spark) + efo_cell_line = extract_ontology_from_json( + self.SAMPLE_EFO_PATH, spark + ).retain_rows_with_ancestor_id(["CL_0000000"]) + assert isinstance( cell_ontology, BiosampleIndex ), "Cell ontology subset is not parsed correctly to BiosampleIndex." - - def test_uberon_parser(self: TestOntologyParger, spark: SparkSession) -> None: - """Test uberon parser.""" - uberon = extract_ontology_from_json(self.SAMPLE_UBERON_PATH, spark) assert isinstance( uberon, BiosampleIndex ), "Uberon subset is not parsed correctly to BiosampleIndex." + assert isinstance( + efo_cell_line, BiosampleIndex + ), "EFO cell line subset is not parsed correctly to BiosampleIndex." def test_merge_biosample_indices( self: TestOntologyParger, spark: SparkSession @@ -43,8 +46,9 @@ def test_merge_biosample_indices( self.SAMPLE_CELL_ONTOLOGY_PATH, spark ) uberon = extract_ontology_from_json(self.SAMPLE_UBERON_PATH, spark) + efo = extract_ontology_from_json(self.SAMPLE_EFO_PATH, spark) - merged = cell_ontology.merge_indices([uberon]) + merged = cell_ontology.merge_indices([uberon, efo]) assert isinstance( merged, BiosampleIndex ), "Merging of biosample indices is not correct." From 7b20d55275bae4baefd95774b7279ea362635a80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Irene=20L=C3=B3pez=20Santiago?= <45119610+ireneisdoomed@users.noreply.github.com> Date: Mon, 21 Oct 2024 15:20:48 +0100 Subject: [PATCH 120/188] feat(l2g): extend colocalisation neighbourhood metrics to missing genes in the vicinity (#851) * feat(l2g): wip - limit colocalisation neighbourhood to protein coding genes * feat: adjust logic in `common_neighbourhood_colocalisation_feature_logic` * fix: correct logic in `common_neighbourhood_vep_feature_logic` * chore: adjust tests * chore: wip * feat: add `extend_missing_colocalisation_to_neighbourhood_genes` * feat: add variant index as a dependency to the colocalisation nbh features * test: add `test_extend_missing_colocalisation_to_neighbourhood_genes` * chore: minor * chore: fixes tests --- .../datasets/l2g_features/colocalisation.md | 1 + .../dataset/l2g_features/colocalisation.py | 117 +++++++++- src/gentropy/dataset/l2g_features/vep.py | 2 +- tests/gentropy/dataset/test_l2g_feature.py | 211 ++++++++++++------ 4 files changed, 252 insertions(+), 79 deletions(-) diff --git a/docs/python_api/datasets/l2g_features/colocalisation.md b/docs/python_api/datasets/l2g_features/colocalisation.md index c38c690d7..2b2680e66 100644 --- a/docs/python_api/datasets/l2g_features/colocalisation.md +++ b/docs/python_api/datasets/l2g_features/colocalisation.md @@ -20,4 +20,5 @@ title: From colocalisation ## Common logic ::: gentropy.dataset.l2g_features.colocalisation.common_colocalisation_feature_logic +::: gentropy.dataset.l2g_features.colocalisation.extend_missing_colocalisation_to_neighbourhood_genes ::: gentropy.dataset.l2g_features.colocalisation.common_neighbourhood_colocalisation_feature_logic diff --git a/src/gentropy/dataset/l2g_features/colocalisation.py b/src/gentropy/dataset/l2g_features/colocalisation.py index 319a128da..c7161dc55 100644 --- a/src/gentropy/dataset/l2g_features/colocalisation.py +++ b/src/gentropy/dataset/l2g_features/colocalisation.py @@ -13,6 +13,7 @@ from gentropy.dataset.l2g_gold_standard import L2GGoldStandard from gentropy.dataset.study_index import StudyIndex from gentropy.dataset.study_locus import StudyLocus +from gentropy.dataset.variant_index import VariantIndex if TYPE_CHECKING: from pyspark.sql import DataFrame @@ -68,6 +69,54 @@ def common_colocalisation_feature_logic( ) +def extend_missing_colocalisation_to_neighbourhood_genes( + feature_name: str, + local_features: DataFrame, + variant_index: VariantIndex, + gene_index: GeneIndex, + study_locus: StudyLocus, +) -> DataFrame: + """This function creates an artificial dataset of features that represents the missing colocalisation to the neighbourhood genes. + + Args: + feature_name (str): The name of the feature to extend + local_features (DataFrame): The dataframe of features to extend + variant_index (VariantIndex): Variant index containing all variant/gene relationships + gene_index (GeneIndex): Gene index to fetch the gene information + study_locus (StudyLocus): Study locus to traverse between colocalisation and variant index + + Returns: + DataFrame: Dataframe of features that include genes in the neighbourhood not present in the colocalisation results. For these genes, the feature value is set to 0. + """ + coding_variant_gene_lut = ( + variant_index.df.select( + "variantId", f.explode("transcriptConsequences").alias("tc") + ) + .select(f.col("tc.targetId").alias("geneId"), "variantId") + .join(gene_index.df.select("geneId", "biotype"), "geneId", "left") + .filter(f.col("biotype") == "protein_coding") + .drop("biotype") + .distinct() + ) + local_features_w_variant = local_features.join( + study_locus.df.select("studyLocusId", "variantId"), "studyLocusId" + ) + return ( + # Get the genes that are not present in the colocalisation results + coding_variant_gene_lut.join( + local_features_w_variant, ["variantId", "geneId"], "left_anti" + ) + # We now link the missing variant/gene to the study locus from the original dataframe + .join( + local_features_w_variant.select("studyLocusId", "variantId").distinct(), + "variantId", + ) + .drop("variantId") + # Fill the information for missing genes with 0 + .withColumn(feature_name, f.lit(0.0)) + ) + + def common_neighbourhood_colocalisation_feature_logic( study_loci_to_annotate: StudyLocus | L2GGoldStandard, colocalisation_method: str, @@ -79,6 +128,7 @@ def common_neighbourhood_colocalisation_feature_logic( study_index: StudyIndex, gene_index: GeneIndex, study_locus: StudyLocus, + variant_index: VariantIndex, ) -> DataFrame: """Wrapper to call the logic that creates a type of colocalisation features. @@ -92,6 +142,7 @@ def common_neighbourhood_colocalisation_feature_logic( study_index (StudyIndex): Study index to fetch study type and gene gene_index (GeneIndex): Gene index to add gene type study_locus (StudyLocus): Study locus to traverse between colocalisation and study index + variant_index (VariantIndex): Variant index to annotate all overlapping genes Returns: DataFrame: Feature annotation in long format with the columns: studyLocusId, geneId, featureName, featureValue @@ -107,11 +158,23 @@ def common_neighbourhood_colocalisation_feature_logic( colocalisation=colocalisation, study_index=study_index, study_locus=study_locus, - ).join(gene_index.df.select("geneId", "biotype"), "geneId", "left") + ) + extended_local_max = local_max.unionByName( + extend_missing_colocalisation_to_neighbourhood_genes( + local_feature_name, + local_max, + variant_index, + gene_index, + study_locus, + ) + ) # Compute average score in the vicinity (feature will be the same for any gene associated with a studyLocus) # (non protein coding genes in the vicinity are excluded see #3552) regional_mean_per_study_locus = ( - local_max.filter(f.col("biotype") == "protein_coding") + extended_local_max.join( + gene_index.df.select("geneId", "biotype"), "geneId", "left" + ) + .filter(f.col("biotype") == "protein_coding") .groupBy("studyLocusId") .agg(f.mean(local_feature_name).alias("regional_mean")) ) @@ -121,7 +184,7 @@ def common_neighbourhood_colocalisation_feature_logic( feature_name, f.col(local_feature_name) - f.coalesce(f.col("regional_mean"), f.lit(0.0)), ) - .drop("regional_mean", local_feature_name, "biotype") + .drop("regional_mean", local_feature_name) ) @@ -171,7 +234,13 @@ def compute( class EQtlColocClppMaximumNeighbourhoodFeature(L2GFeature): """Max CLPP for each (study, locus) aggregating over all eQTLs.""" - feature_dependency_type = [Colocalisation, StudyIndex, GeneIndex, StudyLocus] + feature_dependency_type = [ + Colocalisation, + StudyIndex, + GeneIndex, + StudyLocus, + VariantIndex, + ] feature_name = "eQtlColocClppMaximumNeighbourhood" @classmethod @@ -256,7 +325,13 @@ def compute( class PQtlColocClppMaximumNeighbourhoodFeature(L2GFeature): """Max CLPP for each (study, locus, gene) aggregating over all pQTLs.""" - feature_dependency_type = [Colocalisation, StudyIndex, GeneIndex, StudyLocus] + feature_dependency_type = [ + Colocalisation, + StudyIndex, + GeneIndex, + StudyLocus, + VariantIndex, + ] feature_name = "pQtlColocClppMaximumNeighbourhood" @classmethod @@ -340,7 +415,13 @@ def compute( class SQtlColocClppMaximumNeighbourhoodFeature(L2GFeature): """Max CLPP for each (study, locus, gene) aggregating over all sQTLs.""" - feature_dependency_type = [Colocalisation, StudyIndex, GeneIndex, StudyLocus] + feature_dependency_type = [ + Colocalisation, + StudyIndex, + GeneIndex, + StudyLocus, + VariantIndex, + ] feature_name = "sQtlColocClppMaximumNeighbourhood" @classmethod @@ -424,7 +505,13 @@ def compute( class EQtlColocH4MaximumNeighbourhoodFeature(L2GFeature): """Max H4 for each (study, locus) aggregating over all eQTLs.""" - feature_dependency_type = [Colocalisation, StudyIndex, GeneIndex, StudyLocus] + feature_dependency_type = [ + Colocalisation, + StudyIndex, + GeneIndex, + StudyLocus, + VariantIndex, + ] feature_name = "eQtlColocH4MaximumNeighbourhood" @classmethod @@ -508,7 +595,13 @@ def compute( class PQtlColocH4MaximumNeighbourhoodFeature(L2GFeature): """Max H4 for each (study, locus) aggregating over all pQTLs.""" - feature_dependency_type = [Colocalisation, StudyIndex, GeneIndex, StudyLocus] + feature_dependency_type = [ + Colocalisation, + StudyIndex, + GeneIndex, + StudyLocus, + VariantIndex, + ] feature_name = "pQtlColocH4MaximumNeighbourhood" @classmethod @@ -592,7 +685,13 @@ def compute( class SQtlColocH4MaximumNeighbourhoodFeature(L2GFeature): """Max H4 for each (study, locus) aggregating over all sQTLs.""" - feature_dependency_type = [Colocalisation, StudyIndex, GeneIndex, StudyLocus] + feature_dependency_type = [ + Colocalisation, + StudyIndex, + GeneIndex, + StudyLocus, + VariantIndex, + ] feature_name = "sQtlColocH4MaximumNeighbourhood" @classmethod diff --git a/src/gentropy/dataset/l2g_features/vep.py b/src/gentropy/dataset/l2g_features/vep.py index 557d9a509..91b03d57b 100644 --- a/src/gentropy/dataset/l2g_features/vep.py +++ b/src/gentropy/dataset/l2g_features/vep.py @@ -114,7 +114,7 @@ def common_neighbourhood_vep_feature_logic( feature_name, f.col(local_feature_name) - f.coalesce(f.col("regional_mean"), f.lit(0.0)), ) - .drop("regional_metric", local_feature_name, "biotype") + .drop("regional_mean", local_feature_name, "biotype") ) diff --git a/tests/gentropy/dataset/test_l2g_feature.py b/tests/gentropy/dataset/test_l2g_feature.py index bd6fca97c..212ad32a6 100644 --- a/tests/gentropy/dataset/test_l2g_feature.py +++ b/tests/gentropy/dataset/test_l2g_feature.py @@ -34,6 +34,7 @@ SQtlColocH4MaximumNeighbourhoodFeature, common_colocalisation_feature_logic, common_neighbourhood_colocalisation_feature_logic, + extend_missing_colocalisation_to_neighbourhood_genes, ) from gentropy.dataset.l2g_features.distance import ( DistanceFootprintMeanFeature, @@ -135,6 +136,11 @@ def sample_gene_index(spark: SparkSession) -> GeneIndex: "biotype": "lncRNA", "chromosome": "1", }, + { + "geneId": "gene3", + "biotype": "protein_coding", + "chromosome": "1", + }, ], GeneIndex.get_schema(), ), @@ -142,6 +148,66 @@ def sample_gene_index(spark: SparkSession) -> GeneIndex: ) +@pytest.fixture(scope="module") +def sample_variant_index(spark: SparkSession) -> VariantIndex: + """Create a sample variant index for testing.""" + return VariantIndex( + _df=spark.createDataFrame( + [ + ( + "var1", + "chrom", + 1, + "A", + "T", + [ + { + "targetId": "gene1", + "consequenceScore": 0.66, + "isEnsemblCanonical": True, + }, + { + "targetId": "gene2", + "consequenceScore": 1.0, + "isEnsemblCanonical": True, + }, + { + "targetId": "gene3", + "consequenceScore": 0.0, + "isEnsemblCanonical": True, + }, + ], + ), + ], + schema=StructType( + [ + StructField("variantId", StringType(), True), + StructField("chromosome", StringType(), True), + StructField("position", IntegerType(), True), + StructField("referenceAllele", StringType(), True), + StructField("alternateAllele", StringType(), True), + StructField( + "transcriptConsequences", + ArrayType( + StructType( + [ + StructField("targetId", StringType(), True), + StructField( + "isEnsemblCanonical", BooleanType(), True + ), + StructField("consequenceScore", FloatType(), True), + ] + ) + ), + True, + ), + ] + ), + ), + _schema=VariantIndex.get_schema(), + ) + + class TestCommonColocalisationFeatureLogic: """Test the common logic of the colocalisation features.""" @@ -183,10 +249,46 @@ def test__common_colocalisation_feature_logic( observed_df.collect() == expected_df.collect() ), "The feature values are not as expected." - def test__common_neighbourhood_colocalisation_feature_logic( + def test_extend_missing_colocalisation_to_neighbourhood_genes( self: TestCommonColocalisationFeatureLogic, spark: SparkSession, sample_gene_index: GeneIndex, + sample_variant_index: VariantIndex, + ) -> None: + """Test the extend_missing_colocalisation_to_neighbourhood_genes function.""" + local_features = spark.createDataFrame( + [ + { + "studyLocusId": "1", + "geneId": "gene1", + "eQtlColocH4Maximum": 0.81, + }, + { + "studyLocusId": "1", + "geneId": "gene2", + "eQtlColocH4Maximum": 0.9, + }, + ], + ) + observed_df = extend_missing_colocalisation_to_neighbourhood_genes( + feature_name="eQtlColocH4Maximum", + local_features=local_features, + variant_index=sample_variant_index, + gene_index=sample_gene_index, + study_locus=self.sample_study_locus, + ).select("studyLocusId", "geneId", "eQtlColocH4Maximum") + expected_df = spark.createDataFrame( + [{"geneId": "gene3", "studyLocusId": "1", "eQtlColocH4Maximum": 0.0}] + ).select("studyLocusId", "geneId", "eQtlColocH4Maximum") + assert ( + observed_df.collect() == expected_df.collect() + ), "The feature values are not as expected." + + def test_common_neighbourhood_colocalisation_feature_logic( + self: TestCommonColocalisationFeatureLogic, + spark: SparkSession, + sample_gene_index: GeneIndex, + sample_variant_index: VariantIndex, ) -> None: """Test the common logic of the neighbourhood colocalisation features.""" feature_name = "eQtlColocH4MaximumNeighbourhood" @@ -200,19 +302,20 @@ def test__common_neighbourhood_colocalisation_feature_logic( study_index=self.sample_studies, study_locus=self.sample_study_locus, gene_index=sample_gene_index, - ).withColumn(feature_name, f.round(f.col(feature_name), 2)) - # expected average is (0.81)/1 = 0.81 + variant_index=sample_variant_index, + ).withColumn(feature_name, f.round(f.col(feature_name), 3)) + # expected average is (0.81 + 0)/2 = 0.405 expected_df = spark.createDataFrame( [ { "studyLocusId": "1", "geneId": "gene1", - "eQtlColocH4MaximumNeighbourhood": 0.0, # 0.81 - 0.81 + "eQtlColocH4MaximumNeighbourhood": 0.405, # 0.81 - 0.405 }, { "studyLocusId": "1", "geneId": "gene2", - "eQtlColocH4MaximumNeighbourhood": 0.09, # 0.9 - 0.81 + "eQtlColocH4MaximumNeighbourhood": 0.495, # 0.9 - 0.405 }, ], ).select("studyLocusId", "geneId", "eQtlColocH4MaximumNeighbourhood") @@ -232,7 +335,7 @@ def _setup(self: TestCommonColocalisationFeatureLogic, spark: SparkSession) -> N [ { "studyLocusId": "1", - "variantId": "lead1", + "variantId": "var1", "studyId": "study1", # this is a GWAS "chromosome": "1", }, @@ -281,25 +384,25 @@ def _setup(self: TestCommonColocalisationFeatureLogic, spark: SparkSession) -> N [ { "studyLocusId": "1", - "variantId": "lead1", + "variantId": "var1", "studyId": "study1", # this is a GWAS "chromosome": "1", }, { "studyLocusId": "2", - "variantId": "lead1", + "variantId": "var1", "studyId": "study2", # this is a QTL (same gee) "chromosome": "1", }, { "studyLocusId": "3", - "variantId": "lead1", + "variantId": "var1", "studyId": "study3", # this is another QTL (same gene) "chromosome": "1", }, { "studyLocusId": "4", - "variantId": "lead1", + "variantId": "var1", "studyId": "study4", # this is another QTL (diff gene) "chromosome": "1", }, @@ -533,6 +636,11 @@ class TestCommonVepFeatureLogic: ( "vepMean", [ + { + "studyLocusId": "1", + "geneId": "gene3", + "vepMean": "0.00", + }, { "studyLocusId": "1", "geneId": "gene1", @@ -548,6 +656,11 @@ class TestCommonVepFeatureLogic: ( "vepMaximum", [ + { + "studyLocusId": "1", + "geneId": "gene3", + "vepMaximum": "0.00", + }, { "studyLocusId": "1", "geneId": "gene1", @@ -567,12 +680,13 @@ def test_common_vep_feature_logic( spark: SparkSession, feature_name: str, expected_data: dict[str, Any], + sample_variant_index: VariantIndex, ) -> None: """Test the logic of the function that extracts features from VEP's functional consequences.""" observed_df = ( common_vep_feature_logic( self.sample_study_locus, - variant_index=self.sample_variant_index, + variant_index=sample_variant_index, feature_name=feature_name, ) .orderBy(feature_name) @@ -593,17 +707,22 @@ def test_common_neighbourhood_vep_feature_logic_no_protein_coding( self: TestCommonVepFeatureLogic, spark: SparkSession, sample_gene_index: GeneIndex, + sample_variant_index: VariantIndex, ) -> None: """Test the logic of the function that extracts the maximum severity score for a gene given the average of the maximum scores for all protein coding genes in the vicinity. Because the genes in the vicinity are all non coding, the neighbourhood features should equal the local ones. """ feature_name = "vepMaximumNeighbourhood" + non_protein_coding_gene_index = GeneIndex( + _df=sample_gene_index.df.filter(f.col("geneId") != "gene3"), + _schema=GeneIndex.get_schema(), + ) observed_df = ( common_neighbourhood_vep_feature_logic( self.sample_study_locus, - variant_index=self.sample_variant_index, - gene_index=sample_gene_index, + variant_index=sample_variant_index, + gene_index=non_protein_coding_gene_index, feature_name=feature_name, ) .withColumn(feature_name, f.round(f.col(feature_name), 2)) @@ -616,7 +735,7 @@ def test_common_neighbourhood_vep_feature_logic_no_protein_coding( ( ["1", "gene1", 0.0], ["1", "gene2", 0.34], - ), # (0.66-0.66) and (1.0 -0.66) + ), # (0.66-0.66) and (1.0-0.66) ["studyLocusId", "geneId", feature_name], ) .orderBy(feature_name) @@ -630,13 +749,14 @@ def test_common_neighbourhood_vep_feature_logic( self: TestCommonVepFeatureLogic, spark: SparkSession, sample_gene_index: GeneIndex, + sample_variant_index: VariantIndex, ) -> None: """Test the logic of the function that extracts the maximum severity score for a gene given the average of the maximum scores for all protein coding genes in the vicinity.""" feature_name = "vepMaximumNeighbourhood" observed_df = ( common_neighbourhood_vep_feature_logic( self.sample_study_locus, - variant_index=self.sample_variant_index, + variant_index=sample_variant_index, gene_index=sample_gene_index, feature_name=feature_name, ) @@ -645,11 +765,16 @@ def test_common_neighbourhood_vep_feature_logic( ) expected_df = ( spark.createDataFrame( - (["1", "gene1", 0.0], ["1", "gene2", 0.34]), + # regional mean is 0.66/2 = 0.33 + ( + ["1", "gene3", -0.33], + ["1", "gene1", 0.33], + ["1", "gene2", 0.67], + ), # (0 - 0.33) and (0.66-0.33) and (1.0 -0.33) ["studyLocusId", "geneId", feature_name], ) - .select("studyLocusId", "geneId", feature_name) .orderBy(feature_name) + .select("studyLocusId", "geneId", feature_name) ) assert ( observed_df.collect() == expected_df.collect() @@ -678,55 +803,3 @@ def _setup(self: TestCommonVepFeatureLogic, spark: SparkSession) -> None: ), _schema=StudyLocus.get_schema(), ) - self.sample_variant_index = VariantIndex( - _df=spark.createDataFrame( - [ - ( - "var1", - "chrom", - 1, - "A", - "T", - [ - { - "targetId": "gene1", - "consequenceScore": 0.66, - "isEnsemblCanonical": True, - }, - { - "targetId": "gene2", - "consequenceScore": 1.0, - "isEnsemblCanonical": True, - }, - ], - ), - ], - schema=StructType( - [ - StructField("variantId", StringType(), True), - StructField("chromosome", StringType(), True), - StructField("position", IntegerType(), True), - StructField("referenceAllele", StringType(), True), - StructField("alternateAllele", StringType(), True), - StructField( - "transcriptConsequences", - ArrayType( - StructType( - [ - StructField("targetId", StringType(), True), - StructField( - "isEnsemblCanonical", BooleanType(), True - ), - StructField( - "consequenceScore", FloatType(), True - ), - ] - ) - ), - True, - ), - ] - ), - ), - _schema=VariantIndex.get_schema(), - ) From de4627f8c076fac899646aa89cdefe1007e28b19 Mon Sep 17 00:00:00 2001 From: Yakov Date: Tue, 22 Oct 2024 10:16:02 +0100 Subject: [PATCH 121/188] fix: add scQTLs into coloc features (#833) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: add scQTLs into coloc features * fix: include single cell qtls in the list of valid study types --------- Co-authored-by: Irene López --- src/gentropy/dataset/colocalisation.py | 7 ++++++- .../dataset/l2g_features/colocalisation.py | 16 ++++++++-------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/gentropy/dataset/colocalisation.py b/src/gentropy/dataset/colocalisation.py index 568b46007..db0040652 100644 --- a/src/gentropy/dataset/colocalisation.py +++ b/src/gentropy/dataset/colocalisation.py @@ -62,7 +62,12 @@ def extract_maximum_coloc_probability_per_region_and_gene( valid_qtls = list( set(EqtlCatalogueStudyIndex.method_to_study_type_mapping.values()) - ) + ) + [ + f"sc{qtl}" + for qtl in set( + EqtlCatalogueStudyIndex.method_to_study_type_mapping.values() + ) + ] if filter_by_qtls: filter_by_qtls = ( diff --git a/src/gentropy/dataset/l2g_features/colocalisation.py b/src/gentropy/dataset/l2g_features/colocalisation.py index c7161dc55..fdbf3ed18 100644 --- a/src/gentropy/dataset/l2g_features/colocalisation.py +++ b/src/gentropy/dataset/l2g_features/colocalisation.py @@ -211,7 +211,7 @@ def compute( """ colocalisation_method = "ECaviar" colocalisation_metric = "clpp" - qtl_type = "eqtl" + qtl_type = ["eqtl", "sceqtl"] return cls( _df=convert_from_wide_to_long( @@ -260,7 +260,7 @@ def compute( """ colocalisation_method = "ECaviar" colocalisation_metric = "clpp" - qtl_type = "eqtl" + qtl_type = ["eqtl", "sceqtl"] return cls( _df=convert_from_wide_to_long( @@ -393,7 +393,7 @@ def compute( """ colocalisation_method = "ECaviar" colocalisation_metric = "clpp" - qtl_types = ["sqtl", "tuqtl"] + qtl_types = ["sqtl", "tuqtl", "scsqtl", "sctuqtl"] return cls( _df=convert_from_wide_to_long( common_colocalisation_feature_logic( @@ -441,7 +441,7 @@ def compute( """ colocalisation_method = "ECaviar" colocalisation_metric = "clpp" - qtl_types = ["sqtl", "tuqtl"] + qtl_types = ["sqtl", "tuqtl", "scsqtl", "sctuqtl"] return cls( _df=convert_from_wide_to_long( common_neighbourhood_colocalisation_feature_logic( @@ -483,7 +483,7 @@ def compute( """ colocalisation_method = "Coloc" colocalisation_metric = "h4" - qtl_type = "eqtl" + qtl_type = ["eqtl", "sceqtl"] return cls( _df=convert_from_wide_to_long( common_colocalisation_feature_logic( @@ -531,7 +531,7 @@ def compute( """ colocalisation_method = "Coloc" colocalisation_metric = "h4" - qtl_type = "eqtl" + qtl_type = ["eqtl", "sceqtl"] return cls( _df=convert_from_wide_to_long( common_neighbourhood_colocalisation_feature_logic( @@ -663,7 +663,7 @@ def compute( """ colocalisation_method = "Coloc" colocalisation_metric = "h4" - qtl_types = ["sqtl", "tuqtl"] + qtl_types = ["sqtl", "tuqtl", "scsqtl", "sctuqtl"] return cls( _df=convert_from_wide_to_long( common_colocalisation_feature_logic( @@ -711,7 +711,7 @@ def compute( """ colocalisation_method = "Coloc" colocalisation_metric = "h4" - qtl_types = ["sqtl", "tuqtl"] + qtl_types = ["sqtl", "tuqtl", "scsqtl", "sctuqtl"] return cls( _df=convert_from_wide_to_long( common_neighbourhood_colocalisation_feature_logic( From 782a458f6f8f274f8f55d677a4a2e2db3594bf1f Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 22 Oct 2024 10:44:21 +0100 Subject: [PATCH 122/188] chore: pre-commit autoupdate (#866) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.6.7 → v0.7.0](https://github.com/astral-sh/ruff-pre-commit/compare/v0.6.7...v0.7.0) - [github.com/pre-commit/pre-commit-hooks: v4.6.0 → v5.0.0](https://github.com/pre-commit/pre-commit-hooks/compare/v4.6.0...v5.0.0) - [github.com/pre-commit/mirrors-mypy: v1.11.2 → v1.12.1](https://github.com/pre-commit/mirrors-mypy/compare/v1.11.2...v1.12.1) - [github.com/jsh9/pydoclint: 0.5.8 → 0.5.9](https://github.com/jsh9/pydoclint/compare/0.5.8...0.5.9) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a938f03a3..7d2d55fc2 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -6,7 +6,7 @@ ci: skip: [poetry-lock] repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.6.7 + rev: v0.7.0 hooks: - id: ruff args: @@ -15,7 +15,7 @@ repos: files: ^((gentropy|utils|tests)/.+)?[^/]+\.py$ - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.6.0 + rev: v5.0.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer @@ -65,7 +65,7 @@ repos: stages: [commit-msg] - repo: https://github.com/pre-commit/mirrors-mypy - rev: "v1.11.2" + rev: "v1.12.1" hooks: - id: mypy args: @@ -98,7 +98,7 @@ repos: - id: beautysh - repo: https://github.com/jsh9/pydoclint - rev: 0.5.8 + rev: 0.5.9 hooks: - id: pydoclint From df220e967f9f663317c8b50435f36fda349557da Mon Sep 17 00:00:00 2001 From: David Ochoa Date: Tue, 22 Oct 2024 11:25:06 +0100 Subject: [PATCH 123/188] feat: gwas catalog top-hit + study step (#808) * fix: wrong step parameter * fix: persist va_subset * fix: remove broadcasts * feat: new gwas_catalog_top_hits step * docs: new step added to documentation * fix: incorrect target * fix: failing tests * fix: extra argument * fix: select does not require hasSumstats anymore * feat: study inclusion step repurposed into study index step * docs: fix path for documentation * feat: remove GWASCatalogIngestionStep as it will no longer be necessary * fix: gwas catalog study curation step * refactor: rename step * perf: repartition study locus before PICS to gain parallellisation * fix: incorrect partitioning * revert: partitioning * fix: drop duplicate rows after ingesting associations * fix: fix in study index ingestion * fix: v1 * feat: working study index with sumstats qc and curation * test: deprecate obsoleted testt * test: remove colon causing tests to fail * test: curation quality controls no longer * fix: changing mapping for ancestries adding CSA * fix: revert changes in mapping --------- Co-authored-by: Daniel Suveges Co-authored-by: Vivien Ho <56025826+vivienho@users.noreply.github.com> Co-authored-by: Yakov Co-authored-by: Szymon Szyszkowski <69353402+project-defiant@users.noreply.github.com> --- .../steps/gwas_catalog_inclusion.md | 5 - .../steps/gwas_catalog_ingestion.md | 5 - .../steps/gwas_catalog_study_index.md | 5 + .../python_api/steps/gwas_catalog_top_hits.md | 5 + src/gentropy/assets/schemas/study_index.json | 31 +-- src/gentropy/config.py | 36 ++-- src/gentropy/dataset/study_index.py | 156 +++++++++++++- .../datasource/gwas_catalog/associations.py | 17 +- .../datasource/gwas_catalog/study_index.py | 152 +++----------- .../gwas_catalog/study_index_ot_curation.py | 90 +++++++++ src/gentropy/gwas_catalog_study_curation.py | 34 ++-- src/gentropy/gwas_catalog_study_inclusion.py | 190 ------------------ src/gentropy/gwas_catalog_study_index.py | 99 +++++++++ ..._ingestion.py => gwas_catalog_top_hits.py} | 40 +--- .../dataset/test_dataset_exclusion.py | 8 +- .../test_gwas_catalog_curation.py | 33 --- .../test_gwas_catalog_study_index.py | 18 -- 17 files changed, 436 insertions(+), 488 deletions(-) delete mode 100644 docs/python_api/steps/gwas_catalog_inclusion.md delete mode 100644 docs/python_api/steps/gwas_catalog_ingestion.md create mode 100644 docs/python_api/steps/gwas_catalog_study_index.md create mode 100644 docs/python_api/steps/gwas_catalog_top_hits.md create mode 100644 src/gentropy/datasource/gwas_catalog/study_index_ot_curation.py delete mode 100644 src/gentropy/gwas_catalog_study_inclusion.py create mode 100644 src/gentropy/gwas_catalog_study_index.py rename src/gentropy/{gwas_catalog_ingestion.py => gwas_catalog_top_hits.py} (59%) diff --git a/docs/python_api/steps/gwas_catalog_inclusion.md b/docs/python_api/steps/gwas_catalog_inclusion.md deleted file mode 100644 index e9ede6dd6..000000000 --- a/docs/python_api/steps/gwas_catalog_inclusion.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: gwas_catalog_study_inclusion ---- - -::: gentropy.gwas_catalog_study_inclusion.GWASCatalogStudyInclusionGenerator diff --git a/docs/python_api/steps/gwas_catalog_ingestion.md b/docs/python_api/steps/gwas_catalog_ingestion.md deleted file mode 100644 index 69ea92479..000000000 --- a/docs/python_api/steps/gwas_catalog_ingestion.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: gwas_catalog_ingestion ---- - -::: gentropy.gwas_catalog_ingestion.GWASCatalogIngestionStep diff --git a/docs/python_api/steps/gwas_catalog_study_index.md b/docs/python_api/steps/gwas_catalog_study_index.md new file mode 100644 index 000000000..4984de2a0 --- /dev/null +++ b/docs/python_api/steps/gwas_catalog_study_index.md @@ -0,0 +1,5 @@ +--- +title: gwas_catalog_study_inclusion +--- + +::: gentropy.gwas_catalog_study_index.GWASCatalogStudyIndexGenerationStep diff --git a/docs/python_api/steps/gwas_catalog_top_hits.md b/docs/python_api/steps/gwas_catalog_top_hits.md new file mode 100644 index 000000000..03d81eafb --- /dev/null +++ b/docs/python_api/steps/gwas_catalog_top_hits.md @@ -0,0 +1,5 @@ +--- +title: GWAS Catalog Top Hits Ingestion Step +--- + +::: gentropy.gwas_catalog_top_hits.GWASCatalogTopHitIngestionStep diff --git a/src/gentropy/assets/schemas/study_index.json b/src/gentropy/assets/schemas/study_index.json index a2dac1bca..9c50d4a19 100644 --- a/src/gentropy/assets/schemas/study_index.json +++ b/src/gentropy/assets/schemas/study_index.json @@ -264,33 +264,12 @@ "metadata": {} }, { - "name": "sumStatQCPerformed", - "type": "boolean", - "nullable": true, - "metadata": {} - }, - { - "name": "sumStatQCValues", + "name": "sumstatQCValues", "type": { - "type": "array", - "elementType": { - "type": "struct", - "fields": [ - { - "name": "QCCheckName", - "type": "string", - "nullable": true, - "metadata": {} - }, - { - "name": "QCCheckValue", - "type": "float", - "nullable": true, - "metadata": {} - } - ] - }, - "containsNull": true + "type": "map", + "keyType": "string", + "valueType": "float", + "valueContainsNull": true }, "nullable": true, "metadata": {} diff --git a/src/gentropy/config.py b/src/gentropy/config.py index 26c676e9b..d47c1b8ab 100644 --- a/src/gentropy/config.py +++ b/src/gentropy/config.py @@ -68,44 +68,36 @@ class GWASCatalogStudyCurationConfig(StepConfig): catalog_study_files: list[str] = MISSING catalog_ancestry_files: list[str] = MISSING - catalog_sumstats_lut: str = MISSING gwas_catalog_study_curation_out: str = MISSING gwas_catalog_study_curation_file: str = MISSING _target_: str = "gentropy.gwas_catalog_study_curation.GWASCatalogStudyCurationStep" @dataclass -class GWASCatalogStudyInclusionConfig(StepConfig): - """GWAS Catalog study inclusion step configuration.""" +class GWASCatalogStudyIndexGenerationStep(StepConfig): + """GWAS Catalog study index generation.""" catalog_study_files: list[str] = MISSING catalog_ancestry_files: list[str] = MISSING - catalog_associations_file: str = MISSING - gwas_catalog_study_curation_file: str = MISSING - variant_annotation_path: str = MISSING - harmonised_study_file: str = MISSING - criteria: str = MISSING - inclusion_list_path: str = MISSING - exclusion_list_path: str = MISSING + study_index_path: str = MISSING + gwas_catalog_study_curation_file: str | None = None + sumstats_qc_path: str | None = None _target_: str = ( - "gentropy.gwas_catalog_study_inclusion.GWASCatalogStudyInclusionGenerator" + "gentropy.gwas_catalog_study_index.GWASCatalogStudyIndexGenerationStep" ) @dataclass -class GWASCatalogIngestionConfig(StepConfig): +class GWASCatalogTopHitIngestionConfig(StepConfig): """GWAS Catalog ingestion step configuration.""" catalog_study_files: list[str] = MISSING catalog_ancestry_files: list[str] = MISSING - catalog_sumstats_lut: str = MISSING catalog_associations_file: str = MISSING variant_annotation_path: str = MISSING catalog_studies_out: str = MISSING catalog_associations_out: str = MISSING - gwas_catalog_study_curation_file: str | None = None - inclusion_list_path: str | None = None - _target_: str = "gentropy.gwas_catalog_ingestion.GWASCatalogIngestionStep" + _target_: str = "gentropy.gwas_catalog_top_hits.GWASCatalogTopHitIngestionStep" @dataclass @@ -658,17 +650,19 @@ def register_config() -> None: ) cs.store( group="step", - name="gwas_catalog_study_inclusion", - node=GWASCatalogStudyInclusionConfig, - ) - cs.store( - group="step", name="gwas_catalog_ingestion", node=GWASCatalogIngestionConfig + name="gwas_catalog_study_index", + node=GWASCatalogStudyIndexGenerationStep, ) cs.store( group="step", name="gwas_catalog_sumstat_preprocess", node=GWASCatalogSumstatsPreprocessConfig, ) + cs.store( + group="step", + name="gwas_catalog_top_hit_ingestion", + node=GWASCatalogTopHitIngestionConfig, + ) cs.store(group="step", name="ld_based_clumping", node=LDBasedClumpingConfig) cs.store(group="step", name="ld_index", node=LDIndexConfig) cs.store(group="step", name="locus_to_gene", node=LocusToGeneConfig) diff --git a/src/gentropy/dataset/study_index.py b/src/gentropy/dataset/study_index.py index e7023ee9b..92bdc61a4 100644 --- a/src/gentropy/dataset/study_index.py +++ b/src/gentropy/dataset/study_index.py @@ -13,6 +13,7 @@ from gentropy.assets import data from gentropy.common.schemas import parse_spark_schema +from gentropy.common.spark_helpers import convert_from_wide_to_long from gentropy.dataset.dataset import Dataset if TYPE_CHECKING: @@ -32,13 +33,29 @@ class StudyQualityCheck(Enum): UNKNOWN_STUDY_TYPE (str): Indicating the provided type of study is not supported. UNKNOWN_BIOSAMPLE (str): Flagging if a biosample identifier is not found in the reference. DUPLICATED_STUDY (str): Flagging if a study identifier is not unique. + SUMSTATS_NOT_AVAILABLE (str): Flagging if harmonized summary statistics are not available or empty. + NO_OT_CURATION (str): Flagging if a study has not been curated by Open Targets. + FAILED_MEAN_BETA_CHECK (str): Flagging if the mean beta QC check value is not within the expected range. + FAILED_PZ_CHECK (str): Flagging if the PZ QC check values are not within the expected range. + FAILED_GC_LAMBDA_CHECK (str): Flagging if the GC lambda value is not within the expected range. + SMALL_NUMBER_OF_SNPS (str): Flagging if the number of SNPs in the study is below the expected threshold. """ - UNRESOLVED_TARGET = "Target/gene identifier could not match to reference." - UNRESOLVED_DISEASE = "No valid disease identifier found." - UNKNOWN_STUDY_TYPE = "This type of study is not supported." - UNKNOWN_BIOSAMPLE = "Biosample identifier was not found in the reference." - DUPLICATED_STUDY = "The identifier of this study is not unique." + UNRESOLVED_TARGET = "Target/gene identifier could not match to reference" + UNRESOLVED_DISEASE = "No valid disease identifier found" + UNKNOWN_STUDY_TYPE = "This type of study is not supported" + UNKNOWN_BIOSAMPLE = "Biosample identifier was not found in the reference" + DUPLICATED_STUDY = "The identifier of this study is not unique" + SUMSTATS_NOT_AVAILABLE = "Harmonized summary statistics are not available or empty" + NO_OT_CURATION = "GWAS Catalog study has not been curated by Open Targets" + FAILED_MEAN_BETA_CHECK = ( + "The mean beta QC check value is not within the expected range" + ) + FAILED_PZ_CHECK = "The PZ QC check values are not within the expected range" + FAILED_GC_LAMBDA_CHECK = "The GC lambda value is not within the expected range" + SMALL_NUMBER_OF_SNPS = ( + "The number of SNPs in the study is below the expected threshold" + ) @dataclass @@ -410,7 +427,9 @@ def validate_target(self: StudyIndex, target_index: GeneIndex) -> StudyIndex: return StudyIndex(_df=validated_df, _schema=StudyIndex.get_schema()) - def validate_biosample(self: StudyIndex, biosample_index: BiosampleIndex) -> StudyIndex: + def validate_biosample( + self: StudyIndex, biosample_index: BiosampleIndex + ) -> StudyIndex: """Validating biosample identifiers in the study index against the provided biosample index. Args: @@ -419,7 +438,9 @@ def validate_biosample(self: StudyIndex, biosample_index: BiosampleIndex) -> Stu Returns: StudyIndex: where non-gwas studies are flagged if biosampleIndex could not be validated. """ - biosample_set = biosample_index.df.select("biosampleId", f.lit(True).alias("isIdFound")) + biosample_set = biosample_index.df.select( + "biosampleId", f.lit(True).alias("isIdFound") + ) # If biosampleId in df, we need to drop it: if "biosampleId" in self.df.columns: @@ -430,7 +451,11 @@ def validate_biosample(self: StudyIndex, biosample_index: BiosampleIndex) -> Stu return self validated_df = ( - self.df.join(biosample_set, self.df.biosampleFromSourceId == biosample_set.biosampleId, how="left") + self.df.join( + biosample_set, + self.df.biosampleFromSourceId == biosample_set.biosampleId, + how="left", + ) .withColumn( "isIdFound", f.when( @@ -450,3 +475,118 @@ def validate_biosample(self: StudyIndex, biosample_index: BiosampleIndex) -> Stu ) return StudyIndex(_df=validated_df, _schema=StudyIndex.get_schema()) + + def annotate_sumstats_qc( + self: StudyIndex, + sumstats_qc: DataFrame, + threshold_mean_beta: float = 0.05, + threshold_mean_diff_pz: float = 0.05, + threshold_se_diff_pz: float = 0.05, + threshold_min_gc_lambda: float = 0.7, + threshold_max_gc_lambda: float = 2.5, + threshold_min_n_variants: int = 2_000_000, + ) -> StudyIndex: + """Annotate summary stats QC information. + + Args: + sumstats_qc (DataFrame): containing summary statistics-based quality controls. + threshold_mean_beta (float): Threshold for mean beta check. Defaults to 0.05. + threshold_mean_diff_pz (float): Threshold for mean diff PZ check. Defaults to 0.05. + threshold_se_diff_pz (float): Threshold for SE diff PZ check. Defaults to 0.05. + threshold_min_gc_lambda (float): Minimum threshold for GC lambda check. Defaults to 0.7. + threshold_max_gc_lambda (float): Maximum threshold for GC lambda check. Defaults to 2.5. + threshold_min_n_variants (int): Minimum number of variants for SuSiE check. Defaults to 2_000_000. + + Returns: + StudyIndex: Updated study index with QC information + """ + # convert all columns in sumstats_qc dataframe in array of structs grouped by studyId + cols = [c for c in sumstats_qc.columns if c != "studyId"] + + studies = self.df + + melted_df = convert_from_wide_to_long( + sumstats_qc, + id_vars=["studyId"], + value_vars=cols, + var_name="QCCheckName", + value_name="QCCheckValue", + ) + + qc_df = ( + melted_df.groupBy("studyId") + .agg( + f.map_from_entries( + f.collect_list( + f.struct(f.col("QCCheckName"), f.col("QCCheckValue")) + ) + ).alias("sumStatQCValues") + ) + .select("studyId", "sumstatQCValues") + ) + + df = ( + studies.drop("sumStatQCValues", "hasSumstats") + .join( + qc_df.withColumn("hasSumstats", f.lit(True)), how="left", on="studyId" + ) + .withColumn("hasSumstats", f.coalesce(f.col("hasSumstats"), f.lit(False))) + .withColumn( + "qualityControls", + StudyIndex.update_quality_flag( + f.col("qualityControls"), + ~f.col("hasSumstats"), + StudyQualityCheck.SUMSTATS_NOT_AVAILABLE, + ), + ) + .withColumn( + "qualityControls", + StudyIndex.update_quality_flag( + f.col("qualityControls"), + ~(f.abs(f.col("sumstatQCValues.mean_beta")) <= threshold_mean_beta), + StudyQualityCheck.FAILED_MEAN_BETA_CHECK, + ), + ) + .withColumn( + "qualityControls", + StudyIndex.update_quality_flag( + f.col("qualityControls"), + ~( + ( + f.abs(f.col("sumstatQCValues.mean_diff_pz")) + <= threshold_mean_diff_pz + ) + & (f.col("sumstatQCValues.se_diff_pz") <= threshold_se_diff_pz) + ), + StudyQualityCheck.FAILED_PZ_CHECK, + ), + ) + .withColumn( + "qualityControls", + StudyIndex.update_quality_flag( + f.col("qualityControls"), + ~( + (f.col("sumstatQCValues.gc_lambda") <= threshold_max_gc_lambda) + & ( + f.col("sumstatQCValues.gc_lambda") + >= threshold_min_gc_lambda + ) + ), + StudyQualityCheck.FAILED_GC_LAMBDA_CHECK, + ), + ) + .withColumn( + "qualityControls", + StudyIndex.update_quality_flag( + f.col("qualityControls"), + (f.col("sumstatQCValues.n_variants") < threshold_min_n_variants), + StudyQualityCheck.SMALL_NUMBER_OF_SNPS, + ), + ) + ) + + # Annotate study index with QC information: + return StudyIndex( + _df=df, + _schema=StudyIndex.get_schema(), + ) diff --git a/src/gentropy/datasource/gwas_catalog/associations.py b/src/gentropy/datasource/gwas_catalog/associations.py index b34944b11..da2bcc6df 100644 --- a/src/gentropy/datasource/gwas_catalog/associations.py +++ b/src/gentropy/datasource/gwas_catalog/associations.py @@ -230,7 +230,9 @@ def _map_variants_to_gnomad_variants( "chromosome", # Calculate the position in Ensembl coordinates for indels: GWASCatalogCuratedAssociationsParser.convert_gnomad_position_to_ensembl( - f.col("position"), f.col("referenceAllele"), f.col("alternateAllele") + f.col("position"), + f.col("referenceAllele"), + f.col("alternateAllele"), ).alias("ensemblPosition"), # Keeping GnomAD position: "position", @@ -240,11 +242,7 @@ def _map_variants_to_gnomad_variants( "alleleFrequencies", variant_index.max_maf().alias("maxMaf"), ).join( - f.broadcast( - gwas_associations_subset.select( - "chromosome", "ensemblPosition" - ).distinct() - ), + gwas_associations_subset.select("chromosome", "ensemblPosition").distinct(), on=["chromosome", "ensemblPosition"], how="inner", ) @@ -253,7 +251,7 @@ def _map_variants_to_gnomad_variants( # based on rsIds or allele concordance) filtered_associations = ( gwas_associations_subset.join( - f.broadcast(va_subset), + va_subset, on=["chromosome", "ensemblPosition"], how="left", ) @@ -1108,7 +1106,10 @@ def from_source( pvalue_threshold is keeped in sync with the WindowBasedClumpingStep gwas_significance. """ return StudyLocusGWASCatalog( - _df=gwas_associations.withColumn( + _df=gwas_associations + # drop duplicate rows + .distinct() + .withColumn( "studyLocusId", f.monotonically_increasing_id().cast(StringType()) ) .transform( diff --git a/src/gentropy/datasource/gwas_catalog/study_index.py b/src/gentropy/datasource/gwas_catalog/study_index.py index d0d841105..421f53d0f 100644 --- a/src/gentropy/datasource/gwas_catalog/study_index.py +++ b/src/gentropy/datasource/gwas_catalog/study_index.py @@ -7,61 +7,15 @@ import pyspark.sql.functions as f import pyspark.sql.types as t -from pyspark import SparkFiles -from gentropy.common.session import Session from gentropy.common.spark_helpers import column2camel_case from gentropy.common.utils import parse_efos -from gentropy.dataset.study_index import StudyIndex +from gentropy.dataset.study_index import StudyIndex, StudyQualityCheck if TYPE_CHECKING: from pyspark.sql import Column, DataFrame -def read_curation_table( - curation_path: str | None, session: Session -) -> DataFrame | None: - """Read curation table if path or URL is given. - - Curation itself is fully optional everything should work without it. - - Args: - curation_path (str | None): Optionally given path the curation tsv. - session (Session): session object - - Returns: - DataFrame | None: if curation was provided, - """ - # If no curation path provided, we are returning none: - if curation_path is None: - return None - # Read curation from the web: - elif curation_path.startswith("http"): - # Registering file: - session.spark.sparkContext.addFile(curation_path) - - # Reading file: - curation_df = session.spark.read.csv( - SparkFiles.get(curation_path.split("/")[-1]), sep="\t", header=True - ) - # Read curation from file: - else: - curation_df = session.spark.read.csv(curation_path, sep="\t", header=True) - return curation_df.select( - "studyId", - "studyType", - f.when(f.col("analysisFlag").isNotNull(), f.split(f.col("analysisFlag"), r"\|")) - .otherwise(f.array()) - .alias("analysisFlags"), - f.when( - f.col("qualityControl").isNotNull(), f.split(f.col("qualityControl"), r"\|") - ) - .otherwise(f.array()) - .alias("qualityControls"), - f.col("isCurated").cast(t.BooleanType()), - ) - - @dataclass class StudyIndexGWASCatalogParser: """GWAS Catalog study index parser. @@ -316,14 +270,12 @@ def from_source( cls: type[StudyIndexGWASCatalogParser], catalog_studies: DataFrame, ancestry_file: DataFrame, - sumstats_lut: DataFrame, ) -> StudyIndexGWASCatalog: """Ingests study level metadata from the GWAS Catalog. Args: catalog_studies (DataFrame): GWAS Catalog raw study table ancestry_file (DataFrame): GWAS Catalog ancestry table. - sumstats_lut (DataFrame): GWAS Catalog summary statistics list. Returns: StudyIndexGWASCatalog: Parsed and annotated GWAS Catalog study table. @@ -332,7 +284,6 @@ def from_source( return ( cls._parse_study_table(catalog_studies) .annotate_ancestries(ancestry_file) - .annotate_sumstats_info(sumstats_lut) .annotate_discovery_sample_sizes() ) @@ -403,7 +354,13 @@ def annotate_from_study_curation( if curation_table is None: return self - columns = self.df.columns + studies = self.df + + if "qualityControls" not in studies.columns: + studies = studies.withColumn("qualityControls", f.array()) + + if "analysisFlags" not in studies.columns: + studies = studies.withColumn("analysisFlags", f.array()) # Adding prefix to columns in the curation table: curation_table = curation_table.select( @@ -415,46 +372,34 @@ def annotate_from_study_curation( ] ) - # Create expression how to update/create quality controls dataset: - qualityControls_expression = ( - f.col("curation_qualityControls") - if "qualityControls" not in columns - else f.when( - f.col("curation_qualityControls").isNotNull(), - f.array_union( - f.col("qualityControls"), f.array(f.col("curation_qualityControls")) - ), - ).otherwise(f.col("qualityControls")) - ) - - # Create expression how to update/create analysis flag: - analysis_expression = ( - f.col("curation_analysisFlags") - if "analysisFlags" not in columns - else f.when( - f.col("curation_analysisFlags").isNotNull(), - f.array_union( - f.col("analysisFlags"), f.array(f.col("curation_analysisFlags")) - ), - ).otherwise(f.col("analysisFlags")) - ) - - # Updating columns list. We might or might not list columns twice, but that doesn't matter, unique set will generated: - columns = list(set(columns + ["qualityControls", "analysisFlags"])) - # Based on the curation table, columns needs to be updated: curated_df = ( - self.df.join(curation_table, on="studyId", how="left") + studies.join( + curation_table.withColumn("isCurated", f.lit(True)), + on="studyId", + how="left", + ) + .withColumn("isCurated", f.coalesce(f.col("isCurated"), f.lit(False))) # Updating study type: .withColumn( "studyType", f.coalesce(f.col("curation_studyType"), f.col("studyType")) ) - # Updating quality controls: - .withColumn("qualityControls", qualityControls_expression) # Updating study annotation flags: - .withColumn("analysisFlags", analysis_expression) + .withColumn( + "analysisFlags", + f.array_union(f.col("analysisFlags"), f.col("curation_analysisFlags")), + ) + .withColumn("analysisFlags", f.coalesce(f.col("analysisFlags"), f.array())) + .withColumn( + "qualityControls", + StudyIndex.update_quality_flag( + f.col("qualityControls"), + ~f.col("isCurated"), + StudyQualityCheck.NO_OT_CURATION, + ), + ) # Dropping columns coming from the curation table: - .select(*columns) + .select(*studies.columns) ) return StudyIndexGWASCatalog( _df=curated_df, _schema=StudyIndexGWASCatalog.get_schema() @@ -641,47 +586,6 @@ def annotate_ancestries( self.df = self.df.join(parsed_ancestry_lut, on="studyId", how="left") return self - def annotate_sumstats_info( - self: StudyIndexGWASCatalog, sumstats_lut: DataFrame - ) -> StudyIndexGWASCatalog: - """Annotate summary stat locations. - - Args: - sumstats_lut (DataFrame): listing GWAS Catalog summary stats paths - - Returns: - StudyIndexGWASCatalog: including `summarystatsLocation` and `hasSumstats` columns - - Raises: - ValueError: if the sumstats_lut table doesn't have the right columns - """ - gwas_sumstats_base_uri = ( - "ftp://ftp.ebi.ac.uk/pub/databases/gwas/summary_statistics/" - ) - - if "_c0" not in sumstats_lut.columns: - raise ValueError( - f'Sumstats look-up table needs to have `_c0` column. However it has: {",".join(sumstats_lut.columns)}' - ) - - parsed_sumstats_lut = sumstats_lut.withColumn( - "summarystatsLocation", - f.concat( - f.lit(gwas_sumstats_base_uri), - f.regexp_replace(f.col("_c0"), r"^\.\/", ""), - ), - ).select( - self._parse_gwas_catalog_study_id("summarystatsLocation").alias("studyId"), - "summarystatsLocation", - f.lit(True).alias("hasSumstats"), - ) - self.df = ( - self.df.drop("hasSumstats") - .join(parsed_sumstats_lut, on="studyId", how="left") - .withColumn("hasSumstats", f.coalesce(f.col("hasSumstats"), f.lit(False))) - ) - return self - def annotate_discovery_sample_sizes( self: StudyIndexGWASCatalog, ) -> StudyIndexGWASCatalog: diff --git a/src/gentropy/datasource/gwas_catalog/study_index_ot_curation.py b/src/gentropy/datasource/gwas_catalog/study_index_ot_curation.py new file mode 100644 index 000000000..8d75e4824 --- /dev/null +++ b/src/gentropy/datasource/gwas_catalog/study_index_ot_curation.py @@ -0,0 +1,90 @@ +"""Study Index for GWAS Catalog data source.""" + +from __future__ import annotations + +from dataclasses import dataclass +from typing import TYPE_CHECKING + +import pyspark.sql.functions as f +import pyspark.sql.types as t +from pyspark import SparkFiles + +from gentropy.common.session import Session + +if TYPE_CHECKING: + from pyspark.sql import DataFrame + + +@dataclass +class StudyIndexGWASCatalogOTCuration: + """Study Index Curation for GWAS Catalog data source. + + This class is responsible for parsing additional curation for the GWAS Catalog studies. + """ + + @staticmethod + def _parser(df: DataFrame) -> DataFrame: + """Parse the curation table. + + Args: + df (DataFrame): DataFrame with the curation table. + + Returns: + DataFrame: DataFrame with the parsed curation table. + """ + if "qualityControl" not in df.columns: + # Add the 'qualityControl' column with null values + df = df.withColumn("qualityControl", f.lit(None).cast("string")) + return df.select( + "studyId", + "studyType", + f.when( + f.col("analysisFlag").isNotNull(), f.split(f.col("analysisFlag"), r"\|") + ) + .otherwise(f.array()) + .alias("analysisFlags"), + f.when( + f.col("qualityControl").isNotNull(), + f.split(f.col("qualityControl"), r"\|"), + ) + .otherwise(f.array()) + .alias("qualityControls"), + f.col("isCurated").cast(t.BooleanType()), + ) + + @classmethod + def from_csv( + cls: type[StudyIndexGWASCatalogOTCuration], session: Session, curation_path: str + ) -> DataFrame: + """Read curation table from csv. + + Args: + session (Session): Session object. + curation_path (str): Path to the curation table. + + Returns: + DataFrame: DataFrame with the curation table. + """ + return cls._parser(session.spark.read.csv(curation_path, sep="\t", header=True)) + + @classmethod + def from_url( + cls: type[StudyIndexGWASCatalogOTCuration], session: Session, curation_url: str + ) -> DataFrame: + """Read curation table from URL. + + Args: + session (Session): Session object. + curation_url (str): URL to the curation table. + + Returns: + DataFrame: DataFrame with the curation table. + """ + # Registering file: + session.spark.sparkContext.addFile(curation_url) + + return cls._parser( + session.spark.read.csv( + SparkFiles.get(curation_url.split("/")[-1]), sep="\t", header=True + ) + ) diff --git a/src/gentropy/gwas_catalog_study_curation.py b/src/gentropy/gwas_catalog_study_curation.py index 7329a1679..530e03ea6 100644 --- a/src/gentropy/gwas_catalog_study_curation.py +++ b/src/gentropy/gwas_catalog_study_curation.py @@ -1,10 +1,13 @@ """Step to update GWAS Catalog study curation file based on newly released GWAS Catalog dataset.""" + from __future__ import annotations from gentropy.common.session import Session from gentropy.datasource.gwas_catalog.study_index import ( StudyIndexGWASCatalogParser, - read_curation_table, +) +from gentropy.datasource.gwas_catalog.study_index_ot_curation import ( + StudyIndexGWASCatalogOTCuration, ) @@ -16,7 +19,6 @@ def __init__( session: Session, catalog_study_files: list[str], catalog_ancestry_files: list[str], - catalog_sumstats_lut: str, gwas_catalog_study_curation_out: str, gwas_catalog_study_curation_file: str | None, ) -> None: @@ -26,9 +28,11 @@ def __init__( session (Session): Session object. catalog_study_files (list[str]): List of raw GWAS catalog studies file. catalog_ancestry_files (list[str]): List of raw ancestry annotations files from GWAS Catalog. - catalog_sumstats_lut (str): GWAS Catalog summary statistics lookup table. gwas_catalog_study_curation_out (str): Path for the updated curation table. gwas_catalog_study_curation_file (str | None): Path to the original curation table. Optinal + + Raises: + ValueError: If the curation file is provided but not a CSV file or URL. """ catalog_studies = session.spark.read.csv( list(catalog_study_files), sep="\t", header=True @@ -36,18 +40,24 @@ def __init__( ancestry_lut = session.spark.read.csv( list(catalog_ancestry_files), sep="\t", header=True ) - sumstats_lut = session.spark.read.csv( - catalog_sumstats_lut, sep="\t", header=False - ) - gwas_catalog_study_curation = read_curation_table( - gwas_catalog_study_curation_file, session - ) + + if gwas_catalog_study_curation_file: + if gwas_catalog_study_curation_file.endswith(".csv"): + gwas_catalog_study_curation = StudyIndexGWASCatalogOTCuration.from_csv( + session, gwas_catalog_study_curation_file + ) + elif gwas_catalog_study_curation_file.startswith("http"): + gwas_catalog_study_curation = StudyIndexGWASCatalogOTCuration.from_url( + session, gwas_catalog_study_curation_file + ) + else: + raise ValueError( + "Only CSV files or URLs are accepted as curation file." + ) # Process GWAS Catalog studies and get list of studies for curation: ( - StudyIndexGWASCatalogParser.from_source( - catalog_studies, ancestry_lut, sumstats_lut - ) + StudyIndexGWASCatalogParser.from_source(catalog_studies, ancestry_lut) # Adding existing curation: .annotate_from_study_curation(gwas_catalog_study_curation) # Extract new studies for curation: diff --git a/src/gentropy/gwas_catalog_study_inclusion.py b/src/gentropy/gwas_catalog_study_inclusion.py deleted file mode 100644 index f07f851a7..000000000 --- a/src/gentropy/gwas_catalog_study_inclusion.py +++ /dev/null @@ -1,190 +0,0 @@ -"""Step to generate an GWAS Catalog study identifier inclusion and exclusion list.""" - -from __future__ import annotations - -from typing import TYPE_CHECKING - -from pyspark.sql import functions as f - -from gentropy.common.session import Session -from gentropy.dataset.variant_index import VariantIndex -from gentropy.datasource.gwas_catalog.associations import ( - GWASCatalogCuratedAssociationsParser, -) -from gentropy.datasource.gwas_catalog.study_index import ( - StudyIndexGWASCatalog, - StudyIndexGWASCatalogParser, - read_curation_table, -) -from gentropy.datasource.gwas_catalog.study_splitter import GWASCatalogStudySplitter - -if TYPE_CHECKING: - from pyspark.sql import Column, DataFrame - - -class GWASCatalogStudyInclusionGenerator: - """GWAS Catalog study eligibility for ingestion based on curation and the provided criteria.""" - - @staticmethod - def flag_eligible_studies( - study_index: StudyIndexGWASCatalog, criteria: str - ) -> DataFrame: - """Apply filter on GWAS Catalog studies based on the provided criteria. - - Args: - study_index (StudyIndexGWASCatalog): complete study index to be filtered based on the provided filter set - criteria (str): name of the filter set to be applied. - - Raises: - ValueError: if the provided filter set is not in the accepted values. - - Returns: - DataFrame: filtered dataframe containing only eligible studies. - """ - filters: dict[str, Column] = { - # Filters applied on studies for ingesting curated associations: - "curation": (study_index.is_gwas() & study_index.has_mapped_trait()), - # Filters applied on studies for ingesting summary statistics: - "summary_stats": ( - study_index.is_gwas() - & study_index.has_mapped_trait() - & (~study_index.is_quality_flagged()) - & study_index.has_summarystats() - ), - } - - if criteria not in filters: - raise ValueError( - f'Wrong value as filter set ({criteria}). Accepted: {",".join(filters.keys())}' - ) - - # Applying the relevant filter to the study: - return study_index.df.select( - "studyId", - "studyType", - "traitFromSource", - "traitFromSourceMappedIds", - "qualityControls", - "hasSumstats", - filters[criteria].alias("isEligible"), - ) - - @staticmethod - def process_harmonised_list(studies: list[str], session: Session) -> DataFrame: - """Generate spark dataframe from the provided list. - - Args: - studies (list[str]): list of path pointing to harmonised summary statistics. - session (Session): session - - Returns: - DataFrame: column name is consistent with original implementatin - """ - return session.spark.createDataFrame([{"_c0": path} for path in studies]) - - @staticmethod - def get_gwas_catalog_study_index( - session: Session, - gnomad_variant_path: str, - catalog_study_files: list[str], - catalog_ancestry_files: list[str], - harmonised_study_file: str, - catalog_associations_file: str, - gwas_catalog_study_curation_file: str, - ) -> StudyIndexGWASCatalog: - """Return GWAS Catalog study index. - - Args: - session (Session): Session object. - gnomad_variant_path (str): Path to GnomAD variant list. - catalog_study_files (list[str]): List of raw GWAS catalog studies file. - catalog_ancestry_files (list[str]): List of raw ancestry annotations files from GWAS Catalog. - harmonised_study_file (str): GWAS Catalog summary statistics lookup table. - catalog_associations_file (str): Raw GWAS catalog associations file. - gwas_catalog_study_curation_file (str): file of the curation table. Optional. - - Returns: - StudyIndexGWASCatalog: Completely processed and fully annotated study index. - """ - # Extract - gnomad_variants = VariantIndex.from_parquet(session, gnomad_variant_path) - catalog_studies = session.spark.read.csv( - list(catalog_study_files), sep="\t", header=True - ) - ancestry_lut = session.spark.read.csv( - list(catalog_ancestry_files), sep="\t", header=True - ) - sumstats_lut = session.spark.read.csv( - harmonised_study_file, sep="\t", header=False - ) - catalog_associations = session.spark.read.csv( - catalog_associations_file, sep="\t", header=True - ).persist() - gwas_catalog_study_curation = read_curation_table( - gwas_catalog_study_curation_file, session - ) - - # Transform - study_index, _ = GWASCatalogStudySplitter.split( - StudyIndexGWASCatalogParser.from_source( - catalog_studies, - ancestry_lut, - sumstats_lut, - ).annotate_from_study_curation(gwas_catalog_study_curation), - GWASCatalogCuratedAssociationsParser.from_source( - catalog_associations, gnomad_variants - ), - ) - - return study_index - - def __init__( - self, - session: Session, - catalog_study_files: list[str], - catalog_ancestry_files: list[str], - catalog_associations_file: str, - gwas_catalog_study_curation_file: str, - gnomad_variant_path: str, - harmonised_study_file: str, - criteria: str, - inclusion_list_path: str, - exclusion_list_path: str, - ) -> None: - """Run step. - - Args: - session (Session): Session objecct. - catalog_study_files (list[str]): List of raw GWAS catalog studies file. - catalog_ancestry_files (list[str]): List of raw ancestry annotations files from GWAS Catalog. - catalog_associations_file (str): Raw GWAS catalog associations file. - gwas_catalog_study_curation_file (str): file of the curation table. Optional. - gnomad_variant_path (str): Path to GnomAD variant list. - harmonised_study_file (str): GWAS Catalog summary statistics lookup table. - criteria (str): name of the filter set to be applied. - inclusion_list_path (str): Output path for the inclusion list. - exclusion_list_path (str): Output path for the exclusion list. - """ - # Create study index: - study_index = self.get_gwas_catalog_study_index( - session, - gnomad_variant_path, - catalog_study_files, - catalog_ancestry_files, - harmonised_study_file, - catalog_associations_file, - gwas_catalog_study_curation_file, - ) - - # Get study indices for inclusion: - flagged_studies = self.flag_eligible_studies(study_index, criteria) - - # Output inclusion list: - eligible = ( - flagged_studies.filter(f.col("isEligible")).select("studyId").persist() - ) - eligible.write.mode(session.write_mode).parquet(inclusion_list_path) - - # Output exclusion list: - excluded = flagged_studies.filter(~f.col("isEligible")).persist() - excluded.write.mode(session.write_mode).parquet(exclusion_list_path) diff --git a/src/gentropy/gwas_catalog_study_index.py b/src/gentropy/gwas_catalog_study_index.py new file mode 100644 index 000000000..6c19b6909 --- /dev/null +++ b/src/gentropy/gwas_catalog_study_index.py @@ -0,0 +1,99 @@ +"""Step to generate an GWAS Catalog study identifier inclusion and exclusion list.""" + +from __future__ import annotations + +from pyspark.sql.types import DoubleType, LongType, StringType, StructField, StructType + +from gentropy.common.session import Session +from gentropy.datasource.gwas_catalog.study_index import StudyIndexGWASCatalogParser +from gentropy.datasource.gwas_catalog.study_index_ot_curation import ( + StudyIndexGWASCatalogOTCuration, +) + + +class GWASCatalogStudyIndexGenerationStep: + """GWAS Catalog study index generation. + + This step generates a study index from the GWAS Catalog studies and ancestry files. It can also add additional curation information and summary statistics QC information when available. + + ''' warning + This step does not generate study index for gwas catalog top hits. + + This step provides several optional arguments to add additional information to the study index: + + - gwas_catalog_study_curation_file: csv file or URL containing the curation table. If provided it annotates the study index with the additional curation information performed by the Open Targets team. + - sumstats_qc_path: Path to the summary statistics QC table. If provided it annotates the study index with the summary statistics QC information in the `sumStatQCValues` columns (e.g. `n_variants`, `n_variants_sig` etc.). + """ + + def __init__( + self, + session: Session, + catalog_study_files: list[str], + catalog_ancestry_files: list[str], + study_index_path: str, + gwas_catalog_study_curation_file: str | None = None, + sumstats_qc_path: str | None = None, + ) -> None: + """Run step. + + Args: + session (Session): Session objecct. + catalog_study_files (list[str]): List of raw GWAS catalog studies file. + catalog_ancestry_files (list[str]): List of raw ancestry annotations files from GWAS Catalog. + study_index_path (str): Output GWAS catalog studies path. + gwas_catalog_study_curation_file (str | None): csv file or URL containing the curation table. Optional. + sumstats_qc_path (str | None): Path to the summary statistics QC table. Optional. + + Raises: + ValueError: If the curation file is provided but not a CSV file or URL. + """ + # Core Study Index Generation: + study_index = StudyIndexGWASCatalogParser.from_source( + session.spark.read.csv(list(catalog_study_files), sep="\t", header=True), + session.spark.read.csv(list(catalog_ancestry_files), sep="\t", header=True), + ) + + # Annotate with curation if provided: + if gwas_catalog_study_curation_file: + if gwas_catalog_study_curation_file.endswith( + ".tsv" + ) | gwas_catalog_study_curation_file.endswith(".tsv"): + gwas_catalog_study_curation = StudyIndexGWASCatalogOTCuration.from_csv( + session, gwas_catalog_study_curation_file + ) + elif gwas_catalog_study_curation_file.startswith("http"): + gwas_catalog_study_curation = StudyIndexGWASCatalogOTCuration.from_url( + session, gwas_catalog_study_curation_file + ) + else: + raise ValueError( + "Only CSV/TSV files or URLs are accepted as curation file." + ) + study_index = study_index.annotate_from_study_curation( + gwas_catalog_study_curation + ) + + # Annotate with sumstats QC if provided: + if sumstats_qc_path: + schema = StructType( + [ + StructField("studyId", StringType(), True), + StructField("mean_beta", DoubleType(), True), + StructField("mean_diff_pz", DoubleType(), True), + StructField("se_diff_pz", DoubleType(), True), + StructField("gc_lambda", DoubleType(), True), + StructField("n_variants", LongType(), True), + StructField("n_variants_sig", LongType(), True), + ] + ) + sumstats_qc = session.spark.read.schema(schema).parquet( + sumstats_qc_path, recursiveFileLookup=True + ) + study_index_with_qc = study_index.annotate_sumstats_qc(sumstats_qc) + + # Write the study + study_index_with_qc.df.write.mode(session.write_mode).parquet( + study_index_path + ) + else: + study_index.df.write.mode(session.write_mode).parquet(study_index_path) diff --git a/src/gentropy/gwas_catalog_ingestion.py b/src/gentropy/gwas_catalog_top_hits.py similarity index 59% rename from src/gentropy/gwas_catalog_ingestion.py rename to src/gentropy/gwas_catalog_top_hits.py index 5dab5bf16..95722c768 100644 --- a/src/gentropy/gwas_catalog_ingestion.py +++ b/src/gentropy/gwas_catalog_top_hits.py @@ -10,30 +10,23 @@ ) from gentropy.datasource.gwas_catalog.study_index import ( StudyIndexGWASCatalogParser, - read_curation_table, ) from gentropy.datasource.gwas_catalog.study_splitter import GWASCatalogStudySplitter -class GWASCatalogIngestionStep: - """GWAS Catalog ingestion step to extract GWASCatalog Study and StudyLocus tables. - - !!! note This step currently only processes the GWAS Catalog curated list of top hits. - """ +class GWASCatalogTopHitIngestionStep: + """GWAS Catalog ingestion step to extract GWASCatalog top hits.""" def __init__( self, session: Session, catalog_study_files: list[str], catalog_ancestry_files: list[str], - catalog_sumstats_lut: str, catalog_associations_file: str, - gnomad_variant_path: str, + variant_annotation_path: str, catalog_studies_out: str, catalog_associations_out: str, distance: int = WindowBasedClumpingStepConfig().distance, - gwas_catalog_study_curation_file: str | None = None, - inclusion_list_path: str | None = None, ) -> None: """Run step. @@ -41,52 +34,31 @@ def __init__( session (Session): Session object. catalog_study_files (list[str]): List of raw GWAS catalog studies file. catalog_ancestry_files (list[str]): List of raw ancestry annotations files from GWAS Catalog. - catalog_sumstats_lut (str): GWAS Catalog summary statistics lookup table. catalog_associations_file (str): Raw GWAS catalog associations file. - gnomad_variant_path (str): Path to GnomAD variants. + variant_annotation_path (str): Path to GnomAD variants. catalog_studies_out (str): Output GWAS catalog studies path. catalog_associations_out (str): Output GWAS catalog associations path. distance (int): Distance, within which tagging variants are collected around the semi-index. - gwas_catalog_study_curation_file (str | None): file of the curation table. Optional. - inclusion_list_path (str | None): optional inclusion list (parquet) """ # Extract - gnomad_variants = VariantIndex.from_parquet(session, gnomad_variant_path) + gnomad_variants = VariantIndex.from_parquet(session, variant_annotation_path) catalog_studies = session.spark.read.csv( list(catalog_study_files), sep="\t", header=True ) ancestry_lut = session.spark.read.csv( list(catalog_ancestry_files), sep="\t", header=True ) - sumstats_lut = session.spark.read.csv( - catalog_sumstats_lut, sep="\t", header=False - ) catalog_associations = session.spark.read.csv( catalog_associations_file, sep="\t", header=True ).persist() - gwas_catalog_study_curation = read_curation_table( - gwas_catalog_study_curation_file, session - ) # Transform study_index, study_locus = GWASCatalogStudySplitter.split( - StudyIndexGWASCatalogParser.from_source( - catalog_studies, ancestry_lut, sumstats_lut - ).annotate_from_study_curation(gwas_catalog_study_curation), + StudyIndexGWASCatalogParser.from_source(catalog_studies, ancestry_lut), GWASCatalogCuratedAssociationsParser.from_source( catalog_associations, gnomad_variants ), ) - - # if inclusion list is provided apply filter: - if inclusion_list_path: - inclusion_list = session.spark.read.parquet( - inclusion_list_path, sep="\t", header=True - ) - - study_index = study_index.apply_inclusion_list(inclusion_list) - study_locus = study_locus.apply_inclusion_list(inclusion_list) - # Load study_index.df.write.mode(session.write_mode).parquet(catalog_studies_out) diff --git a/tests/gentropy/dataset/test_dataset_exclusion.py b/tests/gentropy/dataset/test_dataset_exclusion.py index 329a0a1d5..1b6fce967 100644 --- a/tests/gentropy/dataset/test_dataset_exclusion.py +++ b/tests/gentropy/dataset/test_dataset_exclusion.py @@ -24,11 +24,11 @@ class TestDataExclusion: # Good study no flag: ("S1", None), # Good study permissive flag: - ("S2", "This type of study is not supported."), - ("S2", "No valid disease identifier found."), + ("S2", "This type of study is not supported"), + ("S2", "No valid disease identifier found"), # Bad study: - ("S3", "The identifier of this study is not unique."), - ("S3", "This type of study is not supported."), + ("S3", "The identifier of this study is not unique"), + ("S3", "This type of study is not supported"), ] @pytest.fixture(autouse=True) diff --git a/tests/gentropy/datasource/gwas_catalog/test_gwas_catalog_curation.py b/tests/gentropy/datasource/gwas_catalog/test_gwas_catalog_curation.py index 4163531cb..0dd1a7363 100644 --- a/tests/gentropy/datasource/gwas_catalog/test_gwas_catalog_curation.py +++ b/tests/gentropy/datasource/gwas_catalog/test_gwas_catalog_curation.py @@ -143,39 +143,6 @@ def test_curation__study_type_update( assert expected == observed - # Test update qc flag - @staticmethod - def test_curation__quality_controls( - mock_gwas_study_index: StudyIndexGWASCatalog, mock_study_curation: DataFrame - ) -> None: - """Test for making sure the study type got updated.""" - curated = mock_gwas_study_index.annotate_from_study_curation( - mock_study_curation - ) - - # Expected studyIds: - expected = [ - row["studyId"] - for row in ( - mock_study_curation.filter(f.col("qualityControls").isNotNull()) - .select("studyId") - .distinct() - .collect() - ) - ] - - observed = [ - row["studyId"] - for row in ( - curated.df.filter(f.size(f.col("qualityControls")) > 0) - .select("studyId") - .distinct() - .collect() - ) - ] - - assert expected == observed - # Test updated method flag @staticmethod def test_curation__analysis_flags( diff --git a/tests/gentropy/datasource/gwas_catalog/test_gwas_catalog_study_index.py b/tests/gentropy/datasource/gwas_catalog/test_gwas_catalog_study_index.py index b91529b3d..b3ff4e486 100644 --- a/tests/gentropy/datasource/gwas_catalog/test_gwas_catalog_study_index.py +++ b/tests/gentropy/datasource/gwas_catalog/test_gwas_catalog_study_index.py @@ -31,25 +31,8 @@ def test_parse_study_table(sample_gwas_catalog_studies: DataFrame) -> None: ) -def test_annotate_sumstats( - mock_study_index_gwas_catalog: StudyIndexGWASCatalog, - sample_gwas_catalog_harmonised_sumstats_list: DataFrame, -) -> None: - """Test annotate sumstats of GWASCatalogStudyIndex.""" - mock_study_index_gwas_catalog.df = mock_study_index_gwas_catalog.df.drop( - "summarystatsLocation" - ) - assert isinstance( - mock_study_index_gwas_catalog.annotate_sumstats_info( - sample_gwas_catalog_harmonised_sumstats_list - ), - StudyIndexGWASCatalog, - ) - - def test_study_index_from_source( sample_gwas_catalog_studies: DataFrame, - sample_gwas_catalog_harmonised_sumstats_list: DataFrame, sample_gwas_catalog_ancestries_lut: DataFrame, ) -> None: """Test study index from source.""" @@ -57,7 +40,6 @@ def test_study_index_from_source( StudyIndexGWASCatalogParser.from_source( sample_gwas_catalog_studies, sample_gwas_catalog_ancestries_lut, - sample_gwas_catalog_harmonised_sumstats_list, ), StudyIndexGWASCatalog, ) From a78bae3069470e8302a0030971b4ee38215ce48f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 22 Oct 2024 11:38:54 +0100 Subject: [PATCH 124/188] build(deps-dev): bump mypy from 1.11.0 to 1.12.1 (#865) Bumps [mypy](https://github.com/python/mypy) from 1.11.0 to 1.12.1. - [Changelog](https://github.com/python/mypy/blob/master/CHANGELOG.md) - [Commits](https://github.com/python/mypy/compare/v1.11...v1.12.1) --- updated-dependencies: - dependency-name: mypy dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- poetry.lock | 63 +++++++++++++++++++++++++++----------------------- pyproject.toml | 2 +- 2 files changed, 35 insertions(+), 30 deletions(-) diff --git a/poetry.lock b/poetry.lock index 254c05a75..40d24a800 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2755,38 +2755,43 @@ files = [ [[package]] name = "mypy" -version = "1.11.0" +version = "1.12.1" description = "Optional static typing for Python" optional = false python-versions = ">=3.8" files = [ - {file = "mypy-1.11.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a3824187c99b893f90c845bab405a585d1ced4ff55421fdf5c84cb7710995229"}, - {file = "mypy-1.11.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:96f8dbc2c85046c81bcddc246232d500ad729cb720da4e20fce3b542cab91287"}, - {file = "mypy-1.11.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1a5d8d8dd8613a3e2be3eae829ee891b6b2de6302f24766ff06cb2875f5be9c6"}, - {file = "mypy-1.11.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:72596a79bbfb195fd41405cffa18210af3811beb91ff946dbcb7368240eed6be"}, - {file = "mypy-1.11.0-cp310-cp310-win_amd64.whl", hash = "sha256:35ce88b8ed3a759634cb4eb646d002c4cef0a38f20565ee82b5023558eb90c00"}, - {file = "mypy-1.11.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:98790025861cb2c3db8c2f5ad10fc8c336ed2a55f4daf1b8b3f877826b6ff2eb"}, - {file = "mypy-1.11.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:25bcfa75b9b5a5f8d67147a54ea97ed63a653995a82798221cca2a315c0238c1"}, - {file = "mypy-1.11.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0bea2a0e71c2a375c9fa0ede3d98324214d67b3cbbfcbd55ac8f750f85a414e3"}, - {file = "mypy-1.11.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d2b3d36baac48e40e3064d2901f2fbd2a2d6880ec6ce6358825c85031d7c0d4d"}, - {file = "mypy-1.11.0-cp311-cp311-win_amd64.whl", hash = "sha256:d8e2e43977f0e09f149ea69fd0556623919f816764e26d74da0c8a7b48f3e18a"}, - {file = "mypy-1.11.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:1d44c1e44a8be986b54b09f15f2c1a66368eb43861b4e82573026e04c48a9e20"}, - {file = "mypy-1.11.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cea3d0fb69637944dd321f41bc896e11d0fb0b0aa531d887a6da70f6e7473aba"}, - {file = "mypy-1.11.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a83ec98ae12d51c252be61521aa5731f5512231d0b738b4cb2498344f0b840cd"}, - {file = "mypy-1.11.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:c7b73a856522417beb78e0fb6d33ef89474e7a622db2653bc1285af36e2e3e3d"}, - {file = "mypy-1.11.0-cp312-cp312-win_amd64.whl", hash = "sha256:f2268d9fcd9686b61ab64f077be7ffbc6fbcdfb4103e5dd0cc5eaab53a8886c2"}, - {file = "mypy-1.11.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:940bfff7283c267ae6522ef926a7887305945f716a7704d3344d6d07f02df850"}, - {file = "mypy-1.11.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:14f9294528b5f5cf96c721f231c9f5b2733164e02c1c018ed1a0eff8a18005ac"}, - {file = "mypy-1.11.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d7b54c27783991399046837df5c7c9d325d921394757d09dbcbf96aee4649fe9"}, - {file = "mypy-1.11.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:65f190a6349dec29c8d1a1cd4aa71284177aee5949e0502e6379b42873eddbe7"}, - {file = "mypy-1.11.0-cp38-cp38-win_amd64.whl", hash = "sha256:dbe286303241fea8c2ea5466f6e0e6a046a135a7e7609167b07fd4e7baf151bf"}, - {file = "mypy-1.11.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:104e9c1620c2675420abd1f6c44bab7dd33cc85aea751c985006e83dcd001095"}, - {file = "mypy-1.11.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f006e955718ecd8d159cee9932b64fba8f86ee6f7728ca3ac66c3a54b0062abe"}, - {file = "mypy-1.11.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:becc9111ca572b04e7e77131bc708480cc88a911adf3d0239f974c034b78085c"}, - {file = "mypy-1.11.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6801319fe76c3f3a3833f2b5af7bd2c17bb93c00026a2a1b924e6762f5b19e13"}, - {file = "mypy-1.11.0-cp39-cp39-win_amd64.whl", hash = "sha256:c1a184c64521dc549324ec6ef7cbaa6b351912be9cb5edb803c2808a0d7e85ac"}, - {file = "mypy-1.11.0-py3-none-any.whl", hash = "sha256:56913ec8c7638b0091ef4da6fcc9136896914a9d60d54670a75880c3e5b99ace"}, - {file = "mypy-1.11.0.tar.gz", hash = "sha256:93743608c7348772fdc717af4aeee1997293a1ad04bc0ea6efa15bf65385c538"}, + {file = "mypy-1.12.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3d7d4371829184e22fda4015278fbfdef0327a4b955a483012bd2d423a788801"}, + {file = "mypy-1.12.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f59f1dfbf497d473201356966e353ef09d4daec48caeacc0254db8ef633a28a5"}, + {file = "mypy-1.12.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b947097fae68004b8328c55161ac9db7d3566abfef72d9d41b47a021c2fba6b1"}, + {file = "mypy-1.12.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:96af62050971c5241afb4701c15189ea9507db89ad07794a4ee7b4e092dc0627"}, + {file = "mypy-1.12.1-cp310-cp310-win_amd64.whl", hash = "sha256:d90da248f4c2dba6c44ddcfea94bb361e491962f05f41990ff24dbd09969ce20"}, + {file = "mypy-1.12.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1230048fec1380faf240be6385e709c8570604d2d27ec6ca7e573e3bc09c3735"}, + {file = "mypy-1.12.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:02dcfe270c6ea13338210908f8cadc8d31af0f04cee8ca996438fe6a97b4ec66"}, + {file = "mypy-1.12.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a5a437c9102a6a252d9e3a63edc191a3aed5f2fcb786d614722ee3f4472e33f6"}, + {file = "mypy-1.12.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:186e0c8346efc027ee1f9acf5ca734425fc4f7dc2b60144f0fbe27cc19dc7931"}, + {file = "mypy-1.12.1-cp311-cp311-win_amd64.whl", hash = "sha256:673ba1140a478b50e6d265c03391702fa11a5c5aff3f54d69a62a48da32cb811"}, + {file = "mypy-1.12.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:9fb83a7be97c498176fb7486cafbb81decccaef1ac339d837c377b0ce3743a7f"}, + {file = "mypy-1.12.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:389e307e333879c571029d5b93932cf838b811d3f5395ed1ad05086b52148fb0"}, + {file = "mypy-1.12.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:94b2048a95a21f7a9ebc9fbd075a4fcd310410d078aa0228dbbad7f71335e042"}, + {file = "mypy-1.12.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ee5932370ccf7ebf83f79d1c157a5929d7ea36313027b0d70a488493dc1b179"}, + {file = "mypy-1.12.1-cp312-cp312-win_amd64.whl", hash = "sha256:19bf51f87a295e7ab2894f1d8167622b063492d754e69c3c2fed6563268cb42a"}, + {file = "mypy-1.12.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d34167d43613ffb1d6c6cdc0cc043bb106cac0aa5d6a4171f77ab92a3c758bcc"}, + {file = "mypy-1.12.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:427878aa54f2e2c5d8db31fa9010c599ed9f994b3b49e64ae9cd9990c40bd635"}, + {file = "mypy-1.12.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5fcde63ea2c9f69d6be859a1e6dd35955e87fa81de95bc240143cf00de1f7f81"}, + {file = "mypy-1.12.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:d54d840f6c052929f4a3d2aab2066af0f45a020b085fe0e40d4583db52aab4e4"}, + {file = "mypy-1.12.1-cp313-cp313-win_amd64.whl", hash = "sha256:20db6eb1ca3d1de8ece00033b12f793f1ea9da767334b7e8c626a4872090cf02"}, + {file = "mypy-1.12.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b16fe09f9c741d85a2e3b14a5257a27a4f4886c171d562bc5a5e90d8591906b8"}, + {file = "mypy-1.12.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0dcc1e843d58f444fce19da4cce5bd35c282d4bde232acdeca8279523087088a"}, + {file = "mypy-1.12.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e10ba7de5c616e44ad21005fa13450cd0de7caaa303a626147d45307492e4f2d"}, + {file = "mypy-1.12.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:0e6fe449223fa59fbee351db32283838a8fee8059e0028e9e6494a03802b4004"}, + {file = "mypy-1.12.1-cp38-cp38-win_amd64.whl", hash = "sha256:dc6e2a2195a290a7fd5bac3e60b586d77fc88e986eba7feced8b778c373f9afe"}, + {file = "mypy-1.12.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:de5b2a8988b4e1269a98beaf0e7cc71b510d050dce80c343b53b4955fff45f19"}, + {file = "mypy-1.12.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:843826966f1d65925e8b50d2b483065c51fc16dc5d72647e0236aae51dc8d77e"}, + {file = "mypy-1.12.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9fe20f89da41a95e14c34b1ddb09c80262edcc295ad891f22cc4b60013e8f78d"}, + {file = "mypy-1.12.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8135ffec02121a75f75dc97c81af7c14aa4ae0dda277132cfcd6abcd21551bfd"}, + {file = "mypy-1.12.1-cp39-cp39-win_amd64.whl", hash = "sha256:a7b76fa83260824300cc4834a3ab93180db19876bce59af921467fd03e692810"}, + {file = "mypy-1.12.1-py3-none-any.whl", hash = "sha256:ce561a09e3bb9863ab77edf29ae3a50e65685ad74bba1431278185b7e5d5486e"}, + {file = "mypy-1.12.1.tar.gz", hash = "sha256:f5b3936f7a6d0e8280c9bdef94c7ce4847f5cdfc258fbb2c29a8c1711e8bb96d"}, ] [package.dependencies] @@ -5219,4 +5224,4 @@ multidict = ">=4.0" [metadata] lock-version = "2.0" python-versions = "^3.10, <3.11" -content-hash = "e786d680aaa9f4a57bfc91fc2a18002199156ccc840c52e372171026506cdf04" +content-hash = "f4355a99419384b34057818bc3d8fdb4b8746f406631678976668426fbb95183" diff --git a/pyproject.toml b/pyproject.toml index 6f0e2e919..2d38452cb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -37,7 +37,7 @@ google-cloud-secret-manager = "^2.20.0" [tool.poetry.dev-dependencies] pre-commit = "^4.0.0" -mypy = "^1.11" +mypy = "^1.12" pep8-naming = "^0.14.1" interrogate = "^1.7.0" isort = "^5.13.2" From 34a4e6106772a6aa5a396db2525cb7b9f246cd00 Mon Sep 17 00:00:00 2001 From: Yakov Date: Tue, 22 Oct 2024 11:50:59 +0100 Subject: [PATCH 125/188] feat: adding desision tree to fine-mapper (#860) * feat: adding dession tree to fine-mapper * fix: adding the rest * fix: v1 * fix: v3 * fix: v3 * fix: v5 * fix: v6 * fix: v7 * fix: change flags * fix: keys --------- Co-authored-by: Szymon Szyszkowski <69353402+project-defiant@users.noreply.github.com> --- src/gentropy/susie_finemapper.py | 106 +++++++++++++++++++++++++++++-- 1 file changed, 100 insertions(+), 6 deletions(-) diff --git a/src/gentropy/susie_finemapper.py b/src/gentropy/susie_finemapper.py index d0759f565..adda2874c 100644 --- a/src/gentropy/susie_finemapper.py +++ b/src/gentropy/susie_finemapper.py @@ -28,6 +28,7 @@ from gentropy.dataset.study_index import StudyIndex from gentropy.dataset.study_locus import StudyLocus, StudyLocusQualityCheck from gentropy.method.carma import CARMA +from gentropy.method.ld import LDAnnotator from gentropy.method.ld_matrix_interface import LDMatrixInterface from gentropy.method.sumstat_imputation import SummaryStatisticsImputation from gentropy.method.susie_inf import SUSIE_inf @@ -712,12 +713,32 @@ def susie_finemapper_one_sl_row_gathered_boundaries( # noqa: C901 study_index_df = study_index._df study_index_df = study_index_df.filter(f.col("studyId") == studyId) - major_population = study_index_df.select( - "studyId", - order_array_of_structs_by_field( - "ldPopulationStructure", "relativeSampleSize" - )[0]["ldPopulation"].alias("majorPopulation"), - ).collect()[0]["majorPopulation"] + + # Desision tree - study index + if study_index_df.count() == 0: + logging.warning("No study index found for the studyId") + return None + + major_population = ( + study_index_df.select( + "studyId", + order_array_of_structs_by_field( + "ldPopulationStructure", "relativeSampleSize" + ).alias("ldPopulationStructure"), + ) + .withColumn( + "majorPopulation", + f.when( + f.col("ldPopulationStructure").isNotNull(), + LDAnnotator._get_major_population(f.col("ldPopulationStructure")), + ), + ) + .collect()[0]["majorPopulation"] + ) + + # This is a temporary solution + if major_population == "eas": + major_population = "csa" N_total = int(study_index_df.select("nSamples").collect()[0]["nSamples"]) if N_total is None: @@ -727,6 +748,79 @@ def susie_finemapper_one_sl_row_gathered_boundaries( # noqa: C901 region = chromosome + ":" + str(int(locusStart)) + "-" + str(int(locusEnd)) + # Desision tree - studyType + if study_index_df.select("studyType").collect()[0]["studyType"] in [ + "gwas", + "pqtl", + ]: + logging.warning("Study type is not GWAS or non gwas catalog pqtl") + return None + + # Desision tree - ancestry + if major_population not in ["nfe", "csa", "afr"]: + logging.warning("Major ancestry is not nfe, csa or afr") + return None + + # Desision tree - hasSumstats + if not study_index_df.select("hasSumstats").collect()[0]["hasSumstats"]: + logging.warning("No sumstats found for the studyId") + return None + + # Desision tree - qulityControls + keys_reasons = [ + "SMALL_NUMBER_OF_SNPS", + "FAILED_GC_LAMBDA_CHECK", + "FAILED_PZ_CHECK", + "FAILED_MEAN_BETA_CHECK", + "NO_OT_CURATION", + "SUMSTATS_NOT_AVAILABLE", + ] + + qc_mappings_dict = StudyIndex.get_QC_mappings() + invalid_reasons = [ + qc_mappings_dict[key] for key in keys_reasons if key in qc_mappings_dict + ] + + x_boolean = ( + study_index_df.withColumn( + "FailedQC", + f.arrays_overlap( + f.col("qualityControls"), + f.array([f.lit(reason) for reason in invalid_reasons]), + ), + ) + .select("FailedQC") + .collect()[0]["FailedQC"] + ) + if x_boolean: + logging.warning("Quality control check failed for this study") + return None + + # Desision tree - analysisFlags + study_index_df = study_index_df.drop("FailedQC") + invalid_reasons = [ + "Multivariate analysis", + "ExWAS", + "Non-additive model", + "GxG", + "GxE", + "Case-case study", + ] + x_boolean = ( + study_index_df.withColumn( + "FailedQC", + f.arrays_overlap( + f.col("analysisFlags"), + f.array([f.lit(reason) for reason in invalid_reasons]), + ), + ) + .select("FailedQC") + .collect()[0]["FailedQC"] + ) + if x_boolean: + logging.warning("Analysis Flags check failed for this study") + return None + schema = StudyLocus.get_schema() gwas_df = session.spark.createDataFrame([study_locus_row], schema=schema) exploded_df = gwas_df.select(f.explode("locus").alias("locus")) From c5adb7512ec26c68e0c744720d74676f3b88ad49 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 22 Oct 2024 15:36:36 +0100 Subject: [PATCH 126/188] build(deps-dev): bump ruff from 0.6.1 to 0.7.0 (#864) Bumps [ruff](https://github.com/astral-sh/ruff) from 0.6.1 to 0.7.0. - [Release notes](https://github.com/astral-sh/ruff/releases) - [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md) - [Commits](https://github.com/astral-sh/ruff/compare/0.6.1...0.7.0) --- updated-dependencies: - dependency-name: ruff dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- poetry.lock | 40 ++++++++++++++++++++-------------------- pyproject.toml | 2 +- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/poetry.lock b/poetry.lock index 40d24a800..9ce219f6b 100644 --- a/poetry.lock +++ b/poetry.lock @@ -4267,29 +4267,29 @@ pyasn1 = ">=0.1.3" [[package]] name = "ruff" -version = "0.6.1" +version = "0.7.0" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.6.1-py3-none-linux_armv6l.whl", hash = "sha256:b4bb7de6a24169dc023f992718a9417380301b0c2da0fe85919f47264fb8add9"}, - {file = "ruff-0.6.1-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:45efaae53b360c81043e311cdec8a7696420b3d3e8935202c2846e7a97d4edae"}, - {file = "ruff-0.6.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:bc60c7d71b732c8fa73cf995efc0c836a2fd8b9810e115be8babb24ae87e0850"}, - {file = "ruff-0.6.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c7477c3b9da822e2db0b4e0b59e61b8a23e87886e727b327e7dcaf06213c5cf"}, - {file = "ruff-0.6.1-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3a0af7ab3f86e3dc9f157a928e08e26c4b40707d0612b01cd577cc84b8905cc9"}, - {file = "ruff-0.6.1-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:392688dbb50fecf1bf7126731c90c11a9df1c3a4cdc3f481b53e851da5634fa5"}, - {file = "ruff-0.6.1-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:5278d3e095ccc8c30430bcc9bc550f778790acc211865520f3041910a28d0024"}, - {file = "ruff-0.6.1-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fe6d5f65d6f276ee7a0fc50a0cecaccb362d30ef98a110f99cac1c7872df2f18"}, - {file = "ruff-0.6.1-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2e0dd11e2ae553ee5c92a81731d88a9883af8db7408db47fc81887c1f8b672e"}, - {file = "ruff-0.6.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d812615525a34ecfc07fd93f906ef5b93656be01dfae9a819e31caa6cfe758a1"}, - {file = "ruff-0.6.1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:faaa4060f4064c3b7aaaa27328080c932fa142786f8142aff095b42b6a2eb631"}, - {file = "ruff-0.6.1-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:99d7ae0df47c62729d58765c593ea54c2546d5de213f2af2a19442d50a10cec9"}, - {file = "ruff-0.6.1-py3-none-musllinux_1_2_i686.whl", hash = "sha256:9eb18dfd7b613eec000e3738b3f0e4398bf0153cb80bfa3e351b3c1c2f6d7b15"}, - {file = "ruff-0.6.1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:c62bc04c6723a81e25e71715aa59489f15034d69bf641df88cb38bdc32fd1dbb"}, - {file = "ruff-0.6.1-py3-none-win32.whl", hash = "sha256:9fb4c4e8b83f19c9477a8745e56d2eeef07a7ff50b68a6998f7d9e2e3887bdc4"}, - {file = "ruff-0.6.1-py3-none-win_amd64.whl", hash = "sha256:c2ebfc8f51ef4aca05dad4552bbcf6fe8d1f75b2f6af546cc47cc1c1ca916b5b"}, - {file = "ruff-0.6.1-py3-none-win_arm64.whl", hash = "sha256:3bc81074971b0ffad1bd0c52284b22411f02a11a012082a76ac6da153536e014"}, - {file = "ruff-0.6.1.tar.gz", hash = "sha256:af3ffd8c6563acb8848d33cd19a69b9bfe943667f0419ca083f8ebe4224a3436"}, + {file = "ruff-0.7.0-py3-none-linux_armv6l.whl", hash = "sha256:0cdf20c2b6ff98e37df47b2b0bd3a34aaa155f59a11182c1303cce79be715628"}, + {file = "ruff-0.7.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:496494d350c7fdeb36ca4ef1c9f21d80d182423718782222c29b3e72b3512737"}, + {file = "ruff-0.7.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:214b88498684e20b6b2b8852c01d50f0651f3cc6118dfa113b4def9f14faaf06"}, + {file = "ruff-0.7.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:630fce3fefe9844e91ea5bbf7ceadab4f9981f42b704fae011bb8efcaf5d84be"}, + {file = "ruff-0.7.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:211d877674e9373d4bb0f1c80f97a0201c61bcd1e9d045b6e9726adc42c156aa"}, + {file = "ruff-0.7.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:194d6c46c98c73949a106425ed40a576f52291c12bc21399eb8f13a0f7073495"}, + {file = "ruff-0.7.0-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:82c2579b82b9973a110fab281860403b397c08c403de92de19568f32f7178598"}, + {file = "ruff-0.7.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9af971fe85dcd5eaed8f585ddbc6bdbe8c217fb8fcf510ea6bca5bdfff56040e"}, + {file = "ruff-0.7.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b641c7f16939b7d24b7bfc0be4102c56562a18281f84f635604e8a6989948914"}, + {file = "ruff-0.7.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d71672336e46b34e0c90a790afeac8a31954fd42872c1f6adaea1dff76fd44f9"}, + {file = "ruff-0.7.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:ab7d98c7eed355166f367597e513a6c82408df4181a937628dbec79abb2a1fe4"}, + {file = "ruff-0.7.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:1eb54986f770f49edb14f71d33312d79e00e629a57387382200b1ef12d6a4ef9"}, + {file = "ruff-0.7.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:dc452ba6f2bb9cf8726a84aa877061a2462afe9ae0ea1d411c53d226661c601d"}, + {file = "ruff-0.7.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:4b406c2dce5be9bad59f2de26139a86017a517e6bcd2688da515481c05a2cb11"}, + {file = "ruff-0.7.0-py3-none-win32.whl", hash = "sha256:f6c968509f767776f524a8430426539587d5ec5c662f6addb6aa25bc2e8195ec"}, + {file = "ruff-0.7.0-py3-none-win_amd64.whl", hash = "sha256:ff4aabfbaaba880e85d394603b9e75d32b0693152e16fa659a3064a85df7fce2"}, + {file = "ruff-0.7.0-py3-none-win_arm64.whl", hash = "sha256:10842f69c245e78d6adec7e1db0a7d9ddc2fff0621d730e61657b64fa36f207e"}, + {file = "ruff-0.7.0.tar.gz", hash = "sha256:47a86360cf62d9cd53ebfb0b5eb0e882193fc191c6d717e8bef4462bc3b9ea2b"}, ] [[package]] @@ -5224,4 +5224,4 @@ multidict = ">=4.0" [metadata] lock-version = "2.0" python-versions = "^3.10, <3.11" -content-hash = "f4355a99419384b34057818bc3d8fdb4b8746f406631678976668426fbb95183" +content-hash = "2dcd05168a809a2a9dc0728ee7ed1578ad008d0c3a290bf9a41895b10f2d849a" diff --git a/pyproject.toml b/pyproject.toml index 2d38452cb..fea630906 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -42,7 +42,7 @@ pep8-naming = "^0.14.1" interrogate = "^1.7.0" isort = "^5.13.2" darglint = "^1.8.1" -ruff = "^0.6.1" +ruff = "^0.7.0" [tool.poetry.group.docs.dependencies] mkdocs = "^1.5.3" From 6e6687b270211698753e6c2479575a7484d2d0f5 Mon Sep 17 00:00:00 2001 From: Yakov Date: Wed, 23 Oct 2024 10:14:54 +0100 Subject: [PATCH 127/188] fix: logging of finemamper (#870) --- src/gentropy/susie_finemapper.py | 139 +++++++++++++++++++++++++++++-- 1 file changed, 133 insertions(+), 6 deletions(-) diff --git a/src/gentropy/susie_finemapper.py b/src/gentropy/susie_finemapper.py index adda2874c..03a8730ef 100644 --- a/src/gentropy/susie_finemapper.py +++ b/src/gentropy/susie_finemapper.py @@ -131,6 +131,7 @@ def __init__( imputed_r2_threshold=imputed_r2_threshold, ld_score_threshold=ld_score_threshold, ld_min_r2=ld_min_r2, + log_output=log_output, ) if result_logging is not None: @@ -149,11 +150,35 @@ def __init__( df.write.mode(session.write_mode).parquet(study_locus_output) if result_logging["log"] is not None: # Write log - result_logging["log"].to_parquet( - log_output, - engine="pyarrow", - index=False, - ) + result_logging["log"].to_csv(log_output, index=False, sep="\t") + + @staticmethod + def _empty_log_mg(studyId: str, region: str, error_mg: str, path_out: str) -> None: + """Create an empty log DataFrame with error message. + + Args: + studyId (str): study ID + region (str): region + error_mg (str): error message + path_out (str): output path + """ + pd.DataFrame( + { + "studyId": studyId, + "region": region, + "N_gwas_before_dedupl": 0, + "N_gwas": 0, + "N_ld": 0, + "N_overlap": 0, + "N_outliers": 0, + "N_imputed": 0, + "N_final_to_fm": 0, + "elapsed_time": 0, + "number_of_CS": 0, + "error": error_mg, + }, + index=[0], + ).to_csv(path_out, index=False, sep="\t") @staticmethod def susie_inf_to_studylocus( # noqa: C901 @@ -631,6 +656,7 @@ def susie_finemapper_from_prepared_dataframes( "N_final_to_fm": len(ld_to_fm), "elapsed_time": end_time - start_time, "number_of_CS": study_locus.df.count(), + "error": "", }, index=[0], ) @@ -648,6 +674,7 @@ def susie_finemapper_from_prepared_dataframes( "N_final_to_fm": len(ld_to_fm), "elapsed_time": end_time - start_time, "number_of_CS": 0, + "error": "", }, index=[0], ) @@ -678,6 +705,7 @@ def susie_finemapper_one_sl_row_gathered_boundaries( # noqa: C901 purity_min_r2_threshold: float = 0.25, cs_lbf_thr: float = 2, ld_min_r2: float = 0.9, + log_output: str = "", ) -> dict[str, Any] | None: """Susie fine-mapper function that uses study-locus row with collected locus, chromosome and position as inputs. @@ -699,6 +727,7 @@ def susie_finemapper_one_sl_row_gathered_boundaries( # noqa: C901 purity_min_r2_threshold (float): thrshold for purity min r2 qc metrics for filtering credible sets cs_lbf_thr (float): credible set logBF threshold for filtering credible sets, default is 2 ld_min_r2 (float): Threshold to fillter CS by leads in high LD, default is 0.9 + log_output (str): path to the log output Returns: dict[str, Any] | None: dictionary with study locus, number of GWAS variants, number of LD variants, number of variants after merge, number of outliers, number of imputed variants, number of variants to fine-map, or None @@ -716,6 +745,13 @@ def susie_finemapper_one_sl_row_gathered_boundaries( # noqa: C901 # Desision tree - study index if study_index_df.count() == 0: + if log_output != "": + SusieFineMapperStep._empty_log_mg( + studyId=studyId, + region="", + error_mg="No study index found for the studyId", + path_out=log_output, + ) logging.warning("No study index found for the studyId") return None @@ -749,20 +785,41 @@ def susie_finemapper_one_sl_row_gathered_boundaries( # noqa: C901 region = chromosome + ":" + str(int(locusStart)) + "-" + str(int(locusEnd)) # Desision tree - studyType - if study_index_df.select("studyType").collect()[0]["studyType"] in [ + if study_index_df.select("studyType").collect()[0]["studyType"] not in [ "gwas", "pqtl", ]: + if log_output != "": + SusieFineMapperStep._empty_log_mg( + studyId=studyId, + region=region, + error_mg="Study type is not GWAS or non gwas catalog pqtl", + path_out=log_output, + ) logging.warning("Study type is not GWAS or non gwas catalog pqtl") return None # Desision tree - ancestry if major_population not in ["nfe", "csa", "afr"]: + if log_output != "": + SusieFineMapperStep._empty_log_mg( + studyId=studyId, + region=region, + error_mg="Major ancestry is not nfe, csa or afr", + path_out=log_output, + ) logging.warning("Major ancestry is not nfe, csa or afr") return None # Desision tree - hasSumstats if not study_index_df.select("hasSumstats").collect()[0]["hasSumstats"]: + if log_output != "": + SusieFineMapperStep._empty_log_mg( + studyId=studyId, + region=region, + error_mg="No sumstats found for the studyId", + path_out=log_output, + ) logging.warning("No sumstats found for the studyId") return None @@ -793,6 +850,13 @@ def susie_finemapper_one_sl_row_gathered_boundaries( # noqa: C901 .collect()[0]["FailedQC"] ) if x_boolean: + if log_output != "": + SusieFineMapperStep._empty_log_mg( + studyId=studyId, + region=region, + error_mg="Quality control check failed for this study", + path_out=log_output, + ) logging.warning("Quality control check failed for this study") return None @@ -818,6 +882,13 @@ def susie_finemapper_one_sl_row_gathered_boundaries( # noqa: C901 .collect()[0]["FailedQC"] ) if x_boolean: + if log_output != "": + SusieFineMapperStep._empty_log_mg( + studyId=studyId, + region=region, + error_mg="Analysis Flags check failed for this study", + path_out=log_output, + ) logging.warning("Analysis Flags check failed for this study") return None @@ -875,6 +946,13 @@ def susie_finemapper_one_sl_row_gathered_boundaries( # noqa: C901 "z", "chromosome", "position", "beta", "StandardError" ) if gwas_index.rdd.isEmpty(): + if log_output != "": + SusieFineMapperStep._empty_log_mg( + studyId=studyId, + region=region, + error_mg="No overlapping variants in the LD Index", + path_out=log_output, + ) logging.warning("No overlapping variants in the LD Index") return None gnomad_ld = LDMatrixInterface.get_numpy_matrix( @@ -894,6 +972,13 @@ def susie_finemapper_one_sl_row_gathered_boundaries( # noqa: C901 gwas_index = gwas_index.iloc[indices, :] if len(gwas_index) == 0: + if log_output != "": + SusieFineMapperStep._empty_log_mg( + studyId=studyId, + region=region, + error_mg="No overlapping variants in the LD Index", + path_out=log_output, + ) logging.warning("No overlapping variants in the LD Index") return None @@ -906,6 +991,13 @@ def susie_finemapper_one_sl_row_gathered_boundaries( # noqa: C901 gwas_index = gwas_index.iloc[indices, :] if len(gwas_index) == 0: + if log_output != "": + SusieFineMapperStep._empty_log_mg( + studyId=studyId, + region=region, + error_mg="No overlapping variants in the LD Index", + path_out=log_output, + ) logging.warning("No overlapping variants in the LD Index") return None @@ -916,6 +1008,13 @@ def susie_finemapper_one_sl_row_gathered_boundaries( # noqa: C901 ld_index.select("variantId", "idx", "alleleOrder"), on="variantId" ).sort("idx") if gwas_index.rdd.isEmpty(): + if log_output != "": + SusieFineMapperStep._empty_log_mg( + studyId=studyId, + region=region, + error_mg="No overlapping variants in the LD Index", + path_out=log_output, + ) logging.warning("No overlapping variants in the LD Index") return None gwas_index = ld_index @@ -936,6 +1035,13 @@ def susie_finemapper_one_sl_row_gathered_boundaries( # noqa: C901 gwas_index = gwas_index.iloc[indices, :] if len(gwas_index) == 0: + if log_output != "": + SusieFineMapperStep._empty_log_mg( + studyId=studyId, + region=region, + error_mg="No overlapping variants in the LD Index", + path_out=log_output, + ) logging.warning("No overlapping variants in the LD Index") return None @@ -948,6 +1054,13 @@ def susie_finemapper_one_sl_row_gathered_boundaries( # noqa: C901 gwas_index = gwas_index.iloc[indices, :] if len(gwas_index) == 0: + if log_output != "": + SusieFineMapperStep._empty_log_mg( + studyId=studyId, + region=region, + error_mg="No overlapping variants in the LD Index", + path_out=log_output, + ) logging.warning("No overlapping variants in the LD Index") return None @@ -965,9 +1078,23 @@ def susie_finemapper_one_sl_row_gathered_boundaries( # noqa: C901 # Desision tree - number of variants if gwas_index.count() < 100: + if log_output != "": + SusieFineMapperStep._empty_log_mg( + studyId=studyId, + region=region, + error_mg="Less than 100 variants after joining GWAS and LD index", + path_out=log_output, + ) logging.warning("Less than 100 variants after joining GWAS and LD index") return None elif gwas_index.count() >= 15_000: + if log_output != "": + SusieFineMapperStep._empty_log_mg( + studyId=studyId, + region=region, + error_mg="More than 15000 variants after joining GWAS and LD index", + path_out=log_output, + ) logging.warning("More than 15000 variants after joining GWAS and LD index") return None From 52da70f4abccae613c2620970ac45d70643e2d3d Mon Sep 17 00:00:00 2001 From: Yakov Date: Wed, 23 Oct 2024 10:23:20 +0100 Subject: [PATCH 128/188] chore: add chromosome validation (#869) * chore: add chromosome validation * test: chromosome validation --------- Co-authored-by: DSuveges --- src/gentropy/dataset/study_locus.py | 31 +++++++++++++++++ tests/gentropy/dataset/test_study_locus.py | 40 ++++++++++++++++++++++ 2 files changed, 71 insertions(+) diff --git a/src/gentropy/dataset/study_locus.py b/src/gentropy/dataset/study_locus.py index eaec9672b..a68a00a6d 100644 --- a/src/gentropy/dataset/study_locus.py +++ b/src/gentropy/dataset/study_locus.py @@ -82,6 +82,8 @@ class StudyLocusQualityCheck(Enum): IN_MHC (str): Flagging study loci in the MHC region REDUNDANT_PICS_TOP_HIT (str): Flagging study loci in studies with PICS results from summary statistics EXPLAINED_BY_SUSIE (str): Study locus in region explained by a SuSiE credible set + OUT_OF_SAMPLE_LD (str): Study locus finemapped without in-sample LD reference + INVALID_CHROMOSOME (str): Chromosome not in 1:22, X, Y, XY or MT """ SUBSIGNIFICANT_FLAG = "Subsignificant p-value" @@ -111,6 +113,7 @@ class StudyLocusQualityCheck(Enum): TOP_HIT = "Study locus from curated top hit" EXPLAINED_BY_SUSIE = "Study locus in region explained by a SuSiE credible set" OUT_OF_SAMPLE_LD = "Study locus finemapped without in-sample LD reference" + INVALID_CHROMOSOME = "Chromosome not in 1:22, X, Y, XY or MT" class CredibleInterval(Enum): @@ -205,6 +208,34 @@ def annotate_study_type(self: StudyLocus, study_index: StudyIndex) -> StudyLocus _schema=self.get_schema(), ) + def validate_chromosome_label(self: StudyLocus) -> StudyLocus: + """Flagging study loci, where chromosome is coded not as 1:22, X, Y, Xy and MT. + + Returns: + StudyLocus: Updated study locus with quality control flags. + """ + # QC column might not be present in the variant index schema, so we have to be ready to handle it: + qc_select_expression = ( + f.col("qualityControls") + if "qualityControls" in self.df.columns + else f.lit(None).cast(ArrayType(StringType())) + ) + valid_chromosomes = [str(i) for i in range(1, 23)] + ["X", "Y", "XY", "MT"] + + return StudyLocus( + _df=( + self.df.withColumn( + "qualityControls", + self.update_quality_flag( + qc_select_expression, + ~f.col("chromosome").isin(valid_chromosomes), + StudyLocusQualityCheck.INVALID_CHROMOSOME, + ), + ) + ), + _schema=self.get_schema(), + ) + def validate_variant_identifiers( self: StudyLocus, variant_index: VariantIndex ) -> StudyLocus: diff --git a/tests/gentropy/dataset/test_study_locus.py b/tests/gentropy/dataset/test_study_locus.py index 94da005b9..eaee0ebf3 100644 --- a/tests/gentropy/dataset/test_study_locus.py +++ b/tests/gentropy/dataset/test_study_locus.py @@ -1081,3 +1081,43 @@ def test_qc_explained_by_SuSiE_correctness( ) .count() ) == 3 + + +def test_qc_valid_chromosomes( + spark: SparkSession, +) -> None: + """Testing if chredible sets with invalid chromosomes are properly flagged.""" + df = spark.createDataFrame( + [ + # Chromosome is fine: + ("1", "v1", "s1", "X", []), + ("2", "v2", "s1", "1", []), + # Should be flagged: + ("3", "v3", "s1", "11325", []), + ("4", "v4", "s1", "CICAFUL", []), + ], + schema=t.StructType( + [ + t.StructField("studyLocusId", t.StringType(), False), + t.StructField("variantId", t.StringType(), False), + t.StructField("studyId", t.StringType(), False), + t.StructField("chromosome", t.StringType(), False), + t.StructField("qualityControls", t.ArrayType(t.StringType()), False), + ] + ), + ) + + sl = StudyLocus(_df=df, _schema=StudyLocus.get_schema()).validate_chromosome_label() + + # Assert return type: + assert isinstance(sl, StudyLocus) + + # Assert flagging correctness: + for row in sl.df.collect(): + if row["chromosome"] in ["1", "X"]: + assert not row["qualityControls"] + else: + assert ( + StudyLocusQualityCheck.INVALID_CHROMOSOME.value + in row["qualityControls"] + ) From 9fe77ca8e8f816f6fd9d33638affac52b6f6bd84 Mon Sep 17 00:00:00 2001 From: xyg123 <33658607+xyg123@users.noreply.github.com> Date: Thu, 24 Oct 2024 10:16:37 +0100 Subject: [PATCH 129/188] feat: add gene count features to l2g (#852) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: add gene count features to l2g * fix: add genecount to pytest * fix: use alias in gene count * fix: use alias in gene count * fix: pytest now works * chore: pre-commit auto fixes [...] * fix: type hint * feat(coloc): step refactoring (#845) * feat: prior fix * refactor: coloc step * fix: subclasss colocalisation methods on interface * fix: failing coloc step * chore(coloc): step tests * chore: restore old script --------- Co-authored-by: Szymon Szyszkowski Co-authored-by: project-defiant * test: skip `fetch_coordinates_from_rsids` (#850) * fix(eqtl): deduplicating credible set loci (#849) * fix(eqtl): deduplicating credible set loci * fix: removing * chore: adding logging even when no CS in locus (#848) * chore: adding logging even when no CS in locus * fix: addin CS count to log * fix: type hints * added test_l2g_feature tests * fix: remove print statements from tests * feat: add genecount features to FM + config * feat: add to l2g config * chore: pre-commit auto fixes [...] --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Szymon Szyszkowski <69353402+project-defiant@users.noreply.github.com> Co-authored-by: Szymon Szyszkowski Co-authored-by: project-defiant Co-authored-by: Irene López Santiago <45119610+ireneisdoomed@users.noreply.github.com> Co-authored-by: Daniel Suveges Co-authored-by: Yakov --- .../python_api/datasets/l2g_features/other.md | 12 ++ src/gentropy/config.py | 6 + src/gentropy/dataset/l2g_features/other.py | 162 ++++++++++++++++++ src/gentropy/method/l2g/feature_factory.py | 6 + tests/gentropy/dataset/test_l2g_feature.py | 114 +++++++++++- .../dataset/test_l2g_feature_matrix.py | 34 +++- 6 files changed, 331 insertions(+), 3 deletions(-) create mode 100644 docs/python_api/datasets/l2g_features/other.md create mode 100644 src/gentropy/dataset/l2g_features/other.py diff --git a/docs/python_api/datasets/l2g_features/other.md b/docs/python_api/datasets/l2g_features/other.md new file mode 100644 index 000000000..e294e1813 --- /dev/null +++ b/docs/python_api/datasets/l2g_features/other.md @@ -0,0 +1,12 @@ +--- +title: Other features +--- + +## List of features + +::: gentropy.dataset.l2g_features.other.GeneCountFeature +::: gentropy.dataset.l2g_features.other.ProteinGeneCountFeature + +## Common logic + +::: gentropy.dataset.l2g_features.other.common_genecount_feature_logic diff --git a/src/gentropy/config.py b/src/gentropy/config.py index d47c1b8ab..f6b699f0a 100644 --- a/src/gentropy/config.py +++ b/src/gentropy/config.py @@ -258,6 +258,9 @@ class LocusToGeneConfig(StepConfig): "vepMaximumNeighbourhood", "vepMean", "vepMeanNeighbourhood", + # other + "geneCount500kb", + "proteinGeneCount500kb", ] ) hyperparameters: dict[str, Any] = field( @@ -325,6 +328,9 @@ class LocusToGeneFeatureMatrixConfig(StepConfig): "vepMaximumNeighbourhood", "vepMean", "vepMeanNeighbourhood", + # other + "geneCount500kb", + "proteinGeneCount500kb", ] ) _target_: str = "gentropy.l2g.LocusToGeneFeatureMatrixStep" diff --git a/src/gentropy/dataset/l2g_features/other.py b/src/gentropy/dataset/l2g_features/other.py new file mode 100644 index 000000000..a033192a8 --- /dev/null +++ b/src/gentropy/dataset/l2g_features/other.py @@ -0,0 +1,162 @@ +"""Methods to generate features which are not obviously categorised.""" + +from __future__ import annotations + +from typing import TYPE_CHECKING, Any + +import pyspark.sql.functions as f + +from gentropy.common.spark_helpers import convert_from_wide_to_long +from gentropy.dataset.gene_index import GeneIndex +from gentropy.dataset.l2g_features.l2g_feature import L2GFeature +from gentropy.dataset.l2g_gold_standard import L2GGoldStandard +from gentropy.dataset.study_locus import StudyLocus + +if TYPE_CHECKING: + from pyspark.sql import DataFrame + + +def common_genecount_feature_logic( + study_loci_to_annotate: StudyLocus | L2GGoldStandard, + *, + gene_index: GeneIndex, + feature_name: str, + genomic_window: int, + protein_coding_only: bool = False, +) -> DataFrame: + """Computes the feature. + + Args: + study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci + that will be used for annotation + gene_index (GeneIndex): Dataset containing information related to all genes in release. + feature_name (str): The name of the feature + genomic_window (int): The maximum window size to consider + protein_coding_only (bool): Whether to only consider protein coding genes in calculation. + + Returns: + DataFrame: Feature dataset + """ + study_loci_window = ( + study_loci_to_annotate.df.withColumn( + "window_start", f.col("position") - (genomic_window / 2) + ) + .withColumn("window_end", f.col("position") + (genomic_window / 2)) + .withColumnRenamed("chromosome", "SL_chromosome") + ) + gene_index_filter = gene_index.df + + if protein_coding_only: + gene_index_filter = gene_index_filter.filter( + f.col("biotype") == "protein_coding" + ) + + distinct_gene_counts = ( + study_loci_window.join( + gene_index_filter.alias("genes"), + on=( + (f.col("SL_chromosome") == f.col("genes.chromosome")) + & (f.col("genes.tss") >= f.col("window_start")) + & (f.col("genes.tss") <= f.col("window_end")) + ), + how="inner", + ) + .groupBy("studyLocusId") + .agg(f.approx_count_distinct("geneId").alias(feature_name)) + ) + + return ( + study_loci_window.join( + gene_index_filter.alias("genes"), + on=( + (f.col("SL_chromosome") == f.col("genes.chromosome")) + & (f.col("genes.tss") >= f.col("window_start")) + & (f.col("genes.tss") <= f.col("window_end")) + ), + how="inner", + ) + .join(distinct_gene_counts, on="studyLocusId", how="inner") + .select("studyLocusId", "geneId", feature_name) + .distinct() + ) + + +class GeneCountFeature(L2GFeature): + """Counts the number of genes within a specified window size from the study locus.""" + + feature_dependency_type = GeneIndex + feature_name = "geneCount500kb" + + @classmethod + def compute( + cls: type[GeneCountFeature], + study_loci_to_annotate: StudyLocus | L2GGoldStandard, + feature_dependency: dict[str, Any], + ) -> GeneCountFeature: + """Computes the gene count feature. + + Args: + study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation + feature_dependency (dict[str, Any]): Dictionary containing dependencies, with gene index and window size + + Returns: + GeneCountFeature: Feature dataset + """ + genomic_window = 500000 + gene_count_df = common_genecount_feature_logic( + study_loci_to_annotate=study_loci_to_annotate, + feature_name=cls.feature_name, + genomic_window=genomic_window, + **feature_dependency, + ) + + return cls( + _df=convert_from_wide_to_long( + gene_count_df, + id_vars=("studyLocusId", "geneId"), + var_name="featureName", + value_name="featureValue", + ), + _schema=cls.get_schema(), + ) + + +class ProteinGeneCountFeature(L2GFeature): + """Counts the number of protein coding genes within a specified window size from the study locus.""" + + feature_dependency_type = GeneIndex + feature_name = "proteinGeneCount500kb" + + @classmethod + def compute( + cls: type[ProteinGeneCountFeature], + study_loci_to_annotate: StudyLocus | L2GGoldStandard, + feature_dependency: dict[str, Any], + ) -> ProteinGeneCountFeature: + """Computes the gene count feature. + + Args: + study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation + feature_dependency (dict[str, Any]): Dictionary containing dependencies, with gene index and window size + + Returns: + ProteinGeneCountFeature: Feature dataset + """ + genomic_window = 500000 + gene_count_df = common_genecount_feature_logic( + study_loci_to_annotate=study_loci_to_annotate, + feature_name=cls.feature_name, + genomic_window=genomic_window, + protein_coding_only=True, + **feature_dependency, + ) + + return cls( + _df=convert_from_wide_to_long( + gene_count_df, + id_vars=("studyLocusId", "geneId"), + var_name="featureName", + value_name="featureValue", + ), + _schema=cls.get_schema(), + ) diff --git a/src/gentropy/method/l2g/feature_factory.py b/src/gentropy/method/l2g/feature_factory.py index 1077fc825..dbb5ecf48 100644 --- a/src/gentropy/method/l2g/feature_factory.py +++ b/src/gentropy/method/l2g/feature_factory.py @@ -29,6 +29,10 @@ DistanceTssMeanNeighbourhoodFeature, ) from gentropy.dataset.l2g_features.l2g_feature import L2GFeature +from gentropy.dataset.l2g_features.other import ( + GeneCountFeature, + ProteinGeneCountFeature, +) from gentropy.dataset.l2g_features.vep import ( VepMaximumFeature, VepMaximumNeighbourhoodFeature, @@ -119,6 +123,8 @@ class FeatureFactory: "vepMeanNeighbourhood": VepMeanNeighbourhoodFeature, "vepMaximum": VepMaximumFeature, "vepMaximumNeighbourhood": VepMaximumNeighbourhoodFeature, + "geneCount500kb": GeneCountFeature, + "proteinGeneCount500kb": ProteinGeneCountFeature, } def __init__( diff --git a/tests/gentropy/dataset/test_l2g_feature.py b/tests/gentropy/dataset/test_l2g_feature.py index 212ad32a6..a841af0a6 100644 --- a/tests/gentropy/dataset/test_l2g_feature.py +++ b/tests/gentropy/dataset/test_l2g_feature.py @@ -1,3 +1,5 @@ +# pylint: disable=too-few-public-methods +# isort: skip_file """Test locus-to-gene feature generation.""" from __future__ import annotations @@ -57,6 +59,11 @@ common_neighbourhood_vep_feature_logic, common_vep_feature_logic, ) +from gentropy.dataset.l2g_features.other import ( + common_genecount_feature_logic, + GeneCountFeature, + ProteinGeneCountFeature, +) from gentropy.dataset.study_index import StudyIndex from gentropy.dataset.study_locus import StudyLocus from gentropy.dataset.variant_index import VariantIndex @@ -93,6 +100,8 @@ VepMeanFeature, VepMaximumNeighbourhoodFeature, VepMeanNeighbourhoodFeature, + GeneCountFeature, + ProteinGeneCountFeature, ], ) def test_feature_factory_return_type( @@ -391,7 +400,7 @@ def _setup(self: TestCommonColocalisationFeatureLogic, spark: SparkSession) -> N { "studyLocusId": "2", "variantId": "var1", - "studyId": "study2", # this is a QTL (same gee) + "studyId": "study2", # this is a QTL (same gene) "chromosome": "1", }, { @@ -803,3 +812,106 @@ def _setup(self: TestCommonVepFeatureLogic, spark: SparkSession) -> None: ), _schema=StudyLocus.get_schema(), ) + + +class TestCommonGeneCountFeatureLogic: + """Test the CommonGeneCountFeatureLogic methods.""" + + @pytest.mark.parametrize( + ("feature_name", "expected_data", "protein_coding_only"), + [ + ( + "geneCount", + [ + {"studyLocusId": "1", "geneId": "gene1", "geneCount": 3}, + {"studyLocusId": "1", "geneId": "gene2", "geneCount": 3}, + {"studyLocusId": "1", "geneId": "gene3", "geneCount": 3}, + ], + False, # Test case for all genes + ), + ( + "geneCountProteinCoding", + [ + { + "studyLocusId": "1", + "geneId": "gene1", + "geneCountProteinCoding": 2, + }, + { + "studyLocusId": "1", + "geneId": "gene2", + "geneCountProteinCoding": 2, + }, + ], + True, # Test case for protein-coding genes only + ), + ], + ) + def test_common_genecount_feature_logic( + self: TestCommonGeneCountFeatureLogic, + spark: SparkSession, + feature_name: str, + expected_data: list[dict[str, Any]], + protein_coding_only: bool, + ) -> None: + """Test the common logic of the gene count features.""" + observed_df = common_genecount_feature_logic( + study_loci_to_annotate=self.sample_study_locus, + gene_index=self.sample_gene_index, + feature_name=feature_name, + genomic_window=500000, + protein_coding_only=protein_coding_only, + ).orderBy("studyLocusId", "geneId") + expected_df = ( + spark.createDataFrame(expected_data) + .select("studyLocusId", "geneId", feature_name) + .orderBy("studyLocusId", "geneId") + ) + assert ( + observed_df.collect() == expected_df.collect() + ), f"Expected and observed dataframes do not match for feature {feature_name}." + + @pytest.fixture(autouse=True) + def _setup(self: TestCommonGeneCountFeatureLogic, spark: SparkSession) -> None: + """Set up testing fixtures.""" + self.sample_study_locus = StudyLocus( + _df=spark.createDataFrame( + [ + { + "studyLocusId": "1", + "variantId": "var1", + "studyId": "study1", + "chromosome": "1", + "position": 1000000, + }, + ], + StudyLocus.get_schema(), + ), + _schema=StudyLocus.get_schema(), + ) + self.sample_gene_index = GeneIndex( + _df=spark.createDataFrame( + [ + { + "geneId": "gene1", + "chromosome": "1", + "tss": 950000, + "biotype": "protein_coding", + }, + { + "geneId": "gene2", + "chromosome": "1", + "tss": 1050000, + "biotype": "protein_coding", + }, + { + "geneId": "gene3", + "chromosome": "1", + "tss": 1010000, + "biotype": "non_coding", + }, + ], + GeneIndex.get_schema(), + ), + _schema=GeneIndex.get_schema(), + ) diff --git a/tests/gentropy/dataset/test_l2g_feature_matrix.py b/tests/gentropy/dataset/test_l2g_feature_matrix.py index f4859844a..76661e170 100644 --- a/tests/gentropy/dataset/test_l2g_feature_matrix.py +++ b/tests/gentropy/dataset/test_l2g_feature_matrix.py @@ -5,9 +5,17 @@ from typing import TYPE_CHECKING import pytest -from pyspark.sql.types import ArrayType, DoubleType, StringType, StructField, StructType +from pyspark.sql.types import ( + ArrayType, + DoubleType, + IntegerType, + StringType, + StructField, + StructType, +) from gentropy.dataset.colocalisation import Colocalisation +from gentropy.dataset.gene_index import GeneIndex from gentropy.dataset.l2g_feature_matrix import L2GFeatureMatrix from gentropy.dataset.l2g_gold_standard import L2GGoldStandard from gentropy.dataset.study_index import StudyIndex @@ -40,11 +48,12 @@ def test_study_locus( self: TestFromFeaturesList, ) -> None: """Test building feature matrix for a SL with the eQtlColocH4Maximum feature.""" - features_list = ["eQtlColocH4Maximum"] + features_list = ["eQtlColocH4Maximum", "geneCount500kb"] loader = L2GFeatureInputLoader( colocalisation=self.sample_colocalisation, study_index=self.sample_study_index, study_locus=self.sample_study_locus, + gene_index=self.sample_gene_index, ) fm = L2GFeatureMatrix.from_features_list( self.sample_study_locus, features_list, loader @@ -89,6 +98,8 @@ def _setup(self: TestFromFeaturesList, spark: SparkSession) -> None: "1", "var1", "gwas1", + "X", + 2, [ {"variantId": "var1", "posteriorProbability": 0.8}, {"variantId": "var12", "posteriorProbability": 0.2}, @@ -98,6 +109,8 @@ def _setup(self: TestFromFeaturesList, spark: SparkSession) -> None: "2", "var2", "eqtl1", + "X", + 10, [ {"variantId": "var2", "posteriorProbability": 1.0}, ], @@ -108,6 +121,8 @@ def _setup(self: TestFromFeaturesList, spark: SparkSession) -> None: StructField("studyLocusId", StringType(), True), StructField("variantId", StringType(), True), StructField("studyId", StringType(), True), + StructField("chromosome", StringType(), True), + StructField("position", IntegerType(), True), StructField( "locus", ArrayType( @@ -154,3 +169,18 @@ def _setup(self: TestFromFeaturesList, spark: SparkSession) -> None: ), _schema=Colocalisation.get_schema(), ) + self.sample_gene_index = GeneIndex( + _df=spark.createDataFrame( + [ + ("g1", "X", "protein_coding", 200), + ("g2", "X", "protein_coding", 300), + ], + [ + "geneId", + "chromosome", + "biotype", + "tss", + ], + ), + _schema=GeneIndex.get_schema(), + ) From e233dac0a2ed5a55daa1ddb98955e18bfe717888 Mon Sep 17 00:00:00 2001 From: Daniel-Considine <113430683+Daniel-Considine@users.noreply.github.com> Date: Thu, 24 Oct 2024 10:57:33 +0100 Subject: [PATCH 130/188] feat: change betas to posterior mean from susie for Finngen credible sets (#872) * feat: using mean instead of univariate beta * fix: missing f-string * fix: typo * fix: beta column in locus * feat: populating locusStart and locusEnd from region column * fix: locusStart/End cast to integer --------- Co-authored-by: Yakov --- .../datasource/finngen/finemapping.py | 42 +++++++++++++++++-- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/src/gentropy/datasource/finngen/finemapping.py b/src/gentropy/datasource/finngen/finemapping.py index 5b8d21864..36ab97e80 100644 --- a/src/gentropy/datasource/finngen/finemapping.py +++ b/src/gentropy/datasource/finngen/finemapping.py @@ -211,7 +211,7 @@ def from_finngen_susie_finemapping( ) -> StudyLocus: """Process the SuSIE finemapping output for FinnGen studies. - The finngen_susue_finemapping_snp_files are files that contain variant summaries with credible set information with following shema: + The finngen_susie_finemapping_snp_files are files that contain variant summaries with credible set information with following shema: - trait: phenotype - region: region for which the fine-mapping was run. - v, rsid: variant ids @@ -312,8 +312,7 @@ def from_finngen_susie_finemapping( f.col("allele2").cast(t.StringType()).alias("alt"), # Parse p-value into mantissa and exponent. *parse_pvalue(f.col("p")), - # Add beta, standard error, and allele frequency information. - f.col("beta").cast("double"), + # Add standard error, and allele frequency information. f.col("se").cast("double").alias("standardError"), f.col("maf").cast("float").alias("effectAlleleFrequencyFromSource"), f.lit("SuSie").cast("string").alias("finemappingMethod"), @@ -325,6 +324,10 @@ def from_finngen_susie_finemapping( f.col(f"lbf_variable{i}").cast(t.DoubleType()).alias(f"lbf_{i}") for i in range(1, 11) ], + *[ + f.col(f"mean{i}").cast(t.DoubleType()).alias(f"beta_{i}") + for i in range(1, 11) + ], ) .withColumn( "posteriorProbability", @@ -376,6 +379,31 @@ def from_finngen_susie_finemapping( "lbf_9", "lbf_10", ) + .withColumn( + "beta", + f.when(f.col("credibleSetIndex") == 1, f.col("beta_1")) + .when(f.col("credibleSetIndex") == 2, f.col("beta_2")) + .when(f.col("credibleSetIndex") == 3, f.col("beta_3")) + .when(f.col("credibleSetIndex") == 4, f.col("beta_4")) + .when(f.col("credibleSetIndex") == 5, f.col("beta_5")) + .when(f.col("credibleSetIndex") == 6, f.col("beta_6")) + .when(f.col("credibleSetIndex") == 7, f.col("beta_7")) + .when(f.col("credibleSetIndex") == 8, f.col("beta_8")) + .when(f.col("credibleSetIndex") == 9, f.col("beta_9")) + .when(f.col("credibleSetIndex") == 10, f.col("beta_10")), + ) + .drop( + "beta_1", + "beta_2", + "beta_3", + "beta_4", + "beta_5", + "beta_6", + "beta_7", + "beta_8", + "beta_9", + "beta_10", + ) ) bgzip_compressed_cs_summaries = cls._infer_block_gzip_compression( @@ -475,6 +503,14 @@ def from_finngen_susie_finemapping( on=["studyId", "region", "credibleSetIndex"], how="inner", ) + .withColumns( + { + "locusStart": f.split(f.split("region", ":")[1], "-")[0].cast( + "int" + ), + "locusEnd": f.split(f.split("region", ":")[1], "-")[1].cast("int"), + } + ) ).withColumn( "studyLocusId", StudyLocus.assign_study_locus_id( From d4b91d61fdc0a7a65133a4e02678c46b7e728c8f Mon Sep 17 00:00:00 2001 From: Daniel Suveges Date: Thu, 24 Oct 2024 11:13:29 +0100 Subject: [PATCH 131/188] feat: step to export disease/target evidence (#867) * feature(l2g): step to export disease/target evidence * fix: sorting out typo in function docstring * fix: evidence is written as json * fix: addressing reviewer comments * docs: adding step documentation * chore: pre-commit auto fixes [...] * fix: removing default value from step definition --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- docs/python_api/steps/l2g.md | 2 ++ src/gentropy/config.py | 17 ++++++++++ src/gentropy/dataset/l2g_prediction.py | 43 ++++++++++++++++++++++++++ src/gentropy/l2g.py | 42 +++++++++++++++++++++++++ 4 files changed, 104 insertions(+) diff --git a/docs/python_api/steps/l2g.md b/docs/python_api/steps/l2g.md index 556e5a275..5594f1605 100644 --- a/docs/python_api/steps/l2g.md +++ b/docs/python_api/steps/l2g.md @@ -5,3 +5,5 @@ title: Locus to Gene (L2G) ::: gentropy.l2g.LocusToGeneFeatureMatrixStep ::: gentropy.l2g.LocusToGeneStep + +::: gentropy.l2g.LocusToGeneEvidenceStep diff --git a/src/gentropy/config.py b/src/gentropy/config.py index f6b699f0a..486778c3a 100644 --- a/src/gentropy/config.py +++ b/src/gentropy/config.py @@ -615,6 +615,18 @@ class StudyValidationStepConfig(StepConfig): _target_: str = "gentropy.study_validation.StudyValidationStep" +@dataclass +class LocusToGeneEvidenceStepConfig(StepConfig): + """Configuration of the locus to gene evidence step.""" + + locus_to_gene_predictions_path: str = MISSING + credible_set_path: str = MISSING + study_index_path: str = MISSING + evidence_output_path: str = MISSING + locus_to_gene_threshold: float = 0.05 + _target_: str = "gentropy.l2g.LocusToGeneEvidenceStep" + + @dataclass class StudyLocusValidationStepConfig(StepConfig): """Configuration of the study index validation step. @@ -710,4 +722,9 @@ def register_config() -> None: name="study_validation", node=StudyValidationStepConfig, ) + cs.store( + group="step", + name="locus_to_gene_evidence", + node=LocusToGeneEvidenceStepConfig, + ) cs.store(group="step", name="finngen_ukb_meta_ingestion", node=FinngenUkbMetaConfig) diff --git a/src/gentropy/dataset/l2g_prediction.py b/src/gentropy/dataset/l2g_prediction.py index c29b359af..169f5a846 100644 --- a/src/gentropy/dataset/l2g_prediction.py +++ b/src/gentropy/dataset/l2g_prediction.py @@ -6,11 +6,13 @@ from typing import TYPE_CHECKING, Type import pyspark.sql.functions as f +from pyspark.sql import DataFrame from gentropy.common.schemas import parse_spark_schema from gentropy.common.session import Session from gentropy.dataset.dataset import Dataset from gentropy.dataset.l2g_feature_matrix import L2GFeatureMatrix +from gentropy.dataset.study_index import StudyIndex from gentropy.dataset.study_locus import StudyLocus from gentropy.method.l2g.model import LocusToGeneModel @@ -83,3 +85,44 @@ def from_credible_set( ) return l2g_model.predict(fm, session) + + def to_disease_target_evidence( + self: L2GPrediction, + study_locus: StudyLocus, + study_index: StudyIndex, + l2g_threshold: float = 0.05, + ) -> DataFrame: + """Convert locus to gene predictions to disease target evidence. + + Args: + study_locus (StudyLocus): Study locus dataset + study_index (StudyIndex): Study index dataset + l2g_threshold (float): Threshold to consider a gene as a target. Defaults to 0.05. + + Returns: + DataFrame: Disease target evidence + """ + datasource_id = "gwas_credible_sets" + datatype_id = "genetic_association" + + return ( + self.df.filter(f.col("score") >= l2g_threshold) + .join( + study_locus.df.select("studyLocusId", "studyId"), + on="studyLocusId", + how="inner", + ) + .join( + study_index.df.select("studyId", "diseaseIds"), + on="studyId", + how="inner", + ) + .select( + f.lit(datatype_id).alias("datatypeId"), + f.lit(datasource_id).alias("datasourceId"), + f.col("geneId").alias("targetFromSourceId"), + f.explode(f.col("diseaseIds")).alias("diseaseFromSourceMappedId"), + f.col("score").alias("resourceScore"), + "studyLocusId", + ) + ) diff --git a/src/gentropy/l2g.py b/src/gentropy/l2g.py index 1a5037bb2..ca52fbf04 100644 --- a/src/gentropy/l2g.py +++ b/src/gentropy/l2g.py @@ -278,3 +278,45 @@ def _annotate_gold_standards_w_feature_matrix(self) -> L2GFeatureMatrix: .persist() ) raise ValueError("Dependencies for train mode not set.") + + +class LocusToGeneEvidenceStep: + """Locus to gene evidence step.""" + + def __init__( + self, + session: Session, + locus_to_gene_predictions_path: str, + credible_set_path: str, + study_index_path: str, + evidence_output_path: str, + locus_to_gene_threshold: float, + ) -> None: + """Initialise the step and generate disease/target evidence. + + Args: + session (Session): Session object that contains the Spark session + locus_to_gene_predictions_path (str): Path to the L2G predictions dataset + credible_set_path (str): Path to the credible set dataset + study_index_path (str): Path to the study index dataset + evidence_output_path (str): Path to the L2G evidence output dataset + locus_to_gene_threshold (float, optional): Threshold to consider a gene as a target. Defaults to 0.05. + """ + # Reading the predictions + locus_to_gene_prediction = L2GPrediction.from_parquet( + session, locus_to_gene_predictions_path + ) + # Reading the credible set + credible_sets = StudyLocus.from_parquet(session, credible_set_path) + + # Reading the study index + study_index = StudyIndex.from_parquet(session, study_index_path) + + # Generate evidence and save file: + ( + locus_to_gene_prediction.to_disease_target_evidence( + credible_sets, study_index, locus_to_gene_threshold + ) + .write.mode(session.write_mode) + .json(evidence_output_path) + ) From c252dcb6ca12455bc61d9bbb88ccf8996556034a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Irene=20L=C3=B3pez=20Santiago?= <45119610+ireneisdoomed@users.noreply.github.com> Date: Thu, 24 Oct 2024 13:17:53 +0100 Subject: [PATCH 132/188] feat(variant_index): hash variants at the time of instance creation (#874) * fix(variant_index): pass config threshold after joining with gnomad * feat(dataset): ability to pass class params to `from_parquet` * feat(variant_index): hash variants after initialising class * test: ensure hashing happens and params are correcly separated * fix: add threshold in `test_extract_variant_index_from_vep` * feat(variant_index): make hash threshold inclusive --- src/gentropy/dataset/dataset.py | 41 ++++++++++++++++--- src/gentropy/dataset/variant_index.py | 33 ++++++++++----- src/gentropy/datasource/ensembl/vep_parser.py | 5 ++- src/gentropy/variant_index.py | 14 ++----- tests/gentropy/dataset/test_dataset.py | 20 ++++++--- tests/gentropy/dataset/test_variant_index.py | 22 ++++++++-- .../datasource/ensembl/test_vep_variants.py | 2 +- 7 files changed, 98 insertions(+), 39 deletions(-) diff --git a/src/gentropy/dataset/dataset.py b/src/gentropy/dataset/dataset.py index d033e129d..779faefe2 100644 --- a/src/gentropy/dataset/dataset.py +++ b/src/gentropy/dataset/dataset.py @@ -66,6 +66,30 @@ def schema(self: Dataset) -> StructType: """ return self._schema + @classmethod + def _process_class_params( + cls, params: dict[str, Any] + ) -> tuple[dict[str, Any], dict[str, Any]]: + """Separate class initialization parameters from spark session parameters. + + Args: + params (dict[str, Any]): Combined parameters dictionary + + Returns: + tuple[dict[str, Any], dict[str, Any]]: (class_params, spark_params) + """ + # Get all field names from the class (including parent classes) + class_field_names = { + field.name + for cls_ in cls.__mro__ + if hasattr(cls_, "__dataclass_fields__") + for field in cls_.__dataclass_fields__.values() + } + # Separate parameters + class_params = {k: v for k, v in params.items() if k in class_field_names} + spark_params = {k: v for k, v in params.items() if k not in class_field_names} + return class_params, spark_params + @classmethod @abstractmethod def get_schema(cls: type[Self]) -> StructType: @@ -120,10 +144,14 @@ def from_parquet( ValueError: Parquet file is empty """ schema = cls.get_schema() - df = session.load_data(path, format="parquet", schema=schema, **kwargs) + + # Separate class params from spark params + class_params, spark_params = cls._process_class_params(kwargs) + + df = session.load_data(path, format="parquet", schema=schema, **spark_params) if df.isEmpty(): raise ValueError(f"Parquet file is empty: {path}") - return cls(_df=df, _schema=schema) + return cls(_df=df, _schema=schema, **class_params) def filter(self: Self, condition: Column) -> Self: """Creates a new instance of a Dataset with the DataFrame filtered by the condition. @@ -321,7 +349,10 @@ def generate_identifier(uniqueness_defining_columns: list[str]) -> Column: Returns: Column: column with a unique identifier """ - hashable_columns = [f.when(f.col(column).cast("string").isNull(), f.lit("None")) - .otherwise(f.col(column).cast("string")) - for column in uniqueness_defining_columns] + hashable_columns = [ + f.when(f.col(column).cast("string").isNull(), f.lit("None")).otherwise( + f.col(column).cast("string") + ) + for column in uniqueness_defining_columns + ] return f.md5(f.concat(*hashable_columns)) diff --git a/src/gentropy/dataset/variant_index.py b/src/gentropy/dataset/variant_index.py index a1a2e2a4d..9e8740aa6 100644 --- a/src/gentropy/dataset/variant_index.py +++ b/src/gentropy/dataset/variant_index.py @@ -2,7 +2,7 @@ from __future__ import annotations -from dataclasses import dataclass +from dataclasses import dataclass, field from typing import TYPE_CHECKING import pyspark.sql.functions as f @@ -25,6 +25,8 @@ class VariantIndex(Dataset): """Dataset for representing variants and methods applied on them.""" + id_threshold: int = field(default=300) + def __post_init__(self: VariantIndex) -> None: """Forcing the presence of empty arrays even if the schema allows missing values. @@ -45,7 +47,16 @@ def __post_init__(self: VariantIndex) -> None: } # Not returning, but changing the data: - self.df = self.df.withColumns(array_columns) + self.df = self.df.withColumns(array_columns).withColumn( + # Hashing long variant identifiers: + "variantId", + self.hash_long_variant_ids( + f.col("variantId"), + f.col("chromosome"), + f.col("position"), + self.id_threshold, + ), + ) @classmethod def get_schema(cls: type[VariantIndex]) -> StructType: @@ -58,7 +69,7 @@ def get_schema(cls: type[VariantIndex]) -> StructType: @staticmethod def hash_long_variant_ids( - variant_id: Column, chromosome: Column, position: Column, threshold: int = 100 + variant_id: Column, chromosome: Column, position: Column, threshold: int ) -> Column: """Hash long variant identifiers. @@ -98,7 +109,7 @@ def hash_long_variant_ids( ) # If chromosome and position are given, but alleles are too long, create hash: .when( - f.length(variant_id) > threshold, + f.length(variant_id) >= threshold, f.concat_ws( "_", f.lit("OTVAR"), @@ -132,20 +143,20 @@ def add_annotation( select_expressions = [] # Collect columns by iterating over the variant index schema: - for field in VariantIndex.get_schema(): - column = field.name + for schema_field in VariantIndex.get_schema(): + column = schema_field.name # If an annotation column can be found in both datasets: if (column in self.df.columns) and (column in annotation_source.df.columns): # Arrays are merged: - if isinstance(field.dataType, t.ArrayType): + if isinstance(schema_field.dataType, t.ArrayType): fields_order = None - if isinstance(field.dataType.elementType, t.StructType): + if isinstance(schema_field.dataType.elementType, t.StructType): # Extract the schema of the array to get the order of the fields: array_schema = [ - field - for field in VariantIndex.get_schema().fields - if field.name == column + schema_field + for schema_field in VariantIndex.get_schema().fields + if schema_field.name == column ][0].dataType fields_order = get_nested_struct_schema( array_schema diff --git a/src/gentropy/datasource/ensembl/vep_parser.py b/src/gentropy/datasource/ensembl/vep_parser.py index 6931b96de..01c820513 100644 --- a/src/gentropy/datasource/ensembl/vep_parser.py +++ b/src/gentropy/datasource/ensembl/vep_parser.py @@ -59,7 +59,7 @@ def extract_variant_index_from_vep( cls: type[VariantEffectPredictorParser], spark: SparkSession, vep_output_path: str | list[str], - hash_threshold: int = 100, + hash_threshold: int, **kwargs: bool | float | int | str | None, ) -> VariantIndex: """Extract variant index from VEP output. @@ -67,7 +67,7 @@ def extract_variant_index_from_vep( Args: spark (SparkSession): Spark session. vep_output_path (str | list[str]): Path to the VEP output. - hash_threshold (int): Threshold above which variant identifiers will be hashed. Default is 100, + hash_threshold (int): Threshold above which variant identifiers will be hashed. **kwargs (bool | float | int | str | None): Additional arguments to pass to spark.read.json. Returns: @@ -93,6 +93,7 @@ def extract_variant_index_from_vep( vep_data, hash_threshold ), _schema=VariantIndex.get_schema(), + id_threshold=hash_threshold, ) @staticmethod diff --git a/src/gentropy/variant_index.py b/src/gentropy/variant_index.py index dba087c79..b50b470b2 100644 --- a/src/gentropy/variant_index.py +++ b/src/gentropy/variant_index.py @@ -2,10 +2,7 @@ from __future__ import annotations -from pyspark.sql.functions import col - from gentropy.common.session import Session -from gentropy.config import VariantIndexConfig from gentropy.dataset.variant_index import VariantIndex from gentropy.datasource.ensembl.vep_parser import VariantEffectPredictorParser from gentropy.datasource.open_targets.variants import OpenTargetsVariant @@ -23,7 +20,7 @@ def __init__( session: Session, vep_output_json_path: str, variant_index_path: str, - hash_threshold: int = VariantIndexConfig().hash_threshold, + hash_threshold: int, gnomad_variant_annotations_path: str | None = None, ) -> None: """Run VariantIndex step. @@ -47,19 +44,14 @@ def __init__( session=session, path=gnomad_variant_annotations_path, recursiveFileLookup=True, + id_threshold=hash_threshold, ) # Update file with extra annotations: variant_index = variant_index.add_annotation(annotations) ( - variant_index.df.withColumn( - "variantId", - VariantIndex.hash_long_variant_ids( - col("variantId"), col("chromosome"), col("position") - ), - ) - .repartitionByRange("chromosome", "position") + variant_index.df.repartitionByRange("chromosome", "position") .sortWithinPartitions("chromosome", "position") .write.mode(session.write_mode) .parquet(variant_index_path) diff --git a/tests/gentropy/dataset/test_dataset.py b/tests/gentropy/dataset/test_dataset.py index a152b1ac8..7c61f3f52 100644 --- a/tests/gentropy/dataset/test_dataset.py +++ b/tests/gentropy/dataset/test_dataset.py @@ -6,12 +6,7 @@ import pyspark.sql.functions as f import pytest from pyspark.sql import SparkSession -from pyspark.sql.types import ( - DoubleType, - IntegerType, - StructField, - StructType, -) +from pyspark.sql.types import DoubleType, IntegerType, StructField, StructType from gentropy.dataset.dataset import Dataset from gentropy.dataset.study_index import StudyIndex @@ -79,3 +74,16 @@ def test_dataset_drop_infinity_values() -> None: assert ds.drop_infinity_values().df.count() == 7 # otherwise drop all columns assert ds.drop_infinity_values("field").df.count() == 1 + + +def test__process_class_params(spark: SparkSession) -> None: + """Test splitting of parameters between class and spark parameters.""" + params = { + "_df": spark.createDataFrame([(1,)], schema=MockDataset.get_schema()), + "recursiveFileLookup": True, + } + class_params, spark_params = Dataset._process_class_params(params) + assert "_df" in class_params, "Class params should contain _df" + assert ( + "recursiveFileLookup" in spark_params + ), "Spark params should contain recursiveFileLookup" diff --git a/tests/gentropy/dataset/test_variant_index.py b/tests/gentropy/dataset/test_variant_index.py index 15b102415..43c409ea6 100644 --- a/tests/gentropy/dataset/test_variant_index.py +++ b/tests/gentropy/dataset/test_variant_index.py @@ -24,14 +24,22 @@ class TestVariantIndex: MOCK_ANNOTATION_DATA = [ ("v1", "c1", 2, "T", "A", ["rs5"], "really bad consequence"), - ("v4", "c1", 5, "T", "A", ["rs6"], "mild consequence"), + ( + "v4_long", + "c1", + 5, + "T", + "A", + ["rs6"], + "mild consequence", + ), # should be hashed automatically ] MOCK_DATA = [ ("v1", "c1", 2, "T", "A", ["rs1"]), ("v2", "c1", 3, "T", "A", ["rs2", "rs3"]), ("v3", "c1", 4, "T", "A", None), - ("v4", "c1", 5, "T", "A", None), + ("v4_long", "c1", 5, "T", "A", None), # should be hashed automatically ] MOCK_SCHEMA = t.StructType( @@ -69,7 +77,7 @@ def _setup(self: TestVariantIndex, spark: SparkSession) -> None: self.df = spark.createDataFrame(self.MOCK_DATA, schema=self.MOCK_SCHEMA) # Loading variant index: self.variant_index = VariantIndex( - _df=self.df, _schema=VariantIndex.get_schema() + _df=self.df, _schema=VariantIndex.get_schema(), id_threshold=2 ) # Loading annotation variant index: @@ -78,6 +86,7 @@ def _setup(self: TestVariantIndex, spark: SparkSession) -> None: self.MOCK_ANNOTATION_DATA, schema=self.MOCK_ANNOTATION_SCHEMA ), _schema=VariantIndex.get_schema(), + id_threshold=2, ) def test_init_type(self: TestVariantIndex) -> None: @@ -132,6 +141,13 @@ def test_rsid_column_updated(self: TestVariantIndex) -> None: == 2 ) + def test_variantid_column_hashed(self: TestVariantIndex) -> None: + """Make sure the variantId column is hashed during initialisation. Threshold is set to 2, so var_4_long should be hashed.""" + assert ( + self.variant_index.df.filter(f.col("variantId").startswith("OTVAR")).count() + != 0 + ) + @pytest.mark.parametrize( "distance_type", ["distanceFromTss", "distanceFromFootprint"] ) diff --git a/tests/gentropy/datasource/ensembl/test_vep_variants.py b/tests/gentropy/datasource/ensembl/test_vep_variants.py index 5757fa2f5..556a22411 100644 --- a/tests/gentropy/datasource/ensembl/test_vep_variants.py +++ b/tests/gentropy/datasource/ensembl/test_vep_variants.py @@ -113,7 +113,7 @@ def test_extract_variant_index_from_vep( ) -> None: """Test if the variant index can be extracted from the VEP output.""" variant_index = VariantEffectPredictorParser.extract_variant_index_from_vep( - spark, self.SAMPLE_VEP_DATA_PATH + spark, self.SAMPLE_VEP_DATA_PATH, hash_threshold=100 ) assert isinstance( From b694d80d382d438801f16f24e3ad67557a3c8a3b Mon Sep 17 00:00:00 2001 From: Yakov Date: Thu, 24 Oct 2024 17:06:16 +0100 Subject: [PATCH 133/188] fix: fix in calculate_credible_set_log10bf (#868) --- src/gentropy/dataset/study_locus.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/gentropy/dataset/study_locus.py b/src/gentropy/dataset/study_locus.py index a68a00a6d..a0a231cfa 100644 --- a/src/gentropy/dataset/study_locus.py +++ b/src/gentropy/dataset/study_locus.py @@ -553,11 +553,14 @@ def calculate_credible_set_log10bf(cls: type[StudyLocus], logbfs: Column) -> Col +------------------+ |credibleSetlog10BF| +------------------+ - | 1.4765565| + | 0.6412604| +------------------+ """ - logsumexp_udf = f.udf(lambda x: get_logsum(x), FloatType()) + # log10=log/log(10)=log*0.43429448190325176 + logsumexp_udf = f.udf( + lambda x: (get_logsum(x) * 0.43429448190325176), FloatType() + ) return logsumexp_udf(logbfs).cast("double").alias("credibleSetlog10BF") @classmethod From 4c1013ea8f6349bc0c5e56985e924dbb6227eae5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Irene=20L=C3=B3pez=20Santiago?= <45119610+ireneisdoomed@users.noreply.github.com> Date: Fri, 25 Oct 2024 12:13:26 +0100 Subject: [PATCH 134/188] feat(l2g_feature_matrix): add `credibleSetConfidence` to L2G (#875) * feat(feature_matrix): add `credibleSetConfidence` * feat: add feature to l2g * test: add semantic and minor fixes * test: fix * test: fix --- .../python_api/datasets/l2g_features/other.md | 1 + src/gentropy/config.py | 2 + src/gentropy/dataset/l2g_features/other.py | 102 +++++++++++++- src/gentropy/method/l2g/feature_factory.py | 2 + tests/gentropy/dataset/test_l2g_feature.py | 128 ++++++++++++++---- 5 files changed, 209 insertions(+), 26 deletions(-) diff --git a/docs/python_api/datasets/l2g_features/other.md b/docs/python_api/datasets/l2g_features/other.md index e294e1813..6120f8b7a 100644 --- a/docs/python_api/datasets/l2g_features/other.md +++ b/docs/python_api/datasets/l2g_features/other.md @@ -6,6 +6,7 @@ title: Other features ::: gentropy.dataset.l2g_features.other.GeneCountFeature ::: gentropy.dataset.l2g_features.other.ProteinGeneCountFeature +::: gentropy.dataset.l2g_features.other.CredibleSetConfidenceFeature ## Common logic diff --git a/src/gentropy/config.py b/src/gentropy/config.py index 486778c3a..b3fe73aa8 100644 --- a/src/gentropy/config.py +++ b/src/gentropy/config.py @@ -261,6 +261,7 @@ class LocusToGeneConfig(StepConfig): # other "geneCount500kb", "proteinGeneCount500kb", + "credibleSetConfidence", ] ) hyperparameters: dict[str, Any] = field( @@ -331,6 +332,7 @@ class LocusToGeneFeatureMatrixConfig(StepConfig): # other "geneCount500kb", "proteinGeneCount500kb", + "credibleSetConfidence", ] ) _target_: str = "gentropy.l2g.LocusToGeneFeatureMatrixStep" diff --git a/src/gentropy/dataset/l2g_features/other.py b/src/gentropy/dataset/l2g_features/other.py index a033192a8..39348b00b 100644 --- a/src/gentropy/dataset/l2g_features/other.py +++ b/src/gentropy/dataset/l2g_features/other.py @@ -10,10 +10,11 @@ from gentropy.dataset.gene_index import GeneIndex from gentropy.dataset.l2g_features.l2g_feature import L2GFeature from gentropy.dataset.l2g_gold_standard import L2GGoldStandard -from gentropy.dataset.study_locus import StudyLocus +from gentropy.dataset.study_locus import CredibleSetConfidenceClasses, StudyLocus +from gentropy.dataset.variant_index import VariantIndex if TYPE_CHECKING: - from pyspark.sql import DataFrame + from pyspark.sql import Column, DataFrame def common_genecount_feature_logic( @@ -160,3 +161,100 @@ def compute( ), _schema=cls.get_schema(), ) + + +class CredibleSetConfidenceFeature(L2GFeature): + """Distance of the sentinel variant to gene TSS. This is not weighted by the causal probability.""" + + feature_dependency_type = [StudyLocus, VariantIndex] + feature_name = "credibleSetConfidence" + + @classmethod + def compute( + cls: type[CredibleSetConfidenceFeature], + study_loci_to_annotate: StudyLocus | L2GGoldStandard, + feature_dependency: dict[str, Any], + ) -> CredibleSetConfidenceFeature: + """Computes the feature. + + Args: + study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation + feature_dependency (dict[str, Any]): Dataset that contains the distance information + + Returns: + CredibleSetConfidenceFeature: Feature dataset + """ + full_credible_set = feature_dependency["study_locus"].df.select( + "studyLocusId", + "studyId", + f.explode("locus.variantId").alias("variantId"), + cls.score_credible_set_confidence(f.col("confidence")).alias( + cls.feature_name + ), + ) + + return cls( + _df=convert_from_wide_to_long( + ( + study_loci_to_annotate.df.drop("studyLocusId") + # Annotate genes + .join( + feature_dependency["variant_index"].df.select( + "variantId", + f.explode("transcriptConsequences.targetId").alias( + "geneId" + ), + ), + on="variantId", + how="left", + ) + # Annotate credible set confidence + .join(full_credible_set, ["variantId", "studyId"], "left") + .select("studyLocusId", "geneId", cls.feature_name) + ), + id_vars=("studyLocusId", "geneId"), + var_name="featureName", + value_name="featureValue", + ), + _schema=cls.get_schema(), + ) + + @classmethod + def score_credible_set_confidence( + cls: type[CredibleSetConfidenceFeature], + confidence_column: Column, + ) -> Column: + """Expression that assigns a score to the credible set confidence. + + Args: + confidence_column (Column): Confidence column in the StudyLocus object + + Returns: + Column: A confidence score between 0 and 1 + """ + return ( + f.when( + f.col("confidence") + == CredibleSetConfidenceClasses.FINEMAPPED_IN_SAMPLE_LD.value, + f.lit(1.0), + ) + .when( + f.col("confidence") + == CredibleSetConfidenceClasses.FINEMAPPED_OUT_OF_SAMPLE_LD.value, + f.lit(0.75), + ) + .when( + f.col("confidence") + == CredibleSetConfidenceClasses.PICSED_SUMMARY_STATS.value, + f.lit(0.5), + ) + .when( + f.col("confidence") + == CredibleSetConfidenceClasses.PICSED_TOP_HIT.value, + f.lit(0.25), + ) + .when( + f.col("confidence") == CredibleSetConfidenceClasses.UNKNOWN.value, + f.lit(0.0), + ) + ) diff --git a/src/gentropy/method/l2g/feature_factory.py b/src/gentropy/method/l2g/feature_factory.py index dbb5ecf48..ac3b5976e 100644 --- a/src/gentropy/method/l2g/feature_factory.py +++ b/src/gentropy/method/l2g/feature_factory.py @@ -30,6 +30,7 @@ ) from gentropy.dataset.l2g_features.l2g_feature import L2GFeature from gentropy.dataset.l2g_features.other import ( + CredibleSetConfidenceFeature, GeneCountFeature, ProteinGeneCountFeature, ) @@ -125,6 +126,7 @@ class FeatureFactory: "vepMaximumNeighbourhood": VepMaximumNeighbourhoodFeature, "geneCount500kb": GeneCountFeature, "proteinGeneCount500kb": ProteinGeneCountFeature, + "credibleSetConfidence": CredibleSetConfidenceFeature, } def __init__( diff --git a/tests/gentropy/dataset/test_l2g_feature.py b/tests/gentropy/dataset/test_l2g_feature.py index a841af0a6..5fc3e8eaa 100644 --- a/tests/gentropy/dataset/test_l2g_feature.py +++ b/tests/gentropy/dataset/test_l2g_feature.py @@ -63,6 +63,7 @@ common_genecount_feature_logic, GeneCountFeature, ProteinGeneCountFeature, + CredibleSetConfidenceFeature, ) from gentropy.dataset.study_index import StudyIndex from gentropy.dataset.study_locus import StudyLocus @@ -102,6 +103,7 @@ VepMeanNeighbourhoodFeature, GeneCountFeature, ProteinGeneCountFeature, + CredibleSetConfidenceFeature, ], ) def test_feature_factory_return_type( @@ -217,6 +219,33 @@ def sample_variant_index(spark: SparkSession) -> VariantIndex: ) +@pytest.fixture(scope="module") +def sample_variant_index_schema() -> StructType: + """Partial schema of the variant index.""" + return StructType( + [ + StructField("variantId", StringType(), True), + StructField("chromosome", StringType(), True), + StructField("position", IntegerType(), True), + StructField("referenceAllele", StringType(), True), + StructField("alternateAllele", StringType(), True), + StructField( + "transcriptConsequences", + ArrayType( + StructType( + [ + StructField("distanceFromTss", LongType(), True), + StructField("targetId", StringType(), True), + StructField("isEnsemblCanonical", BooleanType(), True), + ] + ) + ), + True, + ), + ] + ) + + class TestCommonColocalisationFeatureLogic: """Test the common logic of the colocalisation features.""" @@ -544,7 +573,11 @@ def test_common_neighbourhood_distance_feature_logic( ), "Output doesn't meet the expectation." @pytest.fixture(autouse=True) - def _setup(self: TestCommonDistanceFeatureLogic, spark: SparkSession) -> None: + def _setup( + self: TestCommonDistanceFeatureLogic, + spark: SparkSession, + sample_variant_index_schema: StructType, + ) -> None: """Set up testing fixtures.""" self.distance_type = "distanceFromTss" self.sample_study_locus = StudyLocus( @@ -571,28 +604,6 @@ def _setup(self: TestCommonDistanceFeatureLogic, spark: SparkSession) -> None: ), _schema=StudyLocus.get_schema(), ) - self.variant_index_schema = StructType( - [ - StructField("variantId", StringType(), True), - StructField("chromosome", StringType(), True), - StructField("position", IntegerType(), True), - StructField("referenceAllele", StringType(), True), - StructField("alternateAllele", StringType(), True), - StructField( - "transcriptConsequences", - ArrayType( - StructType( - [ - StructField("distanceFromTss", LongType(), True), - StructField("targetId", StringType(), True), - StructField("isEnsemblCanonical", BooleanType(), True), - ] - ) - ), - True, - ), - ] - ) self.sample_variant_index = VariantIndex( _df=spark.createDataFrame( [ @@ -630,7 +641,7 @@ def _setup(self: TestCommonDistanceFeatureLogic, spark: SparkSession) -> None: ], ), ], - self.variant_index_schema, + sample_variant_index_schema, ), _schema=VariantIndex.get_schema(), ) @@ -915,3 +926,72 @@ def _setup(self: TestCommonGeneCountFeatureLogic, spark: SparkSession) -> None: ), _schema=GeneIndex.get_schema(), ) + + +class TestCredibleSetConfidenceFeatureLogic: + """Test the CredibleSetConfidenceFeature method.""" + + def test_compute( + self: TestCredibleSetConfidenceFeatureLogic, + spark: SparkSession, + ) -> None: + """Test the logic of the function that scores a credible set's confidence.""" + sample_study_loci_to_annotate = self.sample_study_locus + observed_df = CredibleSetConfidenceFeature.compute( + study_loci_to_annotate=sample_study_loci_to_annotate, + feature_dependency={ + "study_locus": self.sample_study_locus, + "variant_index": self.sample_variant_index, + }, + ) + assert observed_df.df.first()["featureValue"] == 0.25 + + @pytest.fixture(autouse=True) + def _setup( + self: TestCredibleSetConfidenceFeatureLogic, + spark: SparkSession, + sample_variant_index_schema: StructType, + ) -> None: + """Set up testing fixtures.""" + self.sample_study_locus = StudyLocus( + _df=spark.createDataFrame( + [ + { + "studyLocusId": "1", + "variantId": "lead1", + "studyId": "study1", + "confidence": "PICS fine-mapped credible set based on reported top hit", + "chromosome": "1", + "locus": [ + { + "variantId": "lead1", + }, + ], + }, + ], + StudyLocus.get_schema(), + ), + _schema=StudyLocus.get_schema(), + ) + self.sample_variant_index = VariantIndex( + _df=spark.createDataFrame( + [ + ( + "lead1", + "chrom", + 1, + "A", + "T", + [ + { + "distanceFromTss": 10, + "targetId": "gene1", + "isEnsemblCanonical": True, + }, + ], + ) + ], + sample_variant_index_schema, + ), + _schema=VariantIndex.get_schema(), + ) From 3e61996a36fa9cd3d255692946ede3c30aa9915c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Irene=20L=C3=B3pez=20Santiago?= <45119610+ireneisdoomed@users.noreply.github.com> Date: Fri, 25 Oct 2024 12:40:42 +0100 Subject: [PATCH 135/188] feat(l2g): normalise distance features (#878) * feat(l2g): normalise distance features * feat(l2g): normalise distance features * chore: fix tests --- src/gentropy/dataset/l2g_features/distance.py | 11 +++++++++-- tests/gentropy/dataset/test_l2g_feature.py | 8 ++++---- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/gentropy/dataset/l2g_features/distance.py b/src/gentropy/dataset/l2g_features/distance.py index 8d42d30ed..2149dc339 100644 --- a/src/gentropy/dataset/l2g_features/distance.py +++ b/src/gentropy/dataset/l2g_features/distance.py @@ -64,7 +64,10 @@ def common_distance_feature_logic( on="variantId", how="inner", ) - .withColumn("distance_score", f.log10(distance_score_expr)) + .withColumn( + "distance_score", + f.log10(distance_score_expr) / f.log10(f.lit(genomic_window + 1)), + ) .groupBy("studyLocusId", "geneId") .agg(agg_expr.alias(feature_name)) ) @@ -105,7 +108,11 @@ def common_neighbourhood_distance_feature_logic( "regional_metric", f.mean(f.col(local_feature_name)).over(Window.partitionBy("studyLocusId")), ) - .withColumn(feature_name, f.col(local_feature_name) - f.col("regional_metric")) + .withColumn( + feature_name, + (f.col(local_feature_name) - f.col("regional_metric")) + / f.log10(f.lit(genomic_window + 1)), + ) .drop("regional_metric", local_feature_name) ) diff --git a/tests/gentropy/dataset/test_l2g_feature.py b/tests/gentropy/dataset/test_l2g_feature.py index 5fc3e8eaa..1757b7f68 100644 --- a/tests/gentropy/dataset/test_l2g_feature.py +++ b/tests/gentropy/dataset/test_l2g_feature.py @@ -502,15 +502,15 @@ class TestCommonDistanceFeatureLogic: { "studyLocusId": "1", "geneId": "gene2", - "distanceSentinelTss": 0.95, + "distanceSentinelTss": 0.92, }, ], ), ( "distanceTssMean", [ - {"studyLocusId": "1", "geneId": "gene1", "distanceTssMean": 0.09}, - {"studyLocusId": "1", "geneId": "gene2", "distanceTssMean": 0.65}, + {"studyLocusId": "1", "geneId": "gene1", "distanceTssMean": 0.08}, + {"studyLocusId": "1", "geneId": "gene2", "distanceTssMean": 0.63}, ], ), ], @@ -565,7 +565,7 @@ def test_common_neighbourhood_distance_feature_logic( .orderBy(f.col(feature_name).asc()) ) expected_df = spark.createDataFrame( - (["1", "gene1", -0.48], ["1", "gene2", 0.48]), + (["1", "gene1", -0.44], ["1", "gene2", 0.44]), ["studyLocusId", "geneId", feature_name], ).orderBy(feature_name) assert ( From ee96c11c450557399d91897add73f7ceeb323f46 Mon Sep 17 00:00:00 2001 From: xyg123 <33658607+xyg123@users.noreply.github.com> Date: Fri, 25 Oct 2024 13:04:26 +0100 Subject: [PATCH 136/188] feat: l2g feature to indicate if gene is protein-coding or not (#873) * feat: l2g feature to indicate if gene is protein-coding or not * chore: pre-commit auto fixes [...] * fix: remove print from tests * fix: remove print from tests * fix: correct window size for gene annotation * fix: test error with MkDocs * fix: rename feature to remove range --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .../python_api/datasets/l2g_features/other.md | 2 + src/gentropy/config.py | 2 + src/gentropy/dataset/l2g_features/other.py | 85 +++++++++++++++++ src/gentropy/method/l2g/feature_factory.py | 3 + tests/gentropy/dataset/test_l2g_feature.py | 95 +++++++++++++++++++ 5 files changed, 187 insertions(+) diff --git a/docs/python_api/datasets/l2g_features/other.md b/docs/python_api/datasets/l2g_features/other.md index 6120f8b7a..a3d89c13b 100644 --- a/docs/python_api/datasets/l2g_features/other.md +++ b/docs/python_api/datasets/l2g_features/other.md @@ -6,8 +6,10 @@ title: Other features ::: gentropy.dataset.l2g_features.other.GeneCountFeature ::: gentropy.dataset.l2g_features.other.ProteinGeneCountFeature +::: gentropy.dataset.l2g_features.other.ProteinCodingFeature ::: gentropy.dataset.l2g_features.other.CredibleSetConfidenceFeature ## Common logic ::: gentropy.dataset.l2g_features.other.common_genecount_feature_logic +::: gentropy.dataset.l2g_features.other.is_protein_coding_feature_logic diff --git a/src/gentropy/config.py b/src/gentropy/config.py index b3fe73aa8..5533043d2 100644 --- a/src/gentropy/config.py +++ b/src/gentropy/config.py @@ -262,6 +262,7 @@ class LocusToGeneConfig(StepConfig): "geneCount500kb", "proteinGeneCount500kb", "credibleSetConfidence", + "isProteinCoding", ] ) hyperparameters: dict[str, Any] = field( @@ -333,6 +334,7 @@ class LocusToGeneFeatureMatrixConfig(StepConfig): "geneCount500kb", "proteinGeneCount500kb", "credibleSetConfidence", + "isProteinCoding", ] ) _target_: str = "gentropy.l2g.LocusToGeneFeatureMatrixStep" diff --git a/src/gentropy/dataset/l2g_features/other.py b/src/gentropy/dataset/l2g_features/other.py index 39348b00b..4c28c2a0c 100644 --- a/src/gentropy/dataset/l2g_features/other.py +++ b/src/gentropy/dataset/l2g_features/other.py @@ -82,6 +82,51 @@ def common_genecount_feature_logic( ) +def is_protein_coding_feature_logic( + study_loci_to_annotate: StudyLocus | L2GGoldStandard, + *, + gene_index: GeneIndex, + feature_name: str, + genomic_window: int, +) -> DataFrame: + """Computes the feature to indicate if a gene is protein-coding or not. + + Args: + study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci + that will be used for annotation + gene_index (GeneIndex): Dataset containing information related to all genes in release. + feature_name (str): The name of the feature + genomic_window (int): The maximum window size to consider + + Returns: + DataFrame: Feature dataset, with 1 if the gene is protein-coding, 0 if not. + """ + study_loci_window = ( + study_loci_to_annotate.df.withColumn( + "window_start", f.col("position") - (genomic_window / 2) + ) + .withColumn("window_end", f.col("position") + (genomic_window / 2)) + .withColumnRenamed("chromosome", "SL_chromosome") + ) + return ( + study_loci_window.join( + gene_index.df.alias("genes"), + on=( + (f.col("SL_chromosome") == f.col("genes.chromosome")) + & (f.col("genes.tss") >= f.col("window_start")) + & (f.col("genes.tss") <= f.col("window_end")) + ), + how="inner", + ) + .withColumn( + feature_name, + f.when(f.col("biotype") == "protein_coding", f.lit(1)).otherwise(f.lit(0)), + ) + .select("studyLocusId", "geneId", feature_name) + .distinct() + ) + + class GeneCountFeature(L2GFeature): """Counts the number of genes within a specified window size from the study locus.""" @@ -163,6 +208,46 @@ def compute( ) +class ProteinCodingFeature(L2GFeature): + """Indicates whether a gene is protein-coding within a specified window size from the study locus.""" + + feature_dependency_type = GeneIndex + feature_name = "isProteinCoding" + + @classmethod + def compute( + cls: type[ProteinCodingFeature], + study_loci_to_annotate: StudyLocus | L2GGoldStandard, + feature_dependency: dict[str, Any], + ) -> ProteinCodingFeature: + """Computes the protein coding feature. + + Args: + study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation + feature_dependency (dict[str, Any]): Dictionary containing dependencies, including gene index + + Returns: + ProteinCodingFeature: Feature dataset with 1 if the gene is protein-coding, 0 otherwise + """ + genomic_window = 1000000 + protein_coding_df = is_protein_coding_feature_logic( + study_loci_to_annotate=study_loci_to_annotate, + feature_name=cls.feature_name, + genomic_window=genomic_window, + **feature_dependency, + ) + + return cls( + _df=convert_from_wide_to_long( + protein_coding_df, + id_vars=("studyLocusId", "geneId"), + var_name="featureName", + value_name="featureValue", + ), + _schema=cls.get_schema(), + ) + + class CredibleSetConfidenceFeature(L2GFeature): """Distance of the sentinel variant to gene TSS. This is not weighted by the causal probability.""" diff --git a/src/gentropy/method/l2g/feature_factory.py b/src/gentropy/method/l2g/feature_factory.py index ac3b5976e..fe792058a 100644 --- a/src/gentropy/method/l2g/feature_factory.py +++ b/src/gentropy/method/l2g/feature_factory.py @@ -1,3 +1,4 @@ +# isort: skip_file """Factory that computes features based on an input list.""" from __future__ import annotations @@ -33,6 +34,7 @@ CredibleSetConfidenceFeature, GeneCountFeature, ProteinGeneCountFeature, + ProteinCodingFeature, ) from gentropy.dataset.l2g_features.vep import ( VepMaximumFeature, @@ -126,6 +128,7 @@ class FeatureFactory: "vepMaximumNeighbourhood": VepMaximumNeighbourhoodFeature, "geneCount500kb": GeneCountFeature, "proteinGeneCount500kb": ProteinGeneCountFeature, + "isProteinCoding": ProteinCodingFeature, "credibleSetConfidence": CredibleSetConfidenceFeature, } diff --git a/tests/gentropy/dataset/test_l2g_feature.py b/tests/gentropy/dataset/test_l2g_feature.py index 1757b7f68..c6019cefc 100644 --- a/tests/gentropy/dataset/test_l2g_feature.py +++ b/tests/gentropy/dataset/test_l2g_feature.py @@ -1,5 +1,6 @@ # pylint: disable=too-few-public-methods # isort: skip_file + """Test locus-to-gene feature generation.""" from __future__ import annotations @@ -61,9 +62,11 @@ ) from gentropy.dataset.l2g_features.other import ( common_genecount_feature_logic, + is_protein_coding_feature_logic, GeneCountFeature, ProteinGeneCountFeature, CredibleSetConfidenceFeature, + ProteinCodingFeature, ) from gentropy.dataset.study_index import StudyIndex from gentropy.dataset.study_locus import StudyLocus @@ -104,6 +107,7 @@ GeneCountFeature, ProteinGeneCountFeature, CredibleSetConfidenceFeature, + ProteinCodingFeature, ], ) def test_feature_factory_return_type( @@ -878,6 +882,7 @@ def test_common_genecount_feature_logic( .select("studyLocusId", "geneId", feature_name) .orderBy("studyLocusId", "geneId") ) + assert ( observed_df.collect() == expected_df.collect() ), f"Expected and observed dataframes do not match for feature {feature_name}." @@ -928,6 +933,96 @@ def _setup(self: TestCommonGeneCountFeatureLogic, spark: SparkSession) -> None: ) +class TestCommonProteinCodingFeatureLogic: + """Test the CommonGeneCountFeatureLogic methods.""" + + @pytest.mark.parametrize( + ("expected_data"), + [ + ( + [ + {"studyLocusId": "1", "geneId": "gene1", "isProteinCoding500kb": 1}, + {"studyLocusId": "1", "geneId": "gene2", "isProteinCoding500kb": 1}, + {"studyLocusId": "1", "geneId": "gene3", "isProteinCoding500kb": 0}, + ] + ), + ], + ) + def test_is_protein_coding_feature_logic( + self: TestCommonProteinCodingFeatureLogic, + spark: SparkSession, + expected_data: list[dict[str, Any]], + ) -> None: + """Test the logic of the is_protein_coding_feature_logic function.""" + observed_df = ( + is_protein_coding_feature_logic( + study_loci_to_annotate=self.sample_study_locus, + gene_index=self.sample_gene_index, + feature_name="isProteinCoding500kb", + genomic_window=500000, + ) + .select("studyLocusId", "geneId", "isProteinCoding500kb") + .orderBy("studyLocusId", "geneId") + ) + + expected_df = ( + spark.createDataFrame(expected_data) + .select("studyLocusId", "geneId", "isProteinCoding500kb") + .orderBy("studyLocusId", "geneId") + ) + assert ( + observed_df.collect() == expected_df.collect() + ), "Expected and observed DataFrames do not match." + + @pytest.fixture(autouse=True) + def _setup(self: TestCommonProteinCodingFeatureLogic, spark: SparkSession) -> None: + """Set up sample data for the test.""" + # Sample study locus data + self.sample_study_locus = StudyLocus( + _df=spark.createDataFrame( + [ + { + "studyLocusId": "1", + "variantId": "var1", + "studyId": "study1", + "chromosome": "1", + "position": 1000000, + }, + ], + StudyLocus.get_schema(), + ), + _schema=StudyLocus.get_schema(), + ) + + # Sample gene index data with biotype + self.sample_gene_index = GeneIndex( + _df=spark.createDataFrame( + [ + { + "geneId": "gene1", + "chromosome": "1", + "tss": 950000, + "biotype": "protein_coding", + }, + { + "geneId": "gene2", + "chromosome": "1", + "tss": 1050000, + "biotype": "protein_coding", + }, + { + "geneId": "gene3", + "chromosome": "1", + "tss": 1010000, + "biotype": "non_coding", + }, + ], + GeneIndex.get_schema(), + ), + _schema=GeneIndex.get_schema(), + ) + + class TestCredibleSetConfidenceFeatureLogic: """Test the CredibleSetConfidenceFeature method.""" From 85be796c48a8c8afdd45cadde386d0cc76d3e692 Mon Sep 17 00:00:00 2001 From: Daniel-Considine <113430683+Daniel-Considine@users.noreply.github.com> Date: Fri, 25 Oct 2024 13:18:07 +0100 Subject: [PATCH 137/188] feat: making credset qc have an option to coalsce and deduplicate credible sets without ld pruning (#877) * feat: making credset qc have an option to coalsce and deduplicate credible sets without ld pruning * fix: adding recursiveFileLookup for reading credible sets * Update src/gentropy/credible_set_qc.py Co-authored-by: Szymon Szyszkowski <69353402+project-defiant@users.noreply.github.com> * Update src/gentropy/method/susie_inf.py Co-authored-by: Szymon Szyszkowski <69353402+project-defiant@users.noreply.github.com> * Update src/gentropy/method/susie_inf.py Co-authored-by: Szymon Szyszkowski <69353402+project-defiant@users.noreply.github.com> * chore: pre-commit auto fixes [...] * fix: few typos from review * fix: if statement tweaks --------- Co-authored-by: Yakov Co-authored-by: Szymon Szyszkowski <69353402+project-defiant@users.noreply.github.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- src/gentropy/credible_set_qc.py | 30 ++++++++++++++------- src/gentropy/method/susie_inf.py | 45 ++++++++++++++++++++++---------- 2 files changed, 51 insertions(+), 24 deletions(-) diff --git a/src/gentropy/credible_set_qc.py b/src/gentropy/credible_set_qc.py index 31d298886..8ea9e06dd 100644 --- a/src/gentropy/credible_set_qc.py +++ b/src/gentropy/credible_set_qc.py @@ -16,11 +16,12 @@ def __init__( self, session: Session, credible_sets_path: str, - study_index_path: str, - ld_index_path: str, output_path: str, p_value_threshold: float = 1e-5, purity_min_r2: float = 0.01, + clump: bool = False, + ld_index_path: str | None = None, + study_index_path: str | None = None, ld_min_r2: float = 0.8, ) -> None: """Run credible set quality control step. @@ -28,23 +29,32 @@ def __init__( Args: session (Session): Session object. credible_sets_path (str): Path to credible sets file. - study_index_path (str): Path to study index file. - ld_index_path (str): Path to LD index file. output_path (str): Path to write the output file. p_value_threshold (float): P-value threshold for credible set quality control. Default is 1e-5. purity_min_r2 (float): Minimum R2 for purity estimation. Default is 0.01. + clump (bool): Whether to clump the credible sets by LD. Default is False. + ld_index_path (str | None): Path to LD index file. + study_index_path (str | None): Path to study index file. ld_min_r2 (float): Minimum R2 for LD estimation. Default is 0.8. """ - cred_sets = StudyLocus.from_parquet(session, credible_sets_path) - study_index = StudyIndex.from_parquet(session, study_index_path) - ld_index = LDIndex.from_parquet(session, ld_index_path) - + cred_sets = StudyLocus.from_parquet( + session, credible_sets_path, recursiveFileLookup=True + ).coalesce(200) + ld_index = ( + LDIndex.from_parquet(session, ld_index_path) if ld_index_path else None + ) + study_index = ( + StudyIndex.from_parquet(session, study_index_path) + if study_index_path + else None + ) cred_sets_clean = SUSIE_inf.credible_set_qc( cred_sets, - study_index, - ld_index, p_value_threshold, purity_min_r2, + clump, + ld_index, + study_index, ld_min_r2, ) diff --git a/src/gentropy/method/susie_inf.py b/src/gentropy/method/susie_inf.py index 4f75faad8..f90d15a14 100644 --- a/src/gentropy/method/susie_inf.py +++ b/src/gentropy/method/susie_inf.py @@ -9,6 +9,7 @@ import pyspark.sql.functions as f import scipy.linalg import scipy.special +from pyspark.sql.window import Window from scipy.optimize import minimize, minimize_scalar from scipy.special import logsumexp @@ -469,43 +470,59 @@ def cred_inf( @staticmethod def credible_set_qc( cred_sets: StudyLocus, - study_index: StudyIndex, - ld_index: LDIndex, p_value_threshold: float = 1e-5, purity_min_r2: float = 0.01, + clump: bool = False, + ld_index: LDIndex | None = None, + study_index: StudyIndex | None = None, ld_min_r2: float = 0.8, ) -> StudyLocus: """Filter credible sets by lead P-value and min-R2 purity, and performs LD clumping. + In case of duplicated loci, the filtering retains the loci wth the highest credibleSetLog10BF + Args: cred_sets (StudyLocus): StudyLocus object with credible sets to filter/clump - study_index (StudyIndex): StudyIndex object - ld_index (LDIndex): LDIndex object p_value_threshold (float): p-value threshold for filtering credible sets, default is 1e-5 purity_min_r2 (float): min-R2 purity threshold for filtering credible sets, default is 0.01 + clump (bool): Whether to clump the credible sets by LD, default is False + ld_index (LDIndex | None): LDIndex object + study_index (StudyIndex | None): StudyIndex object ld_min_r2 (float): LD R2 threshold for clumping, default is 0.8 Returns: StudyLocus: Credible sets which pass filters and LD clumping. """ - df = ( + cred_sets.df = ( cred_sets.df.withColumn( "pValue", f.col("pValueMantissa") * f.pow(10, f.col("pValueExponent")) ) .filter(f.col("pValue") <= p_value_threshold) .filter(f.col("purityMinR2") >= purity_min_r2) .drop("pValue") + .withColumn( + "rn", + f.row_number().over( + Window.partitionBy("studyLocusId").orderBy( + f.desc("credibleSetLog10BF") + ) + ), + ) + .filter(f.col("rn") == 1) + .drop("rn") ) - cred_sets.df = df - cred_sets = ( - cred_sets.annotate_ld(study_index, ld_index, ld_min_r2) - .clump() - .filter( - ~f.array_contains( - f.col("qualityControls"), - "Explained by a more significant variant in high LD (clumped)", + if clump: + assert study_index, "Running in clump mode, which requires study_index." + assert ld_index, "Running in clump mode, which requires ld_index." + cred_sets = ( + cred_sets.annotate_ld(study_index, ld_index, ld_min_r2) + .clump() + .filter( + ~f.array_contains( + f.col("qualityControls"), + "Explained by a more significant variant in high LD (clumped)", + ) ) ) - ) return cred_sets From 5d9d7cbb6487ec3cc4d7d4152f23c1b62a4ba0ab Mon Sep 17 00:00:00 2001 From: Szymon Szyszkowski <69353402+project-defiant@users.noreply.github.com> Date: Fri, 25 Oct 2024 18:06:55 +0100 Subject: [PATCH 138/188] test(study_locus) credible_set_qc step integration test (#880) * test(credible_set_qc_step): added main functionality test * chore: moved default values to step config * chore: ensure to save with study locus schema * chore: enhanced docs * docs(credible_set_qc_ste): docs page * chore: typo --------- Co-authored-by: Szymon Szyszkowski --- docs/python_api/steps/credible_set_qc_step.md | 7 + src/gentropy/config.py | 11 +- src/gentropy/credible_set_qc.py | 46 ++++-- src/gentropy/method/susie_inf.py | 12 +- tests/gentropy/step/test_credible_set_qc.py | 151 ++++++++++++++++++ 5 files changed, 203 insertions(+), 24 deletions(-) create mode 100644 docs/python_api/steps/credible_set_qc_step.md create mode 100644 tests/gentropy/step/test_credible_set_qc.py diff --git a/docs/python_api/steps/credible_set_qc_step.md b/docs/python_api/steps/credible_set_qc_step.md new file mode 100644 index 000000000..2999115e7 --- /dev/null +++ b/docs/python_api/steps/credible_set_qc_step.md @@ -0,0 +1,7 @@ +--- +title: credible_set_qc +--- + +::: gentropy.credible_set_qc.CredibleSetQCStep + +::: gentropy.config.CredibleSetQCStepConfig diff --git a/src/gentropy/config.py b/src/gentropy/config.py index 5533043d2..c5889dbab 100644 --- a/src/gentropy/config.py +++ b/src/gentropy/config.py @@ -589,16 +589,18 @@ class SummaryStatisticsQCStepConfig(StepConfig): @dataclass -class CredibleSetQCConfig(StepConfig): +class CredibleSetQCStepConfig(StepConfig): """Credible set quality control step configuration.""" credible_sets_path: str = MISSING - study_index_path: str = MISSING - ld_index_path: str = MISSING output_path: str = MISSING p_value_threshold: float = 1e-5 purity_min_r2: float = 0.01 - ld_min_r2: float = 0.8 + clump: bool = False + ld_index_path: str | None = None + study_index_path: str | None = None + ld_min_r2: float | None = 0.8 + n_partitions: int | None = 200 _target_: str = "gentropy.credible_set_qc.CredibleSetQCStep" @@ -732,3 +734,4 @@ def register_config() -> None: node=LocusToGeneEvidenceStepConfig, ) cs.store(group="step", name="finngen_ukb_meta_ingestion", node=FinngenUkbMetaConfig) + cs.store(group="step", name="credible_set_qc", node=CredibleSetQCStepConfig) diff --git a/src/gentropy/credible_set_qc.py b/src/gentropy/credible_set_qc.py index 8ea9e06dd..5b89faf59 100644 --- a/src/gentropy/credible_set_qc.py +++ b/src/gentropy/credible_set_qc.py @@ -17,29 +17,38 @@ def __init__( session: Session, credible_sets_path: str, output_path: str, - p_value_threshold: float = 1e-5, - purity_min_r2: float = 0.01, - clump: bool = False, - ld_index_path: str | None = None, - study_index_path: str | None = None, - ld_min_r2: float = 0.8, + p_value_threshold: float, + purity_min_r2: float, + clump: bool, + ld_index_path: str | None, + study_index_path: str | None, + ld_min_r2: float | None, + n_partitions: int | None, ) -> None: """Run credible set quality control step. + Check defaults used by steps in hydra configuration `gentropy.config.CredibleSetQCStepConfig` + + Due to the large number of partitions at the input credible_set_path after finemapping, the + best strategy it is to repartition and save the dataset after deduplication. + + The `clump` mode will perform additional LD based clumping on the input credible sets. + Enabling `clump` mode requires providing `ld_index_path`, `study_index_path` and `ld_min_r2`. + Args: session (Session): Session object. credible_sets_path (str): Path to credible sets file. output_path (str): Path to write the output file. - p_value_threshold (float): P-value threshold for credible set quality control. Default is 1e-5. - purity_min_r2 (float): Minimum R2 for purity estimation. Default is 0.01. - clump (bool): Whether to clump the credible sets by LD. Default is False. + p_value_threshold (float): P-value threshold for credible set quality control. + purity_min_r2 (float): Minimum R2 for purity estimation. + clump (bool): Whether to clump the credible sets by LD. ld_index_path (str | None): Path to LD index file. study_index_path (str | None): Path to study index file. - ld_min_r2 (float): Minimum R2 for LD estimation. Default is 0.8. + ld_min_r2 (float | None): Minimum R2 for LD estimation. + n_partitions (int | None): Number of partitions to coalesce the dataset after reading. Defaults to 200 """ - cred_sets = StudyLocus.from_parquet( - session, credible_sets_path, recursiveFileLookup=True - ).coalesce(200) + n_partitions = n_partitions or 200 + ld_index = ( LDIndex.from_parquet(session, ld_index_path) if ld_index_path else None ) @@ -48,6 +57,11 @@ def __init__( if study_index_path else None ) + + cred_sets = StudyLocus.from_parquet( + session, credible_sets_path, recursiveFileLookup=True + ).coalesce(n_partitions) + cred_sets_clean = SUSIE_inf.credible_set_qc( cred_sets, p_value_threshold, @@ -57,5 +71,7 @@ def __init__( study_index, ld_min_r2, ) - - cred_sets_clean.df.write.mode(session.write_mode).parquet(output_path) + # ensure the saved object is still a valid StudyLocus + StudyLocus( + _df=cred_sets_clean.df, _schema=StudyLocus.get_schema() + ).df.write.mode(session.write_mode).parquet(output_path) diff --git a/src/gentropy/method/susie_inf.py b/src/gentropy/method/susie_inf.py index f90d15a14..e8a4a57b1 100644 --- a/src/gentropy/method/susie_inf.py +++ b/src/gentropy/method/susie_inf.py @@ -15,7 +15,7 @@ from gentropy.dataset.ld_index import LDIndex from gentropy.dataset.study_index import StudyIndex -from gentropy.dataset.study_locus import StudyLocus +from gentropy.dataset.study_locus import StudyLocus, StudyLocusQualityCheck @dataclass @@ -475,11 +475,12 @@ def credible_set_qc( clump: bool = False, ld_index: LDIndex | None = None, study_index: StudyIndex | None = None, - ld_min_r2: float = 0.8, + ld_min_r2: float | None = 0.8, ) -> StudyLocus: """Filter credible sets by lead P-value and min-R2 purity, and performs LD clumping. - In case of duplicated loci, the filtering retains the loci wth the highest credibleSetLog10BF + In case of duplicated loci, the filtering retains the loci wth the highest credibleSetlog10BF. + Args: cred_sets (StudyLocus): StudyLocus object with credible sets to filter/clump @@ -488,7 +489,7 @@ def credible_set_qc( clump (bool): Whether to clump the credible sets by LD, default is False ld_index (LDIndex | None): LDIndex object study_index (StudyIndex | None): StudyIndex object - ld_min_r2 (float): LD R2 threshold for clumping, default is 0.8 + ld_min_r2 (float | None): LD R2 threshold for clumping, default is 0.8 Returns: StudyLocus: Credible sets which pass filters and LD clumping. @@ -514,13 +515,14 @@ def credible_set_qc( if clump: assert study_index, "Running in clump mode, which requires study_index." assert ld_index, "Running in clump mode, which requires ld_index." + assert ld_min_r2, "Running in clump mode, which requires ld_min_r2 value." cred_sets = ( cred_sets.annotate_ld(study_index, ld_index, ld_min_r2) .clump() .filter( ~f.array_contains( f.col("qualityControls"), - "Explained by a more significant variant in high LD (clumped)", + StudyLocusQualityCheck.LD_CLUMPED.value, ) ) ) diff --git a/tests/gentropy/step/test_credible_set_qc.py b/tests/gentropy/step/test_credible_set_qc.py new file mode 100644 index 000000000..c7fb58c8c --- /dev/null +++ b/tests/gentropy/step/test_credible_set_qc.py @@ -0,0 +1,151 @@ +"""Test credible set qc step.""" + +from pathlib import Path + +import pytest +from pyspark.sql import functions as f +from pyspark.sql import types as t + +from gentropy.common.session import Session +from gentropy.credible_set_qc import CredibleSetQCStep +from gentropy.dataset.study_locus import StudyLocus + + +@pytest.mark.step_test +class TestCredibleSetQCStep: + """Test credible set qc.""" + + @pytest.fixture(autouse=True) + def _setup(self, session: Session, tmp_path: Path) -> None: + """Setup StudyLocus for testing.""" + # NOTE: About the input dataset for tests + # Entry dataset contains 6 loci (3 of them contains duplicated studyLocusId, 2 contains the same studyId) + # The step is expected to remove the duplicates of the studyLocus (1 row) + # THe step is expected to remove rows which pValue <= p_val_threshold (1 row) + # The step is expected to remove rows which purityMinR2 >= to purity_min_r2 (1 row) + # at the end we should end up with 2 non duplicated loci + self.purity_min_r2 = 0.01 + self.p_value_threshold = 1e-5 + self.n_partitions = 1 + credible_set_data = [ + ( + "A", # duplicated credibleSetId + "1_100_G_GA", # variantId + "GCST1", # duplicated studyId + 1.0, # pValMantissa + -6, # pValExponent + 1.0, # credibleSetlog10BF -> should be skipped due to the lowest Log10BF + 1.0, # purityMinR2 + ), + ( + "A", # duplicated credibleSetId + "1_100_G_GA", # variantId + "GCST1", # duplicated studyId + 1.0, # pValMantissa + -6, # pValExponent + 2.0, # credibleSetlog10BF -> highest log10BF within duplicates considering single study + 1.0, # purityMinR2 + ), + ( + "A", # duplicated credibleSetId + "1_100_G_GA", # variantId + "GCST2", # studyId + 1.0, # pValMantissa + -6, # pValExponent + 3.0, # credibleSetlog10BF -> highest log10BF within duplicates + 1.0, # purityMinR2 + ), + ( + "B", # credibleSetId + "1_200_G_GA", # variantId + "GCST3", # studyId + 1.0, # pValMantissa + -4, # too high pValExponent => pVal = 1.0e-4 < p_val_threshold + 1.0, # credibleSetlog10BF + 1.0, # purityMinR2 + ), + ( + "C", # credibleSetId + "1_300_G_GA", # variantId + "GCST3", # studyId + 1.0, # pValMantissa + -6, # pValExponent + 1.0, # credibleSetlog10BF + 0.001, # purityMinR2 < purity_min_r2 + ), + ( + # full row OK! + "D", # credibleSetId + "1_400_G_GA", # variantId + "GCST3", # studyId + 1.0, # pValMantissa + -6, # pValExponent + 1.0, # credibleSetlog10BF + 1.0, # purityMinR2 + ), + ] + cs_schema = t.StructType( + [ + t.StructField("studyLocusId", t.StringType(), True), + t.StructField("variantId", t.StringType(), True), + t.StructField("studyId", t.StringType(), True), + t.StructField("pValueMantissa", t.FloatType(), True), + t.StructField("pValueExponent", t.IntegerType(), True), + t.StructField("credibleSetlog10BF", t.DoubleType(), True), + t.StructField("purityMinR2", t.DoubleType(), True), + ] + ) + + # NOTE: Use proper input! + # Ensure the input dataset is saved per studyLocusId in recursive manner. + # This mimics the dataset with multiple loci evaluated separately. + self.credible_set_path = str(tmp_path / "credible_set_datasets") + cs_df = session.spark.createDataFrame(credible_set_data, schema=cs_schema) + cs_path = tmp_path / "credible_set_dataset" + loci_ids = {row["studyLocusId"] for row in cs_df.collect()} + for loci_id in loci_ids: + loci_path = str(cs_path / loci_id) + cs_df.filter(f.col("studyLocusId") == loci_id).write.parquet(loci_path) + self.input_cs_df = cs_df + self.cs_path = str(cs_path) + self.output_path = str(tmp_path / "clean_credible_sets") + + def test_step(self, session: Session) -> None: + """Invoke the step to check if it works correctly.""" + assert not Path(self.output_path).exists(), "Input for qc does not exists." + assert Path(self.cs_path).exists(), "Output of qc is not emptied before test." + assert self.input_cs_df.count() == 6, "Incorrect number of rows." + CredibleSetQCStep( + session=session, + credible_sets_path=self.cs_path, + output_path=self.output_path, + p_value_threshold=self.p_value_threshold, + purity_min_r2=self.purity_min_r2, + clump=False, + ld_index_path=None, + study_index_path=None, + ld_min_r2=None, + n_partitions=self.n_partitions, + ) + + assert Path(self.output_path).exists(), "Output of qc does not exists." + # check the number of partitions + partitions = [ + str(p) + for p in Path(self.output_path).iterdir() + if str(p).endswith(".parquet") + ] + assert ( + len(partitions) == self.n_partitions + ), "Incorrect number of partitions in the output." + cs = StudyLocus.from_parquet( + session, self.output_path, recursiveFileLookup=True + ) + assert cs.df.count() == 2 # Row A where LogBF == 3.0 and row D + assert cs.df.rdd.getNumPartitions() == self.n_partitions + data = { + row["studyLocusId"]: row["credibleSetlog10BF"] for row in cs.df.collect() + } + assert sorted(data.keys()) == ["A", "D"] + # ensure the Locus A with highest credibleSetlog10BF was chosen + assert data["A"] == 3.0 From cbbf3c5d39f685ea8adeae70f3e4591294e8f9a3 Mon Sep 17 00:00:00 2001 From: Daniel Suveges Date: Sat, 26 Oct 2024 18:07:07 +0100 Subject: [PATCH 139/188] feat: flagging duplicated entries while keeping one of the duplicates (#876) * feat: flagging duplicated entries while keeping one of the duplicates * feat: turning validation on for validation step * fix: test for duplication flagging * fix: test for duplication flagging --------- Co-authored-by: Yakov --- src/gentropy/dataset/dataset.py | 11 ++--- src/gentropy/study_locus_validation.py | 2 + tests/gentropy/dataset/test_study_index.py | 8 ++-- tests/gentropy/dataset/test_study_locus.py | 55 ++++++++++++++++++++++ 4 files changed, 65 insertions(+), 11 deletions(-) diff --git a/src/gentropy/dataset/dataset.py b/src/gentropy/dataset/dataset.py index 779faefe2..67fe05eaf 100644 --- a/src/gentropy/dataset/dataset.py +++ b/src/gentropy/dataset/dataset.py @@ -322,7 +322,9 @@ def update_quality_flag( @staticmethod def flag_duplicates(test_column: Column) -> Column: - """Return True for duplicated values in column. + """Return True for rows, where the value was already seen in column. + + This implementation allows keeping the first occurrence of the value. Args: test_column (Column): Column to check for duplicates @@ -331,12 +333,7 @@ def flag_duplicates(test_column: Column) -> Column: Column: Column with a boolean flag for duplicates """ return ( - f.count(test_column).over( - Window.partitionBy(test_column).rowsBetween( - Window.unboundedPreceding, Window.unboundedFollowing - ) - ) - > 1 + f.row_number().over(Window.partitionBy(test_column).orderBy(f.rand())) > 1 ) @staticmethod diff --git a/src/gentropy/study_locus_validation.py b/src/gentropy/study_locus_validation.py index 0be046a67..bca6b8e11 100644 --- a/src/gentropy/study_locus_validation.py +++ b/src/gentropy/study_locus_validation.py @@ -49,6 +49,8 @@ def __init__( .filter_credible_set(credible_interval=CredibleInterval.IS99) # Annotate credible set confidence: .assign_confidence() + # Flagging credible sets that are duplicated: + .validate_unique_study_locus_id() ).persist() # we will need this for 2 types of outputs study_locus_with_qc.valid_rows(invalid_qc_reasons, invalid=True).df.write.mode( diff --git a/tests/gentropy/dataset/test_study_index.py b/tests/gentropy/dataset/test_study_index.py index 4bfede7d9..05b652752 100644 --- a/tests/gentropy/dataset/test_study_index.py +++ b/tests/gentropy/dataset/test_study_index.py @@ -313,7 +313,7 @@ class TestUniquenessValidation: STUDY_DATA = [ # This is the only study to be flagged: ("s1", "eqtl", "p"), - ("s1", "eqtl", "p"), + ("s1", "eqtl", "p"), # Duplicate -> one should be flagged ("s3", "gwas", "p"), ("s4", "gwas", "p"), ] @@ -337,8 +337,8 @@ def test_uniqueness_correct_data(self: TestUniquenessValidation) -> None: """Testing if the function returns the right type.""" validated = self.study_index.validate_unique_study_id().persist() - # We have more than one flagged studies: - assert validated.df.filter(f.size(f.col("qualityControls")) > 0).count() > 1 + # We have only one flagged study: + assert validated.df.filter(f.size(f.col("qualityControls")) > 0).count() == 1 # The flagged study identifiers are found more than once: flagged_ids = { @@ -350,7 +350,7 @@ def test_uniqueness_correct_data(self: TestUniquenessValidation) -> None: } for _, count in flagged_ids.items(): - assert count > 1 + assert count == 1 # the right study is found: assert "s1" in flagged_ids diff --git a/tests/gentropy/dataset/test_study_locus.py b/tests/gentropy/dataset/test_study_locus.py index eaee0ebf3..3cbaf6866 100644 --- a/tests/gentropy/dataset/test_study_locus.py +++ b/tests/gentropy/dataset/test_study_locus.py @@ -1121,3 +1121,58 @@ def test_qc_valid_chromosomes( StudyLocusQualityCheck.INVALID_CHROMOSOME.value in row["qualityControls"] ) + + +class TestStudyLocusDuplicationFlagging: + """Collection of tests related to flagging redundant credible sets.""" + + STUDY_LOCUS_DATA = [ + # Non-duplicated: + ("1", "v1", "s1", "pics"), + # Triplicate: + ("3", "v3", "s1", "pics"), + ("3", "v3", "s1", "pics"), + ("3", "v3", "s1", "pics"), + ] + + STUDY_LOCUS_SCHEMA = t.StructType( + [ + t.StructField("studyLocusId", t.StringType(), False), + t.StructField("variantId", t.StringType(), False), + t.StructField("studyId", t.StringType(), False), + t.StructField("finemappingMethod", t.StringType(), False), + ] + ) + + @pytest.fixture(autouse=True) + def _setup(self: TestStudyLocusDuplicationFlagging, spark: SparkSession) -> None: + """Setup study locus for testing.""" + self.study_locus = StudyLocus( + _df=spark.createDataFrame( + self.STUDY_LOCUS_DATA, schema=self.STUDY_LOCUS_SCHEMA + ).withColumn( + "qualityControls", f.array().cast(t.ArrayType(t.StringType())) + ), + _schema=StudyLocus.get_schema(), + ) + + # Run validation: + self.validated = self.study_locus.validate_unique_study_locus_id() + + def test_duplication_flag_type(self: TestStudyLocusDuplicationFlagging) -> None: + """Test duplication flagging return type.""" + assert isinstance(self.validated, StudyLocus) + + def test_duplication_flag_no_data_loss( + self: TestStudyLocusDuplicationFlagging, + ) -> None: + """Test duplication flagging no data loss.""" + assert self.validated.df.count() == self.study_locus.df.count() + + def test_duplication_flag_correctness( + self: TestStudyLocusDuplicationFlagging, + ) -> None: + """Make sure that the end, there are two study loci that pass the validation.""" + assert self.validated.df.filter(f.size("qualityControls") == 0).count() == 2 + + assert self.validated.df.filter(f.size("qualityControls") > 0).count() == 2 From d12d65d849b4ca518b5a66a6460f677adffa1d35 Mon Sep 17 00:00:00 2001 From: Tobi Alegbe Date: Mon, 28 Oct 2024 09:54:03 +0000 Subject: [PATCH 140/188] feat: flag and filter credible sets (#879) * feat(flag_and_filter_credible_sets): add code for identifying abnormal credible sets * feat(flag_and_filter_credible_sets): restructure tests * chore(flag_and_filter_credible_sets): update schema for spark loading * feat(flag_and_filter_credible_sets): first comple draft filtering abnormal pips code * fix(flag_and_filter_credible_sets): tweak broken code and unresolved merge * fix(flag_and_filter_credible_sets): amend test logic * fix(flag_and_filter_credible_sets): modify logic to simplify and account for floating point errors * chore(flag_and_filter_credible_sets): simplify logic to boolean --- src/gentropy/dataset/study_locus.py | 51 +++ src/gentropy/study_locus_validation.py | 2 + tests/gentropy/dataset/test_study_locus.py | 490 +++++++++++---------- 3 files changed, 322 insertions(+), 221 deletions(-) diff --git a/src/gentropy/dataset/study_locus.py b/src/gentropy/dataset/study_locus.py index a0a231cfa..e685d828f 100644 --- a/src/gentropy/dataset/study_locus.py +++ b/src/gentropy/dataset/study_locus.py @@ -82,6 +82,7 @@ class StudyLocusQualityCheck(Enum): IN_MHC (str): Flagging study loci in the MHC region REDUNDANT_PICS_TOP_HIT (str): Flagging study loci in studies with PICS results from summary statistics EXPLAINED_BY_SUSIE (str): Study locus in region explained by a SuSiE credible set + ABNORMAL_PIPS (str): Flagging study loci with a sum of PIPs that are not in [0.99,1] OUT_OF_SAMPLE_LD (str): Study locus finemapped without in-sample LD reference INVALID_CHROMOSOME (str): Chromosome not in 1:22, X, Y, XY or MT """ @@ -113,6 +114,7 @@ class StudyLocusQualityCheck(Enum): TOP_HIT = "Study locus from curated top hit" EXPLAINED_BY_SUSIE = "Study locus in region explained by a SuSiE credible set" OUT_OF_SAMPLE_LD = "Study locus finemapped without in-sample LD reference" + ABNORMAL_PIPS = "Study locus with a sum of PIPs that not in the expected range [0.99,1]" INVALID_CHROMOSOME = "Chromosome not in 1:22, X, Y, XY or MT" @@ -391,6 +393,55 @@ def _qc_subsignificant_associations( StudyLocusQualityCheck.SUBSIGNIFICANT_FLAG, ) + def qc_abnormal_pips( + self: StudyLocus, + sum_pips_lower_threshold: float = 0.99, + sum_pips_upper_threshold: float = 1.0001, # Set slightly above 1 to account for floating point errors + ) -> StudyLocus: + """Filter study-locus by sum of posterior inclusion probabilities to ensure that the sum of PIPs is within a given range. + + Args: + sum_pips_lower_threshold (float): Lower threshold for the sum of PIPs. + sum_pips_upper_threshold (float): Upper threshold for the sum of PIPs. + + Returns: + StudyLocus: Filtered study-locus dataset. + """ + # QC column might not be present so we have to be ready to handle it: + qc_select_expression = ( + f.col("qualityControls") + if "qualityControls" in self.df.columns + else f.lit(None).cast(ArrayType(StringType())) + ) + + flag = (self.df.withColumn( + "sumPosteriorProbability", + f.aggregate( + f.col("locus"), + f.lit(0.0), + lambda acc, x: acc + x["posteriorProbability"] + )).withColumn( + "pipOutOfRange", + f.when( + (f.col("sumPosteriorProbability") < sum_pips_lower_threshold) | + (f.col("sumPosteriorProbability") > sum_pips_upper_threshold), + True + ).otherwise(False))) + + return StudyLocus( + _df=(flag + # Flagging loci with failed studies: + .withColumn( + "qualityControls", + self.update_quality_flag( + qc_select_expression, + f.col("pipOutOfRange"), + StudyLocusQualityCheck.ABNORMAL_PIPS + ), + ).drop("sumPosteriorProbability", "pipOutOfRange")), + _schema=self.get_schema() + ) + @staticmethod def _overlapping_peaks( credset_to_overlap: DataFrame, intra_study_overlap: bool = False diff --git a/src/gentropy/study_locus_validation.py b/src/gentropy/study_locus_validation.py index bca6b8e11..1c8ae161c 100644 --- a/src/gentropy/study_locus_validation.py +++ b/src/gentropy/study_locus_validation.py @@ -45,6 +45,8 @@ def __init__( .annotate_study_type(study_index) # Add study type to study locus .qc_redundant_top_hits_from_PICS() # Flagging top hits from studies with PICS summary statistics .qc_explained_by_SuSiE() # Flagging credible sets in regions explained by SuSiE + # Flagging credible sets with PIP > 1 or PIP < 0.99 + .qc_abnormal_pips(sum_pips_lower_threshold=0.99,sum_pips_upper_threshold=1.0001) # Annotates credible intervals and filter to only keep 99% credible sets .filter_credible_set(credible_interval=CredibleInterval.IS99) # Annotate credible set confidence: diff --git a/tests/gentropy/dataset/test_study_locus.py b/tests/gentropy/dataset/test_study_locus.py index 3cbaf6866..7f15a11a6 100644 --- a/tests/gentropy/dataset/test_study_locus.py +++ b/tests/gentropy/dataset/test_study_locus.py @@ -203,72 +203,84 @@ def test_filter_credible_set(mock_study_locus: StudyLocus) -> None: ) -@pytest.mark.parametrize( - ("observed", "expected"), +def test_qc_abnormal_pips(mock_study_locus: StudyLocus) -> None: + """Test that the qc_abnormal_pips method returns a StudyLocus object.""" + assert isinstance(mock_study_locus.qc_abnormal_pips(0.99, 1), StudyLocus) + + +# Used primarily for test_unique_variants_in_locus but also for other tests +test_unique_variants_in_locus_test_data = [ + ( + # Locus is not null, should return union between variants in locus and lead variant + [ + ( + "1", + "traitA", + "22_varA", + [ + {"variantId": "22_varA", "posteriorProbability": 0.44}, + {"variantId": "22_varB", "posteriorProbability": 0.015}, + ], + ), + ], + [ + ( + "22_varA", + "22", + ), + ( + "22_varB", + "22", + ), + ], + ), + ( + # locus is null, should return lead variant + [ + ("1", "traitA", "22_varA", None), + ], + [ + ( + "22_varA", + "22", + ), + ], + ), +] + +test_unique_variants_in_locus_test_schema = StructType( [ - ( - # Locus is not null, should return union between variants in locus and lead variant - [ - ( - "1", - "traitA", - "22_varA", + StructField("studyLocusId", StringType(), True), + StructField("studyId", StringType(), True), + StructField("variantId", StringType(), True), + StructField( + "locus", + ArrayType( + StructType( [ - {"variantId": "22_varA", "posteriorProbability": 0.44}, - {"variantId": "22_varB", "posteriorProbability": 0.015}, - ], - ), - ], - [ - ( - "22_varA", - "22", - ), - ( - "22_varB", - "22", - ), - ], - ), - ( - # locus is null, should return lead variant - [ - ("1", "traitA", "22_varA", None), - ], - [ - ( - "22_varA", - "22", - ), - ], + StructField("variantId", StringType(), True), + StructField("posteriorProbability", DoubleType(), True), + ] + ) + ), + True, ), - ], + ] +) + + +@pytest.mark.parametrize( + ("observed", "expected"), + test_unique_variants_in_locus_test_data, ) def test_unique_variants_in_locus( spark: SparkSession, observed: list[Any], expected: list[Any] ) -> None: """Test unique variants in locus.""" # assert isinstance(mock_study_locus.test_unique_variants_in_locus(), DataFrame) - schema = StructType( - [ - StructField("studyLocusId", StringType(), True), - StructField("studyId", StringType(), True), - StructField("variantId", StringType(), True), - StructField( - "locus", - ArrayType( - StructType( - [ - StructField("variantId", StringType(), True), - ] - ) - ), - True, - ), - ] - ) data_sl = StudyLocus( - _df=spark.createDataFrame(observed, schema), _schema=StudyLocus.get_schema() + _df=spark.createDataFrame(observed, test_unique_variants_in_locus_test_schema), + _schema=StudyLocus.get_schema(), ) expected_df = spark.createDataFrame( expected, schema="variantId: string, chromosome: string" @@ -286,187 +298,223 @@ def test_clump(mock_study_locus: StudyLocus) -> None: assert isinstance(mock_study_locus.clump(), StudyLocus) -@pytest.mark.parametrize( - ("observed", "expected"), +# Used primarily for test_annotate_credible_sets but also for other tests +test_annotate_credible_sets_test_data = [ + ( + # Simple case + [ + # Observed + ( + "1", + "traitA", + "leadB", + [{"variantId": "tagVariantA", "posteriorProbability": 1.0}], + ), + ], + [ + # Expected + ( + "1", + "traitA", + "leadB", + [ + { + "variantId": "tagVariantA", + "posteriorProbability": 1.0, + "is95CredibleSet": True, + "is99CredibleSet": True, + } + ], + ) + ], + ), + ( + # Unordered credible set + [ + # Observed + ( + "1", + "traitA", + "leadA", + [ + {"variantId": "tagVariantA", "posteriorProbability": 0.44}, + {"variantId": "tagVariantB", "posteriorProbability": 0.015}, + {"variantId": "tagVariantC", "posteriorProbability": 0.04}, + {"variantId": "tagVariantD", "posteriorProbability": 0.005}, + {"variantId": "tagVariantE", "posteriorProbability": 0.5}, + {"variantId": "tagVariantNull", "posteriorProbability": None}, + {"variantId": "tagVariantNull", "posteriorProbability": None}, + ], + ) + ], + [ + # Expected + ( + "1", + "traitA", + "leadA", + [ + { + "variantId": "tagVariantE", + "posteriorProbability": 0.5, + "is95CredibleSet": True, + "is99CredibleSet": True, + }, + { + "variantId": "tagVariantA", + "posteriorProbability": 0.44, + "is95CredibleSet": True, + "is99CredibleSet": True, + }, + { + "variantId": "tagVariantC", + "posteriorProbability": 0.04, + "is95CredibleSet": True, + "is99CredibleSet": True, + }, + { + "variantId": "tagVariantB", + "posteriorProbability": 0.015, + "is95CredibleSet": False, + "is99CredibleSet": True, + }, + { + "variantId": "tagVariantD", + "posteriorProbability": 0.005, + "is95CredibleSet": False, + "is99CredibleSet": False, + }, + { + "variantId": "tagVariantNull", + "posteriorProbability": None, + "is95CredibleSet": False, + "is99CredibleSet": False, + }, + { + "variantId": "tagVariantNull", + "posteriorProbability": None, + "is95CredibleSet": False, + "is99CredibleSet": False, + }, + ], + ) + ], + ), + ( + # Null credible set + [ + # Observed + ( + "1", + "traitA", + "leadB", + None, + ), + ], + [ + # Expected + ( + "1", + "traitA", + "leadB", + None, + ) + ], + ), + ( + # Empty credible set + [ + # Observed + ( + "1", + "traitA", + "leadB", + [], + ), + ], + [ + # Expected + ( + "1", + "traitA", + "leadB", + None, + ) + ], + ), +] +test_annotate_credible_sets_test_schema = StructType( [ - ( - # Simple case - [ - # Observed - ( - "1", - "traitA", - "leadB", - [{"variantId": "tagVariantA", "posteriorProbability": 1.0}], - ), - ], - [ - # Expected - ( - "1", - "traitA", - "leadB", - [ - { - "variantId": "tagVariantA", - "posteriorProbability": 1.0, - "is95CredibleSet": True, - "is99CredibleSet": True, - } - ], - ) - ], - ), - ( - # Unordered credible set - [ - # Observed - ( - "1", - "traitA", - "leadA", - [ - {"variantId": "tagVariantA", "posteriorProbability": 0.44}, - {"variantId": "tagVariantB", "posteriorProbability": 0.015}, - {"variantId": "tagVariantC", "posteriorProbability": 0.04}, - {"variantId": "tagVariantD", "posteriorProbability": 0.005}, - {"variantId": "tagVariantE", "posteriorProbability": 0.5}, - {"variantId": "tagVariantNull", "posteriorProbability": None}, - {"variantId": "tagVariantNull", "posteriorProbability": None}, - ], - ) - ], - [ - # Expected - ( - "1", - "traitA", - "leadA", + StructField("studyLocusId", StringType(), True), + StructField("studyId", StringType(), True), + StructField("variantId", StringType(), True), + StructField( + "locus", + ArrayType( + StructType( [ - { - "variantId": "tagVariantE", - "posteriorProbability": 0.5, - "is95CredibleSet": True, - "is99CredibleSet": True, - }, - { - "variantId": "tagVariantA", - "posteriorProbability": 0.44, - "is95CredibleSet": True, - "is99CredibleSet": True, - }, - { - "variantId": "tagVariantC", - "posteriorProbability": 0.04, - "is95CredibleSet": True, - "is99CredibleSet": True, - }, - { - "variantId": "tagVariantB", - "posteriorProbability": 0.015, - "is95CredibleSet": False, - "is99CredibleSet": True, - }, - { - "variantId": "tagVariantD", - "posteriorProbability": 0.005, - "is95CredibleSet": False, - "is99CredibleSet": False, - }, - { - "variantId": "tagVariantNull", - "posteriorProbability": None, - "is95CredibleSet": False, - "is99CredibleSet": False, - }, - { - "variantId": "tagVariantNull", - "posteriorProbability": None, - "is95CredibleSet": False, - "is99CredibleSet": False, - }, - ], + StructField("variantId", StringType(), True), + StructField("posteriorProbability", DoubleType(), True), + StructField("is95CredibleSet", BooleanType(), True), + StructField("is99CredibleSet", BooleanType(), True), + ] ) - ], - ), - ( - # Null credible set - [ - # Observed - ( - "1", - "traitA", - "leadB", - None, - ), - ], - [ - # Expected - ( - "1", - "traitA", - "leadB", - None, - ) - ], - ), - ( - # Empty credible set - [ - # Observed - ( - "1", - "traitA", - "leadB", - [], - ), - ], - [ - # Expected - ( - "1", - "traitA", - "leadB", - None, - ) - ], + ), + True, ), - ], + ] +) + + +@pytest.mark.parametrize( + ("observed", "expected"), + test_annotate_credible_sets_test_data, ) def test_annotate_credible_sets( spark: SparkSession, observed: list[Any], expected: list[Any] ) -> None: """Test annotate_credible_sets.""" - schema = StructType( - [ - StructField("studyLocusId", StringType(), True), - StructField("studyId", StringType(), True), - StructField("variantId", StringType(), True), - StructField( - "locus", - ArrayType( - StructType( - [ - StructField("variantId", StringType(), True), - StructField("posteriorProbability", DoubleType(), True), - StructField("is95CredibleSet", BooleanType(), True), - StructField("is99CredibleSet", BooleanType(), True), - ] - ) - ), - True, - ), - ] - ) data_sl = StudyLocus( - _df=spark.createDataFrame(observed, schema), _schema=StudyLocus.get_schema() + _df=spark.createDataFrame(observed, test_annotate_credible_sets_test_schema), + _schema=StudyLocus.get_schema(), ) expected_sl = StudyLocus( - _df=spark.createDataFrame(expected, schema), _schema=StudyLocus.get_schema() + _df=spark.createDataFrame(expected, test_annotate_credible_sets_test_schema), + _schema=StudyLocus.get_schema(), ) assert data_sl.annotate_credible_sets().df.collect() == expected_sl.df.collect() +def test_qc_abnormal_pips_good_locus(spark: SparkSession) -> None: + """Test qc_abnormal_pips with a well-behaving locus.""" + # Input data + sl = StudyLocus( + _df=spark.createDataFrame( + test_annotate_credible_sets_test_data[1][0], + test_annotate_credible_sets_test_schema, + ), + _schema=StudyLocus.get_schema(), + ) + assert ( + sl.qc_abnormal_pips().df.filter(f.size("qualityControls") > 0).count() == 0 + ), "Expected number of rows differ from observed." + + +def test_qc_abnormal_pips_bad_locus(spark: SparkSession) -> None: + """Test qc_abnormal_pips with an abnormal locus.""" + # Input data + sl = StudyLocus( + _df=spark.createDataFrame( + test_unique_variants_in_locus_test_data[0][0], + test_unique_variants_in_locus_test_schema, + ), + _schema=StudyLocus.get_schema(), + ) + assert ( + sl.qc_abnormal_pips().df.filter(f.size("qualityControls") > 0).count() == 1 + ), "Expected number of rows differ from observed." + + def test_annotate_ld( mock_study_locus: StudyLocus, mock_study_index: StudyIndex, mock_ld_index: LDIndex ) -> None: From 1596c4ca6d5713ca748cdf3dbc637ead52660ebc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Oct 2024 11:33:16 +0000 Subject: [PATCH 141/188] build(deps-dev): bump ipython from 8.28.0 to 8.29.0 (#883) Bumps [ipython](https://github.com/ipython/ipython) from 8.28.0 to 8.29.0. - [Release notes](https://github.com/ipython/ipython/releases) - [Commits](https://github.com/ipython/ipython/compare/8.28.0...8.29.0) --- updated-dependencies: - dependency-name: ipython dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- poetry.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/poetry.lock b/poetry.lock index 9ce219f6b..1ed436a34 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1899,13 +1899,13 @@ test = ["flaky", "ipyparallel", "pre-commit", "pytest (>=7.0)", "pytest-asyncio [[package]] name = "ipython" -version = "8.28.0" +version = "8.29.0" description = "IPython: Productive Interactive Computing" optional = false python-versions = ">=3.10" files = [ - {file = "ipython-8.28.0-py3-none-any.whl", hash = "sha256:530ef1e7bb693724d3cdc37287c80b07ad9b25986c007a53aa1857272dac3f35"}, - {file = "ipython-8.28.0.tar.gz", hash = "sha256:0d0d15ca1e01faeb868ef56bc7ee5a0de5bd66885735682e8a322ae289a13d1a"}, + {file = "ipython-8.29.0-py3-none-any.whl", hash = "sha256:0188a1bd83267192123ccea7f4a8ed0a78910535dbaa3f37671dca76ebd429c8"}, + {file = "ipython-8.29.0.tar.gz", hash = "sha256:40b60e15b22591450eef73e40a027cf77bd652e757523eebc5bd7c7c498290eb"}, ] [package.dependencies] From 31d8716fa3ff0d4071829381876e8d3f5efac6cb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Oct 2024 11:40:44 +0000 Subject: [PATCH 142/188] build(deps-dev): bump mypy from 1.12.1 to 1.13.0 (#884) Bumps [mypy](https://github.com/python/mypy) from 1.12.1 to 1.13.0. - [Changelog](https://github.com/python/mypy/blob/master/CHANGELOG.md) - [Commits](https://github.com/python/mypy/compare/v1.12.1...v1.13.0) --- updated-dependencies: - dependency-name: mypy dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- poetry.lock | 69 +++++++++++++++++++++++++------------------------- pyproject.toml | 2 +- 2 files changed, 36 insertions(+), 35 deletions(-) diff --git a/poetry.lock b/poetry.lock index 1ed436a34..4da042c37 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2755,43 +2755,43 @@ files = [ [[package]] name = "mypy" -version = "1.12.1" +version = "1.13.0" description = "Optional static typing for Python" optional = false python-versions = ">=3.8" files = [ - {file = "mypy-1.12.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3d7d4371829184e22fda4015278fbfdef0327a4b955a483012bd2d423a788801"}, - {file = "mypy-1.12.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f59f1dfbf497d473201356966e353ef09d4daec48caeacc0254db8ef633a28a5"}, - {file = "mypy-1.12.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b947097fae68004b8328c55161ac9db7d3566abfef72d9d41b47a021c2fba6b1"}, - {file = "mypy-1.12.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:96af62050971c5241afb4701c15189ea9507db89ad07794a4ee7b4e092dc0627"}, - {file = "mypy-1.12.1-cp310-cp310-win_amd64.whl", hash = "sha256:d90da248f4c2dba6c44ddcfea94bb361e491962f05f41990ff24dbd09969ce20"}, - {file = "mypy-1.12.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1230048fec1380faf240be6385e709c8570604d2d27ec6ca7e573e3bc09c3735"}, - {file = "mypy-1.12.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:02dcfe270c6ea13338210908f8cadc8d31af0f04cee8ca996438fe6a97b4ec66"}, - {file = "mypy-1.12.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a5a437c9102a6a252d9e3a63edc191a3aed5f2fcb786d614722ee3f4472e33f6"}, - {file = "mypy-1.12.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:186e0c8346efc027ee1f9acf5ca734425fc4f7dc2b60144f0fbe27cc19dc7931"}, - {file = "mypy-1.12.1-cp311-cp311-win_amd64.whl", hash = "sha256:673ba1140a478b50e6d265c03391702fa11a5c5aff3f54d69a62a48da32cb811"}, - {file = "mypy-1.12.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:9fb83a7be97c498176fb7486cafbb81decccaef1ac339d837c377b0ce3743a7f"}, - {file = "mypy-1.12.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:389e307e333879c571029d5b93932cf838b811d3f5395ed1ad05086b52148fb0"}, - {file = "mypy-1.12.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:94b2048a95a21f7a9ebc9fbd075a4fcd310410d078aa0228dbbad7f71335e042"}, - {file = "mypy-1.12.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ee5932370ccf7ebf83f79d1c157a5929d7ea36313027b0d70a488493dc1b179"}, - {file = "mypy-1.12.1-cp312-cp312-win_amd64.whl", hash = "sha256:19bf51f87a295e7ab2894f1d8167622b063492d754e69c3c2fed6563268cb42a"}, - {file = "mypy-1.12.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d34167d43613ffb1d6c6cdc0cc043bb106cac0aa5d6a4171f77ab92a3c758bcc"}, - {file = "mypy-1.12.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:427878aa54f2e2c5d8db31fa9010c599ed9f994b3b49e64ae9cd9990c40bd635"}, - {file = "mypy-1.12.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5fcde63ea2c9f69d6be859a1e6dd35955e87fa81de95bc240143cf00de1f7f81"}, - {file = "mypy-1.12.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:d54d840f6c052929f4a3d2aab2066af0f45a020b085fe0e40d4583db52aab4e4"}, - {file = "mypy-1.12.1-cp313-cp313-win_amd64.whl", hash = "sha256:20db6eb1ca3d1de8ece00033b12f793f1ea9da767334b7e8c626a4872090cf02"}, - {file = "mypy-1.12.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b16fe09f9c741d85a2e3b14a5257a27a4f4886c171d562bc5a5e90d8591906b8"}, - {file = "mypy-1.12.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0dcc1e843d58f444fce19da4cce5bd35c282d4bde232acdeca8279523087088a"}, - {file = "mypy-1.12.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e10ba7de5c616e44ad21005fa13450cd0de7caaa303a626147d45307492e4f2d"}, - {file = "mypy-1.12.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:0e6fe449223fa59fbee351db32283838a8fee8059e0028e9e6494a03802b4004"}, - {file = "mypy-1.12.1-cp38-cp38-win_amd64.whl", hash = "sha256:dc6e2a2195a290a7fd5bac3e60b586d77fc88e986eba7feced8b778c373f9afe"}, - {file = "mypy-1.12.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:de5b2a8988b4e1269a98beaf0e7cc71b510d050dce80c343b53b4955fff45f19"}, - {file = "mypy-1.12.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:843826966f1d65925e8b50d2b483065c51fc16dc5d72647e0236aae51dc8d77e"}, - {file = "mypy-1.12.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9fe20f89da41a95e14c34b1ddb09c80262edcc295ad891f22cc4b60013e8f78d"}, - {file = "mypy-1.12.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8135ffec02121a75f75dc97c81af7c14aa4ae0dda277132cfcd6abcd21551bfd"}, - {file = "mypy-1.12.1-cp39-cp39-win_amd64.whl", hash = "sha256:a7b76fa83260824300cc4834a3ab93180db19876bce59af921467fd03e692810"}, - {file = "mypy-1.12.1-py3-none-any.whl", hash = "sha256:ce561a09e3bb9863ab77edf29ae3a50e65685ad74bba1431278185b7e5d5486e"}, - {file = "mypy-1.12.1.tar.gz", hash = "sha256:f5b3936f7a6d0e8280c9bdef94c7ce4847f5cdfc258fbb2c29a8c1711e8bb96d"}, + {file = "mypy-1.13.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6607e0f1dd1fb7f0aca14d936d13fd19eba5e17e1cd2a14f808fa5f8f6d8f60a"}, + {file = "mypy-1.13.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8a21be69bd26fa81b1f80a61ee7ab05b076c674d9b18fb56239d72e21d9f4c80"}, + {file = "mypy-1.13.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7b2353a44d2179846a096e25691d54d59904559f4232519d420d64da6828a3a7"}, + {file = "mypy-1.13.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0730d1c6a2739d4511dc4253f8274cdd140c55c32dfb0a4cf8b7a43f40abfa6f"}, + {file = "mypy-1.13.0-cp310-cp310-win_amd64.whl", hash = "sha256:c5fc54dbb712ff5e5a0fca797e6e0aa25726c7e72c6a5850cfd2adbc1eb0a372"}, + {file = "mypy-1.13.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:581665e6f3a8a9078f28d5502f4c334c0c8d802ef55ea0e7276a6e409bc0d82d"}, + {file = "mypy-1.13.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3ddb5b9bf82e05cc9a627e84707b528e5c7caaa1c55c69e175abb15a761cec2d"}, + {file = "mypy-1.13.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:20c7ee0bc0d5a9595c46f38beb04201f2620065a93755704e141fcac9f59db2b"}, + {file = "mypy-1.13.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3790ded76f0b34bc9c8ba4def8f919dd6a46db0f5a6610fb994fe8efdd447f73"}, + {file = "mypy-1.13.0-cp311-cp311-win_amd64.whl", hash = "sha256:51f869f4b6b538229c1d1bcc1dd7d119817206e2bc54e8e374b3dfa202defcca"}, + {file = "mypy-1.13.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5c7051a3461ae84dfb5dd15eff5094640c61c5f22257c8b766794e6dd85e72d5"}, + {file = "mypy-1.13.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:39bb21c69a5d6342f4ce526e4584bc5c197fd20a60d14a8624d8743fffb9472e"}, + {file = "mypy-1.13.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:164f28cb9d6367439031f4c81e84d3ccaa1e19232d9d05d37cb0bd880d3f93c2"}, + {file = "mypy-1.13.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a4c1bfcdbce96ff5d96fc9b08e3831acb30dc44ab02671eca5953eadad07d6d0"}, + {file = "mypy-1.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:a0affb3a79a256b4183ba09811e3577c5163ed06685e4d4b46429a271ba174d2"}, + {file = "mypy-1.13.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a7b44178c9760ce1a43f544e595d35ed61ac2c3de306599fa59b38a6048e1aa7"}, + {file = "mypy-1.13.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5d5092efb8516d08440e36626f0153b5006d4088c1d663d88bf79625af3d1d62"}, + {file = "mypy-1.13.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:de2904956dac40ced10931ac967ae63c5089bd498542194b436eb097a9f77bc8"}, + {file = "mypy-1.13.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:7bfd8836970d33c2105562650656b6846149374dc8ed77d98424b40b09340ba7"}, + {file = "mypy-1.13.0-cp313-cp313-win_amd64.whl", hash = "sha256:9f73dba9ec77acb86457a8fc04b5239822df0c14a082564737833d2963677dbc"}, + {file = "mypy-1.13.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:100fac22ce82925f676a734af0db922ecfea991e1d7ec0ceb1e115ebe501301a"}, + {file = "mypy-1.13.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7bcb0bb7f42a978bb323a7c88f1081d1b5dee77ca86f4100735a6f541299d8fb"}, + {file = "mypy-1.13.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bde31fc887c213e223bbfc34328070996061b0833b0a4cfec53745ed61f3519b"}, + {file = "mypy-1.13.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:07de989f89786f62b937851295ed62e51774722e5444a27cecca993fc3f9cd74"}, + {file = "mypy-1.13.0-cp38-cp38-win_amd64.whl", hash = "sha256:4bde84334fbe19bad704b3f5b78c4abd35ff1026f8ba72b29de70dda0916beb6"}, + {file = "mypy-1.13.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0246bcb1b5de7f08f2826451abd947bf656945209b140d16ed317f65a17dc7dc"}, + {file = "mypy-1.13.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7f5b7deae912cf8b77e990b9280f170381fdfbddf61b4ef80927edd813163732"}, + {file = "mypy-1.13.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7029881ec6ffb8bc233a4fa364736789582c738217b133f1b55967115288a2bc"}, + {file = "mypy-1.13.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3e38b980e5681f28f033f3be86b099a247b13c491f14bb8b1e1e134d23bb599d"}, + {file = "mypy-1.13.0-cp39-cp39-win_amd64.whl", hash = "sha256:a6789be98a2017c912ae6ccb77ea553bbaf13d27605d2ca20a76dfbced631b24"}, + {file = "mypy-1.13.0-py3-none-any.whl", hash = "sha256:9c250883f9fd81d212e0952c92dbfcc96fc237f4b7c92f56ac81fd48460b3e5a"}, + {file = "mypy-1.13.0.tar.gz", hash = "sha256:0291a61b6fbf3e6673e3405cfcc0e7650bebc7939659fdca2702958038bd835e"}, ] [package.dependencies] @@ -2801,6 +2801,7 @@ typing-extensions = ">=4.6.0" [package.extras] dmypy = ["psutil (>=4.0)"] +faster-cache = ["orjson"] install-types = ["pip"] mypyc = ["setuptools (>=50)"] reports = ["lxml"] @@ -5224,4 +5225,4 @@ multidict = ">=4.0" [metadata] lock-version = "2.0" python-versions = "^3.10, <3.11" -content-hash = "2dcd05168a809a2a9dc0728ee7ed1578ad008d0c3a290bf9a41895b10f2d849a" +content-hash = "9caf73143d9e3b6d71389d7fce3b554c619492bff8567de39847129ed7309af2" diff --git a/pyproject.toml b/pyproject.toml index fea630906..4985c6709 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -37,7 +37,7 @@ google-cloud-secret-manager = "^2.20.0" [tool.poetry.dev-dependencies] pre-commit = "^4.0.0" -mypy = "^1.12" +mypy = "^1.13" pep8-naming = "^0.14.1" interrogate = "^1.7.0" isort = "^5.13.2" From 759857eb9354f390ca089fb781979bed5b40065a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Irene=20L=C3=B3pez=20Santiago?= <45119610+ireneisdoomed@users.noreply.github.com> Date: Thu, 31 Oct 2024 15:56:25 +0000 Subject: [PATCH 143/188] feat(trainer): log model explanation with shap (#886) * build: add `shap` * feat(l2g): log feature contributions with shap * chore: update lock file * fix: ignore installed packages in `install_dependencies_on_cluster.sh` (problem with llvm) * build: add `matplotlib` * fix: pin `matplotlib` version to avoid mplDeprecation issue * fix(trainer): set default features_list + minor bugs * chore: pre-commit auto fixes [...] --- poetry.lock | 4122 +++++++++++++--------- pyproject.toml | 2 + src/gentropy/method/l2g/model.py | 19 + src/gentropy/method/l2g/trainer.py | 133 +- utils/install_dependencies_on_cluster.sh | 2 +- 5 files changed, 2561 insertions(+), 1717 deletions(-) diff --git a/poetry.lock b/poetry.lock index 4da042c37..edba6ef99 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. [[package]] name = "aiodns" @@ -14,101 +14,128 @@ files = [ [package.dependencies] pycares = ">=3.0.0" +[[package]] +name = "aiohappyeyeballs" +version = "2.4.3" +description = "Happy Eyeballs for asyncio" +optional = false +python-versions = ">=3.8" +files = [ + {file = "aiohappyeyeballs-2.4.3-py3-none-any.whl", hash = "sha256:8a7a83727b2756f394ab2895ea0765a0a8c475e3c71e98d43d76f22b4b435572"}, + {file = "aiohappyeyeballs-2.4.3.tar.gz", hash = "sha256:75cf88a15106a5002a8eb1dab212525c00d1f4c0fa96e551c9fbe6f09a621586"}, +] + [[package]] name = "aiohttp" -version = "3.9.5" +version = "3.10.10" description = "Async http client/server framework (asyncio)" optional = false python-versions = ">=3.8" files = [ - {file = "aiohttp-3.9.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:fcde4c397f673fdec23e6b05ebf8d4751314fa7c24f93334bf1f1364c1c69ac7"}, - {file = "aiohttp-3.9.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5d6b3f1fabe465e819aed2c421a6743d8debbde79b6a8600739300630a01bf2c"}, - {file = "aiohttp-3.9.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6ae79c1bc12c34082d92bf9422764f799aee4746fd7a392db46b7fd357d4a17a"}, - {file = "aiohttp-3.9.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d3ebb9e1316ec74277d19c5f482f98cc65a73ccd5430540d6d11682cd857430"}, - {file = "aiohttp-3.9.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84dabd95154f43a2ea80deffec9cb44d2e301e38a0c9d331cc4aa0166fe28ae3"}, - {file = "aiohttp-3.9.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c8a02fbeca6f63cb1f0475c799679057fc9268b77075ab7cf3f1c600e81dd46b"}, - {file = "aiohttp-3.9.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c26959ca7b75ff768e2776d8055bf9582a6267e24556bb7f7bd29e677932be72"}, - {file = "aiohttp-3.9.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:714d4e5231fed4ba2762ed489b4aec07b2b9953cf4ee31e9871caac895a839c0"}, - {file = "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e7a6a8354f1b62e15d48e04350f13e726fa08b62c3d7b8401c0a1314f02e3558"}, - {file = "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:c413016880e03e69d166efb5a1a95d40f83d5a3a648d16486592c49ffb76d0db"}, - {file = "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:ff84aeb864e0fac81f676be9f4685f0527b660f1efdc40dcede3c251ef1e867f"}, - {file = "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:ad7f2919d7dac062f24d6f5fe95d401597fbb015a25771f85e692d043c9d7832"}, - {file = "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:702e2c7c187c1a498a4e2b03155d52658fdd6fda882d3d7fbb891a5cf108bb10"}, - {file = "aiohttp-3.9.5-cp310-cp310-win32.whl", hash = "sha256:67c3119f5ddc7261d47163ed86d760ddf0e625cd6246b4ed852e82159617b5fb"}, - {file = "aiohttp-3.9.5-cp310-cp310-win_amd64.whl", hash = "sha256:471f0ef53ccedec9995287f02caf0c068732f026455f07db3f01a46e49d76bbb"}, - {file = "aiohttp-3.9.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e0ae53e33ee7476dd3d1132f932eeb39bf6125083820049d06edcdca4381f342"}, - {file = "aiohttp-3.9.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c088c4d70d21f8ca5c0b8b5403fe84a7bc8e024161febdd4ef04575ef35d474d"}, - {file = "aiohttp-3.9.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:639d0042b7670222f33b0028de6b4e2fad6451462ce7df2af8aee37dcac55424"}, - {file = "aiohttp-3.9.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f26383adb94da5e7fb388d441bf09c61e5e35f455a3217bfd790c6b6bc64b2ee"}, - {file = "aiohttp-3.9.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:66331d00fb28dc90aa606d9a54304af76b335ae204d1836f65797d6fe27f1ca2"}, - {file = "aiohttp-3.9.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4ff550491f5492ab5ed3533e76b8567f4b37bd2995e780a1f46bca2024223233"}, - {file = "aiohttp-3.9.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f22eb3a6c1080d862befa0a89c380b4dafce29dc6cd56083f630073d102eb595"}, - {file = "aiohttp-3.9.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a81b1143d42b66ffc40a441379387076243ef7b51019204fd3ec36b9f69e77d6"}, - {file = "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f64fd07515dad67f24b6ea4a66ae2876c01031de91c93075b8093f07c0a2d93d"}, - {file = "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:93e22add827447d2e26d67c9ac0161756007f152fdc5210277d00a85f6c92323"}, - {file = "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:55b39c8684a46e56ef8c8d24faf02de4a2b2ac60d26cee93bc595651ff545de9"}, - {file = "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4715a9b778f4293b9f8ae7a0a7cef9829f02ff8d6277a39d7f40565c737d3771"}, - {file = "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:afc52b8d969eff14e069a710057d15ab9ac17cd4b6753042c407dcea0e40bf75"}, - {file = "aiohttp-3.9.5-cp311-cp311-win32.whl", hash = "sha256:b3df71da99c98534be076196791adca8819761f0bf6e08e07fd7da25127150d6"}, - {file = "aiohttp-3.9.5-cp311-cp311-win_amd64.whl", hash = "sha256:88e311d98cc0bf45b62fc46c66753a83445f5ab20038bcc1b8a1cc05666f428a"}, - {file = "aiohttp-3.9.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:c7a4b7a6cf5b6eb11e109a9755fd4fda7d57395f8c575e166d363b9fc3ec4678"}, - {file = "aiohttp-3.9.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:0a158704edf0abcac8ac371fbb54044f3270bdbc93e254a82b6c82be1ef08f3c"}, - {file = "aiohttp-3.9.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d153f652a687a8e95ad367a86a61e8d53d528b0530ef382ec5aaf533140ed00f"}, - {file = "aiohttp-3.9.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82a6a97d9771cb48ae16979c3a3a9a18b600a8505b1115cfe354dfb2054468b4"}, - {file = "aiohttp-3.9.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:60cdbd56f4cad9f69c35eaac0fbbdf1f77b0ff9456cebd4902f3dd1cf096464c"}, - {file = "aiohttp-3.9.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8676e8fd73141ded15ea586de0b7cda1542960a7b9ad89b2b06428e97125d4fa"}, - {file = "aiohttp-3.9.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da00da442a0e31f1c69d26d224e1efd3a1ca5bcbf210978a2ca7426dfcae9f58"}, - {file = "aiohttp-3.9.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:18f634d540dd099c262e9f887c8bbacc959847cfe5da7a0e2e1cf3f14dbf2daf"}, - {file = "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:320e8618eda64e19d11bdb3bd04ccc0a816c17eaecb7e4945d01deee2a22f95f"}, - {file = "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:2faa61a904b83142747fc6a6d7ad8fccff898c849123030f8e75d5d967fd4a81"}, - {file = "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:8c64a6dc3fe5db7b1b4d2b5cb84c4f677768bdc340611eca673afb7cf416ef5a"}, - {file = "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:393c7aba2b55559ef7ab791c94b44f7482a07bf7640d17b341b79081f5e5cd1a"}, - {file = "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:c671dc117c2c21a1ca10c116cfcd6e3e44da7fcde37bf83b2be485ab377b25da"}, - {file = "aiohttp-3.9.5-cp312-cp312-win32.whl", hash = "sha256:5a7ee16aab26e76add4afc45e8f8206c95d1d75540f1039b84a03c3b3800dd59"}, - {file = "aiohttp-3.9.5-cp312-cp312-win_amd64.whl", hash = "sha256:5ca51eadbd67045396bc92a4345d1790b7301c14d1848feaac1d6a6c9289e888"}, - {file = "aiohttp-3.9.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:694d828b5c41255e54bc2dddb51a9f5150b4eefa9886e38b52605a05d96566e8"}, - {file = "aiohttp-3.9.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0605cc2c0088fcaae79f01c913a38611ad09ba68ff482402d3410bf59039bfb8"}, - {file = "aiohttp-3.9.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4558e5012ee03d2638c681e156461d37b7a113fe13970d438d95d10173d25f78"}, - {file = "aiohttp-3.9.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9dbc053ac75ccc63dc3a3cc547b98c7258ec35a215a92bd9f983e0aac95d3d5b"}, - {file = "aiohttp-3.9.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4109adee842b90671f1b689901b948f347325045c15f46b39797ae1bf17019de"}, - {file = "aiohttp-3.9.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6ea1a5b409a85477fd8e5ee6ad8f0e40bf2844c270955e09360418cfd09abac"}, - {file = "aiohttp-3.9.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3c2890ca8c59ee683fd09adf32321a40fe1cf164e3387799efb2acebf090c11"}, - {file = "aiohttp-3.9.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3916c8692dbd9d55c523374a3b8213e628424d19116ac4308e434dbf6d95bbdd"}, - {file = "aiohttp-3.9.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8d1964eb7617907c792ca00b341b5ec3e01ae8c280825deadbbd678447b127e1"}, - {file = "aiohttp-3.9.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:d5ab8e1f6bee051a4bf6195e38a5c13e5e161cb7bad83d8854524798bd9fcd6e"}, - {file = "aiohttp-3.9.5-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:52c27110f3862a1afbcb2af4281fc9fdc40327fa286c4625dfee247c3ba90156"}, - {file = "aiohttp-3.9.5-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:7f64cbd44443e80094309875d4f9c71d0401e966d191c3d469cde4642bc2e031"}, - {file = "aiohttp-3.9.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8b4f72fbb66279624bfe83fd5eb6aea0022dad8eec62b71e7bf63ee1caadeafe"}, - {file = "aiohttp-3.9.5-cp38-cp38-win32.whl", hash = "sha256:6380c039ec52866c06d69b5c7aad5478b24ed11696f0e72f6b807cfb261453da"}, - {file = "aiohttp-3.9.5-cp38-cp38-win_amd64.whl", hash = "sha256:da22dab31d7180f8c3ac7c7635f3bcd53808f374f6aa333fe0b0b9e14b01f91a"}, - {file = "aiohttp-3.9.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:1732102949ff6087589408d76cd6dea656b93c896b011ecafff418c9661dc4ed"}, - {file = "aiohttp-3.9.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c6021d296318cb6f9414b48e6a439a7f5d1f665464da507e8ff640848ee2a58a"}, - {file = "aiohttp-3.9.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:239f975589a944eeb1bad26b8b140a59a3a320067fb3cd10b75c3092405a1372"}, - {file = "aiohttp-3.9.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3b7b30258348082826d274504fbc7c849959f1989d86c29bc355107accec6cfb"}, - {file = "aiohttp-3.9.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cd2adf5c87ff6d8b277814a28a535b59e20bfea40a101db6b3bdca7e9926bc24"}, - {file = "aiohttp-3.9.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e9a3d838441bebcf5cf442700e3963f58b5c33f015341f9ea86dcd7d503c07e2"}, - {file = "aiohttp-3.9.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e3a1ae66e3d0c17cf65c08968a5ee3180c5a95920ec2731f53343fac9bad106"}, - {file = "aiohttp-3.9.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9c69e77370cce2d6df5d12b4e12bdcca60c47ba13d1cbbc8645dd005a20b738b"}, - {file = "aiohttp-3.9.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0cbf56238f4bbf49dab8c2dc2e6b1b68502b1e88d335bea59b3f5b9f4c001475"}, - {file = "aiohttp-3.9.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:d1469f228cd9ffddd396d9948b8c9cd8022b6d1bf1e40c6f25b0fb90b4f893ed"}, - {file = "aiohttp-3.9.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:45731330e754f5811c314901cebdf19dd776a44b31927fa4b4dbecab9e457b0c"}, - {file = "aiohttp-3.9.5-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:3fcb4046d2904378e3aeea1df51f697b0467f2aac55d232c87ba162709478c46"}, - {file = "aiohttp-3.9.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8cf142aa6c1a751fcb364158fd710b8a9be874b81889c2bd13aa8893197455e2"}, - {file = "aiohttp-3.9.5-cp39-cp39-win32.whl", hash = "sha256:7b179eea70833c8dee51ec42f3b4097bd6370892fa93f510f76762105568cf09"}, - {file = "aiohttp-3.9.5-cp39-cp39-win_amd64.whl", hash = "sha256:38d80498e2e169bc61418ff36170e0aad0cd268da8b38a17c4cf29d254a8b3f1"}, - {file = "aiohttp-3.9.5.tar.gz", hash = "sha256:edea7d15772ceeb29db4aff55e482d4bcfb6ae160ce144f2682de02f6d693551"}, + {file = "aiohttp-3.10.10-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:be7443669ae9c016b71f402e43208e13ddf00912f47f623ee5994e12fc7d4b3f"}, + {file = "aiohttp-3.10.10-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7b06b7843929e41a94ea09eb1ce3927865387e3e23ebe108e0d0d09b08d25be9"}, + {file = "aiohttp-3.10.10-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:333cf6cf8e65f6a1e06e9eb3e643a0c515bb850d470902274239fea02033e9a8"}, + {file = "aiohttp-3.10.10-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:274cfa632350225ce3fdeb318c23b4a10ec25c0e2c880eff951a3842cf358ac1"}, + {file = "aiohttp-3.10.10-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d9e5e4a85bdb56d224f412d9c98ae4cbd032cc4f3161818f692cd81766eee65a"}, + {file = "aiohttp-3.10.10-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2b606353da03edcc71130b52388d25f9a30a126e04caef1fd637e31683033abd"}, + {file = "aiohttp-3.10.10-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab5a5a0c7a7991d90446a198689c0535be89bbd6b410a1f9a66688f0880ec026"}, + {file = "aiohttp-3.10.10-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:578a4b875af3e0daaf1ac6fa983d93e0bbfec3ead753b6d6f33d467100cdc67b"}, + {file = "aiohttp-3.10.10-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:8105fd8a890df77b76dd3054cddf01a879fc13e8af576805d667e0fa0224c35d"}, + {file = "aiohttp-3.10.10-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3bcd391d083f636c06a68715e69467963d1f9600f85ef556ea82e9ef25f043f7"}, + {file = "aiohttp-3.10.10-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fbc6264158392bad9df19537e872d476f7c57adf718944cc1e4495cbabf38e2a"}, + {file = "aiohttp-3.10.10-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:e48d5021a84d341bcaf95c8460b152cfbad770d28e5fe14a768988c461b821bc"}, + {file = "aiohttp-3.10.10-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:2609e9ab08474702cc67b7702dbb8a80e392c54613ebe80db7e8dbdb79837c68"}, + {file = "aiohttp-3.10.10-cp310-cp310-win32.whl", hash = "sha256:84afcdea18eda514c25bc68b9af2a2b1adea7c08899175a51fe7c4fb6d551257"}, + {file = "aiohttp-3.10.10-cp310-cp310-win_amd64.whl", hash = "sha256:9c72109213eb9d3874f7ac8c0c5fa90e072d678e117d9061c06e30c85b4cf0e6"}, + {file = "aiohttp-3.10.10-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c30a0eafc89d28e7f959281b58198a9fa5e99405f716c0289b7892ca345fe45f"}, + {file = "aiohttp-3.10.10-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:258c5dd01afc10015866114e210fb7365f0d02d9d059c3c3415382ab633fcbcb"}, + {file = "aiohttp-3.10.10-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:15ecd889a709b0080f02721255b3f80bb261c2293d3c748151274dfea93ac871"}, + {file = "aiohttp-3.10.10-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3935f82f6f4a3820270842e90456ebad3af15810cf65932bd24da4463bc0a4c"}, + {file = "aiohttp-3.10.10-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:413251f6fcf552a33c981c4709a6bba37b12710982fec8e558ae944bfb2abd38"}, + {file = "aiohttp-3.10.10-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d1720b4f14c78a3089562b8875b53e36b51c97c51adc53325a69b79b4b48ebcb"}, + {file = "aiohttp-3.10.10-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:679abe5d3858b33c2cf74faec299fda60ea9de62916e8b67e625d65bf069a3b7"}, + {file = "aiohttp-3.10.10-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:79019094f87c9fb44f8d769e41dbb664d6e8fcfd62f665ccce36762deaa0e911"}, + {file = "aiohttp-3.10.10-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:fe2fb38c2ed905a2582948e2de560675e9dfbee94c6d5ccdb1301c6d0a5bf092"}, + {file = "aiohttp-3.10.10-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:a3f00003de6eba42d6e94fabb4125600d6e484846dbf90ea8e48a800430cc142"}, + {file = "aiohttp-3.10.10-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:1bbb122c557a16fafc10354b9d99ebf2f2808a660d78202f10ba9d50786384b9"}, + {file = "aiohttp-3.10.10-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:30ca7c3b94708a9d7ae76ff281b2f47d8eaf2579cd05971b5dc681db8caac6e1"}, + {file = "aiohttp-3.10.10-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:df9270660711670e68803107d55c2b5949c2e0f2e4896da176e1ecfc068b974a"}, + {file = "aiohttp-3.10.10-cp311-cp311-win32.whl", hash = "sha256:aafc8ee9b742ce75044ae9a4d3e60e3d918d15a4c2e08a6c3c3e38fa59b92d94"}, + {file = "aiohttp-3.10.10-cp311-cp311-win_amd64.whl", hash = "sha256:362f641f9071e5f3ee6f8e7d37d5ed0d95aae656adf4ef578313ee585b585959"}, + {file = "aiohttp-3.10.10-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:9294bbb581f92770e6ed5c19559e1e99255e4ca604a22c5c6397b2f9dd3ee42c"}, + {file = "aiohttp-3.10.10-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a8fa23fe62c436ccf23ff930149c047f060c7126eae3ccea005f0483f27b2e28"}, + {file = "aiohttp-3.10.10-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5c6a5b8c7926ba5d8545c7dd22961a107526562da31a7a32fa2456baf040939f"}, + {file = "aiohttp-3.10.10-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:007ec22fbc573e5eb2fb7dec4198ef8f6bf2fe4ce20020798b2eb5d0abda6138"}, + {file = "aiohttp-3.10.10-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9627cc1a10c8c409b5822a92d57a77f383b554463d1884008e051c32ab1b3742"}, + {file = "aiohttp-3.10.10-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:50edbcad60d8f0e3eccc68da67f37268b5144ecc34d59f27a02f9611c1d4eec7"}, + {file = "aiohttp-3.10.10-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a45d85cf20b5e0d0aa5a8dca27cce8eddef3292bc29d72dcad1641f4ed50aa16"}, + {file = "aiohttp-3.10.10-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0b00807e2605f16e1e198f33a53ce3c4523114059b0c09c337209ae55e3823a8"}, + {file = "aiohttp-3.10.10-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f2d4324a98062be0525d16f768a03e0bbb3b9fe301ceee99611dc9a7953124e6"}, + {file = "aiohttp-3.10.10-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:438cd072f75bb6612f2aca29f8bd7cdf6e35e8f160bc312e49fbecab77c99e3a"}, + {file = "aiohttp-3.10.10-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:baa42524a82f75303f714108fea528ccacf0386af429b69fff141ffef1c534f9"}, + {file = "aiohttp-3.10.10-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:a7d8d14fe962153fc681f6366bdec33d4356f98a3e3567782aac1b6e0e40109a"}, + {file = "aiohttp-3.10.10-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c1277cd707c465cd09572a774559a3cc7c7a28802eb3a2a9472588f062097205"}, + {file = "aiohttp-3.10.10-cp312-cp312-win32.whl", hash = "sha256:59bb3c54aa420521dc4ce3cc2c3fe2ad82adf7b09403fa1f48ae45c0cbde6628"}, + {file = "aiohttp-3.10.10-cp312-cp312-win_amd64.whl", hash = "sha256:0e1b370d8007c4ae31ee6db7f9a2fe801a42b146cec80a86766e7ad5c4a259cf"}, + {file = "aiohttp-3.10.10-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ad7593bb24b2ab09e65e8a1d385606f0f47c65b5a2ae6c551db67d6653e78c28"}, + {file = "aiohttp-3.10.10-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1eb89d3d29adaf533588f209768a9c02e44e4baf832b08118749c5fad191781d"}, + {file = "aiohttp-3.10.10-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3fe407bf93533a6fa82dece0e74dbcaaf5d684e5a51862887f9eaebe6372cd79"}, + {file = "aiohttp-3.10.10-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50aed5155f819873d23520919e16703fc8925e509abbb1a1491b0087d1cd969e"}, + {file = "aiohttp-3.10.10-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4f05e9727ce409358baa615dbeb9b969db94324a79b5a5cea45d39bdb01d82e6"}, + {file = "aiohttp-3.10.10-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3dffb610a30d643983aeb185ce134f97f290f8935f0abccdd32c77bed9388b42"}, + {file = "aiohttp-3.10.10-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa6658732517ddabe22c9036479eabce6036655ba87a0224c612e1ae6af2087e"}, + {file = "aiohttp-3.10.10-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:741a46d58677d8c733175d7e5aa618d277cd9d880301a380fd296975a9cdd7bc"}, + {file = "aiohttp-3.10.10-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e00e3505cd80440f6c98c6d69269dcc2a119f86ad0a9fd70bccc59504bebd68a"}, + {file = "aiohttp-3.10.10-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ffe595f10566f8276b76dc3a11ae4bb7eba1aac8ddd75811736a15b0d5311414"}, + {file = "aiohttp-3.10.10-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:bdfcf6443637c148c4e1a20c48c566aa694fa5e288d34b20fcdc58507882fed3"}, + {file = "aiohttp-3.10.10-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:d183cf9c797a5291e8301790ed6d053480ed94070637bfaad914dd38b0981f67"}, + {file = "aiohttp-3.10.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:77abf6665ae54000b98b3c742bc6ea1d1fb31c394bcabf8b5d2c1ac3ebfe7f3b"}, + {file = "aiohttp-3.10.10-cp313-cp313-win32.whl", hash = "sha256:4470c73c12cd9109db8277287d11f9dd98f77fc54155fc71a7738a83ffcc8ea8"}, + {file = "aiohttp-3.10.10-cp313-cp313-win_amd64.whl", hash = "sha256:486f7aabfa292719a2753c016cc3a8f8172965cabb3ea2e7f7436c7f5a22a151"}, + {file = "aiohttp-3.10.10-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:1b66ccafef7336a1e1f0e389901f60c1d920102315a56df85e49552308fc0486"}, + {file = "aiohttp-3.10.10-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:acd48d5b80ee80f9432a165c0ac8cbf9253eaddb6113269a5e18699b33958dbb"}, + {file = "aiohttp-3.10.10-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3455522392fb15ff549d92fbf4b73b559d5e43dc522588f7eb3e54c3f38beee7"}, + {file = "aiohttp-3.10.10-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45c3b868724137f713a38376fef8120c166d1eadd50da1855c112fe97954aed8"}, + {file = "aiohttp-3.10.10-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:da1dee8948d2137bb51fbb8a53cce6b1bcc86003c6b42565f008438b806cccd8"}, + {file = "aiohttp-3.10.10-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c5ce2ce7c997e1971b7184ee37deb6ea9922ef5163c6ee5aa3c274b05f9e12fa"}, + {file = "aiohttp-3.10.10-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28529e08fde6f12eba8677f5a8608500ed33c086f974de68cc65ab218713a59d"}, + {file = "aiohttp-3.10.10-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f7db54c7914cc99d901d93a34704833568d86c20925b2762f9fa779f9cd2e70f"}, + {file = "aiohttp-3.10.10-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:03a42ac7895406220124c88911ebee31ba8b2d24c98507f4a8bf826b2937c7f2"}, + {file = "aiohttp-3.10.10-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:7e338c0523d024fad378b376a79faff37fafb3c001872a618cde1d322400a572"}, + {file = "aiohttp-3.10.10-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:038f514fe39e235e9fef6717fbf944057bfa24f9b3db9ee551a7ecf584b5b480"}, + {file = "aiohttp-3.10.10-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:64f6c17757251e2b8d885d728b6433d9d970573586a78b78ba8929b0f41d045a"}, + {file = "aiohttp-3.10.10-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:93429602396f3383a797a2a70e5f1de5df8e35535d7806c9f91df06f297e109b"}, + {file = "aiohttp-3.10.10-cp38-cp38-win32.whl", hash = "sha256:c823bc3971c44ab93e611ab1a46b1eafeae474c0c844aff4b7474287b75fe49c"}, + {file = "aiohttp-3.10.10-cp38-cp38-win_amd64.whl", hash = "sha256:54ca74df1be3c7ca1cf7f4c971c79c2daf48d9aa65dea1a662ae18926f5bc8ce"}, + {file = "aiohttp-3.10.10-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:01948b1d570f83ee7bbf5a60ea2375a89dfb09fd419170e7f5af029510033d24"}, + {file = "aiohttp-3.10.10-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9fc1500fd2a952c5c8e3b29aaf7e3cc6e27e9cfc0a8819b3bce48cc1b849e4cc"}, + {file = "aiohttp-3.10.10-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f614ab0c76397661b90b6851a030004dac502e48260ea10f2441abd2207fbcc7"}, + {file = "aiohttp-3.10.10-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:00819de9e45d42584bed046314c40ea7e9aea95411b38971082cad449392b08c"}, + {file = "aiohttp-3.10.10-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:05646ebe6b94cc93407b3bf34b9eb26c20722384d068eb7339de802154d61bc5"}, + {file = "aiohttp-3.10.10-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:998f3bd3cfc95e9424a6acd7840cbdd39e45bc09ef87533c006f94ac47296090"}, + {file = "aiohttp-3.10.10-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d9010c31cd6fa59438da4e58a7f19e4753f7f264300cd152e7f90d4602449762"}, + {file = "aiohttp-3.10.10-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7ea7ffc6d6d6f8a11e6f40091a1040995cdff02cfc9ba4c2f30a516cb2633554"}, + {file = "aiohttp-3.10.10-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:ef9c33cc5cbca35808f6c74be11eb7f5f6b14d2311be84a15b594bd3e58b5527"}, + {file = "aiohttp-3.10.10-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:ce0cdc074d540265bfeb31336e678b4e37316849d13b308607efa527e981f5c2"}, + {file = "aiohttp-3.10.10-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:597a079284b7ee65ee102bc3a6ea226a37d2b96d0418cc9047490f231dc09fe8"}, + {file = "aiohttp-3.10.10-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:7789050d9e5d0c309c706953e5e8876e38662d57d45f936902e176d19f1c58ab"}, + {file = "aiohttp-3.10.10-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:e7f8b04d83483577fd9200461b057c9f14ced334dcb053090cea1da9c8321a91"}, + {file = "aiohttp-3.10.10-cp39-cp39-win32.whl", hash = "sha256:c02a30b904282777d872266b87b20ed8cc0d1501855e27f831320f471d54d983"}, + {file = "aiohttp-3.10.10-cp39-cp39-win_amd64.whl", hash = "sha256:edfe3341033a6b53a5c522c802deb2079eee5cbfbb0af032a55064bd65c73a23"}, + {file = "aiohttp-3.10.10.tar.gz", hash = "sha256:0631dd7c9f0822cc61c88586ca76d5b5ada26538097d0f1df510b082bad3411a"}, ] [package.dependencies] +aiohappyeyeballs = ">=2.3.0" aiosignal = ">=1.1.2" async-timeout = {version = ">=4.0,<5.0", markers = "python_version < \"3.11\""} attrs = ">=17.3.0" frozenlist = ">=1.1.1" multidict = ">=4.5,<7.0" -yarl = ">=1.0,<2.0" +yarl = ">=1.12.0,<2.0" [package.extras] -speedups = ["Brotli", "aiodns", "brotlicffi"] +speedups = ["Brotli", "aiodns (>=3.2.0)", "brotlicffi"] [[package]] name = "aiosignal" @@ -176,22 +203,22 @@ files = [ [[package]] name = "attrs" -version = "23.2.0" +version = "24.2.0" description = "Classes Without Boilerplate" optional = false python-versions = ">=3.7" files = [ - {file = "attrs-23.2.0-py3-none-any.whl", hash = "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1"}, - {file = "attrs-23.2.0.tar.gz", hash = "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30"}, + {file = "attrs-24.2.0-py3-none-any.whl", hash = "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2"}, + {file = "attrs-24.2.0.tar.gz", hash = "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346"}, ] [package.extras] -cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] -dev = ["attrs[tests]", "pre-commit"] -docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"] -tests = ["attrs[tests-no-zope]", "zope-interface"] -tests-mypy = ["mypy (>=1.6)", "pytest-mypy-plugins"] -tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist[psutil]"] +benchmark = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +cov = ["cloudpickle", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +dev = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier (<24.7)"] +tests = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +tests-mypy = ["mypy (>=1.11.1)", "pytest-mypy-plugins"] [[package]] name = "avro" @@ -220,13 +247,13 @@ files = [ [[package]] name = "azure-core" -version = "1.30.2" +version = "1.31.0" description = "Microsoft Azure Core Library for Python" optional = false python-versions = ">=3.8" files = [ - {file = "azure-core-1.30.2.tar.gz", hash = "sha256:a14dc210efcd608821aa472d9fb8e8d035d29b68993819147bc290a8ac224472"}, - {file = "azure_core-1.30.2-py3-none-any.whl", hash = "sha256:cf019c1ca832e96274ae85abd3d9f752397194d9fea3b41487290562ac8abe4a"}, + {file = "azure_core-1.31.0-py3-none-any.whl", hash = "sha256:22954de3777e0250029360ef31d80448ef1be13b80a459bff80ba7073379e2cd"}, + {file = "azure_core-1.31.0.tar.gz", hash = "sha256:656a0dd61e1869b1506b7c6a3b31d62f15984b1a573d6326f6aa2f3e4123284b"}, ] [package.dependencies] @@ -239,20 +266,20 @@ aio = ["aiohttp (>=3.0)"] [[package]] name = "azure-identity" -version = "1.17.1" +version = "1.19.0" description = "Microsoft Azure Identity Library for Python" optional = false python-versions = ">=3.8" files = [ - {file = "azure-identity-1.17.1.tar.gz", hash = "sha256:32ecc67cc73f4bd0595e4f64b1ca65cd05186f4fe6f98ed2ae9f1aa32646efea"}, - {file = "azure_identity-1.17.1-py3-none-any.whl", hash = "sha256:db8d59c183b680e763722bfe8ebc45930e6c57df510620985939f7f3191e0382"}, + {file = "azure_identity-1.19.0-py3-none-any.whl", hash = "sha256:e3f6558c181692d7509f09de10cca527c7dce426776454fb97df512a46527e81"}, + {file = "azure_identity-1.19.0.tar.gz", hash = "sha256:500144dc18197d7019b81501165d4fa92225f03778f17d7ca8a2a180129a9c83"}, ] [package.dependencies] -azure-core = ">=1.23.0" +azure-core = ">=1.31.0" cryptography = ">=2.5" -msal = ">=1.24.0" -msal-extensions = ">=0.3.0" +msal = ">=1.30.0" +msal-extensions = ">=1.2.0" typing-extensions = ">=4.0.0" [[package]] @@ -287,33 +314,33 @@ msrest = ">=0.6.21" [[package]] name = "azure-storage-blob" -version = "12.20.0" +version = "12.23.1" description = "Microsoft Azure Blob Storage Client Library for Python" optional = false python-versions = ">=3.8" files = [ - {file = "azure-storage-blob-12.20.0.tar.gz", hash = "sha256:eeb91256e41d4b5b9bad6a87fd0a8ade07dd58aa52344e2c8d2746e27a017d3b"}, - {file = "azure_storage_blob-12.20.0-py3-none-any.whl", hash = "sha256:de6b3bf3a90e9341a6bcb96a2ebe981dffff993e9045818f6549afea827a52a9"}, + {file = "azure_storage_blob-12.23.1-py3-none-any.whl", hash = "sha256:1c2238aa841d1545f42714a5017c010366137a44a0605da2d45f770174bfc6b4"}, + {file = "azure_storage_blob-12.23.1.tar.gz", hash = "sha256:a587e54d4e39d2a27bd75109db164ffa2058fe194061e5446c5a89bca918272f"}, ] [package.dependencies] -azure-core = ">=1.28.0" +azure-core = ">=1.30.0" cryptography = ">=2.1.4" isodate = ">=0.6.1" typing-extensions = ">=4.6.0" [package.extras] -aio = ["azure-core[aio] (>=1.28.0)"] +aio = ["azure-core[aio] (>=1.30.0)"] [[package]] name = "babel" -version = "2.15.0" +version = "2.16.0" description = "Internationalization utilities" optional = false python-versions = ">=3.8" files = [ - {file = "Babel-2.15.0-py3-none-any.whl", hash = "sha256:08706bdad8d0a3413266ab61bd6c34d0c28d6e1e7badf40a2cebe67644e2e1fb"}, - {file = "babel-2.15.0.tar.gz", hash = "sha256:8daf0e265d05768bc6c7a314cf1321e9a123afc328cc635c18622a2f30a04413"}, + {file = "babel-2.16.0-py3-none-any.whl", hash = "sha256:368b5b98b37c06b7daf6696391c3240c938b37767d4584413e8438c5c435fa8b"}, + {file = "babel-2.16.0.tar.gz", hash = "sha256:d1f3554ca26605fe173f3de0c65f750f5a42f924499bf134de6423582298e316"}, ] [package.extras] @@ -342,13 +369,13 @@ lxml = ["lxml"] [[package]] name = "bokeh" -version = "3.4.1" +version = "3.6.0" description = "Interactive plots and applications in the browser from Python" optional = false -python-versions = ">=3.9" +python-versions = ">=3.10" files = [ - {file = "bokeh-3.4.1-py3-none-any.whl", hash = "sha256:1e3c502a0a8205338fc74dadbfa321f8a0965441b39501e36796a47b4017b642"}, - {file = "bokeh-3.4.1.tar.gz", hash = "sha256:d824961e4265367b0750ce58b07e564ad0b83ca64b335521cd3421e9b9f10d89"}, + {file = "bokeh-3.6.0-py3-none-any.whl", hash = "sha256:699e0df76cdfe54b5f574738647bd0ce230fa44fa0fcda5923e1f0f550f83d74"}, + {file = "bokeh-3.6.0.tar.gz", hash = "sha256:0032dc1e76ad097b07626e51584685ff48c65481fbaaad105663b1046165867a"}, ] [package.dependencies] @@ -364,17 +391,17 @@ xyzservices = ">=2021.09.1" [[package]] name = "boto3" -version = "1.34.131" +version = "1.35.51" description = "The AWS SDK for Python" optional = false python-versions = ">=3.8" files = [ - {file = "boto3-1.34.131-py3-none-any.whl", hash = "sha256:05e388cb937e82be70bfd7eb0c84cf8011ff35cf582a593873ac21675268683b"}, - {file = "boto3-1.34.131.tar.gz", hash = "sha256:dab8f72a6c4e62b4fd70da09e08a6b2a65ea2115b27dd63737142005776ef216"}, + {file = "boto3-1.35.51-py3-none-any.whl", hash = "sha256:c922f6a18958af9d8af0489d6d8503b517029d8159b26aa4859a8294561c72e9"}, + {file = "boto3-1.35.51.tar.gz", hash = "sha256:a57c6c7012ecb40c43e565a6f7a891f39efa990ff933eab63cd456f7501c2731"}, ] [package.dependencies] -botocore = ">=1.34.131,<1.35.0" +botocore = ">=1.35.51,<1.36.0" jmespath = ">=0.7.1,<2.0.0" s3transfer = ">=0.10.0,<0.11.0" @@ -383,13 +410,13 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "botocore" -version = "1.34.131" +version = "1.35.51" description = "Low-level, data-driven core of boto 3." optional = false python-versions = ">=3.8" files = [ - {file = "botocore-1.34.131-py3-none-any.whl", hash = "sha256:13b011d7b206ce00727dcee26548fa3b550db9046d5a0e90ac25a6e6c8fde6ef"}, - {file = "botocore-1.34.131.tar.gz", hash = "sha256:502ddafe1d627fcf1e4c007c86454e5dd011dba7c58bd8e8a5368a79f3e387dc"}, + {file = "botocore-1.35.51-py3-none-any.whl", hash = "sha256:4d65b00111bd12b98e9f920ecab602cf619cc6a6d0be6e5dd53f517e4b92901c"}, + {file = "botocore-1.35.51.tar.gz", hash = "sha256:a9b3d1da76b3e896ad74605c01d88f596324a3337393d4bfbfa0d6c35822ca9c"}, ] [package.dependencies] @@ -398,100 +425,115 @@ python-dateutil = ">=2.1,<3.0.0" urllib3 = {version = ">=1.25.4,<2.2.0 || >2.2.0,<3", markers = "python_version >= \"3.10\""} [package.extras] -crt = ["awscrt (==0.20.11)"] +crt = ["awscrt (==0.22.0)"] [[package]] name = "bracex" -version = "2.4" +version = "2.5.post1" description = "Bash style brace expander." optional = false python-versions = ">=3.8" files = [ - {file = "bracex-2.4-py3-none-any.whl", hash = "sha256:efdc71eff95eaff5e0f8cfebe7d01adf2c8637c8c92edaf63ef348c241a82418"}, - {file = "bracex-2.4.tar.gz", hash = "sha256:a27eaf1df42cf561fed58b7a8f3fdf129d1ea16a81e1fadd1d17989bc6384beb"}, + {file = "bracex-2.5.post1-py3-none-any.whl", hash = "sha256:13e5732fec27828d6af308628285ad358047cec36801598368cb28bc631dbaf6"}, + {file = "bracex-2.5.post1.tar.gz", hash = "sha256:12c50952415bfa773d2d9ccb8e79651b8cdb1f31a42f6091b804f6ba2b4a66b6"}, ] [[package]] name = "cachetools" -version = "5.3.3" +version = "5.5.0" description = "Extensible memoizing collections and decorators" optional = false python-versions = ">=3.7" files = [ - {file = "cachetools-5.3.3-py3-none-any.whl", hash = "sha256:0abad1021d3f8325b2fc1d2e9c8b9c9d57b04c3932657a72465447332c24d945"}, - {file = "cachetools-5.3.3.tar.gz", hash = "sha256:ba29e2dfa0b8b556606f097407ed1aa62080ee108ab0dc5ec9d6a723a007d105"}, + {file = "cachetools-5.5.0-py3-none-any.whl", hash = "sha256:02134e8439cdc2ffb62023ce1debca2944c3f289d66bb17ead3ab3dede74b292"}, + {file = "cachetools-5.5.0.tar.gz", hash = "sha256:2cc24fb4cbe39633fb7badd9db9ca6295d766d9c2995f245725a46715d050f2a"}, ] [[package]] name = "certifi" -version = "2024.6.2" +version = "2024.8.30" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2024.6.2-py3-none-any.whl", hash = "sha256:ddc6c8ce995e6987e7faf5e3f1b02b302836a0e5d98ece18392cb1a36c72ad56"}, - {file = "certifi-2024.6.2.tar.gz", hash = "sha256:3cd43f1c6fa7dedc5899d69d3ad0398fd018ad1a17fba83ddaf78aa46c747516"}, + {file = "certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8"}, + {file = "certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9"}, ] [[package]] name = "cffi" -version = "1.16.0" +version = "1.17.1" description = "Foreign Function Interface for Python calling C code." optional = false python-versions = ">=3.8" files = [ - {file = "cffi-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088"}, - {file = "cffi-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614"}, - {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743"}, - {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d"}, - {file = "cffi-1.16.0-cp310-cp310-win32.whl", hash = "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a"}, - {file = "cffi-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1"}, - {file = "cffi-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404"}, - {file = "cffi-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e"}, - {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc"}, - {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb"}, - {file = "cffi-1.16.0-cp311-cp311-win32.whl", hash = "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab"}, - {file = "cffi-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba"}, - {file = "cffi-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956"}, - {file = "cffi-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969"}, - {file = "cffi-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520"}, - {file = "cffi-1.16.0-cp312-cp312-win32.whl", hash = "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b"}, - {file = "cffi-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235"}, - {file = "cffi-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324"}, - {file = "cffi-1.16.0-cp38-cp38-win32.whl", hash = "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a"}, - {file = "cffi-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36"}, - {file = "cffi-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed"}, - {file = "cffi-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098"}, - {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000"}, - {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe"}, - {file = "cffi-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4"}, - {file = "cffi-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8"}, - {file = "cffi-1.16.0.tar.gz", hash = "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0"}, + {file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"}, + {file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be"}, + {file = "cffi-1.17.1-cp310-cp310-win32.whl", hash = "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c"}, + {file = "cffi-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15"}, + {file = "cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401"}, + {file = "cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b"}, + {file = "cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655"}, + {file = "cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0"}, + {file = "cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4"}, + {file = "cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93"}, + {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3"}, + {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8"}, + {file = "cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65"}, + {file = "cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903"}, + {file = "cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e"}, + {file = "cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd"}, + {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed"}, + {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9"}, + {file = "cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d"}, + {file = "cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a"}, + {file = "cffi-1.17.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1"}, + {file = "cffi-1.17.1-cp38-cp38-win32.whl", hash = "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8"}, + {file = "cffi-1.17.1-cp38-cp38-win_amd64.whl", hash = "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1"}, + {file = "cffi-1.17.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16"}, + {file = "cffi-1.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e"}, + {file = "cffi-1.17.1-cp39-cp39-win32.whl", hash = "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7"}, + {file = "cffi-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662"}, + {file = "cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824"}, ] [package.dependencies] @@ -510,101 +552,116 @@ files = [ [[package]] name = "charset-normalizer" -version = "3.3.2" +version = "3.4.0" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false python-versions = ">=3.7.0" files = [ - {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"}, - {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5ed2e36c3e9b4f21dd9422f6893dec0abf2cca553af509b10cd630f878d3eb99"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40d3ff7fc90b98c637bda91c89d51264a3dcf210cade3a2c6f838c7268d7a4ca"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1110e22af8ca26b90bd6364fe4c763329b0ebf1ee213ba32b68c73de5752323d"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:86f4e8cca779080f66ff4f191a685ced73d2f72d50216f7112185dc02b90b9b7"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f683ddc7eedd742e2889d2bfb96d69573fde1d92fcb811979cdb7165bb9c7d3"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27623ba66c183eca01bf9ff833875b459cad267aeeb044477fedac35e19ba907"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f606a1881d2663630ea5b8ce2efe2111740df4b687bd78b34a8131baa007f79b"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0b309d1747110feb25d7ed6b01afdec269c647d382c857ef4663bbe6ad95a912"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:136815f06a3ae311fae551c3df1f998a1ebd01ddd424aa5603a4336997629e95"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:14215b71a762336254351b00ec720a8e85cada43b987da5a042e4ce3e82bd68e"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:79983512b108e4a164b9c8d34de3992f76d48cadc9554c9e60b43f308988aabe"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-win32.whl", hash = "sha256:c94057af19bc953643a33581844649a7fdab902624d2eb739738a30e2b3e60fc"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:55f56e2ebd4e3bc50442fbc0888c9d8c94e4e06a933804e2af3e89e2f9c1c749"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-win32.whl", hash = "sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-win32.whl", hash = "sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-win32.whl", hash = "sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:dbe03226baf438ac4fda9e2d0715022fd579cb641c4cf639fa40d53b2fe6f3e2"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd9a8bd8900e65504a305bf8ae6fa9fbc66de94178c420791d0293702fce2df7"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8831399554b92b72af5932cdbbd4ddc55c55f631bb13ff8fe4e6536a06c5c51"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a14969b8691f7998e74663b77b4c36c0337cb1df552da83d5c9004a93afdb574"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dcaf7c1524c0542ee2fc82cc8ec337f7a9f7edee2532421ab200d2b920fc97cf"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:425c5f215d0eecee9a56cdb703203dda90423247421bf0d67125add85d0c4455"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:d5b054862739d276e09928de37c79ddeec42a6e1bfc55863be96a36ba22926f6"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:f3e73a4255342d4eb26ef6df01e3962e73aa29baa3124a8e824c5d3364a65748"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:2f6c34da58ea9c1a9515621f4d9ac379871a8f21168ba1b5e09d74250de5ad62"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:f09cb5a7bbe1ecae6e87901a2eb23e0256bb524a79ccc53eb0b7629fbe7677c4"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:0099d79bdfcf5c1f0c2c72f91516702ebf8b0b8ddd8905f97a8aecf49712c621"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-win32.whl", hash = "sha256:9c98230f5042f4945f957d006edccc2af1e03ed5e37ce7c373f00a5a4daa6149"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:62f60aebecfc7f4b82e3f639a7d1433a20ec32824db2199a11ad4f5e146ef5ee"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:af73657b7a68211996527dbfeffbb0864e043d270580c5aef06dc4b659a4b578"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cab5d0b79d987c67f3b9e9c53f54a61360422a5a0bc075f43cab5621d530c3b6"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9289fd5dddcf57bab41d044f1756550f9e7cf0c8e373b8cdf0ce8773dc4bd417"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b493a043635eb376e50eedf7818f2f322eabbaa974e948bd8bdd29eb7ef2a51"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fa2566ca27d67c86569e8c85297aaf413ffab85a8960500f12ea34ff98e4c41"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8e538f46104c815be19c975572d74afb53f29650ea2025bbfaef359d2de2f7f"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fd30dc99682dc2c603c2b315bded2799019cea829f8bf57dc6b61efde6611c8"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2006769bd1640bdf4d5641c69a3d63b71b81445473cac5ded39740a226fa88ab"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:dc15e99b2d8a656f8e666854404f1ba54765871104e50c8e9813af8a7db07f12"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:ab2e5bef076f5a235c3774b4f4028a680432cded7cad37bba0fd90d64b187d19"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:4ec9dd88a5b71abfc74e9df5ebe7921c35cbb3b641181a531ca65cdb5e8e4dea"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:43193c5cda5d612f247172016c4bb71251c784d7a4d9314677186a838ad34858"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:aa693779a8b50cd97570e5a0f343538a8dbd3e496fa5dcb87e29406ad0299654"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-win32.whl", hash = "sha256:7706f5850360ac01d80c89bcef1640683cc12ed87f42579dab6c5d3ed6888613"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:c3e446d253bd88f6377260d07c895816ebf33ffffd56c1c792b13bff9c3e1ade"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:980b4f289d1d90ca5efcf07958d3eb38ed9c0b7676bf2831a54d4f66f9c27dfa"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f28f891ccd15c514a0981f3b9db9aa23d62fe1a99997512b0491d2ed323d229a"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8aacce6e2e1edcb6ac625fb0f8c3a9570ccc7bfba1f63419b3769ccf6a00ed0"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd7af3717683bea4c87acd8c0d3d5b44d56120b26fd3f8a692bdd2d5260c620a"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ff2ed8194587faf56555927b3aa10e6fb69d931e33953943bc4f837dfee2242"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e91f541a85298cf35433bf66f3fab2a4a2cff05c127eeca4af174f6d497f0d4b"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:309a7de0a0ff3040acaebb35ec45d18db4b28232f21998851cfa709eeff49d62"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:285e96d9d53422efc0d7a17c60e59f37fbf3dfa942073f666db4ac71e8d726d0"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:5d447056e2ca60382d460a604b6302d8db69476fd2015c81e7c35417cfabe4cd"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:20587d20f557fe189b7947d8e7ec5afa110ccf72a3128d61a2a387c3313f46be"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:130272c698667a982a5d0e626851ceff662565379baf0ff2cc58067b81d4f11d"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ab22fbd9765e6954bc0bcff24c25ff71dcbfdb185fcdaca49e81bac68fe724d3"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7782afc9b6b42200f7362858f9e73b1f8316afb276d316336c0ec3bd73312742"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-win32.whl", hash = "sha256:2de62e8801ddfff069cd5c504ce3bc9672b23266597d4e4f50eda28846c322f2"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:95c3c157765b031331dd4db3c775e58deaee050a3042fcad72cbc4189d7c8dca"}, + {file = "charset_normalizer-3.4.0-py3-none-any.whl", hash = "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079"}, + {file = "charset_normalizer-3.4.0.tar.gz", hash = "sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e"}, ] [[package]] @@ -621,6 +678,17 @@ files = [ [package.dependencies] colorama = {version = "*", markers = "platform_system == \"Windows\""} +[[package]] +name = "cloudpickle" +version = "3.1.0" +description = "Pickler class to extend the standard pickle.Pickler functionality" +optional = false +python-versions = ">=3.8" +files = [ + {file = "cloudpickle-3.1.0-py3-none-any.whl", hash = "sha256:fe11acda67f61aaaec473e3afe030feb131d78a43461b718185363384f1ba12e"}, + {file = "cloudpickle-3.1.0.tar.gz", hash = "sha256:81a929b6e3c7335c863c771d673d105f02efdb89dfaba0c90495d1c64796601b"}, +] + [[package]] name = "colorama" version = "0.4.6" @@ -665,126 +733,157 @@ test = ["flake8 (==3.7.8)", "hypothesis (==3.55.3)"] [[package]] name = "contourpy" -version = "1.2.1" +version = "1.3.0" description = "Python library for calculating contours of 2D quadrilateral grids" optional = false python-versions = ">=3.9" files = [ - {file = "contourpy-1.2.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bd7c23df857d488f418439686d3b10ae2fbf9bc256cd045b37a8c16575ea1040"}, - {file = "contourpy-1.2.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5b9eb0ca724a241683c9685a484da9d35c872fd42756574a7cfbf58af26677fd"}, - {file = "contourpy-1.2.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c75507d0a55378240f781599c30e7776674dbaf883a46d1c90f37e563453480"}, - {file = "contourpy-1.2.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:11959f0ce4a6f7b76ec578576a0b61a28bdc0696194b6347ba3f1c53827178b9"}, - {file = "contourpy-1.2.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eb3315a8a236ee19b6df481fc5f997436e8ade24a9f03dfdc6bd490fea20c6da"}, - {file = "contourpy-1.2.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39f3ecaf76cd98e802f094e0d4fbc6dc9c45a8d0c4d185f0f6c2234e14e5f75b"}, - {file = "contourpy-1.2.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:94b34f32646ca0414237168d68a9157cb3889f06b096612afdd296003fdd32fd"}, - {file = "contourpy-1.2.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:457499c79fa84593f22454bbd27670227874cd2ff5d6c84e60575c8b50a69619"}, - {file = "contourpy-1.2.1-cp310-cp310-win32.whl", hash = "sha256:ac58bdee53cbeba2ecad824fa8159493f0bf3b8ea4e93feb06c9a465d6c87da8"}, - {file = "contourpy-1.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:9cffe0f850e89d7c0012a1fb8730f75edd4320a0a731ed0c183904fe6ecfc3a9"}, - {file = "contourpy-1.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6022cecf8f44e36af10bd9118ca71f371078b4c168b6e0fab43d4a889985dbb5"}, - {file = "contourpy-1.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ef5adb9a3b1d0c645ff694f9bca7702ec2c70f4d734f9922ea34de02294fdf72"}, - {file = "contourpy-1.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6150ffa5c767bc6332df27157d95442c379b7dce3a38dff89c0f39b63275696f"}, - {file = "contourpy-1.2.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4c863140fafc615c14a4bf4efd0f4425c02230eb8ef02784c9a156461e62c965"}, - {file = "contourpy-1.2.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:00e5388f71c1a0610e6fe56b5c44ab7ba14165cdd6d695429c5cd94021e390b2"}, - {file = "contourpy-1.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d4492d82b3bc7fbb7e3610747b159869468079fe149ec5c4d771fa1f614a14df"}, - {file = "contourpy-1.2.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:49e70d111fee47284d9dd867c9bb9a7058a3c617274900780c43e38d90fe1205"}, - {file = "contourpy-1.2.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:b59c0ffceff8d4d3996a45f2bb6f4c207f94684a96bf3d9728dbb77428dd8cb8"}, - {file = "contourpy-1.2.1-cp311-cp311-win32.whl", hash = "sha256:7b4182299f251060996af5249c286bae9361fa8c6a9cda5efc29fe8bfd6062ec"}, - {file = "contourpy-1.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2855c8b0b55958265e8b5888d6a615ba02883b225f2227461aa9127c578a4922"}, - {file = "contourpy-1.2.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:62828cada4a2b850dbef89c81f5a33741898b305db244904de418cc957ff05dc"}, - {file = "contourpy-1.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:309be79c0a354afff9ff7da4aaed7c3257e77edf6c1b448a779329431ee79d7e"}, - {file = "contourpy-1.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e785e0f2ef0d567099b9ff92cbfb958d71c2d5b9259981cd9bee81bd194c9a4"}, - {file = "contourpy-1.2.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1cac0a8f71a041aa587410424ad46dfa6a11f6149ceb219ce7dd48f6b02b87a7"}, - {file = "contourpy-1.2.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:af3f4485884750dddd9c25cb7e3915d83c2db92488b38ccb77dd594eac84c4a0"}, - {file = "contourpy-1.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ce6889abac9a42afd07a562c2d6d4b2b7134f83f18571d859b25624a331c90b"}, - {file = "contourpy-1.2.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:a1eea9aecf761c661d096d39ed9026574de8adb2ae1c5bd7b33558af884fb2ce"}, - {file = "contourpy-1.2.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:187fa1d4c6acc06adb0fae5544c59898ad781409e61a926ac7e84b8f276dcef4"}, - {file = "contourpy-1.2.1-cp312-cp312-win32.whl", hash = "sha256:c2528d60e398c7c4c799d56f907664673a807635b857df18f7ae64d3e6ce2d9f"}, - {file = "contourpy-1.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:1a07fc092a4088ee952ddae19a2b2a85757b923217b7eed584fdf25f53a6e7ce"}, - {file = "contourpy-1.2.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bb6834cbd983b19f06908b45bfc2dad6ac9479ae04abe923a275b5f48f1a186b"}, - {file = "contourpy-1.2.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1d59e739ab0e3520e62a26c60707cc3ab0365d2f8fecea74bfe4de72dc56388f"}, - {file = "contourpy-1.2.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd3db01f59fdcbce5b22afad19e390260d6d0222f35a1023d9adc5690a889364"}, - {file = "contourpy-1.2.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a12a813949e5066148712a0626895c26b2578874e4cc63160bb007e6df3436fe"}, - {file = "contourpy-1.2.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fe0ccca550bb8e5abc22f530ec0466136379c01321fd94f30a22231e8a48d985"}, - {file = "contourpy-1.2.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1d59258c3c67c865435d8fbeb35f8c59b8bef3d6f46c1f29f6123556af28445"}, - {file = "contourpy-1.2.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f32c38afb74bd98ce26de7cc74a67b40afb7b05aae7b42924ea990d51e4dac02"}, - {file = "contourpy-1.2.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d31a63bc6e6d87f77d71e1abbd7387ab817a66733734883d1fc0021ed9bfa083"}, - {file = "contourpy-1.2.1-cp39-cp39-win32.whl", hash = "sha256:ddcb8581510311e13421b1f544403c16e901c4e8f09083c881fab2be80ee31ba"}, - {file = "contourpy-1.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:10a37ae557aabf2509c79715cd20b62e4c7c28b8cd62dd7d99e5ed3ce28c3fd9"}, - {file = "contourpy-1.2.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a31f94983fecbac95e58388210427d68cd30fe8a36927980fab9c20062645609"}, - {file = "contourpy-1.2.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef2b055471c0eb466033760a521efb9d8a32b99ab907fc8358481a1dd29e3bd3"}, - {file = "contourpy-1.2.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:b33d2bc4f69caedcd0a275329eb2198f560b325605810895627be5d4b876bf7f"}, - {file = "contourpy-1.2.1.tar.gz", hash = "sha256:4d8908b3bee1c889e547867ca4cdc54e5ab6be6d3e078556814a22457f49423c"}, + {file = "contourpy-1.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:880ea32e5c774634f9fcd46504bf9f080a41ad855f4fef54f5380f5133d343c7"}, + {file = "contourpy-1.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:76c905ef940a4474a6289c71d53122a4f77766eef23c03cd57016ce19d0f7b42"}, + {file = "contourpy-1.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:92f8557cbb07415a4d6fa191f20fd9d2d9eb9c0b61d1b2f52a8926e43c6e9af7"}, + {file = "contourpy-1.3.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:36f965570cff02b874773c49bfe85562b47030805d7d8360748f3eca570f4cab"}, + {file = "contourpy-1.3.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cacd81e2d4b6f89c9f8a5b69b86490152ff39afc58a95af002a398273e5ce589"}, + {file = "contourpy-1.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:69375194457ad0fad3a839b9e29aa0b0ed53bb54db1bfb6c3ae43d111c31ce41"}, + {file = "contourpy-1.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7a52040312b1a858b5e31ef28c2e865376a386c60c0e248370bbea2d3f3b760d"}, + {file = "contourpy-1.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3faeb2998e4fcb256542e8a926d08da08977f7f5e62cf733f3c211c2a5586223"}, + {file = "contourpy-1.3.0-cp310-cp310-win32.whl", hash = "sha256:36e0cff201bcb17a0a8ecc7f454fe078437fa6bda730e695a92f2d9932bd507f"}, + {file = "contourpy-1.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:87ddffef1dbe5e669b5c2440b643d3fdd8622a348fe1983fad7a0f0ccb1cd67b"}, + {file = "contourpy-1.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0fa4c02abe6c446ba70d96ece336e621efa4aecae43eaa9b030ae5fb92b309ad"}, + {file = "contourpy-1.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:834e0cfe17ba12f79963861e0f908556b2cedd52e1f75e6578801febcc6a9f49"}, + {file = "contourpy-1.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dbc4c3217eee163fa3984fd1567632b48d6dfd29216da3ded3d7b844a8014a66"}, + {file = "contourpy-1.3.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4865cd1d419e0c7a7bf6de1777b185eebdc51470800a9f42b9e9decf17762081"}, + {file = "contourpy-1.3.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:303c252947ab4b14c08afeb52375b26781ccd6a5ccd81abcdfc1fafd14cf93c1"}, + {file = "contourpy-1.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:637f674226be46f6ba372fd29d9523dd977a291f66ab2a74fbeb5530bb3f445d"}, + {file = "contourpy-1.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:76a896b2f195b57db25d6b44e7e03f221d32fe318d03ede41f8b4d9ba1bff53c"}, + {file = "contourpy-1.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e1fd23e9d01591bab45546c089ae89d926917a66dceb3abcf01f6105d927e2cb"}, + {file = "contourpy-1.3.0-cp311-cp311-win32.whl", hash = "sha256:d402880b84df3bec6eab53cd0cf802cae6a2ef9537e70cf75e91618a3801c20c"}, + {file = "contourpy-1.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:6cb6cc968059db9c62cb35fbf70248f40994dfcd7aa10444bbf8b3faeb7c2d67"}, + {file = "contourpy-1.3.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:570ef7cf892f0afbe5b2ee410c507ce12e15a5fa91017a0009f79f7d93a1268f"}, + {file = "contourpy-1.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:da84c537cb8b97d153e9fb208c221c45605f73147bd4cadd23bdae915042aad6"}, + {file = "contourpy-1.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0be4d8425bfa755e0fd76ee1e019636ccc7c29f77a7c86b4328a9eb6a26d0639"}, + {file = "contourpy-1.3.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9c0da700bf58f6e0b65312d0a5e695179a71d0163957fa381bb3c1f72972537c"}, + {file = "contourpy-1.3.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eb8b141bb00fa977d9122636b16aa67d37fd40a3d8b52dd837e536d64b9a4d06"}, + {file = "contourpy-1.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3634b5385c6716c258d0419c46d05c8aa7dc8cb70326c9a4fb66b69ad2b52e09"}, + {file = "contourpy-1.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0dce35502151b6bd35027ac39ba6e5a44be13a68f55735c3612c568cac3805fd"}, + {file = "contourpy-1.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:aea348f053c645100612b333adc5983d87be69acdc6d77d3169c090d3b01dc35"}, + {file = "contourpy-1.3.0-cp312-cp312-win32.whl", hash = "sha256:90f73a5116ad1ba7174341ef3ea5c3150ddf20b024b98fb0c3b29034752c8aeb"}, + {file = "contourpy-1.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:b11b39aea6be6764f84360fce6c82211a9db32a7c7de8fa6dd5397cf1d079c3b"}, + {file = "contourpy-1.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:3e1c7fa44aaae40a2247e2e8e0627f4bea3dd257014764aa644f319a5f8600e3"}, + {file = "contourpy-1.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:364174c2a76057feef647c802652f00953b575723062560498dc7930fc9b1cb7"}, + {file = "contourpy-1.3.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:32b238b3b3b649e09ce9aaf51f0c261d38644bdfa35cbaf7b263457850957a84"}, + {file = "contourpy-1.3.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d51fca85f9f7ad0b65b4b9fe800406d0d77017d7270d31ec3fb1cc07358fdea0"}, + {file = "contourpy-1.3.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:732896af21716b29ab3e988d4ce14bc5133733b85956316fb0c56355f398099b"}, + {file = "contourpy-1.3.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d73f659398a0904e125280836ae6f88ba9b178b2fed6884f3b1f95b989d2c8da"}, + {file = "contourpy-1.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c6c7c2408b7048082932cf4e641fa3b8ca848259212f51c8c59c45aa7ac18f14"}, + {file = "contourpy-1.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f317576606de89da6b7e0861cf6061f6146ead3528acabff9236458a6ba467f8"}, + {file = "contourpy-1.3.0-cp313-cp313-win32.whl", hash = "sha256:31cd3a85dbdf1fc002280c65caa7e2b5f65e4a973fcdf70dd2fdcb9868069294"}, + {file = "contourpy-1.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:4553c421929ec95fb07b3aaca0fae668b2eb5a5203d1217ca7c34c063c53d087"}, + {file = "contourpy-1.3.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:345af746d7766821d05d72cb8f3845dfd08dd137101a2cb9b24de277d716def8"}, + {file = "contourpy-1.3.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3bb3808858a9dc68f6f03d319acd5f1b8a337e6cdda197f02f4b8ff67ad2057b"}, + {file = "contourpy-1.3.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:420d39daa61aab1221567b42eecb01112908b2cab7f1b4106a52caaec8d36973"}, + {file = "contourpy-1.3.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4d63ee447261e963af02642ffcb864e5a2ee4cbfd78080657a9880b8b1868e18"}, + {file = "contourpy-1.3.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:167d6c890815e1dac9536dca00828b445d5d0df4d6a8c6adb4a7ec3166812fa8"}, + {file = "contourpy-1.3.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:710a26b3dc80c0e4febf04555de66f5fd17e9cf7170a7b08000601a10570bda6"}, + {file = "contourpy-1.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:75ee7cb1a14c617f34a51d11fa7524173e56551646828353c4af859c56b766e2"}, + {file = "contourpy-1.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:33c92cdae89ec5135d036e7218e69b0bb2851206077251f04a6c4e0e21f03927"}, + {file = "contourpy-1.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a11077e395f67ffc2c44ec2418cfebed032cd6da3022a94fc227b6faf8e2acb8"}, + {file = "contourpy-1.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e8134301d7e204c88ed7ab50028ba06c683000040ede1d617298611f9dc6240c"}, + {file = "contourpy-1.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e12968fdfd5bb45ffdf6192a590bd8ddd3ba9e58360b29683c6bb71a7b41edca"}, + {file = "contourpy-1.3.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fd2a0fc506eccaaa7595b7e1418951f213cf8255be2600f1ea1b61e46a60c55f"}, + {file = "contourpy-1.3.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4cfb5c62ce023dfc410d6059c936dcf96442ba40814aefbfa575425a3a7f19dc"}, + {file = "contourpy-1.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68a32389b06b82c2fdd68276148d7b9275b5f5cf13e5417e4252f6d1a34f72a2"}, + {file = "contourpy-1.3.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:94e848a6b83da10898cbf1311a815f770acc9b6a3f2d646f330d57eb4e87592e"}, + {file = "contourpy-1.3.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:d78ab28a03c854a873787a0a42254a0ccb3cb133c672f645c9f9c8f3ae9d0800"}, + {file = "contourpy-1.3.0-cp39-cp39-win32.whl", hash = "sha256:81cb5ed4952aae6014bc9d0421dec7c5835c9c8c31cdf51910b708f548cf58e5"}, + {file = "contourpy-1.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:14e262f67bd7e6eb6880bc564dcda30b15e351a594657e55b7eec94b6ef72843"}, + {file = "contourpy-1.3.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:fe41b41505a5a33aeaed2a613dccaeaa74e0e3ead6dd6fd3a118fb471644fd6c"}, + {file = "contourpy-1.3.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eca7e17a65f72a5133bdbec9ecf22401c62bcf4821361ef7811faee695799779"}, + {file = "contourpy-1.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:1ec4dc6bf570f5b22ed0d7efba0dfa9c5b9e0431aeea7581aa217542d9e809a4"}, + {file = "contourpy-1.3.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:00ccd0dbaad6d804ab259820fa7cb0b8036bda0686ef844d24125d8287178ce0"}, + {file = "contourpy-1.3.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8ca947601224119117f7c19c9cdf6b3ab54c5726ef1d906aa4a69dfb6dd58102"}, + {file = "contourpy-1.3.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:c6ec93afeb848a0845a18989da3beca3eec2c0f852322efe21af1931147d12cb"}, + {file = "contourpy-1.3.0.tar.gz", hash = "sha256:7ffa0db17717a8ffb127efd0c95a4362d996b892c2904db72428d5b52e1938a4"}, ] [package.dependencies] -numpy = ">=1.20" +numpy = ">=1.23" [package.extras] bokeh = ["bokeh", "selenium"] docs = ["furo", "sphinx (>=7.2)", "sphinx-copybutton"] -mypy = ["contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.8.0)", "types-Pillow"] +mypy = ["contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.11.1)", "types-Pillow"] test = ["Pillow", "contourpy[test-no-images]", "matplotlib"] -test-no-images = ["pytest", "pytest-cov", "pytest-xdist", "wurlitzer"] +test-no-images = ["pytest", "pytest-cov", "pytest-rerunfailures", "pytest-xdist", "wurlitzer"] [[package]] name = "coverage" -version = "7.5.4" +version = "7.6.4" description = "Code coverage measurement for Python" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "coverage-7.5.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6cfb5a4f556bb51aba274588200a46e4dd6b505fb1a5f8c5ae408222eb416f99"}, - {file = "coverage-7.5.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2174e7c23e0a454ffe12267a10732c273243b4f2d50d07544a91198f05c48f47"}, - {file = "coverage-7.5.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2214ee920787d85db1b6a0bd9da5f8503ccc8fcd5814d90796c2f2493a2f4d2e"}, - {file = "coverage-7.5.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1137f46adb28e3813dec8c01fefadcb8c614f33576f672962e323b5128d9a68d"}, - {file = "coverage-7.5.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b385d49609f8e9efc885790a5a0e89f2e3ae042cdf12958b6034cc442de428d3"}, - {file = "coverage-7.5.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b4a474f799456e0eb46d78ab07303286a84a3140e9700b9e154cfebc8f527016"}, - {file = "coverage-7.5.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:5cd64adedf3be66f8ccee418473c2916492d53cbafbfcff851cbec5a8454b136"}, - {file = "coverage-7.5.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e564c2cf45d2f44a9da56f4e3a26b2236504a496eb4cb0ca7221cd4cc7a9aca9"}, - {file = "coverage-7.5.4-cp310-cp310-win32.whl", hash = "sha256:7076b4b3a5f6d2b5d7f1185fde25b1e54eb66e647a1dfef0e2c2bfaf9b4c88c8"}, - {file = "coverage-7.5.4-cp310-cp310-win_amd64.whl", hash = "sha256:018a12985185038a5b2bcafab04ab833a9a0f2c59995b3cec07e10074c78635f"}, - {file = "coverage-7.5.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:db14f552ac38f10758ad14dd7b983dbab424e731588d300c7db25b6f89e335b5"}, - {file = "coverage-7.5.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3257fdd8e574805f27bb5342b77bc65578e98cbc004a92232106344053f319ba"}, - {file = "coverage-7.5.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a6612c99081d8d6134005b1354191e103ec9705d7ba2754e848211ac8cacc6b"}, - {file = "coverage-7.5.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d45d3cbd94159c468b9b8c5a556e3f6b81a8d1af2a92b77320e887c3e7a5d080"}, - {file = "coverage-7.5.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed550e7442f278af76d9d65af48069f1fb84c9f745ae249c1a183c1e9d1b025c"}, - {file = "coverage-7.5.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7a892be37ca35eb5019ec85402c3371b0f7cda5ab5056023a7f13da0961e60da"}, - {file = "coverage-7.5.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8192794d120167e2a64721d88dbd688584675e86e15d0569599257566dec9bf0"}, - {file = "coverage-7.5.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:820bc841faa502e727a48311948e0461132a9c8baa42f6b2b84a29ced24cc078"}, - {file = "coverage-7.5.4-cp311-cp311-win32.whl", hash = "sha256:6aae5cce399a0f065da65c7bb1e8abd5c7a3043da9dceb429ebe1b289bc07806"}, - {file = "coverage-7.5.4-cp311-cp311-win_amd64.whl", hash = "sha256:d2e344d6adc8ef81c5a233d3a57b3c7d5181f40e79e05e1c143da143ccb6377d"}, - {file = "coverage-7.5.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:54317c2b806354cbb2dc7ac27e2b93f97096912cc16b18289c5d4e44fc663233"}, - {file = "coverage-7.5.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:042183de01f8b6d531e10c197f7f0315a61e8d805ab29c5f7b51a01d62782747"}, - {file = "coverage-7.5.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a6bb74ed465d5fb204b2ec41d79bcd28afccf817de721e8a807d5141c3426638"}, - {file = "coverage-7.5.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3d45ff86efb129c599a3b287ae2e44c1e281ae0f9a9bad0edc202179bcc3a2e"}, - {file = "coverage-7.5.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5013ed890dc917cef2c9f765c4c6a8ae9df983cd60dbb635df8ed9f4ebc9f555"}, - {file = "coverage-7.5.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1014fbf665fef86cdfd6cb5b7371496ce35e4d2a00cda501cf9f5b9e6fced69f"}, - {file = "coverage-7.5.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3684bc2ff328f935981847082ba4fdc950d58906a40eafa93510d1b54c08a66c"}, - {file = "coverage-7.5.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:581ea96f92bf71a5ec0974001f900db495488434a6928a2ca7f01eee20c23805"}, - {file = "coverage-7.5.4-cp312-cp312-win32.whl", hash = "sha256:73ca8fbc5bc622e54627314c1a6f1dfdd8db69788f3443e752c215f29fa87a0b"}, - {file = "coverage-7.5.4-cp312-cp312-win_amd64.whl", hash = "sha256:cef4649ec906ea7ea5e9e796e68b987f83fa9a718514fe147f538cfeda76d7a7"}, - {file = "coverage-7.5.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cdd31315fc20868c194130de9ee6bfd99755cc9565edff98ecc12585b90be882"}, - {file = "coverage-7.5.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:02ff6e898197cc1e9fa375581382b72498eb2e6d5fc0b53f03e496cfee3fac6d"}, - {file = "coverage-7.5.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d05c16cf4b4c2fc880cb12ba4c9b526e9e5d5bb1d81313d4d732a5b9fe2b9d53"}, - {file = "coverage-7.5.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c5986ee7ea0795a4095ac4d113cbb3448601efca7f158ec7f7087a6c705304e4"}, - {file = "coverage-7.5.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5df54843b88901fdc2f598ac06737f03d71168fd1175728054c8f5a2739ac3e4"}, - {file = "coverage-7.5.4-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:ab73b35e8d109bffbda9a3e91c64e29fe26e03e49addf5b43d85fc426dde11f9"}, - {file = "coverage-7.5.4-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:aea072a941b033813f5e4814541fc265a5c12ed9720daef11ca516aeacd3bd7f"}, - {file = "coverage-7.5.4-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:16852febd96acd953b0d55fc842ce2dac1710f26729b31c80b940b9afcd9896f"}, - {file = "coverage-7.5.4-cp38-cp38-win32.whl", hash = "sha256:8f894208794b164e6bd4bba61fc98bf6b06be4d390cf2daacfa6eca0a6d2bb4f"}, - {file = "coverage-7.5.4-cp38-cp38-win_amd64.whl", hash = "sha256:e2afe743289273209c992075a5a4913e8d007d569a406ffed0bd080ea02b0633"}, - {file = "coverage-7.5.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b95c3a8cb0463ba9f77383d0fa8c9194cf91f64445a63fc26fb2327e1e1eb088"}, - {file = "coverage-7.5.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3d7564cc09dd91b5a6001754a5b3c6ecc4aba6323baf33a12bd751036c998be4"}, - {file = "coverage-7.5.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:44da56a2589b684813f86d07597fdf8a9c6ce77f58976727329272f5a01f99f7"}, - {file = "coverage-7.5.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e16f3d6b491c48c5ae726308e6ab1e18ee830b4cdd6913f2d7f77354b33f91c8"}, - {file = "coverage-7.5.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dbc5958cb471e5a5af41b0ddaea96a37e74ed289535e8deca404811f6cb0bc3d"}, - {file = "coverage-7.5.4-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:a04e990a2a41740b02d6182b498ee9796cf60eefe40cf859b016650147908029"}, - {file = "coverage-7.5.4-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:ddbd2f9713a79e8e7242d7c51f1929611e991d855f414ca9996c20e44a895f7c"}, - {file = "coverage-7.5.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:b1ccf5e728ccf83acd313c89f07c22d70d6c375a9c6f339233dcf792094bcbf7"}, - {file = "coverage-7.5.4-cp39-cp39-win32.whl", hash = "sha256:56b4eafa21c6c175b3ede004ca12c653a88b6f922494b023aeb1e836df953ace"}, - {file = "coverage-7.5.4-cp39-cp39-win_amd64.whl", hash = "sha256:65e528e2e921ba8fd67d9055e6b9f9e34b21ebd6768ae1c1723f4ea6ace1234d"}, - {file = "coverage-7.5.4-pp38.pp39.pp310-none-any.whl", hash = "sha256:79b356f3dd5b26f3ad23b35c75dbdaf1f9e2450b6bcefc6d0825ea0aa3f86ca5"}, - {file = "coverage-7.5.4.tar.gz", hash = "sha256:a44963520b069e12789d0faea4e9fdb1e410cdc4aab89d94f7f55cbb7fef0353"}, + {file = "coverage-7.6.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5f8ae553cba74085db385d489c7a792ad66f7f9ba2ee85bfa508aeb84cf0ba07"}, + {file = "coverage-7.6.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8165b796df0bd42e10527a3f493c592ba494f16ef3c8b531288e3d0d72c1f6f0"}, + {file = "coverage-7.6.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7c8b95bf47db6d19096a5e052ffca0a05f335bc63cef281a6e8fe864d450a72"}, + {file = "coverage-7.6.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ed9281d1b52628e81393f5eaee24a45cbd64965f41857559c2b7ff19385df51"}, + {file = "coverage-7.6.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0809082ee480bb8f7416507538243c8863ac74fd8a5d2485c46f0f7499f2b491"}, + {file = "coverage-7.6.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d541423cdd416b78626b55f123412fcf979d22a2c39fce251b350de38c15c15b"}, + {file = "coverage-7.6.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:58809e238a8a12a625c70450b48e8767cff9eb67c62e6154a642b21ddf79baea"}, + {file = "coverage-7.6.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c9b8e184898ed014884ca84c70562b4a82cbc63b044d366fedc68bc2b2f3394a"}, + {file = "coverage-7.6.4-cp310-cp310-win32.whl", hash = "sha256:6bd818b7ea14bc6e1f06e241e8234508b21edf1b242d49831831a9450e2f35fa"}, + {file = "coverage-7.6.4-cp310-cp310-win_amd64.whl", hash = "sha256:06babbb8f4e74b063dbaeb74ad68dfce9186c595a15f11f5d5683f748fa1d172"}, + {file = "coverage-7.6.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:73d2b73584446e66ee633eaad1a56aad577c077f46c35ca3283cd687b7715b0b"}, + {file = "coverage-7.6.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:51b44306032045b383a7a8a2c13878de375117946d68dcb54308111f39775a25"}, + {file = "coverage-7.6.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b3fb02fe73bed561fa12d279a417b432e5b50fe03e8d663d61b3d5990f29546"}, + {file = "coverage-7.6.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ed8fe9189d2beb6edc14d3ad19800626e1d9f2d975e436f84e19efb7fa19469b"}, + {file = "coverage-7.6.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b369ead6527d025a0fe7bd3864e46dbee3aa8f652d48df6174f8d0bac9e26e0e"}, + {file = "coverage-7.6.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ade3ca1e5f0ff46b678b66201f7ff477e8fa11fb537f3b55c3f0568fbfe6e718"}, + {file = "coverage-7.6.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:27fb4a050aaf18772db513091c9c13f6cb94ed40eacdef8dad8411d92d9992db"}, + {file = "coverage-7.6.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4f704f0998911abf728a7783799444fcbbe8261c4a6c166f667937ae6a8aa522"}, + {file = "coverage-7.6.4-cp311-cp311-win32.whl", hash = "sha256:29155cd511ee058e260db648b6182c419422a0d2e9a4fa44501898cf918866cf"}, + {file = "coverage-7.6.4-cp311-cp311-win_amd64.whl", hash = "sha256:8902dd6a30173d4ef09954bfcb24b5d7b5190cf14a43170e386979651e09ba19"}, + {file = "coverage-7.6.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:12394842a3a8affa3ba62b0d4ab7e9e210c5e366fbac3e8b2a68636fb19892c2"}, + {file = "coverage-7.6.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2b6b4c83d8e8ea79f27ab80778c19bc037759aea298da4b56621f4474ffeb117"}, + {file = "coverage-7.6.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d5b8007f81b88696d06f7df0cb9af0d3b835fe0c8dbf489bad70b45f0e45613"}, + {file = "coverage-7.6.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b57b768feb866f44eeed9f46975f3d6406380275c5ddfe22f531a2bf187eda27"}, + {file = "coverage-7.6.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5915fcdec0e54ee229926868e9b08586376cae1f5faa9bbaf8faf3561b393d52"}, + {file = "coverage-7.6.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0b58c672d14f16ed92a48db984612f5ce3836ae7d72cdd161001cc54512571f2"}, + {file = "coverage-7.6.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:2fdef0d83a2d08d69b1f2210a93c416d54e14d9eb398f6ab2f0a209433db19e1"}, + {file = "coverage-7.6.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8cf717ee42012be8c0cb205dbbf18ffa9003c4cbf4ad078db47b95e10748eec5"}, + {file = "coverage-7.6.4-cp312-cp312-win32.whl", hash = "sha256:7bb92c539a624cf86296dd0c68cd5cc286c9eef2d0c3b8b192b604ce9de20a17"}, + {file = "coverage-7.6.4-cp312-cp312-win_amd64.whl", hash = "sha256:1032e178b76a4e2b5b32e19d0fd0abbce4b58e77a1ca695820d10e491fa32b08"}, + {file = "coverage-7.6.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:023bf8ee3ec6d35af9c1c6ccc1d18fa69afa1cb29eaac57cb064dbb262a517f9"}, + {file = "coverage-7.6.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b0ac3d42cb51c4b12df9c5f0dd2f13a4f24f01943627120ec4d293c9181219ba"}, + {file = "coverage-7.6.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8fe4984b431f8621ca53d9380901f62bfb54ff759a1348cd140490ada7b693c"}, + {file = "coverage-7.6.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5fbd612f8a091954a0c8dd4c0b571b973487277d26476f8480bfa4b2a65b5d06"}, + {file = "coverage-7.6.4-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dacbc52de979f2823a819571f2e3a350a7e36b8cb7484cdb1e289bceaf35305f"}, + {file = "coverage-7.6.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:dab4d16dfef34b185032580e2f2f89253d302facba093d5fa9dbe04f569c4f4b"}, + {file = "coverage-7.6.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:862264b12ebb65ad8d863d51f17758b1684560b66ab02770d4f0baf2ff75da21"}, + {file = "coverage-7.6.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5beb1ee382ad32afe424097de57134175fea3faf847b9af002cc7895be4e2a5a"}, + {file = "coverage-7.6.4-cp313-cp313-win32.whl", hash = "sha256:bf20494da9653f6410213424f5f8ad0ed885e01f7e8e59811f572bdb20b8972e"}, + {file = "coverage-7.6.4-cp313-cp313-win_amd64.whl", hash = "sha256:182e6cd5c040cec0a1c8d415a87b67ed01193ed9ad458ee427741c7d8513d963"}, + {file = "coverage-7.6.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:a181e99301a0ae128493a24cfe5cfb5b488c4e0bf2f8702091473d033494d04f"}, + {file = "coverage-7.6.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:df57bdbeffe694e7842092c5e2e0bc80fff7f43379d465f932ef36f027179806"}, + {file = "coverage-7.6.4-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0bcd1069e710600e8e4cf27f65c90c7843fa8edfb4520fb0ccb88894cad08b11"}, + {file = "coverage-7.6.4-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:99b41d18e6b2a48ba949418db48159d7a2e81c5cc290fc934b7d2380515bd0e3"}, + {file = "coverage-7.6.4-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a6b1e54712ba3474f34b7ef7a41e65bd9037ad47916ccb1cc78769bae324c01a"}, + {file = "coverage-7.6.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:53d202fd109416ce011578f321460795abfe10bb901b883cafd9b3ef851bacfc"}, + {file = "coverage-7.6.4-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:c48167910a8f644671de9f2083a23630fbf7a1cb70ce939440cd3328e0919f70"}, + {file = "coverage-7.6.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:cc8ff50b50ce532de2fa7a7daae9dd12f0a699bfcd47f20945364e5c31799fef"}, + {file = "coverage-7.6.4-cp313-cp313t-win32.whl", hash = "sha256:b8d3a03d9bfcaf5b0141d07a88456bb6a4c3ce55c080712fec8418ef3610230e"}, + {file = "coverage-7.6.4-cp313-cp313t-win_amd64.whl", hash = "sha256:f3ddf056d3ebcf6ce47bdaf56142af51bb7fad09e4af310241e9db7a3a8022e1"}, + {file = "coverage-7.6.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9cb7fa111d21a6b55cbf633039f7bc2749e74932e3aa7cb7333f675a58a58bf3"}, + {file = "coverage-7.6.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:11a223a14e91a4693d2d0755c7a043db43d96a7450b4f356d506c2562c48642c"}, + {file = "coverage-7.6.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a413a096c4cbac202433c850ee43fa326d2e871b24554da8327b01632673a076"}, + {file = "coverage-7.6.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:00a1d69c112ff5149cabe60d2e2ee948752c975d95f1e1096742e6077affd376"}, + {file = "coverage-7.6.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f76846299ba5c54d12c91d776d9605ae33f8ae2b9d1d3c3703cf2db1a67f2c0"}, + {file = "coverage-7.6.4-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:fe439416eb6380de434886b00c859304338f8b19f6f54811984f3420a2e03858"}, + {file = "coverage-7.6.4-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:0294ca37f1ba500667b1aef631e48d875ced93ad5e06fa665a3295bdd1d95111"}, + {file = "coverage-7.6.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:6f01ba56b1c0e9d149f9ac85a2f999724895229eb36bd997b61e62999e9b0901"}, + {file = "coverage-7.6.4-cp39-cp39-win32.whl", hash = "sha256:bc66f0bf1d7730a17430a50163bb264ba9ded56739112368ba985ddaa9c3bd09"}, + {file = "coverage-7.6.4-cp39-cp39-win_amd64.whl", hash = "sha256:c481b47f6b5845064c65a7bc78bc0860e635a9b055af0df46fdf1c58cebf8e8f"}, + {file = "coverage-7.6.4-pp39.pp310-none-any.whl", hash = "sha256:3c65d37f3a9ebb703e710befdc489a38683a5b152242664b973a7b7b22348a4e"}, + {file = "coverage-7.6.4.tar.gz", hash = "sha256:29fc0f17b1d3fea332f8001d4558f8214af7f1d87a345f3a133c901d60347c73"}, ] [package.dependencies] @@ -795,49 +894,68 @@ toml = ["tomli"] [[package]] name = "cryptography" -version = "41.0.7" +version = "43.0.3" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." optional = false python-versions = ">=3.7" files = [ - {file = "cryptography-41.0.7-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:3c78451b78313fa81607fa1b3f1ae0a5ddd8014c38a02d9db0616133987b9cdf"}, - {file = "cryptography-41.0.7-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:928258ba5d6f8ae644e764d0f996d61a8777559f72dfeb2eea7e2fe0ad6e782d"}, - {file = "cryptography-41.0.7-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5a1b41bc97f1ad230a41657d9155113c7521953869ae57ac39ac7f1bb471469a"}, - {file = "cryptography-41.0.7-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:841df4caa01008bad253bce2a6f7b47f86dc9f08df4b433c404def869f590a15"}, - {file = "cryptography-41.0.7-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:5429ec739a29df2e29e15d082f1d9ad683701f0ec7709ca479b3ff2708dae65a"}, - {file = "cryptography-41.0.7-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:43f2552a2378b44869fe8827aa19e69512e3245a219104438692385b0ee119d1"}, - {file = "cryptography-41.0.7-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:af03b32695b24d85a75d40e1ba39ffe7db7ffcb099fe507b39fd41a565f1b157"}, - {file = "cryptography-41.0.7-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:49f0805fc0b2ac8d4882dd52f4a3b935b210935d500b6b805f321addc8177406"}, - {file = "cryptography-41.0.7-cp37-abi3-win32.whl", hash = "sha256:f983596065a18a2183e7f79ab3fd4c475205b839e02cbc0efbbf9666c4b3083d"}, - {file = "cryptography-41.0.7-cp37-abi3-win_amd64.whl", hash = "sha256:90452ba79b8788fa380dfb587cca692976ef4e757b194b093d845e8d99f612f2"}, - {file = "cryptography-41.0.7-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:079b85658ea2f59c4f43b70f8119a52414cdb7be34da5d019a77bf96d473b960"}, - {file = "cryptography-41.0.7-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:b640981bf64a3e978a56167594a0e97db71c89a479da8e175d8bb5be5178c003"}, - {file = "cryptography-41.0.7-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e3114da6d7f95d2dee7d3f4eec16dacff819740bbab931aff8648cb13c5ff5e7"}, - {file = "cryptography-41.0.7-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d5ec85080cce7b0513cfd233914eb8b7bbd0633f1d1703aa28d1dd5a72f678ec"}, - {file = "cryptography-41.0.7-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:7a698cb1dac82c35fcf8fe3417a3aaba97de16a01ac914b89a0889d364d2f6be"}, - {file = "cryptography-41.0.7-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:37a138589b12069efb424220bf78eac59ca68b95696fc622b6ccc1c0a197204a"}, - {file = "cryptography-41.0.7-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:68a2dec79deebc5d26d617bfdf6e8aab065a4f34934b22d3b5010df3ba36612c"}, - {file = "cryptography-41.0.7-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:09616eeaef406f99046553b8a40fbf8b1e70795a91885ba4c96a70793de5504a"}, - {file = "cryptography-41.0.7-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:48a0476626da912a44cc078f9893f292f0b3e4c739caf289268168d8f4702a39"}, - {file = "cryptography-41.0.7-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c7f3201ec47d5207841402594f1d7950879ef890c0c495052fa62f58283fde1a"}, - {file = "cryptography-41.0.7-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c5ca78485a255e03c32b513f8c2bc39fedb7f5c5f8535545bdc223a03b24f248"}, - {file = "cryptography-41.0.7-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:d6c391c021ab1f7a82da5d8d0b3cee2f4b2c455ec86c8aebbc84837a631ff309"}, - {file = "cryptography-41.0.7.tar.gz", hash = "sha256:13f93ce9bea8016c253b34afc6bd6a75993e5c40672ed5405a9c832f0d4a00bc"}, + {file = "cryptography-43.0.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:bf7a1932ac4176486eab36a19ed4c0492da5d97123f1406cf15e41b05e787d2e"}, + {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63efa177ff54aec6e1c0aefaa1a241232dcd37413835a9b674b6e3f0ae2bfd3e"}, + {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e1ce50266f4f70bf41a2c6dc4358afadae90e2a1e5342d3c08883df1675374f"}, + {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:443c4a81bb10daed9a8f334365fe52542771f25aedaf889fd323a853ce7377d6"}, + {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:74f57f24754fe349223792466a709f8e0c093205ff0dca557af51072ff47ab18"}, + {file = "cryptography-43.0.3-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9762ea51a8fc2a88b70cf2995e5675b38d93bf36bd67d91721c309df184f49bd"}, + {file = "cryptography-43.0.3-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:81ef806b1fef6b06dcebad789f988d3b37ccaee225695cf3e07648eee0fc6b73"}, + {file = "cryptography-43.0.3-cp37-abi3-win32.whl", hash = "sha256:cbeb489927bd7af4aa98d4b261af9a5bc025bd87f0e3547e11584be9e9427be2"}, + {file = "cryptography-43.0.3-cp37-abi3-win_amd64.whl", hash = "sha256:f46304d6f0c6ab8e52770addfa2fc41e6629495548862279641972b6215451cd"}, + {file = "cryptography-43.0.3-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:8ac43ae87929a5982f5948ceda07001ee5e83227fd69cf55b109144938d96984"}, + {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:846da004a5804145a5f441b8530b4bf35afbf7da70f82409f151695b127213d5"}, + {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f996e7268af62598f2fc1204afa98a3b5712313a55c4c9d434aef49cadc91d4"}, + {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:f7b178f11ed3664fd0e995a47ed2b5ff0a12d893e41dd0494f406d1cf555cab7"}, + {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:c2e6fc39c4ab499049df3bdf567f768a723a5e8464816e8f009f121a5a9f4405"}, + {file = "cryptography-43.0.3-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:e1be4655c7ef6e1bbe6b5d0403526601323420bcf414598955968c9ef3eb7d16"}, + {file = "cryptography-43.0.3-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:df6b6c6d742395dd77a23ea3728ab62f98379eff8fb61be2744d4679ab678f73"}, + {file = "cryptography-43.0.3-cp39-abi3-win32.whl", hash = "sha256:d56e96520b1020449bbace2b78b603442e7e378a9b3bd68de65c782db1507995"}, + {file = "cryptography-43.0.3-cp39-abi3-win_amd64.whl", hash = "sha256:0c580952eef9bf68c4747774cde7ec1d85a6e61de97281f2dba83c7d2c806362"}, + {file = "cryptography-43.0.3-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d03b5621a135bffecad2c73e9f4deb1a0f977b9a8ffe6f8e002bf6c9d07b918c"}, + {file = "cryptography-43.0.3-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:a2a431ee15799d6db9fe80c82b055bae5a752bef645bba795e8e52687c69efe3"}, + {file = "cryptography-43.0.3-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:281c945d0e28c92ca5e5930664c1cefd85efe80e5c0d2bc58dd63383fda29f83"}, + {file = "cryptography-43.0.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:f18c716be16bc1fea8e95def49edf46b82fccaa88587a45f8dc0ff6ab5d8e0a7"}, + {file = "cryptography-43.0.3-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:4a02ded6cd4f0a5562a8887df8b3bd14e822a90f97ac5e544c162899bc467664"}, + {file = "cryptography-43.0.3-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:53a583b6637ab4c4e3591a15bc9db855b8d9dee9a669b550f311480acab6eb08"}, + {file = "cryptography-43.0.3-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:1ec0bcf7e17c0c5669d881b1cd38c4972fade441b27bda1051665faaa89bdcaa"}, + {file = "cryptography-43.0.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2ce6fae5bdad59577b44e4dfed356944fbf1d925269114c28be377692643b4ff"}, + {file = "cryptography-43.0.3.tar.gz", hash = "sha256:315b9001266a492a6ff443b61238f956b214dbec9910a081ba5b6646a055a805"}, ] [package.dependencies] -cffi = ">=1.12" +cffi = {version = ">=1.12", markers = "platform_python_implementation != \"PyPy\""} [package.extras] docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.1.1)"] -docstest = ["pyenchant (>=1.6.11)", "sphinxcontrib-spelling (>=4.0.1)", "twine (>=1.12.0)"] +docstest = ["pyenchant (>=1.6.11)", "readme-renderer", "sphinxcontrib-spelling (>=4.0.1)"] nox = ["nox"] -pep8test = ["black", "check-sdist", "mypy", "ruff"] +pep8test = ["check-sdist", "click", "mypy", "ruff"] sdist = ["build"] ssh = ["bcrypt (>=3.1.5)"] -test = ["pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] +test = ["certifi", "cryptography-vectors (==43.0.3)", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] test-randomorder = ["pytest-randomly"] +[[package]] +name = "cycler" +version = "0.12.1" +description = "Composable style cycles" +optional = false +python-versions = ">=3.8" +files = [ + {file = "cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30"}, + {file = "cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c"}, +] + +[package.extras] +docs = ["ipython", "matplotlib", "numpydoc", "sphinx"] +tests = ["pytest", "pytest-cov", "pytest-xdist"] + [[package]] name = "darglint" version = "1.8.1" @@ -851,13 +969,13 @@ files = [ [[package]] name = "db-dtypes" -version = "1.2.0" +version = "1.3.0" description = "Pandas Data Types for SQL systems (BigQuery, Spanner)" optional = false python-versions = ">=3.7" files = [ - {file = "db-dtypes-1.2.0.tar.gz", hash = "sha256:3531bb1fb8b5fbab33121fe243ccc2ade16ab2524f4c113b05cc702a1908e6ea"}, - {file = "db_dtypes-1.2.0-py2.py3-none-any.whl", hash = "sha256:6320bddd31d096447ef749224d64aab00972ed20e4392d86f7d8b81ad79f7ff0"}, + {file = "db_dtypes-1.3.0-py2.py3-none-any.whl", hash = "sha256:7e65c59f849ccbe6f7bc4d0253edcc212a7907662906921caba3e4aadd0bc277"}, + {file = "db_dtypes-1.3.0.tar.gz", hash = "sha256:7bcbc8858b07474dc85b77bb2f3ae488978d1336f5ea73b58c39d9118bc3e91b"}, ] [package.dependencies] @@ -868,44 +986,48 @@ pyarrow = ">=3.0.0" [[package]] name = "dbldatagen" -version = "0.4.0" +version = "0.4.0.post1" description = "Databricks Labs - PySpark Synthetic Data Generator" optional = false python-versions = ">=3.8.10" files = [ - {file = "dbldatagen-0.4.0-py3-none-any.whl", hash = "sha256:e60b0089b0600239d8f291b2b4dc76aafd57708da2eeb58f1a28c5ab13fdced0"}, - {file = "dbldatagen-0.4.0.tar.gz", hash = "sha256:0003ed8d85399a995e178ffea17600f23720ddeb7374ea00afb8a13941859c51"}, + {file = "dbldatagen-0.4.0.post1-py3-none-any.whl", hash = "sha256:b94b5fcf2bf5113fe789f5cdf92b50eb62b5e6c25fc867b634d6543cc1e79d40"}, + {file = "dbldatagen-0.4.0.post1.tar.gz", hash = "sha256:a254fba2a6384c75e2dfb38b1e8cdc1c52b417c59fd6ec977e11175ad7567f34"}, ] [[package]] name = "debugpy" -version = "1.8.1" +version = "1.8.7" description = "An implementation of the Debug Adapter Protocol for Python" optional = false python-versions = ">=3.8" files = [ - {file = "debugpy-1.8.1-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:3bda0f1e943d386cc7a0e71bfa59f4137909e2ed947fb3946c506e113000f741"}, - {file = "debugpy-1.8.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dda73bf69ea479c8577a0448f8c707691152e6c4de7f0c4dec5a4bc11dee516e"}, - {file = "debugpy-1.8.1-cp310-cp310-win32.whl", hash = "sha256:3a79c6f62adef994b2dbe9fc2cc9cc3864a23575b6e387339ab739873bea53d0"}, - {file = "debugpy-1.8.1-cp310-cp310-win_amd64.whl", hash = "sha256:7eb7bd2b56ea3bedb009616d9e2f64aab8fc7000d481faec3cd26c98a964bcdd"}, - {file = "debugpy-1.8.1-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:016a9fcfc2c6b57f939673c874310d8581d51a0fe0858e7fac4e240c5eb743cb"}, - {file = "debugpy-1.8.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd97ed11a4c7f6d042d320ce03d83b20c3fb40da892f994bc041bbc415d7a099"}, - {file = "debugpy-1.8.1-cp311-cp311-win32.whl", hash = "sha256:0de56aba8249c28a300bdb0672a9b94785074eb82eb672db66c8144fff673146"}, - {file = "debugpy-1.8.1-cp311-cp311-win_amd64.whl", hash = "sha256:1a9fe0829c2b854757b4fd0a338d93bc17249a3bf69ecf765c61d4c522bb92a8"}, - {file = "debugpy-1.8.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:3ebb70ba1a6524d19fa7bb122f44b74170c447d5746a503e36adc244a20ac539"}, - {file = "debugpy-1.8.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a2e658a9630f27534e63922ebf655a6ab60c370f4d2fc5c02a5b19baf4410ace"}, - {file = "debugpy-1.8.1-cp312-cp312-win32.whl", hash = "sha256:caad2846e21188797a1f17fc09c31b84c7c3c23baf2516fed5b40b378515bbf0"}, - {file = "debugpy-1.8.1-cp312-cp312-win_amd64.whl", hash = "sha256:edcc9f58ec0fd121a25bc950d4578df47428d72e1a0d66c07403b04eb93bcf98"}, - {file = "debugpy-1.8.1-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:7a3afa222f6fd3d9dfecd52729bc2e12c93e22a7491405a0ecbf9e1d32d45b39"}, - {file = "debugpy-1.8.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d915a18f0597ef685e88bb35e5d7ab968964b7befefe1aaea1eb5b2640b586c7"}, - {file = "debugpy-1.8.1-cp38-cp38-win32.whl", hash = "sha256:92116039b5500633cc8d44ecc187abe2dfa9b90f7a82bbf81d079fcdd506bae9"}, - {file = "debugpy-1.8.1-cp38-cp38-win_amd64.whl", hash = "sha256:e38beb7992b5afd9d5244e96ad5fa9135e94993b0c551ceebf3fe1a5d9beb234"}, - {file = "debugpy-1.8.1-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:bfb20cb57486c8e4793d41996652e5a6a885b4d9175dd369045dad59eaacea42"}, - {file = "debugpy-1.8.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:efd3fdd3f67a7e576dd869c184c5dd71d9aaa36ded271939da352880c012e703"}, - {file = "debugpy-1.8.1-cp39-cp39-win32.whl", hash = "sha256:58911e8521ca0c785ac7a0539f1e77e0ce2df753f786188f382229278b4cdf23"}, - {file = "debugpy-1.8.1-cp39-cp39-win_amd64.whl", hash = "sha256:6df9aa9599eb05ca179fb0b810282255202a66835c6efb1d112d21ecb830ddd3"}, - {file = "debugpy-1.8.1-py2.py3-none-any.whl", hash = "sha256:28acbe2241222b87e255260c76741e1fbf04fdc3b6d094fcf57b6c6f75ce1242"}, - {file = "debugpy-1.8.1.zip", hash = "sha256:f696d6be15be87aef621917585f9bb94b1dc9e8aced570db1b8a6fc14e8f9b42"}, + {file = "debugpy-1.8.7-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:95fe04a573b8b22896c404365e03f4eda0ce0ba135b7667a1e57bd079793b96b"}, + {file = "debugpy-1.8.7-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:628a11f4b295ffb4141d8242a9bb52b77ad4a63a2ad19217a93be0f77f2c28c9"}, + {file = "debugpy-1.8.7-cp310-cp310-win32.whl", hash = "sha256:85ce9c1d0eebf622f86cc68618ad64bf66c4fc3197d88f74bb695a416837dd55"}, + {file = "debugpy-1.8.7-cp310-cp310-win_amd64.whl", hash = "sha256:29e1571c276d643757ea126d014abda081eb5ea4c851628b33de0c2b6245b037"}, + {file = "debugpy-1.8.7-cp311-cp311-macosx_14_0_universal2.whl", hash = "sha256:caf528ff9e7308b74a1749c183d6808ffbedbb9fb6af78b033c28974d9b8831f"}, + {file = "debugpy-1.8.7-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cba1d078cf2e1e0b8402e6bda528bf8fda7ccd158c3dba6c012b7897747c41a0"}, + {file = "debugpy-1.8.7-cp311-cp311-win32.whl", hash = "sha256:171899588bcd412151e593bd40d9907133a7622cd6ecdbdb75f89d1551df13c2"}, + {file = "debugpy-1.8.7-cp311-cp311-win_amd64.whl", hash = "sha256:6e1c4ffb0c79f66e89dfd97944f335880f0d50ad29525dc792785384923e2211"}, + {file = "debugpy-1.8.7-cp312-cp312-macosx_14_0_universal2.whl", hash = "sha256:4d27d842311353ede0ad572600c62e4bcd74f458ee01ab0dd3a1a4457e7e3706"}, + {file = "debugpy-1.8.7-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:703c1fd62ae0356e194f3e7b7a92acd931f71fe81c4b3be2c17a7b8a4b546ec2"}, + {file = "debugpy-1.8.7-cp312-cp312-win32.whl", hash = "sha256:2f729228430ef191c1e4df72a75ac94e9bf77413ce5f3f900018712c9da0aaca"}, + {file = "debugpy-1.8.7-cp312-cp312-win_amd64.whl", hash = "sha256:45c30aaefb3e1975e8a0258f5bbd26cd40cde9bfe71e9e5a7ac82e79bad64e39"}, + {file = "debugpy-1.8.7-cp313-cp313-macosx_14_0_universal2.whl", hash = "sha256:d050a1ec7e925f514f0f6594a1e522580317da31fbda1af71d1530d6ea1f2b40"}, + {file = "debugpy-1.8.7-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2f4349a28e3228a42958f8ddaa6333d6f8282d5edaea456070e48609c5983b7"}, + {file = "debugpy-1.8.7-cp313-cp313-win32.whl", hash = "sha256:11ad72eb9ddb436afb8337891a986302e14944f0f755fd94e90d0d71e9100bba"}, + {file = "debugpy-1.8.7-cp313-cp313-win_amd64.whl", hash = "sha256:2efb84d6789352d7950b03d7f866e6d180284bc02c7e12cb37b489b7083d81aa"}, + {file = "debugpy-1.8.7-cp38-cp38-macosx_14_0_x86_64.whl", hash = "sha256:4b908291a1d051ef3331484de8e959ef3e66f12b5e610c203b5b75d2725613a7"}, + {file = "debugpy-1.8.7-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da8df5b89a41f1fd31503b179d0a84a5fdb752dddd5b5388dbd1ae23cda31ce9"}, + {file = "debugpy-1.8.7-cp38-cp38-win32.whl", hash = "sha256:b12515e04720e9e5c2216cc7086d0edadf25d7ab7e3564ec8b4521cf111b4f8c"}, + {file = "debugpy-1.8.7-cp38-cp38-win_amd64.whl", hash = "sha256:93176e7672551cb5281577cdb62c63aadc87ec036f0c6a486f0ded337c504596"}, + {file = "debugpy-1.8.7-cp39-cp39-macosx_14_0_x86_64.whl", hash = "sha256:90d93e4f2db442f8222dec5ec55ccfc8005821028982f1968ebf551d32b28907"}, + {file = "debugpy-1.8.7-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b6db2a370e2700557a976eaadb16243ec9c91bd46f1b3bb15376d7aaa7632c81"}, + {file = "debugpy-1.8.7-cp39-cp39-win32.whl", hash = "sha256:a6cf2510740e0c0b4a40330640e4b454f928c7b99b0c9dbf48b11efba08a8cda"}, + {file = "debugpy-1.8.7-cp39-cp39-win_amd64.whl", hash = "sha256:6a9d9d6d31846d8e34f52987ee0f1a904c7baa4912bf4843ab39dadf9b8f3e0d"}, + {file = "debugpy-1.8.7-py2.py3-none-any.whl", hash = "sha256:57b00de1c8d2c84a61b90880f7e5b6deaf4c312ecbde3a0e8912f2a56c4ac9ae"}, + {file = "debugpy-1.8.7.zip", hash = "sha256:18b8f731ed3e2e1df8e9cdaa23fb1fc9c24e570cd0081625308ec51c82efe42e"}, ] [[package]] @@ -964,13 +1086,13 @@ tomli = {version = ">=2.0.1", markers = "python_version < \"3.11\""} [[package]] name = "dill" -version = "0.3.8" +version = "0.3.9" description = "serialize all of Python" optional = false python-versions = ">=3.8" files = [ - {file = "dill-0.3.8-py3-none-any.whl", hash = "sha256:c36ca9ffb54365bdd2f8eb3eff7d2a21237f8452b57ace88b1ac615b7e815bd7"}, - {file = "dill-0.3.8.tar.gz", hash = "sha256:3ebe3c479ad625c4553aca177444d89b486b1d84982eeacded644afc0cf797ca"}, + {file = "dill-0.3.9-py3-none-any.whl", hash = "sha256:468dff3b89520b474c0397703366b7b95eebe6303f108adf9b19da1f702be87a"}, + {file = "dill-0.3.9.tar.gz", hash = "sha256:81aa267dddf68cbfe8029c42ca9ec6a4ab3b22371d1c450abc54422577b4512c"}, ] [package.extras] @@ -979,13 +1101,13 @@ profile = ["gprof2dot (>=2022.7.29)"] [[package]] name = "distlib" -version = "0.3.8" +version = "0.3.9" description = "Distribution utilities" optional = false python-versions = "*" files = [ - {file = "distlib-0.3.8-py2.py3-none-any.whl", hash = "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784"}, - {file = "distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64"}, + {file = "distlib-0.3.9-py2.py3-none-any.whl", hash = "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87"}, + {file = "distlib-0.3.9.tar.gz", hash = "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403"}, ] [[package]] @@ -1004,24 +1126,24 @@ six = ">=1.4.0" [[package]] name = "docstring-parser-fork" -version = "0.0.8" +version = "0.0.9" description = "Parse Python docstrings in reST, Google and Numpydoc format" optional = false python-versions = "<4.0,>=3.7" files = [ - {file = "docstring_parser_fork-0.0.8-py3-none-any.whl", hash = "sha256:88098ae01b0909b241954ad2c50c0c29ec2292223366a540bfd68332be8fd595"}, - {file = "docstring_parser_fork-0.0.8.tar.gz", hash = "sha256:59d3b00d42ba9f4e229a7df7e1f6fc742845f88a1190973cc33ba336a5405425"}, + {file = "docstring_parser_fork-0.0.9-py3-none-any.whl", hash = "sha256:0be85ad00cb25bf5beeb673e46e777facf0f47552fa3a7570d120ef7e3374401"}, + {file = "docstring_parser_fork-0.0.9.tar.gz", hash = "sha256:95b23cc5092af85080c716a6da68360f5ae4fcffa75f4a3aca5e539783cbcc3d"}, ] [[package]] name = "exceptiongroup" -version = "1.2.1" +version = "1.2.2" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" files = [ - {file = "exceptiongroup-1.2.1-py3-none-any.whl", hash = "sha256:5258b9ed329c5bbdd31a309f53cbfb0b155341807f6ff7606a1e801a891b29ad"}, - {file = "exceptiongroup-1.2.1.tar.gz", hash = "sha256:a4785e48b045528f5bfe627b6ad554ff32def154f42372786903b7abcfe1aa16"}, + {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"}, + {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"}, ] [package.extras] @@ -1043,13 +1165,13 @@ testing = ["hatch", "pre-commit", "pytest", "tox"] [[package]] name = "executing" -version = "2.0.1" +version = "2.1.0" description = "Get the currently executing AST node of a frame, and other information" optional = false -python-versions = ">=3.5" +python-versions = ">=3.8" files = [ - {file = "executing-2.0.1-py2.py3-none-any.whl", hash = "sha256:eac49ca94516ccc753f9fb5ce82603156e590b27525a8bc32cce8ae302eb61bc"}, - {file = "executing-2.0.1.tar.gz", hash = "sha256:35afe2ce3affba8ee97f2d69927fa823b08b472b7b994e36a52a964b93d16147"}, + {file = "executing-2.1.0-py2.py3-none-any.whl", hash = "sha256:8d63781349375b5ebccc3142f4b30350c0cd9c79f921cde38be2be4637e98eaf"}, + {file = "executing-2.1.0.tar.gz", hash = "sha256:8ea27ddd260da8150fa5a708269c4a10e76161e2496ec3e587da9e3c0fe4b9ab"}, ] [package.extras] @@ -1057,29 +1179,29 @@ tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipyth [[package]] name = "filelock" -version = "3.15.4" +version = "3.16.1" description = "A platform independent file lock." optional = false python-versions = ">=3.8" files = [ - {file = "filelock-3.15.4-py3-none-any.whl", hash = "sha256:6ca1fffae96225dab4c6eaf1c4f4f28cd2568d3ec2a44e15a08520504de468e7"}, - {file = "filelock-3.15.4.tar.gz", hash = "sha256:2207938cbc1844345cb01a5a95524dae30f0ce089eba5b00378295a17e3e90cb"}, + {file = "filelock-3.16.1-py3-none-any.whl", hash = "sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0"}, + {file = "filelock-3.16.1.tar.gz", hash = "sha256:c249fbfcd5db47e5e2d6d62198e565475ee65e4831e2561c8e313fa7eb961435"}, ] [package.extras] -docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8.0.1)", "pytest (>=7.4.3)", "pytest-asyncio (>=0.21)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)", "virtualenv (>=20.26.2)"] -typing = ["typing-extensions (>=4.8)"] +docs = ["furo (>=2024.8.6)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4.1)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.6.1)", "diff-cover (>=9.2)", "pytest (>=8.3.3)", "pytest-asyncio (>=0.24)", "pytest-cov (>=5)", "pytest-mock (>=3.14)", "pytest-timeout (>=2.3.1)", "virtualenv (>=20.26.4)"] +typing = ["typing-extensions (>=4.12.2)"] [[package]] name = "flake8" -version = "7.1.0" +version = "7.1.1" description = "the modular source code checker: pep8 pyflakes and co" optional = false python-versions = ">=3.8.1" files = [ - {file = "flake8-7.1.0-py2.py3-none-any.whl", hash = "sha256:2e416edcc62471a64cea09353f4e7bdba32aeb079b6e360554c659a122b1bc6a"}, - {file = "flake8-7.1.0.tar.gz", hash = "sha256:48a07b626b55236e0fb4784ee69a465fbf59d79eec1f5b4785c3d3bc57d17aa5"}, + {file = "flake8-7.1.1-py2.py3-none-any.whl", hash = "sha256:597477df7860daa5aa0fdd84bf5208a043ab96b8e96ab708770ae0364dd03213"}, + {file = "flake8-7.1.1.tar.gz", hash = "sha256:049d058491e228e03e67b390f311bbf88fce2dbaa8fa673e7aea87b7198b8d38"}, ] [package.dependencies] @@ -1087,101 +1209,187 @@ mccabe = ">=0.7.0,<0.8.0" pycodestyle = ">=2.12.0,<2.13.0" pyflakes = ">=3.2.0,<3.3.0" +[[package]] +name = "fonttools" +version = "4.54.1" +description = "Tools to manipulate font files" +optional = false +python-versions = ">=3.8" +files = [ + {file = "fonttools-4.54.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7ed7ee041ff7b34cc62f07545e55e1468808691dddfd315d51dd82a6b37ddef2"}, + {file = "fonttools-4.54.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:41bb0b250c8132b2fcac148e2e9198e62ff06f3cc472065dff839327945c5882"}, + {file = "fonttools-4.54.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7965af9b67dd546e52afcf2e38641b5be956d68c425bef2158e95af11d229f10"}, + {file = "fonttools-4.54.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:278913a168f90d53378c20c23b80f4e599dca62fbffae4cc620c8eed476b723e"}, + {file = "fonttools-4.54.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0e88e3018ac809b9662615072dcd6b84dca4c2d991c6d66e1970a112503bba7e"}, + {file = "fonttools-4.54.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:4aa4817f0031206e637d1e685251ac61be64d1adef111060df84fdcbc6ab6c44"}, + {file = "fonttools-4.54.1-cp310-cp310-win32.whl", hash = "sha256:7e3b7d44e18c085fd8c16dcc6f1ad6c61b71ff463636fcb13df7b1b818bd0c02"}, + {file = "fonttools-4.54.1-cp310-cp310-win_amd64.whl", hash = "sha256:dd9cc95b8d6e27d01e1e1f1fae8559ef3c02c76317da650a19047f249acd519d"}, + {file = "fonttools-4.54.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5419771b64248484299fa77689d4f3aeed643ea6630b2ea750eeab219588ba20"}, + {file = "fonttools-4.54.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:301540e89cf4ce89d462eb23a89464fef50915255ece765d10eee8b2bf9d75b2"}, + {file = "fonttools-4.54.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76ae5091547e74e7efecc3cbf8e75200bc92daaeb88e5433c5e3e95ea8ce5aa7"}, + {file = "fonttools-4.54.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82834962b3d7c5ca98cb56001c33cf20eb110ecf442725dc5fdf36d16ed1ab07"}, + {file = "fonttools-4.54.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d26732ae002cc3d2ecab04897bb02ae3f11f06dd7575d1df46acd2f7c012a8d8"}, + {file = "fonttools-4.54.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:58974b4987b2a71ee08ade1e7f47f410c367cdfc5a94fabd599c88165f56213a"}, + {file = "fonttools-4.54.1-cp311-cp311-win32.whl", hash = "sha256:ab774fa225238986218a463f3fe151e04d8c25d7de09df7f0f5fce27b1243dbc"}, + {file = "fonttools-4.54.1-cp311-cp311-win_amd64.whl", hash = "sha256:07e005dc454eee1cc60105d6a29593459a06321c21897f769a281ff2d08939f6"}, + {file = "fonttools-4.54.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:54471032f7cb5fca694b5f1a0aaeba4af6e10ae989df408e0216f7fd6cdc405d"}, + {file = "fonttools-4.54.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8fa92cb248e573daab8d032919623cc309c005086d743afb014c836636166f08"}, + {file = "fonttools-4.54.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a911591200114969befa7f2cb74ac148bce5a91df5645443371aba6d222e263"}, + {file = "fonttools-4.54.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93d458c8a6a354dc8b48fc78d66d2a8a90b941f7fec30e94c7ad9982b1fa6bab"}, + {file = "fonttools-4.54.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5eb2474a7c5be8a5331146758debb2669bf5635c021aee00fd7c353558fc659d"}, + {file = "fonttools-4.54.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c9c563351ddc230725c4bdf7d9e1e92cbe6ae8553942bd1fb2b2ff0884e8b714"}, + {file = "fonttools-4.54.1-cp312-cp312-win32.whl", hash = "sha256:fdb062893fd6d47b527d39346e0c5578b7957dcea6d6a3b6794569370013d9ac"}, + {file = "fonttools-4.54.1-cp312-cp312-win_amd64.whl", hash = "sha256:e4564cf40cebcb53f3dc825e85910bf54835e8a8b6880d59e5159f0f325e637e"}, + {file = "fonttools-4.54.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6e37561751b017cf5c40fce0d90fd9e8274716de327ec4ffb0df957160be3bff"}, + {file = "fonttools-4.54.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:357cacb988a18aace66e5e55fe1247f2ee706e01debc4b1a20d77400354cddeb"}, + {file = "fonttools-4.54.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8e953cc0bddc2beaf3a3c3b5dd9ab7554677da72dfaf46951e193c9653e515a"}, + {file = "fonttools-4.54.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:58d29b9a294573d8319f16f2f79e42428ba9b6480442fa1836e4eb89c4d9d61c"}, + {file = "fonttools-4.54.1-cp313-cp313-win32.whl", hash = "sha256:9ef1b167e22709b46bf8168368b7b5d3efeaaa746c6d39661c1b4405b6352e58"}, + {file = "fonttools-4.54.1-cp313-cp313-win_amd64.whl", hash = "sha256:262705b1663f18c04250bd1242b0515d3bbae177bee7752be67c979b7d47f43d"}, + {file = "fonttools-4.54.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ed2f80ca07025551636c555dec2b755dd005e2ea8fbeb99fc5cdff319b70b23b"}, + {file = "fonttools-4.54.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9dc080e5a1c3b2656caff2ac2633d009b3a9ff7b5e93d0452f40cd76d3da3b3c"}, + {file = "fonttools-4.54.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d152d1be65652fc65e695e5619e0aa0982295a95a9b29b52b85775243c06556"}, + {file = "fonttools-4.54.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8583e563df41fdecef31b793b4dd3af8a9caa03397be648945ad32717a92885b"}, + {file = "fonttools-4.54.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:0d1d353ef198c422515a3e974a1e8d5b304cd54a4c2eebcae708e37cd9eeffb1"}, + {file = "fonttools-4.54.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:fda582236fee135d4daeca056c8c88ec5f6f6d88a004a79b84a02547c8f57386"}, + {file = "fonttools-4.54.1-cp38-cp38-win32.whl", hash = "sha256:e7d82b9e56716ed32574ee106cabca80992e6bbdcf25a88d97d21f73a0aae664"}, + {file = "fonttools-4.54.1-cp38-cp38-win_amd64.whl", hash = "sha256:ada215fd079e23e060157aab12eba0d66704316547f334eee9ff26f8c0d7b8ab"}, + {file = "fonttools-4.54.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:f5b8a096e649768c2f4233f947cf9737f8dbf8728b90e2771e2497c6e3d21d13"}, + {file = "fonttools-4.54.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4e10d2e0a12e18f4e2dd031e1bf7c3d7017be5c8dbe524d07706179f355c5dac"}, + {file = "fonttools-4.54.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:31c32d7d4b0958600eac75eaf524b7b7cb68d3a8c196635252b7a2c30d80e986"}, + {file = "fonttools-4.54.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c39287f5c8f4a0c5a55daf9eaf9ccd223ea59eed3f6d467133cc727d7b943a55"}, + {file = "fonttools-4.54.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:a7a310c6e0471602fe3bf8efaf193d396ea561486aeaa7adc1f132e02d30c4b9"}, + {file = "fonttools-4.54.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:d3b659d1029946f4ff9b6183984578041b520ce0f8fb7078bb37ec7445806b33"}, + {file = "fonttools-4.54.1-cp39-cp39-win32.whl", hash = "sha256:e96bc94c8cda58f577277d4a71f51c8e2129b8b36fd05adece6320dd3d57de8a"}, + {file = "fonttools-4.54.1-cp39-cp39-win_amd64.whl", hash = "sha256:e8a4b261c1ef91e7188a30571be6ad98d1c6d9fa2427244c545e2fa0a2494dd7"}, + {file = "fonttools-4.54.1-py3-none-any.whl", hash = "sha256:37cddd62d83dc4f72f7c3f3c2bcf2697e89a30efb152079896544a93907733bd"}, + {file = "fonttools-4.54.1.tar.gz", hash = "sha256:957f669d4922f92c171ba01bef7f29410668db09f6c02111e22b2bce446f3285"}, +] + +[package.extras] +all = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "fs (>=2.2.0,<3)", "lxml (>=4.0)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres", "pycairo", "scipy", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.23.0)", "unicodedata2 (>=15.1.0)", "xattr", "zopfli (>=0.1.4)"] +graphite = ["lz4 (>=1.7.4.2)"] +interpolatable = ["munkres", "pycairo", "scipy"] +lxml = ["lxml (>=4.0)"] +pathops = ["skia-pathops (>=0.5.0)"] +plot = ["matplotlib"] +repacker = ["uharfbuzz (>=0.23.0)"] +symfont = ["sympy"] +type1 = ["xattr"] +ufo = ["fs (>=2.2.0,<3)"] +unicode = ["unicodedata2 (>=15.1.0)"] +woff = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "zopfli (>=0.1.4)"] + [[package]] name = "frozenlist" -version = "1.4.1" +version = "1.5.0" description = "A list-like structure which implements collections.abc.MutableSequence" optional = false python-versions = ">=3.8" files = [ - {file = "frozenlist-1.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f9aa1878d1083b276b0196f2dfbe00c9b7e752475ed3b682025ff20c1c1f51ac"}, - {file = "frozenlist-1.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:29acab3f66f0f24674b7dc4736477bcd4bc3ad4b896f5f45379a67bce8b96868"}, - {file = "frozenlist-1.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:74fb4bee6880b529a0c6560885fce4dc95936920f9f20f53d99a213f7bf66776"}, - {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:590344787a90ae57d62511dd7c736ed56b428f04cd8c161fcc5e7232c130c69a"}, - {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:068b63f23b17df8569b7fdca5517edef76171cf3897eb68beb01341131fbd2ad"}, - {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c849d495bf5154cd8da18a9eb15db127d4dba2968d88831aff6f0331ea9bd4c"}, - {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9750cc7fe1ae3b1611bb8cfc3f9ec11d532244235d75901fb6b8e42ce9229dfe"}, - {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9b2de4cf0cdd5bd2dee4c4f63a653c61d2408055ab77b151c1957f221cabf2a"}, - {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0633c8d5337cb5c77acbccc6357ac49a1770b8c487e5b3505c57b949b4b82e98"}, - {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:27657df69e8801be6c3638054e202a135c7f299267f1a55ed3a598934f6c0d75"}, - {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:f9a3ea26252bd92f570600098783d1371354d89d5f6b7dfd87359d669f2109b5"}, - {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:4f57dab5fe3407b6c0c1cc907ac98e8a189f9e418f3b6e54d65a718aaafe3950"}, - {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e02a0e11cf6597299b9f3bbd3f93d79217cb90cfd1411aec33848b13f5c656cc"}, - {file = "frozenlist-1.4.1-cp310-cp310-win32.whl", hash = "sha256:a828c57f00f729620a442881cc60e57cfcec6842ba38e1b19fd3e47ac0ff8dc1"}, - {file = "frozenlist-1.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:f56e2333dda1fe0f909e7cc59f021eba0d2307bc6f012a1ccf2beca6ba362439"}, - {file = "frozenlist-1.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a0cb6f11204443f27a1628b0e460f37fb30f624be6051d490fa7d7e26d4af3d0"}, - {file = "frozenlist-1.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b46c8ae3a8f1f41a0d2ef350c0b6e65822d80772fe46b653ab6b6274f61d4a49"}, - {file = "frozenlist-1.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fde5bd59ab5357e3853313127f4d3565fc7dad314a74d7b5d43c22c6a5ed2ced"}, - {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:722e1124aec435320ae01ee3ac7bec11a5d47f25d0ed6328f2273d287bc3abb0"}, - {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2471c201b70d58a0f0c1f91261542a03d9a5e088ed3dc6c160d614c01649c106"}, - {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c757a9dd70d72b076d6f68efdbb9bc943665ae954dad2801b874c8c69e185068"}, - {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f146e0911cb2f1da549fc58fc7bcd2b836a44b79ef871980d605ec392ff6b0d2"}, - {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f9c515e7914626b2a2e1e311794b4c35720a0be87af52b79ff8e1429fc25f19"}, - {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c302220494f5c1ebeb0912ea782bcd5e2f8308037b3c7553fad0e48ebad6ad82"}, - {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:442acde1e068288a4ba7acfe05f5f343e19fac87bfc96d89eb886b0363e977ec"}, - {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:1b280e6507ea8a4fa0c0a7150b4e526a8d113989e28eaaef946cc77ffd7efc0a"}, - {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:fe1a06da377e3a1062ae5fe0926e12b84eceb8a50b350ddca72dc85015873f74"}, - {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:db9e724bebd621d9beca794f2a4ff1d26eed5965b004a97f1f1685a173b869c2"}, - {file = "frozenlist-1.4.1-cp311-cp311-win32.whl", hash = "sha256:e774d53b1a477a67838a904131c4b0eef6b3d8a651f8b138b04f748fccfefe17"}, - {file = "frozenlist-1.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:fb3c2db03683b5767dedb5769b8a40ebb47d6f7f45b1b3e3b4b51ec8ad9d9825"}, - {file = "frozenlist-1.4.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:1979bc0aeb89b33b588c51c54ab0161791149f2461ea7c7c946d95d5f93b56ae"}, - {file = "frozenlist-1.4.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:cc7b01b3754ea68a62bd77ce6020afaffb44a590c2289089289363472d13aedb"}, - {file = "frozenlist-1.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c9c92be9fd329ac801cc420e08452b70e7aeab94ea4233a4804f0915c14eba9b"}, - {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c3894db91f5a489fc8fa6a9991820f368f0b3cbdb9cd8849547ccfab3392d86"}, - {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ba60bb19387e13597fb059f32cd4d59445d7b18b69a745b8f8e5db0346f33480"}, - {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8aefbba5f69d42246543407ed2461db31006b0f76c4e32dfd6f42215a2c41d09"}, - {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:780d3a35680ced9ce682fbcf4cb9c2bad3136eeff760ab33707b71db84664e3a"}, - {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9acbb16f06fe7f52f441bb6f413ebae6c37baa6ef9edd49cdd567216da8600cd"}, - {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:23b701e65c7b36e4bf15546a89279bd4d8675faabc287d06bbcfac7d3c33e1e6"}, - {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:3e0153a805a98f5ada7e09826255ba99fb4f7524bb81bf6b47fb702666484ae1"}, - {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:dd9b1baec094d91bf36ec729445f7769d0d0cf6b64d04d86e45baf89e2b9059b"}, - {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:1a4471094e146b6790f61b98616ab8e44f72661879cc63fa1049d13ef711e71e"}, - {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5667ed53d68d91920defdf4035d1cdaa3c3121dc0b113255124bcfada1cfa1b8"}, - {file = "frozenlist-1.4.1-cp312-cp312-win32.whl", hash = "sha256:beee944ae828747fd7cb216a70f120767fc9f4f00bacae8543c14a6831673f89"}, - {file = "frozenlist-1.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:64536573d0a2cb6e625cf309984e2d873979709f2cf22839bf2d61790b448ad5"}, - {file = "frozenlist-1.4.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:20b51fa3f588ff2fe658663db52a41a4f7aa6c04f6201449c6c7c476bd255c0d"}, - {file = "frozenlist-1.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:410478a0c562d1a5bcc2f7ea448359fcb050ed48b3c6f6f4f18c313a9bdb1826"}, - {file = "frozenlist-1.4.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c6321c9efe29975232da3bd0af0ad216800a47e93d763ce64f291917a381b8eb"}, - {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:48f6a4533887e189dae092f1cf981f2e3885175f7a0f33c91fb5b7b682b6bab6"}, - {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6eb73fa5426ea69ee0e012fb59cdc76a15b1283d6e32e4f8dc4482ec67d1194d"}, - {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fbeb989b5cc29e8daf7f976b421c220f1b8c731cbf22b9130d8815418ea45887"}, - {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:32453c1de775c889eb4e22f1197fe3bdfe457d16476ea407472b9442e6295f7a"}, - {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:693945278a31f2086d9bf3df0fe8254bbeaef1fe71e1351c3bd730aa7d31c41b"}, - {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:1d0ce09d36d53bbbe566fe296965b23b961764c0bcf3ce2fa45f463745c04701"}, - {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:3a670dc61eb0d0eb7080890c13de3066790f9049b47b0de04007090807c776b0"}, - {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:dca69045298ce5c11fd539682cff879cc1e664c245d1c64da929813e54241d11"}, - {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:a06339f38e9ed3a64e4c4e43aec7f59084033647f908e4259d279a52d3757d09"}, - {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b7f2f9f912dca3934c1baec2e4585a674ef16fe00218d833856408c48d5beee7"}, - {file = "frozenlist-1.4.1-cp38-cp38-win32.whl", hash = "sha256:e7004be74cbb7d9f34553a5ce5fb08be14fb33bc86f332fb71cbe5216362a497"}, - {file = "frozenlist-1.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:5a7d70357e7cee13f470c7883a063aae5fe209a493c57d86eb7f5a6f910fae09"}, - {file = "frozenlist-1.4.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:bfa4a17e17ce9abf47a74ae02f32d014c5e9404b6d9ac7f729e01562bbee601e"}, - {file = "frozenlist-1.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b7e3ed87d4138356775346e6845cccbe66cd9e207f3cd11d2f0b9fd13681359d"}, - {file = "frozenlist-1.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c99169d4ff810155ca50b4da3b075cbde79752443117d89429595c2e8e37fed8"}, - {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edb678da49d9f72c9f6c609fbe41a5dfb9a9282f9e6a2253d5a91e0fc382d7c0"}, - {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6db4667b187a6742b33afbbaf05a7bc551ffcf1ced0000a571aedbb4aa42fc7b"}, - {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55fdc093b5a3cb41d420884cdaf37a1e74c3c37a31f46e66286d9145d2063bd0"}, - {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82e8211d69a4f4bc360ea22cd6555f8e61a1bd211d1d5d39d3d228b48c83a897"}, - {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89aa2c2eeb20957be2d950b85974b30a01a762f3308cd02bb15e1ad632e22dc7"}, - {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9d3e0c25a2350080e9319724dede4f31f43a6c9779be48021a7f4ebde8b2d742"}, - {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7268252af60904bf52c26173cbadc3a071cece75f873705419c8681f24d3edea"}, - {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:0c250a29735d4f15321007fb02865f0e6b6a41a6b88f1f523ca1596ab5f50bd5"}, - {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:96ec70beabbd3b10e8bfe52616a13561e58fe84c0101dd031dc78f250d5128b9"}, - {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:23b2d7679b73fe0e5a4560b672a39f98dfc6f60df63823b0a9970525325b95f6"}, - {file = "frozenlist-1.4.1-cp39-cp39-win32.whl", hash = "sha256:a7496bfe1da7fb1a4e1cc23bb67c58fab69311cc7d32b5a99c2007b4b2a0e932"}, - {file = "frozenlist-1.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:e6a20a581f9ce92d389a8c7d7c3dd47c81fd5d6e655c8dddf341e14aa48659d0"}, - {file = "frozenlist-1.4.1-py3-none-any.whl", hash = "sha256:04ced3e6a46b4cfffe20f9ae482818e34eba9b5fb0ce4056e4cc9b6e212d09b7"}, - {file = "frozenlist-1.4.1.tar.gz", hash = "sha256:c037a86e8513059a2613aaba4d817bb90b9d9b6b69aace3ce9c877e8c8ed402b"}, + {file = "frozenlist-1.5.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5b6a66c18b5b9dd261ca98dffcb826a525334b2f29e7caa54e182255c5f6a65a"}, + {file = "frozenlist-1.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d1b3eb7b05ea246510b43a7e53ed1653e55c2121019a97e60cad7efb881a97bb"}, + {file = "frozenlist-1.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:15538c0cbf0e4fa11d1e3a71f823524b0c46299aed6e10ebb4c2089abd8c3bec"}, + {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e79225373c317ff1e35f210dd5f1344ff31066ba8067c307ab60254cd3a78ad5"}, + {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9272fa73ca71266702c4c3e2d4a28553ea03418e591e377a03b8e3659d94fa76"}, + {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:498524025a5b8ba81695761d78c8dd7382ac0b052f34e66939c42df860b8ff17"}, + {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:92b5278ed9d50fe610185ecd23c55d8b307d75ca18e94c0e7de328089ac5dcba"}, + {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f3c8c1dacd037df16e85227bac13cca58c30da836c6f936ba1df0c05d046d8d"}, + {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f2ac49a9bedb996086057b75bf93538240538c6d9b38e57c82d51f75a73409d2"}, + {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e66cc454f97053b79c2ab09c17fbe3c825ea6b4de20baf1be28919460dd7877f"}, + {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:5a3ba5f9a0dfed20337d3e966dc359784c9f96503674c2faf015f7fe8e96798c"}, + {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:6321899477db90bdeb9299ac3627a6a53c7399c8cd58d25da094007402b039ab"}, + {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:76e4753701248476e6286f2ef492af900ea67d9706a0155335a40ea21bf3b2f5"}, + {file = "frozenlist-1.5.0-cp310-cp310-win32.whl", hash = "sha256:977701c081c0241d0955c9586ffdd9ce44f7a7795df39b9151cd9a6fd0ce4cfb"}, + {file = "frozenlist-1.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:189f03b53e64144f90990d29a27ec4f7997d91ed3d01b51fa39d2dbe77540fd4"}, + {file = "frozenlist-1.5.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:fd74520371c3c4175142d02a976aee0b4cb4a7cc912a60586ffd8d5929979b30"}, + {file = "frozenlist-1.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2f3f7a0fbc219fb4455264cae4d9f01ad41ae6ee8524500f381de64ffaa077d5"}, + {file = "frozenlist-1.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f47c9c9028f55a04ac254346e92977bf0f166c483c74b4232bee19a6697e4778"}, + {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0996c66760924da6e88922756d99b47512a71cfd45215f3570bf1e0b694c206a"}, + {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a2fe128eb4edeabe11896cb6af88fca5346059f6c8d807e3b910069f39157869"}, + {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1a8ea951bbb6cacd492e3948b8da8c502a3f814f5d20935aae74b5df2b19cf3d"}, + {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de537c11e4aa01d37db0d403b57bd6f0546e71a82347a97c6a9f0dcc532b3a45"}, + {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c2623347b933fcb9095841f1cc5d4ff0b278addd743e0e966cb3d460278840d"}, + {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cee6798eaf8b1416ef6909b06f7dc04b60755206bddc599f52232606e18179d3"}, + {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f5f9da7f5dbc00a604fe74aa02ae7c98bcede8a3b8b9666f9f86fc13993bc71a"}, + {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:90646abbc7a5d5c7c19461d2e3eeb76eb0b204919e6ece342feb6032c9325ae9"}, + {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:bdac3c7d9b705d253b2ce370fde941836a5f8b3c5c2b8fd70940a3ea3af7f4f2"}, + {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:03d33c2ddbc1816237a67f66336616416e2bbb6beb306e5f890f2eb22b959cdf"}, + {file = "frozenlist-1.5.0-cp311-cp311-win32.whl", hash = "sha256:237f6b23ee0f44066219dae14c70ae38a63f0440ce6750f868ee08775073f942"}, + {file = "frozenlist-1.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:0cc974cc93d32c42e7b0f6cf242a6bd941c57c61b618e78b6c0a96cb72788c1d"}, + {file = "frozenlist-1.5.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:31115ba75889723431aa9a4e77d5f398f5cf976eea3bdf61749731f62d4a4a21"}, + {file = "frozenlist-1.5.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7437601c4d89d070eac8323f121fcf25f88674627505334654fd027b091db09d"}, + {file = "frozenlist-1.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7948140d9f8ece1745be806f2bfdf390127cf1a763b925c4a805c603df5e697e"}, + {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:feeb64bc9bcc6b45c6311c9e9b99406660a9c05ca8a5b30d14a78555088b0b3a"}, + {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:683173d371daad49cffb8309779e886e59c2f369430ad28fe715f66d08d4ab1a"}, + {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7d57d8f702221405a9d9b40f9da8ac2e4a1a8b5285aac6100f3393675f0a85ee"}, + {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:30c72000fbcc35b129cb09956836c7d7abf78ab5416595e4857d1cae8d6251a6"}, + {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:000a77d6034fbad9b6bb880f7ec073027908f1b40254b5d6f26210d2dab1240e"}, + {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5d7f5a50342475962eb18b740f3beecc685a15b52c91f7d975257e13e029eca9"}, + {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:87f724d055eb4785d9be84e9ebf0f24e392ddfad00b3fe036e43f489fafc9039"}, + {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:6e9080bb2fb195a046e5177f10d9d82b8a204c0736a97a153c2466127de87784"}, + {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9b93d7aaa36c966fa42efcaf716e6b3900438632a626fb09c049f6a2f09fc631"}, + {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:52ef692a4bc60a6dd57f507429636c2af8b6046db8b31b18dac02cbc8f507f7f"}, + {file = "frozenlist-1.5.0-cp312-cp312-win32.whl", hash = "sha256:29d94c256679247b33a3dc96cce0f93cbc69c23bf75ff715919332fdbb6a32b8"}, + {file = "frozenlist-1.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:8969190d709e7c48ea386db202d708eb94bdb29207a1f269bab1196ce0dcca1f"}, + {file = "frozenlist-1.5.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:7a1a048f9215c90973402e26c01d1cff8a209e1f1b53f72b95c13db61b00f953"}, + {file = "frozenlist-1.5.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:dd47a5181ce5fcb463b5d9e17ecfdb02b678cca31280639255ce9d0e5aa67af0"}, + {file = "frozenlist-1.5.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1431d60b36d15cda188ea222033eec8e0eab488f39a272461f2e6d9e1a8e63c2"}, + {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6482a5851f5d72767fbd0e507e80737f9c8646ae7fd303def99bfe813f76cf7f"}, + {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:44c49271a937625619e862baacbd037a7ef86dd1ee215afc298a417ff3270608"}, + {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:12f78f98c2f1c2429d42e6a485f433722b0061d5c0b0139efa64f396efb5886b"}, + {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ce3aa154c452d2467487765e3adc730a8c153af77ad84096bc19ce19a2400840"}, + {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b7dc0c4338e6b8b091e8faf0db3168a37101943e687f373dce00959583f7439"}, + {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:45e0896250900b5aa25180f9aec243e84e92ac84bd4a74d9ad4138ef3f5c97de"}, + {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:561eb1c9579d495fddb6da8959fd2a1fca2c6d060d4113f5844b433fc02f2641"}, + {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:df6e2f325bfee1f49f81aaac97d2aa757c7646534a06f8f577ce184afe2f0a9e"}, + {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:140228863501b44b809fb39ec56b5d4071f4d0aa6d216c19cbb08b8c5a7eadb9"}, + {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7707a25d6a77f5d27ea7dc7d1fc608aa0a478193823f88511ef5e6b8a48f9d03"}, + {file = "frozenlist-1.5.0-cp313-cp313-win32.whl", hash = "sha256:31a9ac2b38ab9b5a8933b693db4939764ad3f299fcaa931a3e605bc3460e693c"}, + {file = "frozenlist-1.5.0-cp313-cp313-win_amd64.whl", hash = "sha256:11aabdd62b8b9c4b84081a3c246506d1cddd2dd93ff0ad53ede5defec7886b28"}, + {file = "frozenlist-1.5.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:dd94994fc91a6177bfaafd7d9fd951bc8689b0a98168aa26b5f543868548d3ca"}, + {file = "frozenlist-1.5.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2d0da8bbec082bf6bf18345b180958775363588678f64998c2b7609e34719b10"}, + {file = "frozenlist-1.5.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:73f2e31ea8dd7df61a359b731716018c2be196e5bb3b74ddba107f694fbd7604"}, + {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:828afae9f17e6de596825cf4228ff28fbdf6065974e5ac1410cecc22f699d2b3"}, + {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f1577515d35ed5649d52ab4319db757bb881ce3b2b796d7283e6634d99ace307"}, + {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2150cc6305a2c2ab33299453e2968611dacb970d2283a14955923062c8d00b10"}, + {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a72b7a6e3cd2725eff67cd64c8f13335ee18fc3c7befc05aed043d24c7b9ccb9"}, + {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c16d2fa63e0800723139137d667e1056bee1a1cf7965153d2d104b62855e9b99"}, + {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:17dcc32fc7bda7ce5875435003220a457bcfa34ab7924a49a1c19f55b6ee185c"}, + {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:97160e245ea33d8609cd2b8fd997c850b56db147a304a262abc2b3be021a9171"}, + {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:f1e6540b7fa044eee0bb5111ada694cf3dc15f2b0347ca125ee9ca984d5e9e6e"}, + {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:91d6c171862df0a6c61479d9724f22efb6109111017c87567cfeb7b5d1449fdf"}, + {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:c1fac3e2ace2eb1052e9f7c7db480818371134410e1f5c55d65e8f3ac6d1407e"}, + {file = "frozenlist-1.5.0-cp38-cp38-win32.whl", hash = "sha256:b97f7b575ab4a8af9b7bc1d2ef7f29d3afee2226bd03ca3875c16451ad5a7723"}, + {file = "frozenlist-1.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:374ca2dabdccad8e2a76d40b1d037f5bd16824933bf7bcea3e59c891fd4a0923"}, + {file = "frozenlist-1.5.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:9bbcdfaf4af7ce002694a4e10a0159d5a8d20056a12b05b45cea944a4953f972"}, + {file = "frozenlist-1.5.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1893f948bf6681733aaccf36c5232c231e3b5166d607c5fa77773611df6dc336"}, + {file = "frozenlist-1.5.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2b5e23253bb709ef57a8e95e6ae48daa9ac5f265637529e4ce6b003a37b2621f"}, + {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f253985bb515ecd89629db13cb58d702035ecd8cfbca7d7a7e29a0e6d39af5f"}, + {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:04a5c6babd5e8fb7d3c871dc8b321166b80e41b637c31a995ed844a6139942b6"}, + {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a9fe0f1c29ba24ba6ff6abf688cb0b7cf1efab6b6aa6adc55441773c252f7411"}, + {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:226d72559fa19babe2ccd920273e767c96a49b9d3d38badd7c91a0fdeda8ea08"}, + {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15b731db116ab3aedec558573c1a5eec78822b32292fe4f2f0345b7f697745c2"}, + {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:366d8f93e3edfe5a918c874702f78faac300209a4d5bf38352b2c1bdc07a766d"}, + {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:1b96af8c582b94d381a1c1f51ffaedeb77c821c690ea5f01da3d70a487dd0a9b"}, + {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:c03eff4a41bd4e38415cbed054bbaff4a075b093e2394b6915dca34a40d1e38b"}, + {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:50cf5e7ee9b98f22bdecbabf3800ae78ddcc26e4a435515fc72d97903e8488e0"}, + {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1e76bfbc72353269c44e0bc2cfe171900fbf7f722ad74c9a7b638052afe6a00c"}, + {file = "frozenlist-1.5.0-cp39-cp39-win32.whl", hash = "sha256:666534d15ba8f0fda3f53969117383d5dc021266b3c1a42c9ec4855e4b58b9d3"}, + {file = "frozenlist-1.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:5c28f4b5dbef8a0d8aad0d4de24d1e9e981728628afaf4ea0792f5d0939372f0"}, + {file = "frozenlist-1.5.0-py3-none-any.whl", hash = "sha256:d994863bba198a4a518b467bb971c56e1db3f180a25c6cf7bb1949c267f748c3"}, + {file = "frozenlist-1.5.0.tar.gz", hash = "sha256:81d5af29e61b9c8348e876d442253723928dce6433e0e76cd925cd83f1b4b817"}, ] [[package]] name = "fsspec" -version = "2024.6.0" +version = "2024.10.0" description = "File-system specification" optional = false python-versions = ">=3.8" files = [ - {file = "fsspec-2024.6.0-py3-none-any.whl", hash = "sha256:58d7122eb8a1a46f7f13453187bfea4972d66bf01618d37366521b1998034cee"}, - {file = "fsspec-2024.6.0.tar.gz", hash = "sha256:f579960a56e6d8038a9efc8f9c77279ec12e6299aa86b0769a7e9c46b94527c2"}, + {file = "fsspec-2024.10.0-py3-none-any.whl", hash = "sha256:03b9a6785766a4de40368b88906366755e2819e758b83705c88cd7cb5fe81871"}, + {file = "fsspec-2024.10.0.tar.gz", hash = "sha256:eda2d8a4116d4f2429db8550f2457da57279247dd930bb12f821b58391359493"}, ] [package.extras] @@ -1214,19 +1422,19 @@ tqdm = ["tqdm"] [[package]] name = "gcsfs" -version = "2024.6.0" +version = "2024.10.0" description = "Convenient Filesystem interface over GCS" optional = false python-versions = ">=3.8" files = [ - {file = "gcsfs-2024.6.0-py2.py3-none-any.whl", hash = "sha256:92c9239167bd1e209b662b6f4ab71974f276118779c55360215cce5e0098ca7f"}, - {file = "gcsfs-2024.6.0.tar.gz", hash = "sha256:27bd490d7a9dd641d5f6f4ea0b18fabdcfa6129b84ebdb22b23e3460ded1aa8c"}, + {file = "gcsfs-2024.10.0-py2.py3-none-any.whl", hash = "sha256:bb2d23547e61203ea2dda5fa6c4b91a0c34b74ebe8bb6ab1926f6c33381bceb2"}, + {file = "gcsfs-2024.10.0.tar.gz", hash = "sha256:5df54cfe568e8fdeea5aafa7fed695cdc69a9a674e991ca8c1ce634f5df1d314"}, ] [package.dependencies] aiohttp = "<4.0.0a0 || >4.0.0a0,<4.0.0a1 || >4.0.0a1" decorator = ">4.1.2" -fsspec = "2024.6.0" +fsspec = "2024.10.0" google-auth = ">=1.2" google-auth-oauthlib = "*" google-cloud-storage = "*" @@ -1301,13 +1509,13 @@ beautifulsoup4 = "*" [[package]] name = "google-api-core" -version = "2.19.0" +version = "2.22.0" description = "Google API client core library" optional = false python-versions = ">=3.7" files = [ - {file = "google-api-core-2.19.0.tar.gz", hash = "sha256:cf1b7c2694047886d2af1128a03ae99e391108a08804f87cfd35970e49c9cd10"}, - {file = "google_api_core-2.19.0-py3-none-any.whl", hash = "sha256:8661eec4078c35428fd3f69a2c7ee29e342896b70f01d1a1cbcb334372dd6251"}, + {file = "google_api_core-2.22.0-py3-none-any.whl", hash = "sha256:a6652b6bd51303902494998626653671703c420f6f4c88cfd3f50ed723e9d021"}, + {file = "google_api_core-2.22.0.tar.gz", hash = "sha256:26f8d76b96477db42b55fd02a33aae4a42ec8b86b98b94969b7333a2c828bf35"}, ] [package.dependencies] @@ -1316,23 +1524,24 @@ googleapis-common-protos = ">=1.56.2,<2.0.dev0" grpcio = {version = ">=1.33.2,<2.0dev", optional = true, markers = "extra == \"grpc\""} grpcio-status = {version = ">=1.33.2,<2.0.dev0", optional = true, markers = "extra == \"grpc\""} proto-plus = ">=1.22.3,<2.0.0dev" -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0.dev0" +protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<6.0.0.dev0" requests = ">=2.18.0,<3.0.0.dev0" [package.extras] +async-rest = ["google-auth[aiohttp] (>=2.35.0,<3.0.dev0)"] grpc = ["grpcio (>=1.33.2,<2.0dev)", "grpcio (>=1.49.1,<2.0dev)", "grpcio-status (>=1.33.2,<2.0.dev0)", "grpcio-status (>=1.49.1,<2.0.dev0)"] grpcgcp = ["grpcio-gcp (>=0.2.2,<1.0.dev0)"] grpcio-gcp = ["grpcio-gcp (>=0.2.2,<1.0.dev0)"] [[package]] name = "google-auth" -version = "2.30.0" +version = "2.35.0" description = "Google Authentication Library" optional = false python-versions = ">=3.7" files = [ - {file = "google-auth-2.30.0.tar.gz", hash = "sha256:ab630a1320f6720909ad76a7dbdb6841cdf5c66b328d690027e4867bdfb16688"}, - {file = "google_auth-2.30.0-py2.py3-none-any.whl", hash = "sha256:8df7da660f62757388b8a7f249df13549b3373f24388cb5d2f1dd91cc18180b5"}, + {file = "google_auth-2.35.0-py2.py3-none-any.whl", hash = "sha256:25df55f327ef021de8be50bad0dfd4a916ad0de96da86cd05661c9297723ad3f"}, + {file = "google_auth-2.35.0.tar.gz", hash = "sha256:f4c64ed4e01e8e8b646ef34c018f8bf3338df0c8e37d8b3bba40e7f574a3278a"}, ] [package.dependencies] @@ -1342,7 +1551,7 @@ rsa = ">=3.1.4,<5" [package.extras] aiohttp = ["aiohttp (>=3.6.2,<4.0.0.dev0)", "requests (>=2.20.0,<3.0.0.dev0)"] -enterprise-cert = ["cryptography (==36.0.2)", "pyopenssl (==22.0.0)"] +enterprise-cert = ["cryptography", "pyopenssl"] pyopenssl = ["cryptography (>=38.0.3)", "pyopenssl (>=20.0.0)"] reauth = ["pyu2f (>=0.1.5)"] requests = ["requests (>=2.20.0,<3.0.0.dev0)"] @@ -1367,30 +1576,30 @@ tool = ["click (>=6.0.0)"] [[package]] name = "google-cloud-bigquery" -version = "3.25.0" +version = "3.26.0" description = "Google BigQuery API client library" optional = false python-versions = ">=3.7" files = [ - {file = "google-cloud-bigquery-3.25.0.tar.gz", hash = "sha256:5b2aff3205a854481117436836ae1403f11f2594e6810a98886afd57eda28509"}, - {file = "google_cloud_bigquery-3.25.0-py2.py3-none-any.whl", hash = "sha256:7f0c371bc74d2a7fb74dacbc00ac0f90c8c2bec2289b51dd6685a275873b1ce9"}, + {file = "google_cloud_bigquery-3.26.0-py2.py3-none-any.whl", hash = "sha256:e0e9ad28afa67a18696e624cbccab284bf2c0a3f6eeb9eeb0426c69b943793a8"}, + {file = "google_cloud_bigquery-3.26.0.tar.gz", hash = "sha256:edbdc788beea659e04c0af7fe4dcd6d9155344b98951a0d5055bd2f15da4ba23"}, ] [package.dependencies] -google-api-core = {version = ">=1.34.1,<2.0.dev0 || >=2.11.dev0,<3.0.0dev", extras = ["grpc"]} +google-api-core = {version = ">=2.11.1,<3.0.0dev", extras = ["grpc"]} google-auth = ">=2.14.1,<3.0.0dev" -google-cloud-core = ">=1.6.0,<3.0.0dev" -google-resumable-media = ">=0.6.0,<3.0dev" +google-cloud-core = ">=2.4.1,<3.0.0dev" +google-resumable-media = ">=2.0.0,<3.0dev" packaging = ">=20.0.0" -python-dateutil = ">=2.7.2,<3.0dev" +python-dateutil = ">=2.7.3,<3.0dev" requests = ">=2.21.0,<3.0.0dev" [package.extras] -all = ["Shapely (>=1.8.4,<3.0.0dev)", "db-dtypes (>=0.3.0,<2.0.0dev)", "geopandas (>=0.9.0,<1.0dev)", "google-cloud-bigquery-storage (>=2.6.0,<3.0.0dev)", "grpcio (>=1.47.0,<2.0dev)", "grpcio (>=1.49.1,<2.0dev)", "importlib-metadata (>=1.0.0)", "ipykernel (>=6.0.0)", "ipython (>=7.23.1,!=8.1.0)", "ipywidgets (>=7.7.0)", "opentelemetry-api (>=1.1.0)", "opentelemetry-instrumentation (>=0.20b0)", "opentelemetry-sdk (>=1.1.0)", "pandas (>=1.1.0)", "proto-plus (>=1.15.0,<2.0.0dev)", "protobuf (>=3.19.5,!=3.20.0,!=3.20.1,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5,<5.0.0dev)", "pyarrow (>=3.0.0)", "tqdm (>=4.7.4,<5.0.0dev)"] -bigquery-v2 = ["proto-plus (>=1.15.0,<2.0.0dev)", "protobuf (>=3.19.5,!=3.20.0,!=3.20.1,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5,<5.0.0dev)"] +all = ["Shapely (>=1.8.4,<3.0.0dev)", "bigquery-magics (>=0.1.0)", "db-dtypes (>=0.3.0,<2.0.0dev)", "geopandas (>=0.9.0,<1.0dev)", "google-cloud-bigquery-storage (>=2.6.0,<3.0.0dev)", "grpcio (>=1.47.0,<2.0dev)", "grpcio (>=1.49.1,<2.0dev)", "importlib-metadata (>=1.0.0)", "ipykernel (>=6.0.0)", "ipywidgets (>=7.7.0)", "opentelemetry-api (>=1.1.0)", "opentelemetry-instrumentation (>=0.20b0)", "opentelemetry-sdk (>=1.1.0)", "pandas (>=1.1.0)", "proto-plus (>=1.22.3,<2.0.0dev)", "protobuf (>=3.20.2,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5,<6.0.0dev)", "pyarrow (>=3.0.0)", "tqdm (>=4.7.4,<5.0.0dev)"] +bigquery-v2 = ["proto-plus (>=1.22.3,<2.0.0dev)", "protobuf (>=3.20.2,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5,<6.0.0dev)"] bqstorage = ["google-cloud-bigquery-storage (>=2.6.0,<3.0.0dev)", "grpcio (>=1.47.0,<2.0dev)", "grpcio (>=1.49.1,<2.0dev)", "pyarrow (>=3.0.0)"] geopandas = ["Shapely (>=1.8.4,<3.0.0dev)", "geopandas (>=0.9.0,<1.0dev)"] -ipython = ["ipykernel (>=6.0.0)", "ipython (>=7.23.1,!=8.1.0)"] +ipython = ["bigquery-magics (>=0.1.0)"] ipywidgets = ["ipykernel (>=6.0.0)", "ipywidgets (>=7.7.0)"] opentelemetry = ["opentelemetry-api (>=1.1.0)", "opentelemetry-instrumentation (>=0.20b0)", "opentelemetry-sdk (>=1.1.0)"] pandas = ["db-dtypes (>=0.3.0,<2.0.0dev)", "importlib-metadata (>=1.0.0)", "pandas (>=1.1.0)", "pyarrow (>=3.0.0)"] @@ -1416,13 +1625,13 @@ grpc = ["grpcio (>=1.38.0,<2.0dev)", "grpcio-status (>=1.38.0,<2.0.dev0)"] [[package]] name = "google-cloud-dataproc" -version = "5.10.1" +version = "5.15.0" description = "Google Cloud Dataproc API client library" optional = false python-versions = ">=3.7" files = [ - {file = "google-cloud-dataproc-5.10.1.tar.gz", hash = "sha256:f3f0f0f3933328e80273774540368432550e296c255928657069a31a2de01c39"}, - {file = "google_cloud_dataproc-5.10.1-py2.py3-none-any.whl", hash = "sha256:28b763c9b019ca7d7c3e917ade04647c00494e77d4e682ca221d53e8d36f70af"}, + {file = "google_cloud_dataproc-5.15.0-py2.py3-none-any.whl", hash = "sha256:14dfcf327fa1c2ede3601fbbc1d559ace43682481aef42a182fb158af876c083"}, + {file = "google_cloud_dataproc-5.15.0.tar.gz", hash = "sha256:010e335368d0f47963643e323be03916d3e8556b772acbe50215fd54f156f91f"}, ] [package.dependencies] @@ -1434,13 +1643,13 @@ protobuf = ">=3.20.2,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4 [[package]] name = "google-cloud-secret-manager" -version = "2.20.0" +version = "2.21.0" description = "Google Cloud Secret Manager API client library" optional = false python-versions = ">=3.7" files = [ - {file = "google-cloud-secret-manager-2.20.0.tar.gz", hash = "sha256:a086a7413aaf4fffbd1c4fe9229ef0ce9bcf48f5a8df5b449c4a32deb5a2cfde"}, - {file = "google_cloud_secret_manager-2.20.0-py2.py3-none-any.whl", hash = "sha256:c20bf22e59d220c51aa84a1db3411b14b83aa71f788fae8d273c03a4bf3e77ed"}, + {file = "google_cloud_secret_manager-2.21.0-py2.py3-none-any.whl", hash = "sha256:b7fed5c2f3be5e10d94053ea3a7c6a7c5813d38da39c678ef6c1137d6e25a310"}, + {file = "google_cloud_secret_manager-2.21.0.tar.gz", hash = "sha256:d1ae84ecf98cfc319c9a3f1012355cebd19317b662cc9dff1a2c36234580807b"}, ] [package.dependencies] @@ -1448,17 +1657,17 @@ google-api-core = {version = ">=1.34.1,<2.0.dev0 || >=2.11.dev0,<3.0.0dev", extr google-auth = ">=2.14.1,<2.24.0 || >2.24.0,<2.25.0 || >2.25.0,<3.0.0dev" grpc-google-iam-v1 = ">=0.12.4,<1.0.0dev" proto-plus = ">=1.22.3,<2.0.0dev" -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" +protobuf = ">=3.20.2,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<6.0.0dev" [[package]] name = "google-cloud-storage" -version = "2.17.0" +version = "2.18.2" description = "Google Cloud Storage API client library" optional = false python-versions = ">=3.7" files = [ - {file = "google-cloud-storage-2.17.0.tar.gz", hash = "sha256:49378abff54ef656b52dca5ef0f2eba9aa83dc2b2c72c78714b03a1a95fe9388"}, - {file = "google_cloud_storage-2.17.0-py2.py3-none-any.whl", hash = "sha256:5b393bc766b7a3bc6f5407b9e665b2450d36282614b7945e570b3480a456d1e1"}, + {file = "google_cloud_storage-2.18.2-py2.py3-none-any.whl", hash = "sha256:97a4d45c368b7d401ed48c4fdfe86e1e1cb96401c9e199e419d289e2c0370166"}, + {file = "google_cloud_storage-2.18.2.tar.gz", hash = "sha256:aaf7acd70cdad9f274d29332673fcab98708d0e1f4dceb5a5356aaef06af4d99"}, ] [package.dependencies] @@ -1466,87 +1675,47 @@ google-api-core = ">=2.15.0,<3.0.0dev" google-auth = ">=2.26.1,<3.0dev" google-cloud-core = ">=2.3.0,<3.0dev" google-crc32c = ">=1.0,<2.0dev" -google-resumable-media = ">=2.6.0" +google-resumable-media = ">=2.7.2" requests = ">=2.18.0,<3.0.0dev" [package.extras] -protobuf = ["protobuf (<5.0.0dev)"] +protobuf = ["protobuf (<6.0.0dev)"] +tracing = ["opentelemetry-api (>=1.1.0)"] [[package]] name = "google-crc32c" -version = "1.5.0" +version = "1.6.0" description = "A python wrapper of the C library 'Google CRC32C'" optional = false -python-versions = ">=3.7" +python-versions = ">=3.9" files = [ - {file = "google-crc32c-1.5.0.tar.gz", hash = "sha256:89284716bc6a5a415d4eaa11b1726d2d60a0cd12aadf5439828353662ede9dd7"}, - {file = "google_crc32c-1.5.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:596d1f98fc70232fcb6590c439f43b350cb762fb5d61ce7b0e9db4539654cc13"}, - {file = "google_crc32c-1.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:be82c3c8cfb15b30f36768797a640e800513793d6ae1724aaaafe5bf86f8f346"}, - {file = "google_crc32c-1.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:461665ff58895f508e2866824a47bdee72497b091c730071f2b7575d5762ab65"}, - {file = "google_crc32c-1.5.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e2096eddb4e7c7bdae4bd69ad364e55e07b8316653234a56552d9c988bd2d61b"}, - {file = "google_crc32c-1.5.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:116a7c3c616dd14a3de8c64a965828b197e5f2d121fedd2f8c5585c547e87b02"}, - {file = "google_crc32c-1.5.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:5829b792bf5822fd0a6f6eb34c5f81dd074f01d570ed7f36aa101d6fc7a0a6e4"}, - {file = "google_crc32c-1.5.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:64e52e2b3970bd891309c113b54cf0e4384762c934d5ae56e283f9a0afcd953e"}, - {file = "google_crc32c-1.5.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:02ebb8bf46c13e36998aeaad1de9b48f4caf545e91d14041270d9dca767b780c"}, - {file = "google_crc32c-1.5.0-cp310-cp310-win32.whl", hash = "sha256:2e920d506ec85eb4ba50cd4228c2bec05642894d4c73c59b3a2fe20346bd00ee"}, - {file = "google_crc32c-1.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:07eb3c611ce363c51a933bf6bd7f8e3878a51d124acfc89452a75120bc436289"}, - {file = "google_crc32c-1.5.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:cae0274952c079886567f3f4f685bcaf5708f0a23a5f5216fdab71f81a6c0273"}, - {file = "google_crc32c-1.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1034d91442ead5a95b5aaef90dbfaca8633b0247d1e41621d1e9f9db88c36298"}, - {file = "google_crc32c-1.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7c42c70cd1d362284289c6273adda4c6af8039a8ae12dc451dcd61cdabb8ab57"}, - {file = "google_crc32c-1.5.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8485b340a6a9e76c62a7dce3c98e5f102c9219f4cfbf896a00cf48caf078d438"}, - {file = "google_crc32c-1.5.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77e2fd3057c9d78e225fa0a2160f96b64a824de17840351b26825b0848022906"}, - {file = "google_crc32c-1.5.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f583edb943cf2e09c60441b910d6a20b4d9d626c75a36c8fcac01a6c96c01183"}, - {file = "google_crc32c-1.5.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:a1fd716e7a01f8e717490fbe2e431d2905ab8aa598b9b12f8d10abebb36b04dd"}, - {file = "google_crc32c-1.5.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:72218785ce41b9cfd2fc1d6a017dc1ff7acfc4c17d01053265c41a2c0cc39b8c"}, - {file = "google_crc32c-1.5.0-cp311-cp311-win32.whl", hash = "sha256:66741ef4ee08ea0b2cc3c86916ab66b6aef03768525627fd6a1b34968b4e3709"}, - {file = "google_crc32c-1.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:ba1eb1843304b1e5537e1fca632fa894d6f6deca8d6389636ee5b4797affb968"}, - {file = "google_crc32c-1.5.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:98cb4d057f285bd80d8778ebc4fde6b4d509ac3f331758fb1528b733215443ae"}, - {file = "google_crc32c-1.5.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fd8536e902db7e365f49e7d9029283403974ccf29b13fc7028b97e2295b33556"}, - {file = "google_crc32c-1.5.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:19e0a019d2c4dcc5e598cd4a4bc7b008546b0358bd322537c74ad47a5386884f"}, - {file = "google_crc32c-1.5.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:02c65b9817512edc6a4ae7c7e987fea799d2e0ee40c53ec573a692bee24de876"}, - {file = "google_crc32c-1.5.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6ac08d24c1f16bd2bf5eca8eaf8304812f44af5cfe5062006ec676e7e1d50afc"}, - {file = "google_crc32c-1.5.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:3359fc442a743e870f4588fcf5dcbc1bf929df1fad8fb9905cd94e5edb02e84c"}, - {file = "google_crc32c-1.5.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:1e986b206dae4476f41bcec1faa057851f3889503a70e1bdb2378d406223994a"}, - {file = "google_crc32c-1.5.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:de06adc872bcd8c2a4e0dc51250e9e65ef2ca91be023b9d13ebd67c2ba552e1e"}, - {file = "google_crc32c-1.5.0-cp37-cp37m-win32.whl", hash = "sha256:d3515f198eaa2f0ed49f8819d5732d70698c3fa37384146079b3799b97667a94"}, - {file = "google_crc32c-1.5.0-cp37-cp37m-win_amd64.whl", hash = "sha256:67b741654b851abafb7bc625b6d1cdd520a379074e64b6a128e3b688c3c04740"}, - {file = "google_crc32c-1.5.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:c02ec1c5856179f171e032a31d6f8bf84e5a75c45c33b2e20a3de353b266ebd8"}, - {file = "google_crc32c-1.5.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:edfedb64740750e1a3b16152620220f51d58ff1b4abceb339ca92e934775c27a"}, - {file = "google_crc32c-1.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:84e6e8cd997930fc66d5bb4fde61e2b62ba19d62b7abd7a69920406f9ecca946"}, - {file = "google_crc32c-1.5.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:024894d9d3cfbc5943f8f230e23950cd4906b2fe004c72e29b209420a1e6b05a"}, - {file = "google_crc32c-1.5.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:998679bf62b7fb599d2878aa3ed06b9ce688b8974893e7223c60db155f26bd8d"}, - {file = "google_crc32c-1.5.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:83c681c526a3439b5cf94f7420471705bbf96262f49a6fe546a6db5f687a3d4a"}, - {file = "google_crc32c-1.5.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:4c6fdd4fccbec90cc8a01fc00773fcd5fa28db683c116ee3cb35cd5da9ef6c37"}, - {file = "google_crc32c-1.5.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:5ae44e10a8e3407dbe138984f21e536583f2bba1be9491239f942c2464ac0894"}, - {file = "google_crc32c-1.5.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:37933ec6e693e51a5b07505bd05de57eee12f3e8c32b07da7e73669398e6630a"}, - {file = "google_crc32c-1.5.0-cp38-cp38-win32.whl", hash = "sha256:fe70e325aa68fa4b5edf7d1a4b6f691eb04bbccac0ace68e34820d283b5f80d4"}, - {file = "google_crc32c-1.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:74dea7751d98034887dbd821b7aae3e1d36eda111d6ca36c206c44478035709c"}, - {file = "google_crc32c-1.5.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c6c777a480337ac14f38564ac88ae82d4cd238bf293f0a22295b66eb89ffced7"}, - {file = "google_crc32c-1.5.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:759ce4851a4bb15ecabae28f4d2e18983c244eddd767f560165563bf9aefbc8d"}, - {file = "google_crc32c-1.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f13cae8cc389a440def0c8c52057f37359014ccbc9dc1f0827936bcd367c6100"}, - {file = "google_crc32c-1.5.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e560628513ed34759456a416bf86b54b2476c59144a9138165c9a1575801d0d9"}, - {file = "google_crc32c-1.5.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1674e4307fa3024fc897ca774e9c7562c957af85df55efe2988ed9056dc4e57"}, - {file = "google_crc32c-1.5.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:278d2ed7c16cfc075c91378c4f47924c0625f5fc84b2d50d921b18b7975bd210"}, - {file = "google_crc32c-1.5.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d5280312b9af0976231f9e317c20e4a61cd2f9629b7bfea6a693d1878a264ebd"}, - {file = "google_crc32c-1.5.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:8b87e1a59c38f275c0e3676fc2ab6d59eccecfd460be267ac360cc31f7bcde96"}, - {file = "google_crc32c-1.5.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7c074fece789b5034b9b1404a1f8208fc2d4c6ce9decdd16e8220c5a793e6f61"}, - {file = "google_crc32c-1.5.0-cp39-cp39-win32.whl", hash = "sha256:7f57f14606cd1dd0f0de396e1e53824c371e9544a822648cd76c034d209b559c"}, - {file = "google_crc32c-1.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:a2355cba1f4ad8b6988a4ca3feed5bff33f6af2d7f134852cf279c2aebfde541"}, - {file = "google_crc32c-1.5.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:f314013e7dcd5cf45ab1945d92e713eec788166262ae8deb2cfacd53def27325"}, - {file = "google_crc32c-1.5.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3b747a674c20a67343cb61d43fdd9207ce5da6a99f629c6e2541aa0e89215bcd"}, - {file = "google_crc32c-1.5.0-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8f24ed114432de109aa9fd317278518a5af2d31ac2ea6b952b2f7782b43da091"}, - {file = "google_crc32c-1.5.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8667b48e7a7ef66afba2c81e1094ef526388d35b873966d8a9a447974ed9178"}, - {file = "google_crc32c-1.5.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:1c7abdac90433b09bad6c43a43af253e688c9cfc1c86d332aed13f9a7c7f65e2"}, - {file = "google_crc32c-1.5.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:6f998db4e71b645350b9ac28a2167e6632c239963ca9da411523bb439c5c514d"}, - {file = "google_crc32c-1.5.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c99616c853bb585301df6de07ca2cadad344fd1ada6d62bb30aec05219c45d2"}, - {file = "google_crc32c-1.5.0-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2ad40e31093a4af319dadf503b2467ccdc8f67c72e4bcba97f8c10cb078207b5"}, - {file = "google_crc32c-1.5.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cd67cf24a553339d5062eff51013780a00d6f97a39ca062781d06b3a73b15462"}, - {file = "google_crc32c-1.5.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:398af5e3ba9cf768787eef45c803ff9614cc3e22a5b2f7d7ae116df8b11e3314"}, - {file = "google_crc32c-1.5.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:b1f8133c9a275df5613a451e73f36c2aea4fe13c5c8997e22cf355ebd7bd0728"}, - {file = "google_crc32c-1.5.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9ba053c5f50430a3fcfd36f75aff9caeba0440b2d076afdb79a318d6ca245f88"}, - {file = "google_crc32c-1.5.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:272d3892a1e1a2dbc39cc5cde96834c236d5327e2122d3aaa19f6614531bb6eb"}, - {file = "google_crc32c-1.5.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:635f5d4dd18758a1fbd1049a8e8d2fee4ffed124462d837d1a02a0e009c3ab31"}, - {file = "google_crc32c-1.5.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:c672d99a345849301784604bfeaeba4db0c7aae50b95be04dd651fd2a7310b93"}, + {file = "google_crc32c-1.6.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:5bcc90b34df28a4b38653c36bb5ada35671ad105c99cfe915fb5bed7ad6924aa"}, + {file = "google_crc32c-1.6.0-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:d9e9913f7bd69e093b81da4535ce27af842e7bf371cde42d1ae9e9bd382dc0e9"}, + {file = "google_crc32c-1.6.0-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a184243544811e4a50d345838a883733461e67578959ac59964e43cca2c791e7"}, + {file = "google_crc32c-1.6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:236c87a46cdf06384f614e9092b82c05f81bd34b80248021f729396a78e55d7e"}, + {file = "google_crc32c-1.6.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ebab974b1687509e5c973b5c4b8b146683e101e102e17a86bd196ecaa4d099fc"}, + {file = "google_crc32c-1.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:50cf2a96da226dcbff8671233ecf37bf6e95de98b2a2ebadbfdf455e6d05df42"}, + {file = "google_crc32c-1.6.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:f7a1fc29803712f80879b0806cb83ab24ce62fc8daf0569f2204a0cfd7f68ed4"}, + {file = "google_crc32c-1.6.0-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:40b05ab32a5067525670880eb5d169529089a26fe35dce8891127aeddc1950e8"}, + {file = "google_crc32c-1.6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9e4b426c3702f3cd23b933436487eb34e01e00327fac20c9aebb68ccf34117d"}, + {file = "google_crc32c-1.6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51c4f54dd8c6dfeb58d1df5e4f7f97df8abf17a36626a217f169893d1d7f3e9f"}, + {file = "google_crc32c-1.6.0-cp311-cp311-win_amd64.whl", hash = "sha256:bb8b3c75bd157010459b15222c3fd30577042a7060e29d42dabce449c087f2b3"}, + {file = "google_crc32c-1.6.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:ed767bf4ba90104c1216b68111613f0d5926fb3780660ea1198fc469af410e9d"}, + {file = "google_crc32c-1.6.0-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:62f6d4a29fea082ac4a3c9be5e415218255cf11684ac6ef5488eea0c9132689b"}, + {file = "google_crc32c-1.6.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c87d98c7c4a69066fd31701c4e10d178a648c2cac3452e62c6b24dc51f9fcc00"}, + {file = "google_crc32c-1.6.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd5e7d2445d1a958c266bfa5d04c39932dc54093fa391736dbfdb0f1929c1fb3"}, + {file = "google_crc32c-1.6.0-cp312-cp312-win_amd64.whl", hash = "sha256:7aec8e88a3583515f9e0957fe4f5f6d8d4997e36d0f61624e70469771584c760"}, + {file = "google_crc32c-1.6.0-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:e2806553238cd076f0a55bddab37a532b53580e699ed8e5606d0de1f856b5205"}, + {file = "google_crc32c-1.6.0-cp39-cp39-macosx_12_0_x86_64.whl", hash = "sha256:bb0966e1c50d0ef5bc743312cc730b533491d60585a9a08f897274e57c3f70e0"}, + {file = "google_crc32c-1.6.0-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:386122eeaaa76951a8196310432c5b0ef3b53590ef4c317ec7588ec554fec5d2"}, + {file = "google_crc32c-1.6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d2952396dc604544ea7476b33fe87faedc24d666fb0c2d5ac971a2b9576ab871"}, + {file = "google_crc32c-1.6.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:35834855408429cecf495cac67ccbab802de269e948e27478b1e47dfb6465e57"}, + {file = "google_crc32c-1.6.0-cp39-cp39-win_amd64.whl", hash = "sha256:d8797406499f28b5ef791f339594b0b5fdedf54e203b5066675c406ba69d705c"}, + {file = "google_crc32c-1.6.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:48abd62ca76a2cbe034542ed1b6aee851b6f28aaca4e6551b5599b6f3ef175cc"}, + {file = "google_crc32c-1.6.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18e311c64008f1f1379158158bb3f0c8d72635b9eb4f9545f8cf990c5668e59d"}, + {file = "google_crc32c-1.6.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05e2d8c9a2f853ff116db9706b4a27350587f341eda835f46db3c0a8c8ce2f24"}, + {file = "google_crc32c-1.6.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:91ca8145b060679ec9176e6de4f89b07363d6805bd4760631ef254905503598d"}, + {file = "google_crc32c-1.6.0.tar.gz", hash = "sha256:6eceb6ad197656a1ff49ebfbbfa870678c75be4344feb35ac1edf694309413dc"}, ] [package.extras] @@ -1554,13 +1723,13 @@ testing = ["pytest"] [[package]] name = "google-resumable-media" -version = "2.7.1" +version = "2.7.2" description = "Utilities for Google Media Downloads and Resumable Uploads" optional = false python-versions = ">=3.7" files = [ - {file = "google-resumable-media-2.7.1.tar.gz", hash = "sha256:eae451a7b2e2cdbaaa0fd2eb00cc8a1ee5e95e16b55597359cbc3d27d7d90e33"}, - {file = "google_resumable_media-2.7.1-py2.py3-none-any.whl", hash = "sha256:103ebc4ba331ab1bfdac0250f8033627a2cd7cde09e7ccff9181e31ba4315b2c"}, + {file = "google_resumable_media-2.7.2-py2.py3-none-any.whl", hash = "sha256:3ce7551e9fe6d99e9a126101d2536612bb73486721951e9562fee0f90c6ababa"}, + {file = "google_resumable_media-2.7.2.tar.gz", hash = "sha256:5280aed4629f2b60b847b0d42f9857fd4935c11af266744df33d8074cae92fe0"}, ] [package.dependencies] @@ -1572,31 +1741,31 @@ requests = ["requests (>=2.18.0,<3.0.0dev)"] [[package]] name = "googleapis-common-protos" -version = "1.63.1" +version = "1.65.0" description = "Common protobufs used in Google APIs" optional = false python-versions = ">=3.7" files = [ - {file = "googleapis-common-protos-1.63.1.tar.gz", hash = "sha256:c6442f7a0a6b2a80369457d79e6672bb7dcbaab88e0848302497e3ec80780a6a"}, - {file = "googleapis_common_protos-1.63.1-py2.py3-none-any.whl", hash = "sha256:0e1c2cdfcbc354b76e4a211a35ea35d6926a835cba1377073c4861db904a1877"}, + {file = "googleapis_common_protos-1.65.0-py2.py3-none-any.whl", hash = "sha256:2972e6c496f435b92590fd54045060867f3fe9be2c82ab148fc8885035479a63"}, + {file = "googleapis_common_protos-1.65.0.tar.gz", hash = "sha256:334a29d07cddc3aa01dee4988f9afd9b2916ee2ff49d6b757155dc0d197852c0"}, ] [package.dependencies] grpcio = {version = ">=1.44.0,<2.0.0.dev0", optional = true, markers = "extra == \"grpc\""} -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<6.0.0.dev0" +protobuf = ">=3.20.2,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<6.0.0.dev0" [package.extras] grpc = ["grpcio (>=1.44.0,<2.0.0.dev0)"] [[package]] name = "griffe" -version = "1.2.0" +version = "1.5.1" description = "Signatures for entire Python programs. Extract the structure, the frame, the skeleton of your project, to generate API documentation or find breaking changes in your API." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "griffe-1.2.0-py3-none-any.whl", hash = "sha256:a8b2fcb1ecdc5a412e646b0b4375eb20a5d2eac3a11dd8c10c56967a4097663c"}, - {file = "griffe-1.2.0.tar.gz", hash = "sha256:1c9f6ef7455930f3f9b0c4145a961c90385d1e2cbc496f7796fbff560ec60d31"}, + {file = "griffe-1.5.1-py3-none-any.whl", hash = "sha256:ad6a7980f8c424c9102160aafa3bcdf799df0e75f7829d75af9ee5aef656f860"}, + {file = "griffe-1.5.1.tar.gz", hash = "sha256:72964f93e08c553257706d6cd2c42d1c172213feb48b2be386f243380b405d4b"}, ] [package.dependencies] @@ -1604,77 +1773,86 @@ colorama = ">=0.4" [[package]] name = "grpc-google-iam-v1" -version = "0.13.0" +version = "0.13.1" description = "IAM API client library" optional = false python-versions = ">=3.7" files = [ - {file = "grpc-google-iam-v1-0.13.0.tar.gz", hash = "sha256:fad318608b9e093258fbf12529180f400d1c44453698a33509cc6ecf005b294e"}, - {file = "grpc_google_iam_v1-0.13.0-py2.py3-none-any.whl", hash = "sha256:53902e2af7de8df8c1bd91373d9be55b0743ec267a7428ea638db3775becae89"}, + {file = "grpc-google-iam-v1-0.13.1.tar.gz", hash = "sha256:3ff4b2fd9d990965e410965253c0da6f66205d5a8291c4c31c6ebecca18a9001"}, + {file = "grpc_google_iam_v1-0.13.1-py2.py3-none-any.whl", hash = "sha256:c3e86151a981811f30d5e7330f271cee53e73bb87755e88cc3b6f0c7b5fe374e"}, ] [package.dependencies] googleapis-common-protos = {version = ">=1.56.0,<2.0.0dev", extras = ["grpc"]} grpcio = ">=1.44.0,<2.0.0dev" -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" +protobuf = ">=3.20.2,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<6.0.0dev" [[package]] name = "grpcio" -version = "1.64.1" +version = "1.67.1" description = "HTTP/2-based RPC framework" optional = false python-versions = ">=3.8" files = [ - {file = "grpcio-1.64.1-cp310-cp310-linux_armv7l.whl", hash = "sha256:55697ecec192bc3f2f3cc13a295ab670f51de29884ca9ae6cd6247df55df2502"}, - {file = "grpcio-1.64.1-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:3b64ae304c175671efdaa7ec9ae2cc36996b681eb63ca39c464958396697daff"}, - {file = "grpcio-1.64.1-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:bac71b4b28bc9af61efcdc7630b166440bbfbaa80940c9a697271b5e1dabbc61"}, - {file = "grpcio-1.64.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6c024ffc22d6dc59000faf8ad781696d81e8e38f4078cb0f2630b4a3cf231a90"}, - {file = "grpcio-1.64.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e7cd5c1325f6808b8ae31657d281aadb2a51ac11ab081ae335f4f7fc44c1721d"}, - {file = "grpcio-1.64.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:0a2813093ddb27418a4c99f9b1c223fab0b053157176a64cc9db0f4557b69bd9"}, - {file = "grpcio-1.64.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2981c7365a9353f9b5c864595c510c983251b1ab403e05b1ccc70a3d9541a73b"}, - {file = "grpcio-1.64.1-cp310-cp310-win32.whl", hash = "sha256:1262402af5a511c245c3ae918167eca57342c72320dffae5d9b51840c4b2f86d"}, - {file = "grpcio-1.64.1-cp310-cp310-win_amd64.whl", hash = "sha256:19264fc964576ddb065368cae953f8d0514ecc6cb3da8903766d9fb9d4554c33"}, - {file = "grpcio-1.64.1-cp311-cp311-linux_armv7l.whl", hash = "sha256:58b1041e7c870bb30ee41d3090cbd6f0851f30ae4eb68228955d973d3efa2e61"}, - {file = "grpcio-1.64.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:bbc5b1d78a7822b0a84c6f8917faa986c1a744e65d762ef6d8be9d75677af2ca"}, - {file = "grpcio-1.64.1-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:5841dd1f284bd1b3d8a6eca3a7f062b06f1eec09b184397e1d1d43447e89a7ae"}, - {file = "grpcio-1.64.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8caee47e970b92b3dd948371230fcceb80d3f2277b3bf7fbd7c0564e7d39068e"}, - {file = "grpcio-1.64.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:73819689c169417a4f978e562d24f2def2be75739c4bed1992435d007819da1b"}, - {file = "grpcio-1.64.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:6503b64c8b2dfad299749cad1b595c650c91e5b2c8a1b775380fcf8d2cbba1e9"}, - {file = "grpcio-1.64.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1de403fc1305fd96cfa75e83be3dee8538f2413a6b1685b8452301c7ba33c294"}, - {file = "grpcio-1.64.1-cp311-cp311-win32.whl", hash = "sha256:d4d29cc612e1332237877dfa7fe687157973aab1d63bd0f84cf06692f04c0367"}, - {file = "grpcio-1.64.1-cp311-cp311-win_amd64.whl", hash = "sha256:5e56462b05a6f860b72f0fa50dca06d5b26543a4e88d0396259a07dc30f4e5aa"}, - {file = "grpcio-1.64.1-cp312-cp312-linux_armv7l.whl", hash = "sha256:4657d24c8063e6095f850b68f2d1ba3b39f2b287a38242dcabc166453e950c59"}, - {file = "grpcio-1.64.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:62b4e6eb7bf901719fce0ca83e3ed474ae5022bb3827b0a501e056458c51c0a1"}, - {file = "grpcio-1.64.1-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:ee73a2f5ca4ba44fa33b4d7d2c71e2c8a9e9f78d53f6507ad68e7d2ad5f64a22"}, - {file = "grpcio-1.64.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:198908f9b22e2672a998870355e226a725aeab327ac4e6ff3a1399792ece4762"}, - {file = "grpcio-1.64.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39b9d0acaa8d835a6566c640f48b50054f422d03e77e49716d4c4e8e279665a1"}, - {file = "grpcio-1.64.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:5e42634a989c3aa6049f132266faf6b949ec2a6f7d302dbb5c15395b77d757eb"}, - {file = "grpcio-1.64.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:b1a82e0b9b3022799c336e1fc0f6210adc019ae84efb7321d668129d28ee1efb"}, - {file = "grpcio-1.64.1-cp312-cp312-win32.whl", hash = "sha256:55260032b95c49bee69a423c2f5365baa9369d2f7d233e933564d8a47b893027"}, - {file = "grpcio-1.64.1-cp312-cp312-win_amd64.whl", hash = "sha256:c1a786ac592b47573a5bb7e35665c08064a5d77ab88a076eec11f8ae86b3e3f6"}, - {file = "grpcio-1.64.1-cp38-cp38-linux_armv7l.whl", hash = "sha256:a011ac6c03cfe162ff2b727bcb530567826cec85eb8d4ad2bfb4bd023287a52d"}, - {file = "grpcio-1.64.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:4d6dab6124225496010bd22690f2d9bd35c7cbb267b3f14e7a3eb05c911325d4"}, - {file = "grpcio-1.64.1-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:a5e771d0252e871ce194d0fdcafd13971f1aae0ddacc5f25615030d5df55c3a2"}, - {file = "grpcio-1.64.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2c3c1b90ab93fed424e454e93c0ed0b9d552bdf1b0929712b094f5ecfe7a23ad"}, - {file = "grpcio-1.64.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20405cb8b13fd779135df23fabadc53b86522d0f1cba8cca0e87968587f50650"}, - {file = "grpcio-1.64.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:0cc79c982ccb2feec8aad0e8fb0d168bcbca85bc77b080d0d3c5f2f15c24ea8f"}, - {file = "grpcio-1.64.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:a3a035c37ce7565b8f4f35ff683a4db34d24e53dc487e47438e434eb3f701b2a"}, - {file = "grpcio-1.64.1-cp38-cp38-win32.whl", hash = "sha256:1257b76748612aca0f89beec7fa0615727fd6f2a1ad580a9638816a4b2eb18fd"}, - {file = "grpcio-1.64.1-cp38-cp38-win_amd64.whl", hash = "sha256:0a12ddb1678ebc6a84ec6b0487feac020ee2b1659cbe69b80f06dbffdb249122"}, - {file = "grpcio-1.64.1-cp39-cp39-linux_armv7l.whl", hash = "sha256:75dbbf415026d2862192fe1b28d71f209e2fd87079d98470db90bebe57b33179"}, - {file = "grpcio-1.64.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e3d9f8d1221baa0ced7ec7322a981e28deb23749c76eeeb3d33e18b72935ab62"}, - {file = "grpcio-1.64.1-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:5f8b75f64d5d324c565b263c67dbe4f0af595635bbdd93bb1a88189fc62ed2e5"}, - {file = "grpcio-1.64.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c84ad903d0d94311a2b7eea608da163dace97c5fe9412ea311e72c3684925602"}, - {file = "grpcio-1.64.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:940e3ec884520155f68a3b712d045e077d61c520a195d1a5932c531f11883489"}, - {file = "grpcio-1.64.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f10193c69fc9d3d726e83bbf0f3d316f1847c3071c8c93d8090cf5f326b14309"}, - {file = "grpcio-1.64.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ac15b6c2c80a4d1338b04d42a02d376a53395ddf0ec9ab157cbaf44191f3ffdd"}, - {file = "grpcio-1.64.1-cp39-cp39-win32.whl", hash = "sha256:03b43d0ccf99c557ec671c7dede64f023c7da9bb632ac65dbc57f166e4970040"}, - {file = "grpcio-1.64.1-cp39-cp39-win_amd64.whl", hash = "sha256:ed6091fa0adcc7e4ff944090cf203a52da35c37a130efa564ded02b7aff63bcd"}, - {file = "grpcio-1.64.1.tar.gz", hash = "sha256:8d51dd1c59d5fa0f34266b80a3805ec29a1f26425c2a54736133f6d87fc4968a"}, + {file = "grpcio-1.67.1-cp310-cp310-linux_armv7l.whl", hash = "sha256:8b0341d66a57f8a3119b77ab32207072be60c9bf79760fa609c5609f2deb1f3f"}, + {file = "grpcio-1.67.1-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:f5a27dddefe0e2357d3e617b9079b4bfdc91341a91565111a21ed6ebbc51b22d"}, + {file = "grpcio-1.67.1-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:43112046864317498a33bdc4797ae6a268c36345a910de9b9c17159d8346602f"}, + {file = "grpcio-1.67.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c9b929f13677b10f63124c1a410994a401cdd85214ad83ab67cc077fc7e480f0"}, + {file = "grpcio-1.67.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e7d1797a8a3845437d327145959a2c0c47c05947c9eef5ff1a4c80e499dcc6fa"}, + {file = "grpcio-1.67.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:0489063974d1452436139501bf6b180f63d4977223ee87488fe36858c5725292"}, + {file = "grpcio-1.67.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:9fd042de4a82e3e7aca44008ee2fb5da01b3e5adb316348c21980f7f58adc311"}, + {file = "grpcio-1.67.1-cp310-cp310-win32.whl", hash = "sha256:638354e698fd0c6c76b04540a850bf1db27b4d2515a19fcd5cf645c48d3eb1ed"}, + {file = "grpcio-1.67.1-cp310-cp310-win_amd64.whl", hash = "sha256:608d87d1bdabf9e2868b12338cd38a79969eaf920c89d698ead08f48de9c0f9e"}, + {file = "grpcio-1.67.1-cp311-cp311-linux_armv7l.whl", hash = "sha256:7818c0454027ae3384235a65210bbf5464bd715450e30a3d40385453a85a70cb"}, + {file = "grpcio-1.67.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ea33986b70f83844cd00814cee4451055cd8cab36f00ac64a31f5bb09b31919e"}, + {file = "grpcio-1.67.1-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:c7a01337407dd89005527623a4a72c5c8e2894d22bead0895306b23c6695698f"}, + {file = "grpcio-1.67.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:80b866f73224b0634f4312a4674c1be21b2b4afa73cb20953cbbb73a6b36c3cc"}, + {file = "grpcio-1.67.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f9fff78ba10d4250bfc07a01bd6254a6d87dc67f9627adece85c0b2ed754fa96"}, + {file = "grpcio-1.67.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:8a23cbcc5bb11ea7dc6163078be36c065db68d915c24f5faa4f872c573bb400f"}, + {file = "grpcio-1.67.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1a65b503d008f066e994f34f456e0647e5ceb34cfcec5ad180b1b44020ad4970"}, + {file = "grpcio-1.67.1-cp311-cp311-win32.whl", hash = "sha256:e29ca27bec8e163dca0c98084040edec3bc49afd10f18b412f483cc68c712744"}, + {file = "grpcio-1.67.1-cp311-cp311-win_amd64.whl", hash = "sha256:786a5b18544622bfb1e25cc08402bd44ea83edfb04b93798d85dca4d1a0b5be5"}, + {file = "grpcio-1.67.1-cp312-cp312-linux_armv7l.whl", hash = "sha256:267d1745894200e4c604958da5f856da6293f063327cb049a51fe67348e4f953"}, + {file = "grpcio-1.67.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:85f69fdc1d28ce7cff8de3f9c67db2b0ca9ba4449644488c1e0303c146135ddb"}, + {file = "grpcio-1.67.1-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:f26b0b547eb8d00e195274cdfc63ce64c8fc2d3e2d00b12bf468ece41a0423a0"}, + {file = "grpcio-1.67.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4422581cdc628f77302270ff839a44f4c24fdc57887dc2a45b7e53d8fc2376af"}, + {file = "grpcio-1.67.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1d7616d2ded471231c701489190379e0c311ee0a6c756f3c03e6a62b95a7146e"}, + {file = "grpcio-1.67.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8a00efecde9d6fcc3ab00c13f816313c040a28450e5e25739c24f432fc6d3c75"}, + {file = "grpcio-1.67.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:699e964923b70f3101393710793289e42845791ea07565654ada0969522d0a38"}, + {file = "grpcio-1.67.1-cp312-cp312-win32.whl", hash = "sha256:4e7b904484a634a0fff132958dabdb10d63e0927398273917da3ee103e8d1f78"}, + {file = "grpcio-1.67.1-cp312-cp312-win_amd64.whl", hash = "sha256:5721e66a594a6c4204458004852719b38f3d5522082be9061d6510b455c90afc"}, + {file = "grpcio-1.67.1-cp313-cp313-linux_armv7l.whl", hash = "sha256:aa0162e56fd10a5547fac8774c4899fc3e18c1aa4a4759d0ce2cd00d3696ea6b"}, + {file = "grpcio-1.67.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:beee96c8c0b1a75d556fe57b92b58b4347c77a65781ee2ac749d550f2a365dc1"}, + {file = "grpcio-1.67.1-cp313-cp313-manylinux_2_17_aarch64.whl", hash = "sha256:a93deda571a1bf94ec1f6fcda2872dad3ae538700d94dc283c672a3b508ba3af"}, + {file = "grpcio-1.67.1-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0e6f255980afef598a9e64a24efce87b625e3e3c80a45162d111a461a9f92955"}, + {file = "grpcio-1.67.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e838cad2176ebd5d4a8bb03955138d6589ce9e2ce5d51c3ada34396dbd2dba8"}, + {file = "grpcio-1.67.1-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:a6703916c43b1d468d0756c8077b12017a9fcb6a1ef13faf49e67d20d7ebda62"}, + {file = "grpcio-1.67.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:917e8d8994eed1d86b907ba2a61b9f0aef27a2155bca6cbb322430fc7135b7bb"}, + {file = "grpcio-1.67.1-cp313-cp313-win32.whl", hash = "sha256:e279330bef1744040db8fc432becc8a727b84f456ab62b744d3fdb83f327e121"}, + {file = "grpcio-1.67.1-cp313-cp313-win_amd64.whl", hash = "sha256:fa0c739ad8b1996bd24823950e3cb5152ae91fca1c09cc791190bf1627ffefba"}, + {file = "grpcio-1.67.1-cp38-cp38-linux_armv7l.whl", hash = "sha256:178f5db771c4f9a9facb2ab37a434c46cb9be1a75e820f187ee3d1e7805c4f65"}, + {file = "grpcio-1.67.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0f3e49c738396e93b7ba9016e153eb09e0778e776df6090c1b8c91877cc1c426"}, + {file = "grpcio-1.67.1-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:24e8a26dbfc5274d7474c27759b54486b8de23c709d76695237515bc8b5baeab"}, + {file = "grpcio-1.67.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3b6c16489326d79ead41689c4b84bc40d522c9a7617219f4ad94bc7f448c5085"}, + {file = "grpcio-1.67.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:60e6a4dcf5af7bbc36fd9f81c9f372e8ae580870a9e4b6eafe948cd334b81cf3"}, + {file = "grpcio-1.67.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:95b5f2b857856ed78d72da93cd7d09b6db8ef30102e5e7fe0961fe4d9f7d48e8"}, + {file = "grpcio-1.67.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b49359977c6ec9f5d0573ea4e0071ad278ef905aa74e420acc73fd28ce39e9ce"}, + {file = "grpcio-1.67.1-cp38-cp38-win32.whl", hash = "sha256:f5b76ff64aaac53fede0cc93abf57894ab2a7362986ba22243d06218b93efe46"}, + {file = "grpcio-1.67.1-cp38-cp38-win_amd64.whl", hash = "sha256:804c6457c3cd3ec04fe6006c739579b8d35c86ae3298ffca8de57b493524b771"}, + {file = "grpcio-1.67.1-cp39-cp39-linux_armv7l.whl", hash = "sha256:a25bdea92b13ff4d7790962190bf6bf5c4639876e01c0f3dda70fc2769616335"}, + {file = "grpcio-1.67.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:cdc491ae35a13535fd9196acb5afe1af37c8237df2e54427be3eecda3653127e"}, + {file = "grpcio-1.67.1-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:85f862069b86a305497e74d0dc43c02de3d1d184fc2c180993aa8aa86fbd19b8"}, + {file = "grpcio-1.67.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ec74ef02010186185de82cc594058a3ccd8d86821842bbac9873fd4a2cf8be8d"}, + {file = "grpcio-1.67.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:01f616a964e540638af5130469451cf580ba8c7329f45ca998ab66e0c7dcdb04"}, + {file = "grpcio-1.67.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:299b3d8c4f790c6bcca485f9963b4846dd92cf6f1b65d3697145d005c80f9fe8"}, + {file = "grpcio-1.67.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:60336bff760fbb47d7e86165408126f1dded184448e9a4c892189eb7c9d3f90f"}, + {file = "grpcio-1.67.1-cp39-cp39-win32.whl", hash = "sha256:5ed601c4c6008429e3d247ddb367fe8c7259c355757448d7c1ef7bd4a6739e8e"}, + {file = "grpcio-1.67.1-cp39-cp39-win_amd64.whl", hash = "sha256:5db70d32d6703b89912af16d6d45d78406374a8b8ef0d28140351dd0ec610e98"}, + {file = "grpcio-1.67.1.tar.gz", hash = "sha256:3dc2ed4cabea4dc14d5e708c2b426205956077cc5de419b4d4079315017e9732"}, ] [package.extras] -protobuf = ["grpcio-tools (>=1.64.1)"] +protobuf = ["grpcio-tools (>=1.67.1)"] [[package]] name = "grpcio-status" @@ -1741,13 +1919,13 @@ uvloop = {version = ">=0.19.0,<1", markers = "sys_platform != \"win32\""} [[package]] name = "huggingface-hub" -version = "0.23.4" +version = "0.26.2" description = "Client library to download and publish models, datasets and other repos on the huggingface.co hub" optional = false python-versions = ">=3.8.0" files = [ - {file = "huggingface_hub-0.23.4-py3-none-any.whl", hash = "sha256:3a0b957aa87150addf0cc7bd71b4d954b78e749850e1e7fb29ebbd2db64ca037"}, - {file = "huggingface_hub-0.23.4.tar.gz", hash = "sha256:35d99016433900e44ae7efe1c209164a5a81dbbcd53a52f99c281dcd7ce22431"}, + {file = "huggingface_hub-0.26.2-py3-none-any.whl", hash = "sha256:98c2a5a8e786c7b2cb6fdeb2740893cba4d53e312572ed3d8afafda65b128c46"}, + {file = "huggingface_hub-0.26.2.tar.gz", hash = "sha256:b100d853465d965733964d123939ba287da60a547087783ddff8a323f340332b"}, ] [package.dependencies] @@ -1760,17 +1938,17 @@ tqdm = ">=4.42.1" typing-extensions = ">=3.7.4.3" [package.extras] -all = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "fastapi", "gradio", "jedi", "minijinja (>=1.0)", "mypy (==1.5.1)", "numpy", "pytest", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-rerunfailures", "pytest-vcr", "pytest-xdist", "ruff (>=0.3.0)", "soundfile", "types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "typing-extensions (>=4.8.0)", "urllib3 (<2.0)"] +all = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "fastapi", "gradio (>=4.0.0)", "jedi", "libcst (==1.4.0)", "mypy (==1.5.1)", "numpy", "pytest (>=8.1.1,<8.2.2)", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-mock", "pytest-rerunfailures", "pytest-vcr", "pytest-xdist", "ruff (>=0.5.0)", "soundfile", "types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "typing-extensions (>=4.8.0)", "urllib3 (<2.0)"] cli = ["InquirerPy (==0.3.4)"] -dev = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "fastapi", "gradio", "jedi", "minijinja (>=1.0)", "mypy (==1.5.1)", "numpy", "pytest", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-rerunfailures", "pytest-vcr", "pytest-xdist", "ruff (>=0.3.0)", "soundfile", "types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "typing-extensions (>=4.8.0)", "urllib3 (<2.0)"] +dev = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "fastapi", "gradio (>=4.0.0)", "jedi", "libcst (==1.4.0)", "mypy (==1.5.1)", "numpy", "pytest (>=8.1.1,<8.2.2)", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-mock", "pytest-rerunfailures", "pytest-vcr", "pytest-xdist", "ruff (>=0.5.0)", "soundfile", "types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "typing-extensions (>=4.8.0)", "urllib3 (<2.0)"] fastai = ["fastai (>=2.4)", "fastcore (>=1.3.27)", "toml"] hf-transfer = ["hf-transfer (>=0.1.4)"] -inference = ["aiohttp", "minijinja (>=1.0)"] -quality = ["mypy (==1.5.1)", "ruff (>=0.3.0)"] +inference = ["aiohttp"] +quality = ["libcst (==1.4.0)", "mypy (==1.5.1)", "ruff (>=0.5.0)"] tensorflow = ["graphviz", "pydot", "tensorflow"] tensorflow-testing = ["keras (<3.0)", "tensorflow"] -testing = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "fastapi", "gradio", "jedi", "minijinja (>=1.0)", "numpy", "pytest", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-rerunfailures", "pytest-vcr", "pytest-xdist", "soundfile", "urllib3 (<2.0)"] -torch = ["safetensors", "torch"] +testing = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "fastapi", "gradio (>=4.0.0)", "jedi", "numpy", "pytest (>=8.1.1,<8.2.2)", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-mock", "pytest-rerunfailures", "pytest-vcr", "pytest-xdist", "soundfile", "urllib3 (<2.0)"] +torch = ["safetensors[torch]", "torch"] typing = ["types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "typing-extensions (>=4.8.0)"] [[package]] @@ -1805,13 +1983,13 @@ packaging = "*" [[package]] name = "identify" -version = "2.5.36" +version = "2.6.1" description = "File identification library for Python" optional = false python-versions = ">=3.8" files = [ - {file = "identify-2.5.36-py2.py3-none-any.whl", hash = "sha256:37d93f380f4de590500d9dba7db359d0d3da95ffe7f9de1753faa159e71e7dfa"}, - {file = "identify-2.5.36.tar.gz", hash = "sha256:e5e00f54165f9047fbebeb4a560f9acfb8af4c88232be60a488e9b68d122745d"}, + {file = "identify-2.6.1-py2.py3-none-any.whl", hash = "sha256:53863bcac7caf8d2ed85bd20312ea5dcfc22226800f6d6881f232d861db5a8f0"}, + {file = "identify-2.6.1.tar.gz", hash = "sha256:91478c5fb7c3aac5ff7bf9b4344f803843dc586832d5f110d672b19aa1984c98"}, ] [package.extras] @@ -1819,15 +1997,18 @@ license = ["ukkonen"] [[package]] name = "idna" -version = "3.7" +version = "3.10" description = "Internationalized Domain Names in Applications (IDNA)" optional = false -python-versions = ">=3.5" +python-versions = ">=3.6" files = [ - {file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"}, - {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"}, + {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, + {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, ] +[package.extras] +all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] + [[package]] name = "iniconfig" version = "2.0.0" @@ -1866,13 +2047,13 @@ tests = ["coverage[toml]", "pytest", "pytest-cov", "pytest-mock"] [[package]] name = "ipykernel" -version = "6.29.4" +version = "6.29.5" description = "IPython Kernel for Jupyter" optional = false python-versions = ">=3.8" files = [ - {file = "ipykernel-6.29.4-py3-none-any.whl", hash = "sha256:1181e653d95c6808039c509ef8e67c4126b3b3af7781496c7cbfb5ed938a27da"}, - {file = "ipykernel-6.29.4.tar.gz", hash = "sha256:3d44070060f9475ac2092b760123fadf105d2e2493c24848b6691a7c4f42af5c"}, + {file = "ipykernel-6.29.5-py3-none-any.whl", hash = "sha256:afdb66ba5aa354b09b91379bac28ae4afebbb30e8b39510c9690afb7a10421b5"}, + {file = "ipykernel-6.29.5.tar.gz", hash = "sha256:f093a22c4a40f8828f8e330a9c297cb93dcab13bd9678ded6de8e5cf81c56215"}, ] [package.dependencies] @@ -1937,18 +2118,15 @@ test-extra = ["curio", "ipython[test]", "matplotlib (!=3.2.0)", "nbformat", "num [[package]] name = "isodate" -version = "0.6.1" +version = "0.7.2" description = "An ISO 8601 date/time/duration parser and formatter" optional = false -python-versions = "*" +python-versions = ">=3.7" files = [ - {file = "isodate-0.6.1-py2.py3-none-any.whl", hash = "sha256:0751eece944162659049d35f4f549ed815792b38793f07cf73381c1c87cbed96"}, - {file = "isodate-0.6.1.tar.gz", hash = "sha256:48c5881de7e8b0a0d648cb024c8062dc84e7b840ed81e864c7614fd3c127bde9"}, + {file = "isodate-0.7.2-py3-none-any.whl", hash = "sha256:28009937d8031054830160fce6d409ed342816b543597cece116d966c6d99e15"}, + {file = "isodate-0.7.2.tar.gz", hash = "sha256:4cd1aa0f43ca76f4a6c6c0292a85f40b35ec2e43e315b59f06e6d32171a953e6"}, ] -[package.dependencies] -six = "*" - [[package]] name = "isort" version = "5.13.2" @@ -2037,13 +2215,13 @@ files = [ [[package]] name = "jproperties" -version = "2.1.1" +version = "2.1.2" description = "Java Property file parser and writer for Python" optional = false -python-versions = "*" +python-versions = ">=2.7" files = [ - {file = "jproperties-2.1.1-py2.py3-none-any.whl", hash = "sha256:4dfcd7cab56d9c79bce4453f7ca9ffbe0ff0574ddcf1c2a99a8646df60634664"}, - {file = "jproperties-2.1.1.tar.gz", hash = "sha256:40b71124e8d257e8954899a91cd2d5c0f72e0f67f1b72048a5ba264567604f29"}, + {file = "jproperties-2.1.2-py2.py3-none-any.whl", hash = "sha256:4108e868353a9f4a12bb86a92df5462d0e18d00119169533972ce473029be79a"}, + {file = "jproperties-2.1.2.tar.gz", hash = "sha256:036fcd52c10a8a1c21e6fa2a1c292c93892e759b76490acc4809213a36ddc329"}, ] [package.dependencies] @@ -2051,13 +2229,13 @@ six = ">=1.13,<2.0" [[package]] name = "jupyter-client" -version = "8.6.2" +version = "8.6.3" description = "Jupyter protocol implementation and client libraries" optional = false python-versions = ">=3.8" files = [ - {file = "jupyter_client-8.6.2-py3-none-any.whl", hash = "sha256:50cbc5c66fd1b8f65ecb66bc490ab73217993632809b6e505687de18e9dea39f"}, - {file = "jupyter_client-8.6.2.tar.gz", hash = "sha256:2bda14d55ee5ba58552a8c53ae43d215ad9868853489213f37da060ced54d8df"}, + {file = "jupyter_client-8.6.3-py3-none-any.whl", hash = "sha256:e8a19cc986cc45905ac3362915f410f3af85424b4c0905e94fa5f2cb08e8f23f"}, + {file = "jupyter_client-8.6.3.tar.gz", hash = "sha256:35b3a0947c4a6e9d589eb97d7d4cd5e90f910ee73101611f01283732bd6d9419"}, ] [package.dependencies] @@ -2091,6 +2269,159 @@ traitlets = ">=5.3" docs = ["myst-parser", "pydata-sphinx-theme", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-spelling", "traitlets"] test = ["ipykernel", "pre-commit", "pytest (<8)", "pytest-cov", "pytest-timeout"] +[[package]] +name = "kiwisolver" +version = "1.4.7" +description = "A fast implementation of the Cassowary constraint solver" +optional = false +python-versions = ">=3.8" +files = [ + {file = "kiwisolver-1.4.7-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:8a9c83f75223d5e48b0bc9cb1bf2776cf01563e00ade8775ffe13b0b6e1af3a6"}, + {file = "kiwisolver-1.4.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:58370b1ffbd35407444d57057b57da5d6549d2d854fa30249771775c63b5fe17"}, + {file = "kiwisolver-1.4.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:aa0abdf853e09aff551db11fce173e2177d00786c688203f52c87ad7fcd91ef9"}, + {file = "kiwisolver-1.4.7-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:8d53103597a252fb3ab8b5845af04c7a26d5e7ea8122303dd7a021176a87e8b9"}, + {file = "kiwisolver-1.4.7-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:88f17c5ffa8e9462fb79f62746428dd57b46eb931698e42e990ad63103f35e6c"}, + {file = "kiwisolver-1.4.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88a9ca9c710d598fd75ee5de59d5bda2684d9db36a9f50b6125eaea3969c2599"}, + {file = "kiwisolver-1.4.7-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f4d742cb7af1c28303a51b7a27aaee540e71bb8e24f68c736f6f2ffc82f2bf05"}, + {file = "kiwisolver-1.4.7-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e28c7fea2196bf4c2f8d46a0415c77a1c480cc0724722f23d7410ffe9842c407"}, + {file = "kiwisolver-1.4.7-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e968b84db54f9d42046cf154e02911e39c0435c9801681e3fc9ce8a3c4130278"}, + {file = "kiwisolver-1.4.7-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0c18ec74c0472de033e1bebb2911c3c310eef5649133dd0bedf2a169a1b269e5"}, + {file = "kiwisolver-1.4.7-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:8f0ea6da6d393d8b2e187e6a5e3fb81f5862010a40c3945e2c6d12ae45cfb2ad"}, + {file = "kiwisolver-1.4.7-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:f106407dda69ae456dd1227966bf445b157ccc80ba0dff3802bb63f30b74e895"}, + {file = "kiwisolver-1.4.7-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:84ec80df401cfee1457063732d90022f93951944b5b58975d34ab56bb150dfb3"}, + {file = "kiwisolver-1.4.7-cp310-cp310-win32.whl", hash = "sha256:71bb308552200fb2c195e35ef05de12f0c878c07fc91c270eb3d6e41698c3bcc"}, + {file = "kiwisolver-1.4.7-cp310-cp310-win_amd64.whl", hash = "sha256:44756f9fd339de0fb6ee4f8c1696cfd19b2422e0d70b4cefc1cc7f1f64045a8c"}, + {file = "kiwisolver-1.4.7-cp310-cp310-win_arm64.whl", hash = "sha256:78a42513018c41c2ffd262eb676442315cbfe3c44eed82385c2ed043bc63210a"}, + {file = "kiwisolver-1.4.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d2b0e12a42fb4e72d509fc994713d099cbb15ebf1103545e8a45f14da2dfca54"}, + {file = "kiwisolver-1.4.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2a8781ac3edc42ea4b90bc23e7d37b665d89423818e26eb6df90698aa2287c95"}, + {file = "kiwisolver-1.4.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:46707a10836894b559e04b0fd143e343945c97fd170d69a2d26d640b4e297935"}, + {file = "kiwisolver-1.4.7-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef97b8df011141c9b0f6caf23b29379f87dd13183c978a30a3c546d2c47314cb"}, + {file = "kiwisolver-1.4.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ab58c12a2cd0fc769089e6d38466c46d7f76aced0a1f54c77652446733d2d02"}, + {file = "kiwisolver-1.4.7-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:803b8e1459341c1bb56d1c5c010406d5edec8a0713a0945851290a7930679b51"}, + {file = "kiwisolver-1.4.7-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f9a9e8a507420fe35992ee9ecb302dab68550dedc0da9e2880dd88071c5fb052"}, + {file = "kiwisolver-1.4.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18077b53dc3bb490e330669a99920c5e6a496889ae8c63b58fbc57c3d7f33a18"}, + {file = "kiwisolver-1.4.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6af936f79086a89b3680a280c47ea90b4df7047b5bdf3aa5c524bbedddb9e545"}, + {file = "kiwisolver-1.4.7-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:3abc5b19d24af4b77d1598a585b8a719beb8569a71568b66f4ebe1fb0449460b"}, + {file = "kiwisolver-1.4.7-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:933d4de052939d90afbe6e9d5273ae05fb836cc86c15b686edd4b3560cc0ee36"}, + {file = "kiwisolver-1.4.7-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:65e720d2ab2b53f1f72fb5da5fb477455905ce2c88aaa671ff0a447c2c80e8e3"}, + {file = "kiwisolver-1.4.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3bf1ed55088f214ba6427484c59553123fdd9b218a42bbc8c6496d6754b1e523"}, + {file = "kiwisolver-1.4.7-cp311-cp311-win32.whl", hash = "sha256:4c00336b9dd5ad96d0a558fd18a8b6f711b7449acce4c157e7343ba92dd0cf3d"}, + {file = "kiwisolver-1.4.7-cp311-cp311-win_amd64.whl", hash = "sha256:929e294c1ac1e9f615c62a4e4313ca1823ba37326c164ec720a803287c4c499b"}, + {file = "kiwisolver-1.4.7-cp311-cp311-win_arm64.whl", hash = "sha256:e33e8fbd440c917106b237ef1a2f1449dfbb9b6f6e1ce17c94cd6a1e0d438376"}, + {file = "kiwisolver-1.4.7-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:5360cc32706dab3931f738d3079652d20982511f7c0ac5711483e6eab08efff2"}, + {file = "kiwisolver-1.4.7-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:942216596dc64ddb25adb215c3c783215b23626f8d84e8eff8d6d45c3f29f75a"}, + {file = "kiwisolver-1.4.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:48b571ecd8bae15702e4f22d3ff6a0f13e54d3d00cd25216d5e7f658242065ee"}, + {file = "kiwisolver-1.4.7-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ad42ba922c67c5f219097b28fae965e10045ddf145d2928bfac2eb2e17673640"}, + {file = "kiwisolver-1.4.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:612a10bdae23404a72941a0fc8fa2660c6ea1217c4ce0dbcab8a8f6543ea9e7f"}, + {file = "kiwisolver-1.4.7-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9e838bba3a3bac0fe06d849d29772eb1afb9745a59710762e4ba3f4cb8424483"}, + {file = "kiwisolver-1.4.7-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:22f499f6157236c19f4bbbd472fa55b063db77a16cd74d49afe28992dff8c258"}, + {file = "kiwisolver-1.4.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:693902d433cf585133699972b6d7c42a8b9f8f826ebcaf0132ff55200afc599e"}, + {file = "kiwisolver-1.4.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4e77f2126c3e0b0d055f44513ed349038ac180371ed9b52fe96a32aa071a5107"}, + {file = "kiwisolver-1.4.7-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:657a05857bda581c3656bfc3b20e353c232e9193eb167766ad2dc58b56504948"}, + {file = "kiwisolver-1.4.7-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4bfa75a048c056a411f9705856abfc872558e33c055d80af6a380e3658766038"}, + {file = "kiwisolver-1.4.7-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:34ea1de54beef1c104422d210c47c7d2a4999bdecf42c7b5718fbe59a4cac383"}, + {file = "kiwisolver-1.4.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:90da3b5f694b85231cf93586dad5e90e2d71b9428f9aad96952c99055582f520"}, + {file = "kiwisolver-1.4.7-cp312-cp312-win32.whl", hash = "sha256:18e0cca3e008e17fe9b164b55735a325140a5a35faad8de92dd80265cd5eb80b"}, + {file = "kiwisolver-1.4.7-cp312-cp312-win_amd64.whl", hash = "sha256:58cb20602b18f86f83a5c87d3ee1c766a79c0d452f8def86d925e6c60fbf7bfb"}, + {file = "kiwisolver-1.4.7-cp312-cp312-win_arm64.whl", hash = "sha256:f5a8b53bdc0b3961f8b6125e198617c40aeed638b387913bf1ce78afb1b0be2a"}, + {file = "kiwisolver-1.4.7-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:2e6039dcbe79a8e0f044f1c39db1986a1b8071051efba3ee4d74f5b365f5226e"}, + {file = "kiwisolver-1.4.7-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a1ecf0ac1c518487d9d23b1cd7139a6a65bc460cd101ab01f1be82ecf09794b6"}, + {file = "kiwisolver-1.4.7-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7ab9ccab2b5bd5702ab0803676a580fffa2aa178c2badc5557a84cc943fcf750"}, + {file = "kiwisolver-1.4.7-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f816dd2277f8d63d79f9c8473a79fe54047bc0467754962840782c575522224d"}, + {file = "kiwisolver-1.4.7-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf8bcc23ceb5a1b624572a1623b9f79d2c3b337c8c455405ef231933a10da379"}, + {file = "kiwisolver-1.4.7-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dea0bf229319828467d7fca8c7c189780aa9ff679c94539eed7532ebe33ed37c"}, + {file = "kiwisolver-1.4.7-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c06a4c7cf15ec739ce0e5971b26c93638730090add60e183530d70848ebdd34"}, + {file = "kiwisolver-1.4.7-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:913983ad2deb14e66d83c28b632fd35ba2b825031f2fa4ca29675e665dfecbe1"}, + {file = "kiwisolver-1.4.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5337ec7809bcd0f424c6b705ecf97941c46279cf5ed92311782c7c9c2026f07f"}, + {file = "kiwisolver-1.4.7-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4c26ed10c4f6fa6ddb329a5120ba3b6db349ca192ae211e882970bfc9d91420b"}, + {file = "kiwisolver-1.4.7-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c619b101e6de2222c1fcb0531e1b17bbffbe54294bfba43ea0d411d428618c27"}, + {file = "kiwisolver-1.4.7-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:073a36c8273647592ea332e816e75ef8da5c303236ec0167196793eb1e34657a"}, + {file = "kiwisolver-1.4.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:3ce6b2b0231bda412463e152fc18335ba32faf4e8c23a754ad50ffa70e4091ee"}, + {file = "kiwisolver-1.4.7-cp313-cp313-win32.whl", hash = "sha256:f4c9aee212bc89d4e13f58be11a56cc8036cabad119259d12ace14b34476fd07"}, + {file = "kiwisolver-1.4.7-cp313-cp313-win_amd64.whl", hash = "sha256:8a3ec5aa8e38fc4c8af308917ce12c536f1c88452ce554027e55b22cbbfbff76"}, + {file = "kiwisolver-1.4.7-cp313-cp313-win_arm64.whl", hash = "sha256:76c8094ac20ec259471ac53e774623eb62e6e1f56cd8690c67ce6ce4fcb05650"}, + {file = "kiwisolver-1.4.7-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5d5abf8f8ec1f4e22882273c423e16cae834c36856cac348cfbfa68e01c40f3a"}, + {file = "kiwisolver-1.4.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:aeb3531b196ef6f11776c21674dba836aeea9d5bd1cf630f869e3d90b16cfade"}, + {file = "kiwisolver-1.4.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b7d755065e4e866a8086c9bdada157133ff466476a2ad7861828e17b6026e22c"}, + {file = "kiwisolver-1.4.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:08471d4d86cbaec61f86b217dd938a83d85e03785f51121e791a6e6689a3be95"}, + {file = "kiwisolver-1.4.7-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7bbfcb7165ce3d54a3dfbe731e470f65739c4c1f85bb1018ee912bae139e263b"}, + {file = "kiwisolver-1.4.7-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5d34eb8494bea691a1a450141ebb5385e4b69d38bb8403b5146ad279f4b30fa3"}, + {file = "kiwisolver-1.4.7-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9242795d174daa40105c1d86aba618e8eab7bf96ba8c3ee614da8302a9f95503"}, + {file = "kiwisolver-1.4.7-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a0f64a48bb81af7450e641e3fe0b0394d7381e342805479178b3d335d60ca7cf"}, + {file = "kiwisolver-1.4.7-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:8e045731a5416357638d1700927529e2b8ab304811671f665b225f8bf8d8f933"}, + {file = "kiwisolver-1.4.7-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:4322872d5772cae7369f8351da1edf255a604ea7087fe295411397d0cfd9655e"}, + {file = "kiwisolver-1.4.7-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:e1631290ee9271dffe3062d2634c3ecac02c83890ada077d225e081aca8aab89"}, + {file = "kiwisolver-1.4.7-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:edcfc407e4eb17e037bca59be0e85a2031a2ac87e4fed26d3e9df88b4165f92d"}, + {file = "kiwisolver-1.4.7-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:4d05d81ecb47d11e7f8932bd8b61b720bf0b41199358f3f5e36d38e28f0532c5"}, + {file = "kiwisolver-1.4.7-cp38-cp38-win32.whl", hash = "sha256:b38ac83d5f04b15e515fd86f312479d950d05ce2368d5413d46c088dda7de90a"}, + {file = "kiwisolver-1.4.7-cp38-cp38-win_amd64.whl", hash = "sha256:d83db7cde68459fc803052a55ace60bea2bae361fc3b7a6d5da07e11954e4b09"}, + {file = "kiwisolver-1.4.7-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:3f9362ecfca44c863569d3d3c033dbe8ba452ff8eed6f6b5806382741a1334bd"}, + {file = "kiwisolver-1.4.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e8df2eb9b2bac43ef8b082e06f750350fbbaf2887534a5be97f6cf07b19d9583"}, + {file = "kiwisolver-1.4.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f32d6edbc638cde7652bd690c3e728b25332acbadd7cad670cc4a02558d9c417"}, + {file = "kiwisolver-1.4.7-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:e2e6c39bd7b9372b0be21456caab138e8e69cc0fc1190a9dfa92bd45a1e6e904"}, + {file = "kiwisolver-1.4.7-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:dda56c24d869b1193fcc763f1284b9126550eaf84b88bbc7256e15028f19188a"}, + {file = "kiwisolver-1.4.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79849239c39b5e1fd906556c474d9b0439ea6792b637511f3fe3a41158d89ca8"}, + {file = "kiwisolver-1.4.7-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5e3bc157fed2a4c02ec468de4ecd12a6e22818d4f09cde2c31ee3226ffbefab2"}, + {file = "kiwisolver-1.4.7-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3da53da805b71e41053dc670f9a820d1157aae77b6b944e08024d17bcd51ef88"}, + {file = "kiwisolver-1.4.7-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:8705f17dfeb43139a692298cb6637ee2e59c0194538153e83e9ee0c75c2eddde"}, + {file = "kiwisolver-1.4.7-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:82a5c2f4b87c26bb1a0ef3d16b5c4753434633b83d365cc0ddf2770c93829e3c"}, + {file = "kiwisolver-1.4.7-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ce8be0466f4c0d585cdb6c1e2ed07232221df101a4c6f28821d2aa754ca2d9e2"}, + {file = "kiwisolver-1.4.7-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:409afdfe1e2e90e6ee7fc896f3df9a7fec8e793e58bfa0d052c8a82f99c37abb"}, + {file = "kiwisolver-1.4.7-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:5b9c3f4ee0b9a439d2415012bd1b1cc2df59e4d6a9939f4d669241d30b414327"}, + {file = "kiwisolver-1.4.7-cp39-cp39-win32.whl", hash = "sha256:a79ae34384df2b615eefca647a2873842ac3b596418032bef9a7283675962644"}, + {file = "kiwisolver-1.4.7-cp39-cp39-win_amd64.whl", hash = "sha256:cf0438b42121a66a3a667de17e779330fc0f20b0d97d59d2f2121e182b0505e4"}, + {file = "kiwisolver-1.4.7-cp39-cp39-win_arm64.whl", hash = "sha256:764202cc7e70f767dab49e8df52c7455e8de0df5d858fa801a11aa0d882ccf3f"}, + {file = "kiwisolver-1.4.7-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:94252291e3fe68001b1dd747b4c0b3be12582839b95ad4d1b641924d68fd4643"}, + {file = "kiwisolver-1.4.7-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:5b7dfa3b546da08a9f622bb6becdb14b3e24aaa30adba66749d38f3cc7ea9706"}, + {file = "kiwisolver-1.4.7-pp310-pypy310_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bd3de6481f4ed8b734da5df134cd5a6a64fe32124fe83dde1e5b5f29fe30b1e6"}, + {file = "kiwisolver-1.4.7-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a91b5f9f1205845d488c928e8570dcb62b893372f63b8b6e98b863ebd2368ff2"}, + {file = "kiwisolver-1.4.7-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40fa14dbd66b8b8f470d5fc79c089a66185619d31645f9b0773b88b19f7223c4"}, + {file = "kiwisolver-1.4.7-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:eb542fe7933aa09d8d8f9d9097ef37532a7df6497819d16efe4359890a2f417a"}, + {file = "kiwisolver-1.4.7-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:bfa1acfa0c54932d5607e19a2c24646fb4c1ae2694437789129cf099789a3b00"}, + {file = "kiwisolver-1.4.7-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:eee3ea935c3d227d49b4eb85660ff631556841f6e567f0f7bda972df6c2c9935"}, + {file = "kiwisolver-1.4.7-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f3160309af4396e0ed04db259c3ccbfdc3621b5559b5453075e5de555e1f3a1b"}, + {file = "kiwisolver-1.4.7-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a17f6a29cf8935e587cc8a4dbfc8368c55edc645283db0ce9801016f83526c2d"}, + {file = "kiwisolver-1.4.7-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:10849fb2c1ecbfae45a693c070e0320a91b35dd4bcf58172c023b994283a124d"}, + {file = "kiwisolver-1.4.7-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:ac542bf38a8a4be2dc6b15248d36315ccc65f0743f7b1a76688ffb6b5129a5c2"}, + {file = "kiwisolver-1.4.7-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:8b01aac285f91ca889c800042c35ad3b239e704b150cfd3382adfc9dcc780e39"}, + {file = "kiwisolver-1.4.7-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:48be928f59a1f5c8207154f935334d374e79f2b5d212826307d072595ad76a2e"}, + {file = "kiwisolver-1.4.7-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f37cfe618a117e50d8c240555331160d73d0411422b59b5ee217843d7b693608"}, + {file = "kiwisolver-1.4.7-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:599b5c873c63a1f6ed7eead644a8a380cfbdf5db91dcb6f85707aaab213b1674"}, + {file = "kiwisolver-1.4.7-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:801fa7802e5cfabe3ab0c81a34c323a319b097dfb5004be950482d882f3d7225"}, + {file = "kiwisolver-1.4.7-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:0c6c43471bc764fad4bc99c5c2d6d16a676b1abf844ca7c8702bdae92df01ee0"}, + {file = "kiwisolver-1.4.7.tar.gz", hash = "sha256:9893ff81bd7107f7b685d3017cc6583daadb4fc26e4a888350df530e41980a60"}, +] + +[[package]] +name = "llvmlite" +version = "0.43.0" +description = "lightweight wrapper around basic LLVM functionality" +optional = false +python-versions = ">=3.9" +files = [ + {file = "llvmlite-0.43.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a289af9a1687c6cf463478f0fa8e8aa3b6fb813317b0d70bf1ed0759eab6f761"}, + {file = "llvmlite-0.43.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6d4fd101f571a31acb1559ae1af30f30b1dc4b3186669f92ad780e17c81e91bc"}, + {file = "llvmlite-0.43.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7d434ec7e2ce3cc8f452d1cd9a28591745de022f931d67be688a737320dfcead"}, + {file = "llvmlite-0.43.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6912a87782acdff6eb8bf01675ed01d60ca1f2551f8176a300a886f09e836a6a"}, + {file = "llvmlite-0.43.0-cp310-cp310-win_amd64.whl", hash = "sha256:14f0e4bf2fd2d9a75a3534111e8ebeb08eda2f33e9bdd6dfa13282afacdde0ed"}, + {file = "llvmlite-0.43.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3e8d0618cb9bfe40ac38a9633f2493d4d4e9fcc2f438d39a4e854f39cc0f5f98"}, + {file = "llvmlite-0.43.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e0a9a1a39d4bf3517f2af9d23d479b4175ead205c592ceeb8b89af48a327ea57"}, + {file = "llvmlite-0.43.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c1da416ab53e4f7f3bc8d4eeba36d801cc1894b9fbfbf2022b29b6bad34a7df2"}, + {file = "llvmlite-0.43.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:977525a1e5f4059316b183fb4fd34fa858c9eade31f165427a3977c95e3ee749"}, + {file = "llvmlite-0.43.0-cp311-cp311-win_amd64.whl", hash = "sha256:d5bd550001d26450bd90777736c69d68c487d17bf371438f975229b2b8241a91"}, + {file = "llvmlite-0.43.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f99b600aa7f65235a5a05d0b9a9f31150c390f31261f2a0ba678e26823ec38f7"}, + {file = "llvmlite-0.43.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:35d80d61d0cda2d767f72de99450766250560399edc309da16937b93d3b676e7"}, + {file = "llvmlite-0.43.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eccce86bba940bae0d8d48ed925f21dbb813519169246e2ab292b5092aba121f"}, + {file = "llvmlite-0.43.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:df6509e1507ca0760787a199d19439cc887bfd82226f5af746d6977bd9f66844"}, + {file = "llvmlite-0.43.0-cp312-cp312-win_amd64.whl", hash = "sha256:7a2872ee80dcf6b5dbdc838763d26554c2a18aa833d31a2635bff16aafefb9c9"}, + {file = "llvmlite-0.43.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9cd2a7376f7b3367019b664c21f0c61766219faa3b03731113ead75107f3b66c"}, + {file = "llvmlite-0.43.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:18e9953c748b105668487b7c81a3e97b046d8abf95c4ddc0cd3c94f4e4651ae8"}, + {file = "llvmlite-0.43.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:74937acd22dc11b33946b67dca7680e6d103d6e90eeaaaf932603bec6fe7b03a"}, + {file = "llvmlite-0.43.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc9efc739cc6ed760f795806f67889923f7274276f0eb45092a1473e40d9b867"}, + {file = "llvmlite-0.43.0-cp39-cp39-win_amd64.whl", hash = "sha256:47e147cdda9037f94b399bf03bfd8a6b6b1f2f90be94a454e3386f006455a9b4"}, + {file = "llvmlite-0.43.0.tar.gz", hash = "sha256:ae2b5b5c3ef67354824fb75517c8db5fbe93bc02cd9671f3c62271626bc041d5"}, +] + [[package]] name = "lxml" version = "5.3.0" @@ -2247,13 +2578,13 @@ source = ["Cython (>=3.0.11)"] [[package]] name = "markdown" -version = "3.6" +version = "3.7" description = "Python implementation of John Gruber's Markdown." optional = false python-versions = ">=3.8" files = [ - {file = "Markdown-3.6-py3-none-any.whl", hash = "sha256:48f276f4d8cfb8ce6527c8f79e2ee29708508bf4d40aa410fbc3b4ee832c850f"}, - {file = "Markdown-3.6.tar.gz", hash = "sha256:ed4f41f6daecbeeb96e576ce414c41d2d876daa9a16cb35fa8ed8c2ddfad0224"}, + {file = "Markdown-3.7-py3-none-any.whl", hash = "sha256:7eb6df5690b81a1d7942992c97fad2938e956e79df20cbc6186e9c3a77b1c803"}, + {file = "markdown-3.7.tar.gz", hash = "sha256:2ae2471477cfd02dbbf038d5d9bc226d40def84b4fe2986e49b59b6b472bbed2"}, ] [package.extras] @@ -2262,73 +2593,142 @@ testing = ["coverage", "pyyaml"] [[package]] name = "markupsafe" -version = "2.1.5" +version = "3.0.2" description = "Safely add untrusted strings to HTML/XML markup." optional = false -python-versions = ">=3.7" +python-versions = ">=3.9" files = [ - {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-win32.whl", hash = "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-win_amd64.whl", hash = "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-win32.whl", hash = "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-win_amd64.whl", hash = "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-win32.whl", hash = "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5"}, - {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-win32.whl", hash = "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-win32.whl", hash = "sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a"}, + {file = "markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0"}, +] + +[[package]] +name = "matplotlib" +version = "3.7.3" +description = "Python plotting package" +optional = false +python-versions = ">=3.8" +files = [ + {file = "matplotlib-3.7.3-cp310-cp310-macosx_10_12_universal2.whl", hash = "sha256:085c33b27561d9c04386789d5aa5eb4a932ddef43cfcdd0e01735f9a6e85ce0c"}, + {file = "matplotlib-3.7.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:c568e80e1c17f68a727f30f591926751b97b98314d8e59804f54f86ae6fa6a22"}, + {file = "matplotlib-3.7.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7baf98c5ad59c5c4743ea884bb025cbffa52dacdfdac0da3e6021a285a90377e"}, + {file = "matplotlib-3.7.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:236024f582e40dac39bca592258888b38ae47a9fed7b8de652d68d3d02d47d2b"}, + {file = "matplotlib-3.7.3-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:12b4f6795efea037ce2d41e7c417ad8bd02d5719c6ad4a8450a0708f4a1cfb89"}, + {file = "matplotlib-3.7.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78b2136cc6c5415b78977e0e8c608647d597204b05b1d9089ccf513c7d913733"}, + {file = "matplotlib-3.7.3-cp310-cp310-win32.whl", hash = "sha256:122dcbf9be0086e2a95d9e5e0632dbf3bd5b65eaa68c369363310a6c87753059"}, + {file = "matplotlib-3.7.3-cp310-cp310-win_amd64.whl", hash = "sha256:4aab27d9e33293389e3c1d7c881d414a72bdfda0fedc3a6bf46c6fa88d9b8015"}, + {file = "matplotlib-3.7.3-cp311-cp311-macosx_10_12_universal2.whl", hash = "sha256:d5adc743de91e8e0b13df60deb1b1c285b8effea3d66223afceb14b63c9b05de"}, + {file = "matplotlib-3.7.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:55de4cf7cd0071b8ebf203981b53ab64f988a0a1f897a2dff300a1124e8bcd8b"}, + {file = "matplotlib-3.7.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ac03377fd908aaee2312d0b11735753e907adb6f4d1d102de5e2425249693f6c"}, + {file = "matplotlib-3.7.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:755bafc10a46918ce9a39980009b54b02dd249594e5adf52f9c56acfddb5d0b7"}, + {file = "matplotlib-3.7.3-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1a6094c6f8e8d18db631754df4fe9a34dec3caf074f6869a7db09f18f9b1d6b2"}, + {file = "matplotlib-3.7.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:272dba2f1b107790ed78ebf5385b8d14b27ad9e90419de340364b49fe549a993"}, + {file = "matplotlib-3.7.3-cp311-cp311-win32.whl", hash = "sha256:591c123bed1cb4b9996fb60b41a6d89c2ec4943244540776c5f1283fb6960a53"}, + {file = "matplotlib-3.7.3-cp311-cp311-win_amd64.whl", hash = "sha256:3bf3a178c6504694cee8b88b353df0051583f2f6f8faa146f67115c27c856881"}, + {file = "matplotlib-3.7.3-cp312-cp312-macosx_10_12_universal2.whl", hash = "sha256:edf54cac8ee3603f3093616b40a931e8c063969756a4d78a86e82c2fea9659f7"}, + {file = "matplotlib-3.7.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:91e36a85ea639a1ba9f91427041eac064b04829945fe331a92617b6cb21d27e5"}, + {file = "matplotlib-3.7.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:caf5eaaf7c68f8d7df269dfbcaf46f48a70ff482bfcebdcc97519671023f2a7d"}, + {file = "matplotlib-3.7.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:74bf57f505efea376097e948b7cdd87191a7ce8180616390aef496639edf601f"}, + {file = "matplotlib-3.7.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee152a88a0da527840a426535514b6ed8ac4240eb856b1da92cf48124320e346"}, + {file = "matplotlib-3.7.3-cp312-cp312-win_amd64.whl", hash = "sha256:67a410a9c9e07cbc83581eeea144bbe298870bf0ac0ee2f2e10a015ab7efee19"}, + {file = "matplotlib-3.7.3-cp38-cp38-macosx_10_12_universal2.whl", hash = "sha256:259999c05285cb993d7f2a419cea547863fa215379eda81f7254c9e932963729"}, + {file = "matplotlib-3.7.3-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:3f4e7fd5a6157e1d018ce2166ec8e531a481dd4a36f035b5c23edfe05a25419a"}, + {file = "matplotlib-3.7.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:faa3d12d8811d08d14080a8b7b9caea9a457dc495350166b56df0db4b9909ef5"}, + {file = "matplotlib-3.7.3-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:336e88900c11441e458da01c8414fc57e04e17f9d3bb94958a76faa2652bcf6b"}, + {file = "matplotlib-3.7.3-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:12f4c0dd8aa280d796c8772ea8265a14f11a04319baa3a16daa5556065e8baea"}, + {file = "matplotlib-3.7.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1990955b11e7918d256cf3b956b10997f405b7917a3f1c7d8e69c1d15c7b1930"}, + {file = "matplotlib-3.7.3-cp38-cp38-win32.whl", hash = "sha256:e78707b751260b42b721507ad7aa60fe4026d7f51c74cca6b9cd8b123ebb633a"}, + {file = "matplotlib-3.7.3-cp38-cp38-win_amd64.whl", hash = "sha256:e594ee43c59ea39ca5c6244667cac9d017a3527febc31f5532ad9135cf7469ec"}, + {file = "matplotlib-3.7.3-cp39-cp39-macosx_10_12_universal2.whl", hash = "sha256:6eaa1cf0e94c936a26b78f6d756c5fbc12e0a58c8a68b7248a2a31456ce4e234"}, + {file = "matplotlib-3.7.3-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:0a97af9d22e8ebedc9f00b043d9bbd29a375e9e10b656982012dded44c10fd77"}, + {file = "matplotlib-3.7.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1f9c6c16597af660433ab330b59ee2934b832ee1fabcaf5cbde7b2add840f31e"}, + {file = "matplotlib-3.7.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a7240259b4b9cbc62381f6378cff4d57af539162a18e832c1e48042fabc40b6b"}, + {file = "matplotlib-3.7.3-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:747c6191d2e88ae854809e69aa358dbf852ff1a5738401b85c1cc9012309897a"}, + {file = "matplotlib-3.7.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec726b08a5275d827aa91bb951e68234a4423adb91cf65bc0fcdc0f2777663f7"}, + {file = "matplotlib-3.7.3-cp39-cp39-win32.whl", hash = "sha256:40e3b9b450c6534f07278310c4e34caff41c2a42377e4b9d47b0f8d3ac1083a2"}, + {file = "matplotlib-3.7.3-cp39-cp39-win_amd64.whl", hash = "sha256:dfc118642903a23e309b1da32886bb39a4314147d013e820c86b5fb4cb2e36d0"}, + {file = "matplotlib-3.7.3-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:165c8082bf8fc0360c24aa4724a22eaadbfd8c28bf1ccf7e94d685cad48261e4"}, + {file = "matplotlib-3.7.3-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ebd8470cc2a3594746ff0513aecbfa2c55ff6f58e6cef2efb1a54eb87c88ffa2"}, + {file = "matplotlib-3.7.3-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7153453669c9672b52095119fd21dd032d19225d48413a2871519b17db4b0fde"}, + {file = "matplotlib-3.7.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:498a08267dc69dd8f24c4b5d7423fa584d7ce0027ba71f7881df05fc09b89bb7"}, + {file = "matplotlib-3.7.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:d48999c4b19b5a0c058c9cd828ff6fc7748390679f6cf9a2ad653a3e802c87d3"}, + {file = "matplotlib-3.7.3-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:22d65d18b4ee8070a5fea5761d59293f1f9e2fac37ec9ce090463b0e629432fd"}, + {file = "matplotlib-3.7.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c40cde976c36693cc0767e27cf5f443f91c23520060bd9496678364adfafe9c"}, + {file = "matplotlib-3.7.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:39018a2b17592448fbfdf4b8352955e6c3905359939791d4ff429296494d1a0c"}, + {file = "matplotlib-3.7.3.tar.gz", hash = "sha256:f09b3dd6bdeb588de91f853bbb2d6f0ff8ab693485b0c49035eaa510cb4f142e"}, ] +[package.dependencies] +contourpy = ">=1.0.1" +cycler = ">=0.10" +fonttools = ">=4.22.0" +kiwisolver = ">=1.0.1" +numpy = ">=1.20,<2" +packaging = ">=20.0" +pillow = ">=6.2.0" +pyparsing = ">=2.3.1" +python-dateutil = ">=2.7" +setuptools_scm = ">=7" + [[package]] name = "matplotlib-inline" version = "0.1.7" @@ -2367,13 +2767,13 @@ files = [ [[package]] name = "mkdocs" -version = "1.6.0" +version = "1.6.1" description = "Project documentation with Markdown." optional = false python-versions = ">=3.8" files = [ - {file = "mkdocs-1.6.0-py3-none-any.whl", hash = "sha256:1eb5cb7676b7d89323e62b56235010216319217d4af5ddc543a91beb8d125ea7"}, - {file = "mkdocs-1.6.0.tar.gz", hash = "sha256:a73f735824ef83a4f3bcb7a231dcab23f5a838f88b7efc54a0eef5fbdbc3c512"}, + {file = "mkdocs-1.6.1-py3-none-any.whl", hash = "sha256:db91759624d1647f3f34aa0c3f327dd2601beae39a366d6e064c03468d35c20e"}, + {file = "mkdocs-1.6.1.tar.gz", hash = "sha256:7b432f01d928c084353ab39c57282f29f92136665bdd6abf7c1ec8d822ef86f2"}, ] [package.dependencies] @@ -2427,13 +2827,13 @@ mkdocs = ">=1.1" [[package]] name = "mkdocs-awesome-pages-plugin" -version = "2.9.2" +version = "2.9.3" description = "An MkDocs plugin that simplifies configuring page titles and their order" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8.1" files = [ - {file = "mkdocs_awesome_pages_plugin-2.9.2-py3-none-any.whl", hash = "sha256:9c795587695bd1ee85a8b7e43293005418df5a8b9ef296a3e628be427b693b4d"}, - {file = "mkdocs_awesome_pages_plugin-2.9.2.tar.gz", hash = "sha256:c3f7d366ecfe99b64524c49a84d8e13c576c19a918ea2e6f59bb486a259313af"}, + {file = "mkdocs_awesome_pages_plugin-2.9.3-py3-none-any.whl", hash = "sha256:1ba433d4e7edaf8661b15b93267f78f78e2e06ca590fc0e651ea36b191d64ae4"}, + {file = "mkdocs_awesome_pages_plugin-2.9.3.tar.gz", hash = "sha256:bdf6369871f41bb17f09c3cfb573367732dfcceb5673d7a2c5c76ac2567b242f"}, ] [package.dependencies] @@ -2488,13 +2888,13 @@ requests = "*" [[package]] name = "mkdocs-git-revision-date-localized-plugin" -version = "1.2.6" +version = "1.3.0" description = "Mkdocs plugin that enables displaying the localized date of the last git modification of a markdown file." optional = false python-versions = ">=3.8" files = [ - {file = "mkdocs_git_revision_date_localized_plugin-1.2.6-py3-none-any.whl", hash = "sha256:f015cb0f3894a39b33447b18e270ae391c4e25275cac5a626e80b243784e2692"}, - {file = "mkdocs_git_revision_date_localized_plugin-1.2.6.tar.gz", hash = "sha256:e432942ce4ee8aa9b9f4493e993dee9d2cc08b3ea2b40a3d6b03ca0f2a4bcaa2"}, + {file = "mkdocs_git_revision_date_localized_plugin-1.3.0-py3-none-any.whl", hash = "sha256:c99377ee119372d57a9e47cff4e68f04cce634a74831c06bc89b33e456e840a1"}, + {file = "mkdocs_git_revision_date_localized_plugin-1.3.0.tar.gz", hash = "sha256:439e2f14582204050a664c258861c325064d97cdc848c541e48bb034a6c4d0cb"}, ] [package.dependencies] @@ -2503,15 +2903,20 @@ GitPython = "*" mkdocs = ">=1.0" pytz = "*" +[package.extras] +all = ["GitPython", "babel (>=2.7.0)", "click", "codecov", "mkdocs (>=1.0)", "mkdocs-gen-files", "mkdocs-git-authors-plugin", "mkdocs-material", "mkdocs-static-i18n", "pytest", "pytest-cov", "pytz"] +base = ["GitPython", "babel (>=2.7.0)", "mkdocs (>=1.0)", "pytz"] +dev = ["click", "codecov", "mkdocs-gen-files", "mkdocs-git-authors-plugin", "mkdocs-material", "mkdocs-static-i18n", "pytest", "pytest-cov"] + [[package]] name = "mkdocs-material" -version = "9.5.27" +version = "9.5.42" description = "Documentation that simply works" optional = false python-versions = ">=3.8" files = [ - {file = "mkdocs_material-9.5.27-py3-none-any.whl", hash = "sha256:af8cc263fafa98bb79e9e15a8c966204abf15164987569bd1175fd66a7705182"}, - {file = "mkdocs_material-9.5.27.tar.gz", hash = "sha256:a7d4a35f6d4a62b0c43a0cfe7e987da0980c13587b5bc3c26e690ad494427ec0"}, + {file = "mkdocs_material-9.5.42-py3-none-any.whl", hash = "sha256:452a7c5d21284b373f36b981a2cbebfff59263feebeede1bc28652e9c5bbe316"}, + {file = "mkdocs_material-9.5.42.tar.gz", hash = "sha256:92779b5e9b5934540c574c11647131d217dc540dce72b05feeda088c8eb1b8f2"}, ] [package.dependencies] @@ -2559,13 +2964,13 @@ mkdocs = ">=1.2" [[package]] name = "mkdocstrings" -version = "0.26.1" +version = "0.26.2" description = "Automatic documentation from sources, for MkDocs." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "mkdocstrings-0.26.1-py3-none-any.whl", hash = "sha256:29738bfb72b4608e8e55cc50fb8a54f325dc7ebd2014e4e3881a49892d5983cf"}, - {file = "mkdocstrings-0.26.1.tar.gz", hash = "sha256:bb8b8854d6713d5348ad05b069a09f3b79edbc6a0f33a34c6821141adb03fe33"}, + {file = "mkdocstrings-0.26.2-py3-none-any.whl", hash = "sha256:1248f3228464f3b8d1a15bd91249ce1701fe3104ac517a5f167a0e01ca850ba5"}, + {file = "mkdocstrings-0.26.2.tar.gz", hash = "sha256:34a8b50f1e6cfd29546c6c09fbe02154adfb0b361bb758834bf56aa284ba876e"}, ] [package.dependencies] @@ -2585,13 +2990,13 @@ python-legacy = ["mkdocstrings-python-legacy (>=0.2.1)"] [[package]] name = "mkdocstrings-python" -version = "1.12.1" +version = "1.12.2" description = "A Python handler for mkdocstrings." optional = false python-versions = ">=3.9" files = [ - {file = "mkdocstrings_python-1.12.1-py3-none-any.whl", hash = "sha256:205244488199c9aa2a39787ad6a0c862d39b74078ea9aa2be817bc972399563f"}, - {file = "mkdocstrings_python-1.12.1.tar.gz", hash = "sha256:60d6a5ca912c9af4ad431db6d0111ce9f79c6c48d33377dde6a05a8f5f48d792"}, + {file = "mkdocstrings_python-1.12.2-py3-none-any.whl", hash = "sha256:7f7d40d6db3cb1f5d19dbcd80e3efe4d0ba32b073272c0c0de9de2e604eda62a"}, + {file = "mkdocstrings_python-1.12.2.tar.gz", hash = "sha256:7a1760941c0b52a2cd87b960a9e21112ffe52e7df9d0b9583d04d47ed2e186f3"}, ] [package.dependencies] @@ -2601,22 +3006,22 @@ mkdocstrings = ">=0.26" [[package]] name = "msal" -version = "1.29.0" +version = "1.31.0" description = "The Microsoft Authentication Library (MSAL) for Python library enables your app to access the Microsoft Cloud by supporting authentication of users with Microsoft Azure Active Directory accounts (AAD) and Microsoft Accounts (MSA) using industry standard OAuth2 and OpenID Connect." optional = false python-versions = ">=3.7" files = [ - {file = "msal-1.29.0-py3-none-any.whl", hash = "sha256:6b301e63f967481f0cc1a3a3bac0cf322b276855bc1b0955468d9deb3f33d511"}, - {file = "msal-1.29.0.tar.gz", hash = "sha256:8f6725f099752553f9b2fe84125e2a5ebe47b49f92eacca33ebedd3a9ebaae25"}, + {file = "msal-1.31.0-py3-none-any.whl", hash = "sha256:96bc37cff82ebe4b160d5fc0f1196f6ca8b50e274ecd0ec5bf69c438514086e7"}, + {file = "msal-1.31.0.tar.gz", hash = "sha256:2c4f189cf9cc8f00c80045f66d39b7c0f3ed45873fd3d1f2af9f22db2e12ff4b"}, ] [package.dependencies] -cryptography = ">=2.5,<45" +cryptography = ">=2.5,<46" PyJWT = {version = ">=1.0.0,<3", extras = ["crypto"]} requests = ">=2.0.0,<3" [package.extras] -broker = ["pymsalruntime (>=0.13.2,<0.17)"] +broker = ["pymsalruntime (>=0.14,<0.18)", "pymsalruntime (>=0.17,<0.18)"] [[package]] name = "msal-extensions" @@ -2656,103 +3061,108 @@ async = ["aiodns", "aiohttp (>=3.0)"] [[package]] name = "multidict" -version = "6.0.5" +version = "6.1.0" description = "multidict implementation" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "multidict-6.0.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:228b644ae063c10e7f324ab1ab6b548bdf6f8b47f3ec234fef1093bc2735e5f9"}, - {file = "multidict-6.0.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:896ebdcf62683551312c30e20614305f53125750803b614e9e6ce74a96232604"}, - {file = "multidict-6.0.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:411bf8515f3be9813d06004cac41ccf7d1cd46dfe233705933dd163b60e37600"}, - {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d147090048129ce3c453f0292e7697d333db95e52616b3793922945804a433c"}, - {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:215ed703caf15f578dca76ee6f6b21b7603791ae090fbf1ef9d865571039ade5"}, - {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c6390cf87ff6234643428991b7359b5f59cc15155695deb4eda5c777d2b880f"}, - {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21fd81c4ebdb4f214161be351eb5bcf385426bf023041da2fd9e60681f3cebae"}, - {file = "multidict-6.0.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3cc2ad10255f903656017363cd59436f2111443a76f996584d1077e43ee51182"}, - {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6939c95381e003f54cd4c5516740faba40cf5ad3eeff460c3ad1d3e0ea2549bf"}, - {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:220dd781e3f7af2c2c1053da9fa96d9cf3072ca58f057f4c5adaaa1cab8fc442"}, - {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:766c8f7511df26d9f11cd3a8be623e59cca73d44643abab3f8c8c07620524e4a"}, - {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:fe5d7785250541f7f5019ab9cba2c71169dc7d74d0f45253f8313f436458a4ef"}, - {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c1c1496e73051918fcd4f58ff2e0f2f3066d1c76a0c6aeffd9b45d53243702cc"}, - {file = "multidict-6.0.5-cp310-cp310-win32.whl", hash = "sha256:7afcdd1fc07befad18ec4523a782cde4e93e0a2bf71239894b8d61ee578c1319"}, - {file = "multidict-6.0.5-cp310-cp310-win_amd64.whl", hash = "sha256:99f60d34c048c5c2fabc766108c103612344c46e35d4ed9ae0673d33c8fb26e8"}, - {file = "multidict-6.0.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f285e862d2f153a70586579c15c44656f888806ed0e5b56b64489afe4a2dbfba"}, - {file = "multidict-6.0.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:53689bb4e102200a4fafa9de9c7c3c212ab40a7ab2c8e474491914d2305f187e"}, - {file = "multidict-6.0.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:612d1156111ae11d14afaf3a0669ebf6c170dbb735e510a7438ffe2369a847fd"}, - {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7be7047bd08accdb7487737631d25735c9a04327911de89ff1b26b81745bd4e3"}, - {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de170c7b4fe6859beb8926e84f7d7d6c693dfe8e27372ce3b76f01c46e489fcf"}, - {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:04bde7a7b3de05732a4eb39c94574db1ec99abb56162d6c520ad26f83267de29"}, - {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85f67aed7bb647f93e7520633d8f51d3cbc6ab96957c71272b286b2f30dc70ed"}, - {file = "multidict-6.0.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:425bf820055005bfc8aa9a0b99ccb52cc2f4070153e34b701acc98d201693733"}, - {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d3eb1ceec286eba8220c26f3b0096cf189aea7057b6e7b7a2e60ed36b373b77f"}, - {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:7901c05ead4b3fb75113fb1dd33eb1253c6d3ee37ce93305acd9d38e0b5f21a4"}, - {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:e0e79d91e71b9867c73323a3444724d496c037e578a0e1755ae159ba14f4f3d1"}, - {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:29bfeb0dff5cb5fdab2023a7a9947b3b4af63e9c47cae2a10ad58394b517fddc"}, - {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e030047e85cbcedbfc073f71836d62dd5dadfbe7531cae27789ff66bc551bd5e"}, - {file = "multidict-6.0.5-cp311-cp311-win32.whl", hash = "sha256:2f4848aa3baa109e6ab81fe2006c77ed4d3cd1e0ac2c1fbddb7b1277c168788c"}, - {file = "multidict-6.0.5-cp311-cp311-win_amd64.whl", hash = "sha256:2faa5ae9376faba05f630d7e5e6be05be22913782b927b19d12b8145968a85ea"}, - {file = "multidict-6.0.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:51d035609b86722963404f711db441cf7134f1889107fb171a970c9701f92e1e"}, - {file = "multidict-6.0.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:cbebcd5bcaf1eaf302617c114aa67569dd3f090dd0ce8ba9e35e9985b41ac35b"}, - {file = "multidict-6.0.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2ffc42c922dbfddb4a4c3b438eb056828719f07608af27d163191cb3e3aa6cc5"}, - {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ceb3b7e6a0135e092de86110c5a74e46bda4bd4fbfeeb3a3bcec79c0f861e450"}, - {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:79660376075cfd4b2c80f295528aa6beb2058fd289f4c9252f986751a4cd0496"}, - {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e4428b29611e989719874670fd152b6625500ad6c686d464e99f5aaeeaca175a"}, - {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d84a5c3a5f7ce6db1f999fb9438f686bc2e09d38143f2d93d8406ed2dd6b9226"}, - {file = "multidict-6.0.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:76c0de87358b192de7ea9649beb392f107dcad9ad27276324c24c91774ca5271"}, - {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:79a6d2ba910adb2cbafc95dad936f8b9386e77c84c35bc0add315b856d7c3abb"}, - {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:92d16a3e275e38293623ebf639c471d3e03bb20b8ebb845237e0d3664914caef"}, - {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:fb616be3538599e797a2017cccca78e354c767165e8858ab5116813146041a24"}, - {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:14c2976aa9038c2629efa2c148022ed5eb4cb939e15ec7aace7ca932f48f9ba6"}, - {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:435a0984199d81ca178b9ae2c26ec3d49692d20ee29bc4c11a2a8d4514c67eda"}, - {file = "multidict-6.0.5-cp312-cp312-win32.whl", hash = "sha256:9fe7b0653ba3d9d65cbe7698cca585bf0f8c83dbbcc710db9c90f478e175f2d5"}, - {file = "multidict-6.0.5-cp312-cp312-win_amd64.whl", hash = "sha256:01265f5e40f5a17f8241d52656ed27192be03bfa8764d88e8220141d1e4b3556"}, - {file = "multidict-6.0.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:19fe01cea168585ba0f678cad6f58133db2aa14eccaf22f88e4a6dccadfad8b3"}, - {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6bf7a982604375a8d49b6cc1b781c1747f243d91b81035a9b43a2126c04766f5"}, - {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:107c0cdefe028703fb5dafe640a409cb146d44a6ae201e55b35a4af8e95457dd"}, - {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:403c0911cd5d5791605808b942c88a8155c2592e05332d2bf78f18697a5fa15e"}, - {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aeaf541ddbad8311a87dd695ed9642401131ea39ad7bc8cf3ef3967fd093b626"}, - {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e4972624066095e52b569e02b5ca97dbd7a7ddd4294bf4e7247d52635630dd83"}, - {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d946b0a9eb8aaa590df1fe082cee553ceab173e6cb5b03239716338629c50c7a"}, - {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b55358304d7a73d7bdf5de62494aaf70bd33015831ffd98bc498b433dfe5b10c"}, - {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:a3145cb08d8625b2d3fee1b2d596a8766352979c9bffe5d7833e0503d0f0b5e5"}, - {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:d65f25da8e248202bd47445cec78e0025c0fe7582b23ec69c3b27a640dd7a8e3"}, - {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:c9bf56195c6bbd293340ea82eafd0071cb3d450c703d2c93afb89f93b8386ccc"}, - {file = "multidict-6.0.5-cp37-cp37m-win32.whl", hash = "sha256:69db76c09796b313331bb7048229e3bee7928eb62bab5e071e9f7fcc4879caee"}, - {file = "multidict-6.0.5-cp37-cp37m-win_amd64.whl", hash = "sha256:fce28b3c8a81b6b36dfac9feb1de115bab619b3c13905b419ec71d03a3fc1423"}, - {file = "multidict-6.0.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:76f067f5121dcecf0d63a67f29080b26c43c71a98b10c701b0677e4a065fbd54"}, - {file = "multidict-6.0.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b82cc8ace10ab5bd93235dfaab2021c70637005e1ac787031f4d1da63d493c1d"}, - {file = "multidict-6.0.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5cb241881eefd96b46f89b1a056187ea8e9ba14ab88ba632e68d7a2ecb7aadf7"}, - {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8e94e6912639a02ce173341ff62cc1201232ab86b8a8fcc05572741a5dc7d93"}, - {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:09a892e4a9fb47331da06948690ae38eaa2426de97b4ccbfafbdcbe5c8f37ff8"}, - {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55205d03e8a598cfc688c71ca8ea5f66447164efff8869517f175ea632c7cb7b"}, - {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:37b15024f864916b4951adb95d3a80c9431299080341ab9544ed148091b53f50"}, - {file = "multidict-6.0.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2a1dee728b52b33eebff5072817176c172050d44d67befd681609b4746e1c2e"}, - {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:edd08e6f2f1a390bf137080507e44ccc086353c8e98c657e666c017718561b89"}, - {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:60d698e8179a42ec85172d12f50b1668254628425a6bd611aba022257cac1386"}, - {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:3d25f19500588cbc47dc19081d78131c32637c25804df8414463ec908631e453"}, - {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:4cc0ef8b962ac7a5e62b9e826bd0cd5040e7d401bc45a6835910ed699037a461"}, - {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:eca2e9d0cc5a889850e9bbd68e98314ada174ff6ccd1129500103df7a94a7a44"}, - {file = "multidict-6.0.5-cp38-cp38-win32.whl", hash = "sha256:4a6a4f196f08c58c59e0b8ef8ec441d12aee4125a7d4f4fef000ccb22f8d7241"}, - {file = "multidict-6.0.5-cp38-cp38-win_amd64.whl", hash = "sha256:0275e35209c27a3f7951e1ce7aaf93ce0d163b28948444bec61dd7badc6d3f8c"}, - {file = "multidict-6.0.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e7be68734bd8c9a513f2b0cfd508802d6609da068f40dc57d4e3494cefc92929"}, - {file = "multidict-6.0.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1d9ea7a7e779d7a3561aade7d596649fbecfa5c08a7674b11b423783217933f9"}, - {file = "multidict-6.0.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ea1456df2a27c73ce51120fa2f519f1bea2f4a03a917f4a43c8707cf4cbbae1a"}, - {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf590b134eb70629e350691ecca88eac3e3b8b3c86992042fb82e3cb1830d5e1"}, - {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5c0631926c4f58e9a5ccce555ad7747d9a9f8b10619621f22f9635f069f6233e"}, - {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dce1c6912ab9ff5f179eaf6efe7365c1f425ed690b03341911bf4939ef2f3046"}, - {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0868d64af83169e4d4152ec612637a543f7a336e4a307b119e98042e852ad9c"}, - {file = "multidict-6.0.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:141b43360bfd3bdd75f15ed811850763555a251e38b2405967f8e25fb43f7d40"}, - {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7df704ca8cf4a073334e0427ae2345323613e4df18cc224f647f251e5e75a527"}, - {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:6214c5a5571802c33f80e6c84713b2c79e024995b9c5897f794b43e714daeec9"}, - {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:cd6c8fca38178e12c00418de737aef1261576bd1b6e8c6134d3e729a4e858b38"}, - {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:e02021f87a5b6932fa6ce916ca004c4d441509d33bbdbeca70d05dff5e9d2479"}, - {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ebd8d160f91a764652d3e51ce0d2956b38efe37c9231cd82cfc0bed2e40b581c"}, - {file = "multidict-6.0.5-cp39-cp39-win32.whl", hash = "sha256:04da1bb8c8dbadf2a18a452639771951c662c5ad03aefe4884775454be322c9b"}, - {file = "multidict-6.0.5-cp39-cp39-win_amd64.whl", hash = "sha256:d6f6d4f185481c9669b9447bf9d9cf3b95a0e9df9d169bbc17e363b7d5487755"}, - {file = "multidict-6.0.5-py3-none-any.whl", hash = "sha256:0d63c74e3d7ab26de115c49bffc92cc77ed23395303d496eae515d4204a625e7"}, - {file = "multidict-6.0.5.tar.gz", hash = "sha256:f7e301075edaf50500f0b341543c41194d8df3ae5caf4702f2095f3ca73dd8da"}, + {file = "multidict-6.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3380252550e372e8511d49481bd836264c009adb826b23fefcc5dd3c69692f60"}, + {file = "multidict-6.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:99f826cbf970077383d7de805c0681799491cb939c25450b9b5b3ced03ca99f1"}, + {file = "multidict-6.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a114d03b938376557927ab23f1e950827c3b893ccb94b62fd95d430fd0e5cf53"}, + {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1c416351ee6271b2f49b56ad7f308072f6f44b37118d69c2cad94f3fa8a40d5"}, + {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6b5d83030255983181005e6cfbac1617ce9746b219bc2aad52201ad121226581"}, + {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3e97b5e938051226dc025ec80980c285b053ffb1e25a3db2a3aa3bc046bf7f56"}, + {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d618649d4e70ac6efcbba75be98b26ef5078faad23592f9b51ca492953012429"}, + {file = "multidict-6.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10524ebd769727ac77ef2278390fb0068d83f3acb7773792a5080f2b0abf7748"}, + {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ff3827aef427c89a25cc96ded1759271a93603aba9fb977a6d264648ebf989db"}, + {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:06809f4f0f7ab7ea2cabf9caca7d79c22c0758b58a71f9d32943ae13c7ace056"}, + {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f179dee3b863ab1c59580ff60f9d99f632f34ccb38bf67a33ec6b3ecadd0fd76"}, + {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:aaed8b0562be4a0876ee3b6946f6869b7bcdb571a5d1496683505944e268b160"}, + {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3c8b88a2ccf5493b6c8da9076fb151ba106960a2df90c2633f342f120751a9e7"}, + {file = "multidict-6.1.0-cp310-cp310-win32.whl", hash = "sha256:4a9cb68166a34117d6646c0023c7b759bf197bee5ad4272f420a0141d7eb03a0"}, + {file = "multidict-6.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:20b9b5fbe0b88d0bdef2012ef7dee867f874b72528cf1d08f1d59b0e3850129d"}, + {file = "multidict-6.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3efe2c2cb5763f2f1b275ad2bf7a287d3f7ebbef35648a9726e3b69284a4f3d6"}, + {file = "multidict-6.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c7053d3b0353a8b9de430a4f4b4268ac9a4fb3481af37dfe49825bf45ca24156"}, + {file = "multidict-6.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:27e5fc84ccef8dfaabb09d82b7d179c7cf1a3fbc8a966f8274fcb4ab2eb4cadb"}, + {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e2b90b43e696f25c62656389d32236e049568b39320e2735d51f08fd362761b"}, + {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d83a047959d38a7ff552ff94be767b7fd79b831ad1cd9920662db05fec24fe72"}, + {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d1a9dd711d0877a1ece3d2e4fea11a8e75741ca21954c919406b44e7cf971304"}, + {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec2abea24d98246b94913b76a125e855eb5c434f7c46546046372fe60f666351"}, + {file = "multidict-6.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4867cafcbc6585e4b678876c489b9273b13e9fff9f6d6d66add5e15d11d926cb"}, + {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5b48204e8d955c47c55b72779802b219a39acc3ee3d0116d5080c388970b76e3"}, + {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:d8fff389528cad1618fb4b26b95550327495462cd745d879a8c7c2115248e399"}, + {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:a7a9541cd308eed5e30318430a9c74d2132e9a8cb46b901326272d780bf2d423"}, + {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:da1758c76f50c39a2efd5e9859ce7d776317eb1dd34317c8152ac9251fc574a3"}, + {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c943a53e9186688b45b323602298ab727d8865d8c9ee0b17f8d62d14b56f0753"}, + {file = "multidict-6.1.0-cp311-cp311-win32.whl", hash = "sha256:90f8717cb649eea3504091e640a1b8568faad18bd4b9fcd692853a04475a4b80"}, + {file = "multidict-6.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:82176036e65644a6cc5bd619f65f6f19781e8ec2e5330f51aa9ada7504cc1926"}, + {file = "multidict-6.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b04772ed465fa3cc947db808fa306d79b43e896beb677a56fb2347ca1a49c1fa"}, + {file = "multidict-6.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6180c0ae073bddeb5a97a38c03f30c233e0a4d39cd86166251617d1bbd0af436"}, + {file = "multidict-6.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:071120490b47aa997cca00666923a83f02c7fbb44f71cf7f136df753f7fa8761"}, + {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50b3a2710631848991d0bf7de077502e8994c804bb805aeb2925a981de58ec2e"}, + {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b58c621844d55e71c1b7f7c498ce5aa6985d743a1a59034c57a905b3f153c1ef"}, + {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55b6d90641869892caa9ca42ff913f7ff1c5ece06474fbd32fb2cf6834726c95"}, + {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b820514bfc0b98a30e3d85462084779900347e4d49267f747ff54060cc33925"}, + {file = "multidict-6.1.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10a9b09aba0c5b48c53761b7c720aaaf7cf236d5fe394cd399c7ba662d5f9966"}, + {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1e16bf3e5fc9f44632affb159d30a437bfe286ce9e02754759be5536b169b305"}, + {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:76f364861c3bfc98cbbcbd402d83454ed9e01a5224bb3a28bf70002a230f73e2"}, + {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:820c661588bd01a0aa62a1283f20d2be4281b086f80dad9e955e690c75fb54a2"}, + {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:0e5f362e895bc5b9e67fe6e4ded2492d8124bdf817827f33c5b46c2fe3ffaca6"}, + {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3ec660d19bbc671e3a6443325f07263be452c453ac9e512f5eb935e7d4ac28b3"}, + {file = "multidict-6.1.0-cp312-cp312-win32.whl", hash = "sha256:58130ecf8f7b8112cdb841486404f1282b9c86ccb30d3519faf301b2e5659133"}, + {file = "multidict-6.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:188215fc0aafb8e03341995e7c4797860181562380f81ed0a87ff455b70bf1f1"}, + {file = "multidict-6.1.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:d569388c381b24671589335a3be6e1d45546c2988c2ebe30fdcada8457a31008"}, + {file = "multidict-6.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:052e10d2d37810b99cc170b785945421141bf7bb7d2f8799d431e7db229c385f"}, + {file = "multidict-6.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f90c822a402cb865e396a504f9fc8173ef34212a342d92e362ca498cad308e28"}, + {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b225d95519a5bf73860323e633a664b0d85ad3d5bede6d30d95b35d4dfe8805b"}, + {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:23bfd518810af7de1116313ebd9092cb9aa629beb12f6ed631ad53356ed6b86c"}, + {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c09fcfdccdd0b57867577b719c69e347a436b86cd83747f179dbf0cc0d4c1f3"}, + {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf6bea52ec97e95560af5ae576bdac3aa3aae0b6758c6efa115236d9e07dae44"}, + {file = "multidict-6.1.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57feec87371dbb3520da6192213c7d6fc892d5589a93db548331954de8248fd2"}, + {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0c3f390dc53279cbc8ba976e5f8035eab997829066756d811616b652b00a23a3"}, + {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:59bfeae4b25ec05b34f1956eaa1cb38032282cd4dfabc5056d0a1ec4d696d3aa"}, + {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:b2f59caeaf7632cc633b5cf6fc449372b83bbdf0da4ae04d5be36118e46cc0aa"}, + {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:37bb93b2178e02b7b618893990941900fd25b6b9ac0fa49931a40aecdf083fe4"}, + {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4e9f48f58c2c523d5a06faea47866cd35b32655c46b443f163d08c6d0ddb17d6"}, + {file = "multidict-6.1.0-cp313-cp313-win32.whl", hash = "sha256:3a37ffb35399029b45c6cc33640a92bef403c9fd388acce75cdc88f58bd19a81"}, + {file = "multidict-6.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:e9aa71e15d9d9beaad2c6b9319edcdc0a49a43ef5c0a4c8265ca9ee7d6c67774"}, + {file = "multidict-6.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:db7457bac39421addd0c8449933ac32d8042aae84a14911a757ae6ca3eef1392"}, + {file = "multidict-6.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d094ddec350a2fb899fec68d8353c78233debde9b7d8b4beeafa70825f1c281a"}, + {file = "multidict-6.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5845c1fd4866bb5dd3125d89b90e57ed3138241540897de748cdf19de8a2fca2"}, + {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9079dfc6a70abe341f521f78405b8949f96db48da98aeb43f9907f342f627cdc"}, + {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3914f5aaa0f36d5d60e8ece6a308ee1c9784cd75ec8151062614657a114c4478"}, + {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c08be4f460903e5a9d0f76818db3250f12e9c344e79314d1d570fc69d7f4eae4"}, + {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d093be959277cb7dee84b801eb1af388b6ad3ca6a6b6bf1ed7585895789d027d"}, + {file = "multidict-6.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3702ea6872c5a2a4eeefa6ffd36b042e9773f05b1f37ae3ef7264b1163c2dcf6"}, + {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:2090f6a85cafc5b2db085124d752757c9d251548cedabe9bd31afe6363e0aff2"}, + {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:f67f217af4b1ff66c68a87318012de788dd95fcfeb24cc889011f4e1c7454dfd"}, + {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:189f652a87e876098bbc67b4da1049afb5f5dfbaa310dd67c594b01c10388db6"}, + {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:6bb5992037f7a9eff7991ebe4273ea7f51f1c1c511e6a2ce511d0e7bdb754492"}, + {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:ac10f4c2b9e770c4e393876e35a7046879d195cd123b4f116d299d442b335bcd"}, + {file = "multidict-6.1.0-cp38-cp38-win32.whl", hash = "sha256:e27bbb6d14416713a8bd7aaa1313c0fc8d44ee48d74497a0ff4c3a1b6ccb5167"}, + {file = "multidict-6.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:22f3105d4fb15c8f57ff3959a58fcab6ce36814486500cd7485651230ad4d4ef"}, + {file = "multidict-6.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:4e18b656c5e844539d506a0a06432274d7bd52a7487e6828c63a63d69185626c"}, + {file = "multidict-6.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a185f876e69897a6f3325c3f19f26a297fa058c5e456bfcff8015e9a27e83ae1"}, + {file = "multidict-6.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ab7c4ceb38d91570a650dba194e1ca87c2b543488fe9309b4212694174fd539c"}, + {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e617fb6b0b6953fffd762669610c1c4ffd05632c138d61ac7e14ad187870669c"}, + {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:16e5f4bf4e603eb1fdd5d8180f1a25f30056f22e55ce51fb3d6ad4ab29f7d96f"}, + {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f4c035da3f544b1882bac24115f3e2e8760f10a0107614fc9839fd232200b875"}, + {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:957cf8e4b6e123a9eea554fa7ebc85674674b713551de587eb318a2df3e00255"}, + {file = "multidict-6.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:483a6aea59cb89904e1ceabd2b47368b5600fb7de78a6e4a2c2987b2d256cf30"}, + {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:87701f25a2352e5bf7454caa64757642734da9f6b11384c1f9d1a8e699758057"}, + {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:682b987361e5fd7a139ed565e30d81fd81e9629acc7d925a205366877d8c8657"}, + {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ce2186a7df133a9c895dea3331ddc5ddad42cdd0d1ea2f0a51e5d161e4762f28"}, + {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:9f636b730f7e8cb19feb87094949ba54ee5357440b9658b2a32a5ce4bce53972"}, + {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:73eae06aa53af2ea5270cc066dcaf02cc60d2994bbb2c4ef5764949257d10f43"}, + {file = "multidict-6.1.0-cp39-cp39-win32.whl", hash = "sha256:1ca0083e80e791cffc6efce7660ad24af66c8d4079d2a750b29001b53ff59ada"}, + {file = "multidict-6.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:aa466da5b15ccea564bdab9c89175c762bc12825f4659c11227f515cee76fa4a"}, + {file = "multidict-6.1.0-py3-none-any.whl", hash = "sha256:48e171e52d1c4d33888e529b999e5900356b9ae588c2f09a52dcefb158b27506"}, + {file = "multidict-6.1.0.tar.gz", hash = "sha256:22ae2ebf9b0c69d206c003e2f6a914ea33f0a932d4aa16f236afc049d9958f4a"}, ] +[package.dependencies] +typing-extensions = {version = ">=4.1.0", markers = "python_version < \"3.11\""} + [[package]] name = "mypy" version = "1.13.0" @@ -2854,6 +3264,40 @@ files = [ {file = "nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f"}, ] +[[package]] +name = "numba" +version = "0.60.0" +description = "compiling Python code using LLVM" +optional = false +python-versions = ">=3.9" +files = [ + {file = "numba-0.60.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5d761de835cd38fb400d2c26bb103a2726f548dc30368853121d66201672e651"}, + {file = "numba-0.60.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:159e618ef213fba758837f9837fb402bbe65326e60ba0633dbe6c7f274d42c1b"}, + {file = "numba-0.60.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1527dc578b95c7c4ff248792ec33d097ba6bef9eda466c948b68dfc995c25781"}, + {file = "numba-0.60.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fe0b28abb8d70f8160798f4de9d486143200f34458d34c4a214114e445d7124e"}, + {file = "numba-0.60.0-cp310-cp310-win_amd64.whl", hash = "sha256:19407ced081d7e2e4b8d8c36aa57b7452e0283871c296e12d798852bc7d7f198"}, + {file = "numba-0.60.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a17b70fc9e380ee29c42717e8cc0bfaa5556c416d94f9aa96ba13acb41bdece8"}, + {file = "numba-0.60.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3fb02b344a2a80efa6f677aa5c40cd5dd452e1b35f8d1c2af0dfd9ada9978e4b"}, + {file = "numba-0.60.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5f4fde652ea604ea3c86508a3fb31556a6157b2c76c8b51b1d45eb40c8598703"}, + {file = "numba-0.60.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4142d7ac0210cc86432b818338a2bc368dc773a2f5cf1e32ff7c5b378bd63ee8"}, + {file = "numba-0.60.0-cp311-cp311-win_amd64.whl", hash = "sha256:cac02c041e9b5bc8cf8f2034ff6f0dbafccd1ae9590dc146b3a02a45e53af4e2"}, + {file = "numba-0.60.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d7da4098db31182fc5ffe4bc42c6f24cd7d1cb8a14b59fd755bfee32e34b8404"}, + {file = "numba-0.60.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:38d6ea4c1f56417076ecf8fc327c831ae793282e0ff51080c5094cb726507b1c"}, + {file = "numba-0.60.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:62908d29fb6a3229c242e981ca27e32a6e606cc253fc9e8faeb0e48760de241e"}, + {file = "numba-0.60.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0ebaa91538e996f708f1ab30ef4d3ddc344b64b5227b67a57aa74f401bb68b9d"}, + {file = "numba-0.60.0-cp312-cp312-win_amd64.whl", hash = "sha256:f75262e8fe7fa96db1dca93d53a194a38c46da28b112b8a4aca168f0df860347"}, + {file = "numba-0.60.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:01ef4cd7d83abe087d644eaa3d95831b777aa21d441a23703d649e06b8e06b74"}, + {file = "numba-0.60.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:819a3dfd4630d95fd574036f99e47212a1af41cbcb019bf8afac63ff56834449"}, + {file = "numba-0.60.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0b983bd6ad82fe868493012487f34eae8bf7dd94654951404114f23c3466d34b"}, + {file = "numba-0.60.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c151748cd269ddeab66334bd754817ffc0cabd9433acb0f551697e5151917d25"}, + {file = "numba-0.60.0-cp39-cp39-win_amd64.whl", hash = "sha256:3031547a015710140e8c87226b4cfe927cac199835e5bf7d4fe5cb64e814e3ab"}, + {file = "numba-0.60.0.tar.gz", hash = "sha256:5df6158e5584eece5fc83294b949fd30b9f1125df7708862205217e068aabf16"}, +] + +[package.dependencies] +llvmlite = "==0.43.*" +numpy = ">=1.22,<2.1" + [[package]] name = "numpy" version = "1.26.4" @@ -2932,57 +3376,69 @@ PyYAML = ">=5.1.0" [[package]] name = "orjson" -version = "3.10.5" +version = "3.10.10" description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" optional = false python-versions = ">=3.8" files = [ - {file = "orjson-3.10.5-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:545d493c1f560d5ccfc134803ceb8955a14c3fcb47bbb4b2fee0232646d0b932"}, - {file = "orjson-3.10.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4324929c2dd917598212bfd554757feca3e5e0fa60da08be11b4aa8b90013c1"}, - {file = "orjson-3.10.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8c13ca5e2ddded0ce6a927ea5a9f27cae77eee4c75547b4297252cb20c4d30e6"}, - {file = "orjson-3.10.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b6c8e30adfa52c025f042a87f450a6b9ea29649d828e0fec4858ed5e6caecf63"}, - {file = "orjson-3.10.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:338fd4f071b242f26e9ca802f443edc588fa4ab60bfa81f38beaedf42eda226c"}, - {file = "orjson-3.10.5-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6970ed7a3126cfed873c5d21ece1cd5d6f83ca6c9afb71bbae21a0b034588d96"}, - {file = "orjson-3.10.5-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:235dadefb793ad12f7fa11e98a480db1f7c6469ff9e3da5e73c7809c700d746b"}, - {file = "orjson-3.10.5-cp310-none-win32.whl", hash = "sha256:be79e2393679eda6a590638abda16d167754393f5d0850dcbca2d0c3735cebe2"}, - {file = "orjson-3.10.5-cp310-none-win_amd64.whl", hash = "sha256:c4a65310ccb5c9910c47b078ba78e2787cb3878cdded1702ac3d0da71ddc5228"}, - {file = "orjson-3.10.5-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:cdf7365063e80899ae3a697def1277c17a7df7ccfc979990a403dfe77bb54d40"}, - {file = "orjson-3.10.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b68742c469745d0e6ca5724506858f75e2f1e5b59a4315861f9e2b1df77775a"}, - {file = "orjson-3.10.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7d10cc1b594951522e35a3463da19e899abe6ca95f3c84c69e9e901e0bd93d38"}, - {file = "orjson-3.10.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dcbe82b35d1ac43b0d84072408330fd3295c2896973112d495e7234f7e3da2e1"}, - {file = "orjson-3.10.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10c0eb7e0c75e1e486c7563fe231b40fdd658a035ae125c6ba651ca3b07936f5"}, - {file = "orjson-3.10.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:53ed1c879b10de56f35daf06dbc4a0d9a5db98f6ee853c2dbd3ee9d13e6f302f"}, - {file = "orjson-3.10.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:099e81a5975237fda3100f918839af95f42f981447ba8f47adb7b6a3cdb078fa"}, - {file = "orjson-3.10.5-cp311-none-win32.whl", hash = "sha256:1146bf85ea37ac421594107195db8bc77104f74bc83e8ee21a2e58596bfb2f04"}, - {file = "orjson-3.10.5-cp311-none-win_amd64.whl", hash = "sha256:36a10f43c5f3a55c2f680efe07aa93ef4a342d2960dd2b1b7ea2dd764fe4a37c"}, - {file = "orjson-3.10.5-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:68f85ecae7af14a585a563ac741b0547a3f291de81cd1e20903e79f25170458f"}, - {file = "orjson-3.10.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28afa96f496474ce60d3340fe8d9a263aa93ea01201cd2bad844c45cd21f5268"}, - {file = "orjson-3.10.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9cd684927af3e11b6e754df80b9ffafd9fb6adcaa9d3e8fdd5891be5a5cad51e"}, - {file = "orjson-3.10.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d21b9983da032505f7050795e98b5d9eee0df903258951566ecc358f6696969"}, - {file = "orjson-3.10.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ad1de7fef79736dde8c3554e75361ec351158a906d747bd901a52a5c9c8d24b"}, - {file = "orjson-3.10.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2d97531cdfe9bdd76d492e69800afd97e5930cb0da6a825646667b2c6c6c0211"}, - {file = "orjson-3.10.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d69858c32f09c3e1ce44b617b3ebba1aba030e777000ebdf72b0d8e365d0b2b3"}, - {file = "orjson-3.10.5-cp312-none-win32.whl", hash = "sha256:64c9cc089f127e5875901ac05e5c25aa13cfa5dbbbd9602bda51e5c611d6e3e2"}, - {file = "orjson-3.10.5-cp312-none-win_amd64.whl", hash = "sha256:b2efbd67feff8c1f7728937c0d7f6ca8c25ec81373dc8db4ef394c1d93d13dc5"}, - {file = "orjson-3.10.5-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:03b565c3b93f5d6e001db48b747d31ea3819b89abf041ee10ac6988886d18e01"}, - {file = "orjson-3.10.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:584c902ec19ab7928fd5add1783c909094cc53f31ac7acfada817b0847975f26"}, - {file = "orjson-3.10.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5a35455cc0b0b3a1eaf67224035f5388591ec72b9b6136d66b49a553ce9eb1e6"}, - {file = "orjson-3.10.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1670fe88b116c2745a3a30b0f099b699a02bb3482c2591514baf5433819e4f4d"}, - {file = "orjson-3.10.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:185c394ef45b18b9a7d8e8f333606e2e8194a50c6e3c664215aae8cf42c5385e"}, - {file = "orjson-3.10.5-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:ca0b3a94ac8d3886c9581b9f9de3ce858263865fdaa383fbc31c310b9eac07c9"}, - {file = "orjson-3.10.5-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:dfc91d4720d48e2a709e9c368d5125b4b5899dced34b5400c3837dadc7d6271b"}, - {file = "orjson-3.10.5-cp38-none-win32.whl", hash = "sha256:c05f16701ab2a4ca146d0bca950af254cb7c02f3c01fca8efbbad82d23b3d9d4"}, - {file = "orjson-3.10.5-cp38-none-win_amd64.whl", hash = "sha256:8a11d459338f96a9aa7f232ba95679fc0c7cedbd1b990d736467894210205c09"}, - {file = "orjson-3.10.5-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:85c89131d7b3218db1b24c4abecea92fd6c7f9fab87441cfc342d3acc725d807"}, - {file = "orjson-3.10.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb66215277a230c456f9038d5e2d84778141643207f85336ef8d2a9da26bd7ca"}, - {file = "orjson-3.10.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:51bbcdea96cdefa4a9b4461e690c75ad4e33796530d182bdd5c38980202c134a"}, - {file = "orjson-3.10.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dbead71dbe65f959b7bd8cf91e0e11d5338033eba34c114f69078d59827ee139"}, - {file = "orjson-3.10.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5df58d206e78c40da118a8c14fc189207fffdcb1f21b3b4c9c0c18e839b5a214"}, - {file = "orjson-3.10.5-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:c4057c3b511bb8aef605616bd3f1f002a697c7e4da6adf095ca5b84c0fd43595"}, - {file = "orjson-3.10.5-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:b39e006b00c57125ab974362e740c14a0c6a66ff695bff44615dcf4a70ce2b86"}, - {file = "orjson-3.10.5-cp39-none-win32.whl", hash = "sha256:eded5138cc565a9d618e111c6d5c2547bbdd951114eb822f7f6309e04db0fb47"}, - {file = "orjson-3.10.5-cp39-none-win_amd64.whl", hash = "sha256:cc28e90a7cae7fcba2493953cff61da5a52950e78dc2dacfe931a317ee3d8de7"}, - {file = "orjson-3.10.5.tar.gz", hash = "sha256:7a5baef8a4284405d96c90c7c62b755e9ef1ada84c2406c24a9ebec86b89f46d"}, + {file = "orjson-3.10.10-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:b788a579b113acf1c57e0a68e558be71d5d09aa67f62ca1f68e01117e550a998"}, + {file = "orjson-3.10.10-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:804b18e2b88022c8905bb79bd2cbe59c0cd014b9328f43da8d3b28441995cda4"}, + {file = "orjson-3.10.10-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9972572a1d042ec9ee421b6da69f7cc823da5962237563fa548ab17f152f0b9b"}, + {file = "orjson-3.10.10-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc6993ab1c2ae7dd0711161e303f1db69062955ac2668181bfdf2dd410e65258"}, + {file = "orjson-3.10.10-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d78e4cacced5781b01d9bc0f0cd8b70b906a0e109825cb41c1b03f9c41e4ce86"}, + {file = "orjson-3.10.10-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e6eb2598df518281ba0cbc30d24c5b06124ccf7e19169e883c14e0831217a0bc"}, + {file = "orjson-3.10.10-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:23776265c5215ec532de6238a52707048401a568f0fa0d938008e92a147fe2c7"}, + {file = "orjson-3.10.10-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8cc2a654c08755cef90b468ff17c102e2def0edd62898b2486767204a7f5cc9c"}, + {file = "orjson-3.10.10-cp310-none-win32.whl", hash = "sha256:081b3fc6a86d72efeb67c13d0ea7c030017bd95f9868b1e329a376edc456153b"}, + {file = "orjson-3.10.10-cp310-none-win_amd64.whl", hash = "sha256:ff38c5fb749347768a603be1fb8a31856458af839f31f064c5aa74aca5be9efe"}, + {file = "orjson-3.10.10-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:879e99486c0fbb256266c7c6a67ff84f46035e4f8749ac6317cc83dacd7f993a"}, + {file = "orjson-3.10.10-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:019481fa9ea5ff13b5d5d95e6fd5ab25ded0810c80b150c2c7b1cc8660b662a7"}, + {file = "orjson-3.10.10-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0dd57eff09894938b4c86d4b871a479260f9e156fa7f12f8cad4b39ea8028bb5"}, + {file = "orjson-3.10.10-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dbde6d70cd95ab4d11ea8ac5e738e30764e510fc54d777336eec09bb93b8576c"}, + {file = "orjson-3.10.10-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b2625cb37b8fb42e2147404e5ff7ef08712099197a9cd38895006d7053e69d6"}, + {file = "orjson-3.10.10-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dbf3c20c6a7db69df58672a0d5815647ecf78c8e62a4d9bd284e8621c1fe5ccb"}, + {file = "orjson-3.10.10-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:75c38f5647e02d423807d252ce4528bf6a95bd776af999cb1fb48867ed01d1f6"}, + {file = "orjson-3.10.10-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:23458d31fa50ec18e0ec4b0b4343730928296b11111df5f547c75913714116b2"}, + {file = "orjson-3.10.10-cp311-none-win32.whl", hash = "sha256:2787cd9dedc591c989f3facd7e3e86508eafdc9536a26ec277699c0aa63c685b"}, + {file = "orjson-3.10.10-cp311-none-win_amd64.whl", hash = "sha256:6514449d2c202a75183f807bc755167713297c69f1db57a89a1ef4a0170ee269"}, + {file = "orjson-3.10.10-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:8564f48f3620861f5ef1e080ce7cd122ee89d7d6dacf25fcae675ff63b4d6e05"}, + {file = "orjson-3.10.10-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5bf161a32b479034098c5b81f2608f09167ad2fa1c06abd4e527ea6bf4837a9"}, + {file = "orjson-3.10.10-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:68b65c93617bcafa7f04b74ae8bc2cc214bd5cb45168a953256ff83015c6747d"}, + {file = "orjson-3.10.10-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e8e28406f97fc2ea0c6150f4c1b6e8261453318930b334abc419214c82314f85"}, + {file = "orjson-3.10.10-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e4d0d9fe174cc7a5bdce2e6c378bcdb4c49b2bf522a8f996aa586020e1b96cee"}, + {file = "orjson-3.10.10-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b3be81c42f1242cbed03cbb3973501fcaa2675a0af638f8be494eaf37143d999"}, + {file = "orjson-3.10.10-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:65f9886d3bae65be026219c0a5f32dbbe91a9e6272f56d092ab22561ad0ea33b"}, + {file = "orjson-3.10.10-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:730ed5350147db7beb23ddaf072f490329e90a1d059711d364b49fe352ec987b"}, + {file = "orjson-3.10.10-cp312-none-win32.whl", hash = "sha256:a8f4bf5f1c85bea2170800020d53a8877812892697f9c2de73d576c9307a8a5f"}, + {file = "orjson-3.10.10-cp312-none-win_amd64.whl", hash = "sha256:384cd13579a1b4cd689d218e329f459eb9ddc504fa48c5a83ef4889db7fd7a4f"}, + {file = "orjson-3.10.10-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:44bffae68c291f94ff5a9b4149fe9d1bdd4cd0ff0fb575bcea8351d48db629a1"}, + {file = "orjson-3.10.10-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e27b4c6437315df3024f0835887127dac2a0a3ff643500ec27088d2588fa5ae1"}, + {file = "orjson-3.10.10-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bca84df16d6b49325a4084fd8b2fe2229cb415e15c46c529f868c3387bb1339d"}, + {file = "orjson-3.10.10-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c14ce70e8f39bd71f9f80423801b5d10bf93d1dceffdecd04df0f64d2c69bc01"}, + {file = "orjson-3.10.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:24ac62336da9bda1bd93c0491eff0613003b48d3cb5d01470842e7b52a40d5b4"}, + {file = "orjson-3.10.10-cp313-none-win32.whl", hash = "sha256:eb0a42831372ec2b05acc9ee45af77bcaccbd91257345f93780a8e654efc75db"}, + {file = "orjson-3.10.10-cp313-none-win_amd64.whl", hash = "sha256:f0c4f37f8bf3f1075c6cc8dd8a9f843689a4b618628f8812d0a71e6968b95ffd"}, + {file = "orjson-3.10.10-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:829700cc18503efc0cf502d630f612884258020d98a317679cd2054af0259568"}, + {file = "orjson-3.10.10-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e0ceb5e0e8c4f010ac787d29ae6299846935044686509e2f0f06ed441c1ca949"}, + {file = "orjson-3.10.10-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0c25908eb86968613216f3db4d3003f1c45d78eb9046b71056ca327ff92bdbd4"}, + {file = "orjson-3.10.10-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:218cb0bc03340144b6328a9ff78f0932e642199ac184dd74b01ad691f42f93ff"}, + {file = "orjson-3.10.10-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e2277ec2cea3775640dc81ab5195bb5b2ada2fe0ea6eee4677474edc75ea6785"}, + {file = "orjson-3.10.10-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:848ea3b55ab5ccc9d7bbd420d69432628b691fba3ca8ae3148c35156cbd282aa"}, + {file = "orjson-3.10.10-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:e3e67b537ac0c835b25b5f7d40d83816abd2d3f4c0b0866ee981a045287a54f3"}, + {file = "orjson-3.10.10-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:7948cfb909353fce2135dcdbe4521a5e7e1159484e0bb024c1722f272488f2b8"}, + {file = "orjson-3.10.10-cp38-none-win32.whl", hash = "sha256:78bee66a988f1a333dc0b6257503d63553b1957889c17b2c4ed72385cd1b96ae"}, + {file = "orjson-3.10.10-cp38-none-win_amd64.whl", hash = "sha256:f1d647ca8d62afeb774340a343c7fc023efacfd3a39f70c798991063f0c681dd"}, + {file = "orjson-3.10.10-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:5a059afddbaa6dd733b5a2d76a90dbc8af790b993b1b5cb97a1176ca713b5df8"}, + {file = "orjson-3.10.10-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f9b5c59f7e2a1a410f971c5ebc68f1995822837cd10905ee255f96074537ee6"}, + {file = "orjson-3.10.10-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d5ef198bafdef4aa9d49a4165ba53ffdc0a9e1c7b6f76178572ab33118afea25"}, + {file = "orjson-3.10.10-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aaf29ce0bb5d3320824ec3d1508652421000ba466abd63bdd52c64bcce9eb1fa"}, + {file = "orjson-3.10.10-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dddd5516bcc93e723d029c1633ae79c4417477b4f57dad9bfeeb6bc0315e654a"}, + {file = "orjson-3.10.10-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a12f2003695b10817f0fa8b8fca982ed7f5761dcb0d93cff4f2f9f6709903fd7"}, + {file = "orjson-3.10.10-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:672f9874a8a8fb9bb1b771331d31ba27f57702c8106cdbadad8bda5d10bc1019"}, + {file = "orjson-3.10.10-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1dcbb0ca5fafb2b378b2c74419480ab2486326974826bbf6588f4dc62137570a"}, + {file = "orjson-3.10.10-cp39-none-win32.whl", hash = "sha256:d9bbd3a4b92256875cb058c3381b782649b9a3c68a4aa9a2fff020c2f9cfc1be"}, + {file = "orjson-3.10.10-cp39-none-win_amd64.whl", hash = "sha256:766f21487a53aee8524b97ca9582d5c6541b03ab6210fbaf10142ae2f3ced2aa"}, + {file = "orjson-3.10.10.tar.gz", hash = "sha256:37949383c4df7b4337ce82ee35b6d7471e55195efa7dcb45ab8226ceadb0fe3b"}, ] [[package]] @@ -2998,50 +3454,68 @@ files = [ [[package]] name = "paginate" -version = "0.5.6" +version = "0.5.7" description = "Divides large result sets into pages for easier browsing" optional = false python-versions = "*" files = [ - {file = "paginate-0.5.6.tar.gz", hash = "sha256:5e6007b6a9398177a7e1648d04fdd9f8c9766a1a945bceac82f1929e8c78af2d"}, + {file = "paginate-0.5.7-py2.py3-none-any.whl", hash = "sha256:b885e2af73abcf01d9559fd5216b57ef722f8c42affbb63942377668e35c7591"}, + {file = "paginate-0.5.7.tar.gz", hash = "sha256:22bd083ab41e1a8b4f3690544afb2c60c25e5c9a63a30fa2f483f6c60c8e5945"}, ] +[package.extras] +dev = ["pytest", "tox"] +lint = ["black"] + [[package]] name = "pandas" -version = "2.2.2" +version = "2.2.3" description = "Powerful data structures for data analysis, time series, and statistics" optional = false python-versions = ">=3.9" files = [ - {file = "pandas-2.2.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:90c6fca2acf139569e74e8781709dccb6fe25940488755716d1d354d6bc58bce"}, - {file = "pandas-2.2.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c7adfc142dac335d8c1e0dcbd37eb8617eac386596eb9e1a1b77791cf2498238"}, - {file = "pandas-2.2.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4abfe0be0d7221be4f12552995e58723c7422c80a659da13ca382697de830c08"}, - {file = "pandas-2.2.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8635c16bf3d99040fdf3ca3db669a7250ddf49c55dc4aa8fe0ae0fa8d6dcc1f0"}, - {file = "pandas-2.2.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:40ae1dffb3967a52203105a077415a86044a2bea011b5f321c6aa64b379a3f51"}, - {file = "pandas-2.2.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8e5a0b00e1e56a842f922e7fae8ae4077aee4af0acb5ae3622bd4b4c30aedf99"}, - {file = "pandas-2.2.2-cp310-cp310-win_amd64.whl", hash = "sha256:ddf818e4e6c7c6f4f7c8a12709696d193976b591cc7dc50588d3d1a6b5dc8772"}, - {file = "pandas-2.2.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:696039430f7a562b74fa45f540aca068ea85fa34c244d0deee539cb6d70aa288"}, - {file = "pandas-2.2.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8e90497254aacacbc4ea6ae5e7a8cd75629d6ad2b30025a4a8b09aa4faf55151"}, - {file = "pandas-2.2.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:58b84b91b0b9f4bafac2a0ac55002280c094dfc6402402332c0913a59654ab2b"}, - {file = "pandas-2.2.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d2123dc9ad6a814bcdea0f099885276b31b24f7edf40f6cdbc0912672e22eee"}, - {file = "pandas-2.2.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:2925720037f06e89af896c70bca73459d7e6a4be96f9de79e2d440bd499fe0db"}, - {file = "pandas-2.2.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0cace394b6ea70c01ca1595f839cf193df35d1575986e484ad35c4aeae7266c1"}, - {file = "pandas-2.2.2-cp311-cp311-win_amd64.whl", hash = "sha256:873d13d177501a28b2756375d59816c365e42ed8417b41665f346289adc68d24"}, - {file = "pandas-2.2.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:9dfde2a0ddef507a631dc9dc4af6a9489d5e2e740e226ad426a05cabfbd7c8ef"}, - {file = "pandas-2.2.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e9b79011ff7a0f4b1d6da6a61aa1aa604fb312d6647de5bad20013682d1429ce"}, - {file = "pandas-2.2.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1cb51fe389360f3b5a4d57dbd2848a5f033350336ca3b340d1c53a1fad33bcad"}, - {file = "pandas-2.2.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eee3a87076c0756de40b05c5e9a6069c035ba43e8dd71c379e68cab2c20f16ad"}, - {file = "pandas-2.2.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:3e374f59e440d4ab45ca2fffde54b81ac3834cf5ae2cdfa69c90bc03bde04d76"}, - {file = "pandas-2.2.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:43498c0bdb43d55cb162cdc8c06fac328ccb5d2eabe3cadeb3529ae6f0517c32"}, - {file = "pandas-2.2.2-cp312-cp312-win_amd64.whl", hash = "sha256:d187d355ecec3629624fccb01d104da7d7f391db0311145817525281e2804d23"}, - {file = "pandas-2.2.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0ca6377b8fca51815f382bd0b697a0814c8bda55115678cbc94c30aacbb6eff2"}, - {file = "pandas-2.2.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9057e6aa78a584bc93a13f0a9bf7e753a5e9770a30b4d758b8d5f2a62a9433cd"}, - {file = "pandas-2.2.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:001910ad31abc7bf06f49dcc903755d2f7f3a9186c0c040b827e522e9cef0863"}, - {file = "pandas-2.2.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66b479b0bd07204e37583c191535505410daa8df638fd8e75ae1b383851fe921"}, - {file = "pandas-2.2.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:a77e9d1c386196879aa5eb712e77461aaee433e54c68cf253053a73b7e49c33a"}, - {file = "pandas-2.2.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:92fd6b027924a7e178ac202cfbe25e53368db90d56872d20ffae94b96c7acc57"}, - {file = "pandas-2.2.2-cp39-cp39-win_amd64.whl", hash = "sha256:640cef9aa381b60e296db324337a554aeeb883ead99dc8f6c18e81a93942f5f4"}, - {file = "pandas-2.2.2.tar.gz", hash = "sha256:9e79019aba43cb4fda9e4d983f8e88ca0373adbb697ae9c6c43093218de28b54"}, + {file = "pandas-2.2.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1948ddde24197a0f7add2bdc4ca83bf2b1ef84a1bc8ccffd95eda17fd836ecb5"}, + {file = "pandas-2.2.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:381175499d3802cde0eabbaf6324cce0c4f5d52ca6f8c377c29ad442f50f6348"}, + {file = "pandas-2.2.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d9c45366def9a3dd85a6454c0e7908f2b3b8e9c138f5dc38fed7ce720d8453ed"}, + {file = "pandas-2.2.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86976a1c5b25ae3f8ccae3a5306e443569ee3c3faf444dfd0f41cda24667ad57"}, + {file = "pandas-2.2.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b8661b0238a69d7aafe156b7fa86c44b881387509653fdf857bebc5e4008ad42"}, + {file = "pandas-2.2.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:37e0aced3e8f539eccf2e099f65cdb9c8aa85109b0be6e93e2baff94264bdc6f"}, + {file = "pandas-2.2.3-cp310-cp310-win_amd64.whl", hash = "sha256:56534ce0746a58afaf7942ba4863e0ef81c9c50d3f0ae93e9497d6a41a057645"}, + {file = "pandas-2.2.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:66108071e1b935240e74525006034333f98bcdb87ea116de573a6a0dccb6c039"}, + {file = "pandas-2.2.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7c2875855b0ff77b2a64a0365e24455d9990730d6431b9e0ee18ad8acee13dbd"}, + {file = "pandas-2.2.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cd8d0c3be0515c12fed0bdbae072551c8b54b7192c7b1fda0ba56059a0179698"}, + {file = "pandas-2.2.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c124333816c3a9b03fbeef3a9f230ba9a737e9e5bb4060aa2107a86cc0a497fc"}, + {file = "pandas-2.2.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:63cc132e40a2e084cf01adf0775b15ac515ba905d7dcca47e9a251819c575ef3"}, + {file = "pandas-2.2.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:29401dbfa9ad77319367d36940cd8a0b3a11aba16063e39632d98b0e931ddf32"}, + {file = "pandas-2.2.3-cp311-cp311-win_amd64.whl", hash = "sha256:3fc6873a41186404dad67245896a6e440baacc92f5b716ccd1bc9ed2995ab2c5"}, + {file = "pandas-2.2.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b1d432e8d08679a40e2a6d8b2f9770a5c21793a6f9f47fdd52c5ce1948a5a8a9"}, + {file = "pandas-2.2.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a5a1595fe639f5988ba6a8e5bc9649af3baf26df3998a0abe56c02609392e0a4"}, + {file = "pandas-2.2.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5de54125a92bb4d1c051c0659e6fcb75256bf799a732a87184e5ea503965bce3"}, + {file = "pandas-2.2.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fffb8ae78d8af97f849404f21411c95062db1496aeb3e56f146f0355c9989319"}, + {file = "pandas-2.2.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6dfcb5ee8d4d50c06a51c2fffa6cff6272098ad6540aed1a76d15fb9318194d8"}, + {file = "pandas-2.2.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:062309c1b9ea12a50e8ce661145c6aab431b1e99530d3cd60640e255778bd43a"}, + {file = "pandas-2.2.3-cp312-cp312-win_amd64.whl", hash = "sha256:59ef3764d0fe818125a5097d2ae867ca3fa64df032331b7e0917cf5d7bf66b13"}, + {file = "pandas-2.2.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f00d1345d84d8c86a63e476bb4955e46458b304b9575dcf71102b5c705320015"}, + {file = "pandas-2.2.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3508d914817e153ad359d7e069d752cdd736a247c322d932eb89e6bc84217f28"}, + {file = "pandas-2.2.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:22a9d949bfc9a502d320aa04e5d02feab689d61da4e7764b62c30b991c42c5f0"}, + {file = "pandas-2.2.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3a255b2c19987fbbe62a9dfd6cff7ff2aa9ccab3fc75218fd4b7530f01efa24"}, + {file = "pandas-2.2.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:800250ecdadb6d9c78eae4990da62743b857b470883fa27f652db8bdde7f6659"}, + {file = "pandas-2.2.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6374c452ff3ec675a8f46fd9ab25c4ad0ba590b71cf0656f8b6daa5202bca3fb"}, + {file = "pandas-2.2.3-cp313-cp313-win_amd64.whl", hash = "sha256:61c5ad4043f791b61dd4752191d9f07f0ae412515d59ba8f005832a532f8736d"}, + {file = "pandas-2.2.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:3b71f27954685ee685317063bf13c7709a7ba74fc996b84fc6821c59b0f06468"}, + {file = "pandas-2.2.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:38cf8125c40dae9d5acc10fa66af8ea6fdf760b2714ee482ca691fc66e6fcb18"}, + {file = "pandas-2.2.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ba96630bc17c875161df3818780af30e43be9b166ce51c9a18c1feae342906c2"}, + {file = "pandas-2.2.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1db71525a1538b30142094edb9adc10be3f3e176748cd7acc2240c2f2e5aa3a4"}, + {file = "pandas-2.2.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:15c0e1e02e93116177d29ff83e8b1619c93ddc9c49083f237d4312337a61165d"}, + {file = "pandas-2.2.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:ad5b65698ab28ed8d7f18790a0dc58005c7629f227be9ecc1072aa74c0c1d43a"}, + {file = "pandas-2.2.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bc6b93f9b966093cb0fd62ff1a7e4c09e6d546ad7c1de191767baffc57628f39"}, + {file = "pandas-2.2.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5dbca4c1acd72e8eeef4753eeca07de9b1db4f398669d5994086f788a5d7cc30"}, + {file = "pandas-2.2.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8cd6d7cc958a3910f934ea8dbdf17b2364827bb4dafc38ce6eef6bb3d65ff09c"}, + {file = "pandas-2.2.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:99df71520d25fade9db7c1076ac94eb994f4d2673ef2aa2e86ee039b6746d20c"}, + {file = "pandas-2.2.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:31d0ced62d4ea3e231a9f228366919a5ea0b07440d9d4dac345376fd8e1477ea"}, + {file = "pandas-2.2.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7eee9e7cea6adf3e3d24e304ac6b8300646e2a5d1cd3a3c2abed9101b0846761"}, + {file = "pandas-2.2.3-cp39-cp39-win_amd64.whl", hash = "sha256:4850ba03528b6dd51d6c5d273c46f183f39a9baf3f0143e566b89450965b105e"}, + {file = "pandas-2.2.3.tar.gz", hash = "sha256:4f18ba62b61d7e192368b84517265a99b4d7ee8912f8708660fb4a366cc82667"}, ] [package.dependencies] @@ -3080,13 +3554,13 @@ xml = ["lxml (>=4.9.2)"] [[package]] name = "pandas-gbq" -version = "0.23.1" +version = "0.24.0" description = "Google BigQuery connector for pandas" optional = false python-versions = ">=3.8" files = [ - {file = "pandas-gbq-0.23.1.tar.gz", hash = "sha256:6a4942b574643af1372360c807616a98b3f9ed9ca328794daa66d4f28af879be"}, - {file = "pandas_gbq-0.23.1-py2.py3-none-any.whl", hash = "sha256:74165384b6718c75a08cf434fb78f076200aa25d32705c4634eaeedbc4286b6a"}, + {file = "pandas_gbq-0.24.0-py2.py3-none-any.whl", hash = "sha256:e3e39f4fd8651ced033515e5e63a6c19bc757b26155fac01c4367e1aa74ee122"}, + {file = "pandas_gbq-0.24.0.tar.gz", hash = "sha256:264415277059821497e74ed0b2240b538cba9646ee627fb4668cac5cf274e4c3"}, ] [package.dependencies] @@ -3094,16 +3568,17 @@ db-dtypes = ">=1.0.4,<2.0.0" google-api-core = ">=2.10.2,<3.0.0dev" google-auth = ">=2.13.0" google-auth-oauthlib = ">=0.7.0" -google-cloud-bigquery = ">=3.3.5,<4.0.0dev" -numpy = ">=1.16.6" -packaging = ">=20.0.0" +google-cloud-bigquery = ">=3.4.2,<4.0.0dev" +numpy = ">=1.18.1" +packaging = ">=22.0.0" pandas = ">=1.1.4" -pyarrow = ">=3.0.0" +pyarrow = ">=4.0.0" pydata-google-auth = ">=1.5.0" setuptools = "*" [package.extras] bqstorage = ["google-cloud-bigquery-storage (>=2.16.2,<3.0.0dev)"] +geopandas = ["Shapely (>=1.8.4)", "geopandas (>=0.9.0)"] tqdm = ["tqdm (>=4.23.0)"] [[package]] @@ -3176,84 +3651,90 @@ ptyprocess = ">=0.5" [[package]] name = "pillow" -version = "10.3.0" +version = "11.0.0" description = "Python Imaging Library (Fork)" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "pillow-10.3.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:90b9e29824800e90c84e4022dd5cc16eb2d9605ee13f05d47641eb183cd73d45"}, - {file = "pillow-10.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a2c405445c79c3f5a124573a051062300936b0281fee57637e706453e452746c"}, - {file = "pillow-10.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:78618cdbccaa74d3f88d0ad6cb8ac3007f1a6fa5c6f19af64b55ca170bfa1edf"}, - {file = "pillow-10.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:261ddb7ca91fcf71757979534fb4c128448b5b4c55cb6152d280312062f69599"}, - {file = "pillow-10.3.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:ce49c67f4ea0609933d01c0731b34b8695a7a748d6c8d186f95e7d085d2fe475"}, - {file = "pillow-10.3.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:b14f16f94cbc61215115b9b1236f9c18403c15dd3c52cf629072afa9d54c1cbf"}, - {file = "pillow-10.3.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d33891be6df59d93df4d846640f0e46f1a807339f09e79a8040bc887bdcd7ed3"}, - {file = "pillow-10.3.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b50811d664d392f02f7761621303eba9d1b056fb1868c8cdf4231279645c25f5"}, - {file = "pillow-10.3.0-cp310-cp310-win32.whl", hash = "sha256:ca2870d5d10d8726a27396d3ca4cf7976cec0f3cb706debe88e3a5bd4610f7d2"}, - {file = "pillow-10.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:f0d0591a0aeaefdaf9a5e545e7485f89910c977087e7de2b6c388aec32011e9f"}, - {file = "pillow-10.3.0-cp310-cp310-win_arm64.whl", hash = "sha256:ccce24b7ad89adb5a1e34a6ba96ac2530046763912806ad4c247356a8f33a67b"}, - {file = "pillow-10.3.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:5f77cf66e96ae734717d341c145c5949c63180842a545c47a0ce7ae52ca83795"}, - {file = "pillow-10.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e4b878386c4bf293578b48fc570b84ecfe477d3b77ba39a6e87150af77f40c57"}, - {file = "pillow-10.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fdcbb4068117dfd9ce0138d068ac512843c52295ed996ae6dd1faf537b6dbc27"}, - {file = "pillow-10.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9797a6c8fe16f25749b371c02e2ade0efb51155e767a971c61734b1bf6293994"}, - {file = "pillow-10.3.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:9e91179a242bbc99be65e139e30690e081fe6cb91a8e77faf4c409653de39451"}, - {file = "pillow-10.3.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:1b87bd9d81d179bd8ab871603bd80d8645729939f90b71e62914e816a76fc6bd"}, - {file = "pillow-10.3.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:81d09caa7b27ef4e61cb7d8fbf1714f5aec1c6b6c5270ee53504981e6e9121ad"}, - {file = "pillow-10.3.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:048ad577748b9fa4a99a0548c64f2cb8d672d5bf2e643a739ac8faff1164238c"}, - {file = "pillow-10.3.0-cp311-cp311-win32.whl", hash = "sha256:7161ec49ef0800947dc5570f86568a7bb36fa97dd09e9827dc02b718c5643f09"}, - {file = "pillow-10.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:8eb0908e954d093b02a543dc963984d6e99ad2b5e36503d8a0aaf040505f747d"}, - {file = "pillow-10.3.0-cp311-cp311-win_arm64.whl", hash = "sha256:4e6f7d1c414191c1199f8996d3f2282b9ebea0945693fb67392c75a3a320941f"}, - {file = "pillow-10.3.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:e46f38133e5a060d46bd630faa4d9fa0202377495df1f068a8299fd78c84de84"}, - {file = "pillow-10.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:50b8eae8f7334ec826d6eeffaeeb00e36b5e24aa0b9df322c247539714c6df19"}, - {file = "pillow-10.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d3bea1c75f8c53ee4d505c3e67d8c158ad4df0d83170605b50b64025917f338"}, - {file = "pillow-10.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:19aeb96d43902f0a783946a0a87dbdad5c84c936025b8419da0a0cd7724356b1"}, - {file = "pillow-10.3.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:74d28c17412d9caa1066f7a31df8403ec23d5268ba46cd0ad2c50fb82ae40462"}, - {file = "pillow-10.3.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:ff61bfd9253c3915e6d41c651d5f962da23eda633cf02262990094a18a55371a"}, - {file = "pillow-10.3.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d886f5d353333b4771d21267c7ecc75b710f1a73d72d03ca06df49b09015a9ef"}, - {file = "pillow-10.3.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4b5ec25d8b17217d635f8935dbc1b9aa5907962fae29dff220f2659487891cd3"}, - {file = "pillow-10.3.0-cp312-cp312-win32.whl", hash = "sha256:51243f1ed5161b9945011a7360e997729776f6e5d7005ba0c6879267d4c5139d"}, - {file = "pillow-10.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:412444afb8c4c7a6cc11a47dade32982439925537e483be7c0ae0cf96c4f6a0b"}, - {file = "pillow-10.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:798232c92e7665fe82ac085f9d8e8ca98826f8e27859d9a96b41d519ecd2e49a"}, - {file = "pillow-10.3.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:4eaa22f0d22b1a7e93ff0a596d57fdede2e550aecffb5a1ef1106aaece48e96b"}, - {file = "pillow-10.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cd5e14fbf22a87321b24c88669aad3a51ec052eb145315b3da3b7e3cc105b9a2"}, - {file = "pillow-10.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1530e8f3a4b965eb6a7785cf17a426c779333eb62c9a7d1bbcf3ffd5bf77a4aa"}, - {file = "pillow-10.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d512aafa1d32efa014fa041d38868fda85028e3f930a96f85d49c7d8ddc0383"}, - {file = "pillow-10.3.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:339894035d0ede518b16073bdc2feef4c991ee991a29774b33e515f1d308e08d"}, - {file = "pillow-10.3.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:aa7e402ce11f0885305bfb6afb3434b3cd8f53b563ac065452d9d5654c7b86fd"}, - {file = "pillow-10.3.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:0ea2a783a2bdf2a561808fe4a7a12e9aa3799b701ba305de596bc48b8bdfce9d"}, - {file = "pillow-10.3.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c78e1b00a87ce43bb37642c0812315b411e856a905d58d597750eb79802aaaa3"}, - {file = "pillow-10.3.0-cp38-cp38-win32.whl", hash = "sha256:72d622d262e463dfb7595202d229f5f3ab4b852289a1cd09650362db23b9eb0b"}, - {file = "pillow-10.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:2034f6759a722da3a3dbd91a81148cf884e91d1b747992ca288ab88c1de15999"}, - {file = "pillow-10.3.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:2ed854e716a89b1afcedea551cd85f2eb2a807613752ab997b9974aaa0d56936"}, - {file = "pillow-10.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:dc1a390a82755a8c26c9964d457d4c9cbec5405896cba94cf51f36ea0d855002"}, - {file = "pillow-10.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4203efca580f0dd6f882ca211f923168548f7ba334c189e9eab1178ab840bf60"}, - {file = "pillow-10.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3102045a10945173d38336f6e71a8dc71bcaeed55c3123ad4af82c52807b9375"}, - {file = "pillow-10.3.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:6fb1b30043271ec92dc65f6d9f0b7a830c210b8a96423074b15c7bc999975f57"}, - {file = "pillow-10.3.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:1dfc94946bc60ea375cc39cff0b8da6c7e5f8fcdc1d946beb8da5c216156ddd8"}, - {file = "pillow-10.3.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b09b86b27a064c9624d0a6c54da01c1beaf5b6cadfa609cf63789b1d08a797b9"}, - {file = "pillow-10.3.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d3b2348a78bc939b4fed6552abfd2e7988e0f81443ef3911a4b8498ca084f6eb"}, - {file = "pillow-10.3.0-cp39-cp39-win32.whl", hash = "sha256:45ebc7b45406febf07fef35d856f0293a92e7417ae7933207e90bf9090b70572"}, - {file = "pillow-10.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:0ba26351b137ca4e0db0342d5d00d2e355eb29372c05afd544ebf47c0956ffeb"}, - {file = "pillow-10.3.0-cp39-cp39-win_arm64.whl", hash = "sha256:50fd3f6b26e3441ae07b7c979309638b72abc1a25da31a81a7fbd9495713ef4f"}, - {file = "pillow-10.3.0-pp310-pypy310_pp73-macosx_10_10_x86_64.whl", hash = "sha256:6b02471b72526ab8a18c39cb7967b72d194ec53c1fd0a70b050565a0f366d355"}, - {file = "pillow-10.3.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:8ab74c06ffdab957d7670c2a5a6e1a70181cd10b727cd788c4dd9005b6a8acd9"}, - {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:048eeade4c33fdf7e08da40ef402e748df113fd0b4584e32c4af74fe78baaeb2"}, - {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e2ec1e921fd07c7cda7962bad283acc2f2a9ccc1b971ee4b216b75fad6f0463"}, - {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:4c8e73e99da7db1b4cad7f8d682cf6abad7844da39834c288fbfa394a47bbced"}, - {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:16563993329b79513f59142a6b02055e10514c1a8e86dca8b48a893e33cf91e3"}, - {file = "pillow-10.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:dd78700f5788ae180b5ee8902c6aea5a5726bac7c364b202b4b3e3ba2d293170"}, - {file = "pillow-10.3.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:aff76a55a8aa8364d25400a210a65ff59d0168e0b4285ba6bf2bd83cf675ba32"}, - {file = "pillow-10.3.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:b7bc2176354defba3edc2b9a777744462da2f8e921fbaf61e52acb95bafa9828"}, - {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:793b4e24db2e8742ca6423d3fde8396db336698c55cd34b660663ee9e45ed37f"}, - {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d93480005693d247f8346bc8ee28c72a2191bdf1f6b5db469c096c0c867ac015"}, - {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c83341b89884e2b2e55886e8fbbf37c3fa5efd6c8907124aeb72f285ae5696e5"}, - {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:1a1d1915db1a4fdb2754b9de292642a39a7fb28f1736699527bb649484fb966a"}, - {file = "pillow-10.3.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a0eaa93d054751ee9964afa21c06247779b90440ca41d184aeb5d410f20ff591"}, - {file = "pillow-10.3.0.tar.gz", hash = "sha256:9d2455fbf44c914840c793e89aa82d0e1763a14253a000743719ae5946814b2d"}, + {file = "pillow-11.0.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:6619654954dc4936fcff82db8eb6401d3159ec6be81e33c6000dfd76ae189947"}, + {file = "pillow-11.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b3c5ac4bed7519088103d9450a1107f76308ecf91d6dabc8a33a2fcfb18d0fba"}, + {file = "pillow-11.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a65149d8ada1055029fcb665452b2814fe7d7082fcb0c5bed6db851cb69b2086"}, + {file = "pillow-11.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88a58d8ac0cc0e7f3a014509f0455248a76629ca9b604eca7dc5927cc593c5e9"}, + {file = "pillow-11.0.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:c26845094b1af3c91852745ae78e3ea47abf3dbcd1cf962f16b9a5fbe3ee8488"}, + {file = "pillow-11.0.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:1a61b54f87ab5786b8479f81c4b11f4d61702830354520837f8cc791ebba0f5f"}, + {file = "pillow-11.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:674629ff60030d144b7bca2b8330225a9b11c482ed408813924619c6f302fdbb"}, + {file = "pillow-11.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:598b4e238f13276e0008299bd2482003f48158e2b11826862b1eb2ad7c768b97"}, + {file = "pillow-11.0.0-cp310-cp310-win32.whl", hash = "sha256:9a0f748eaa434a41fccf8e1ee7a3eed68af1b690e75328fd7a60af123c193b50"}, + {file = "pillow-11.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:a5629742881bcbc1f42e840af185fd4d83a5edeb96475a575f4da50d6ede337c"}, + {file = "pillow-11.0.0-cp310-cp310-win_arm64.whl", hash = "sha256:ee217c198f2e41f184f3869f3e485557296d505b5195c513b2bfe0062dc537f1"}, + {file = "pillow-11.0.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:1c1d72714f429a521d8d2d018badc42414c3077eb187a59579f28e4270b4b0fc"}, + {file = "pillow-11.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:499c3a1b0d6fc8213519e193796eb1a86a1be4b1877d678b30f83fd979811d1a"}, + {file = "pillow-11.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c8b2351c85d855293a299038e1f89db92a2f35e8d2f783489c6f0b2b5f3fe8a3"}, + {file = "pillow-11.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f4dba50cfa56f910241eb7f883c20f1e7b1d8f7d91c750cd0b318bad443f4d5"}, + {file = "pillow-11.0.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:5ddbfd761ee00c12ee1be86c9c0683ecf5bb14c9772ddbd782085779a63dd55b"}, + {file = "pillow-11.0.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:45c566eb10b8967d71bf1ab8e4a525e5a93519e29ea071459ce517f6b903d7fa"}, + {file = "pillow-11.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b4fd7bd29610a83a8c9b564d457cf5bd92b4e11e79a4ee4716a63c959699b306"}, + {file = "pillow-11.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:cb929ca942d0ec4fac404cbf520ee6cac37bf35be479b970c4ffadf2b6a1cad9"}, + {file = "pillow-11.0.0-cp311-cp311-win32.whl", hash = "sha256:006bcdd307cc47ba43e924099a038cbf9591062e6c50e570819743f5607404f5"}, + {file = "pillow-11.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:52a2d8323a465f84faaba5236567d212c3668f2ab53e1c74c15583cf507a0291"}, + {file = "pillow-11.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:16095692a253047fe3ec028e951fa4221a1f3ed3d80c397e83541a3037ff67c9"}, + {file = "pillow-11.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d2c0a187a92a1cb5ef2c8ed5412dd8d4334272617f532d4ad4de31e0495bd923"}, + {file = "pillow-11.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:084a07ef0821cfe4858fe86652fffac8e187b6ae677e9906e192aafcc1b69903"}, + {file = "pillow-11.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8069c5179902dcdce0be9bfc8235347fdbac249d23bd90514b7a47a72d9fecf4"}, + {file = "pillow-11.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f02541ef64077f22bf4924f225c0fd1248c168f86e4b7abdedd87d6ebaceab0f"}, + {file = "pillow-11.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:fcb4621042ac4b7865c179bb972ed0da0218a076dc1820ffc48b1d74c1e37fe9"}, + {file = "pillow-11.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:00177a63030d612148e659b55ba99527803288cea7c75fb05766ab7981a8c1b7"}, + {file = "pillow-11.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8853a3bf12afddfdf15f57c4b02d7ded92c7a75a5d7331d19f4f9572a89c17e6"}, + {file = "pillow-11.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3107c66e43bda25359d5ef446f59c497de2b5ed4c7fdba0894f8d6cf3822dafc"}, + {file = "pillow-11.0.0-cp312-cp312-win32.whl", hash = "sha256:86510e3f5eca0ab87429dd77fafc04693195eec7fd6a137c389c3eeb4cfb77c6"}, + {file = "pillow-11.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:8ec4a89295cd6cd4d1058a5e6aec6bf51e0eaaf9714774e1bfac7cfc9051db47"}, + {file = "pillow-11.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:27a7860107500d813fcd203b4ea19b04babe79448268403172782754870dac25"}, + {file = "pillow-11.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:bcd1fb5bb7b07f64c15618c89efcc2cfa3e95f0e3bcdbaf4642509de1942a699"}, + {file = "pillow-11.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0e038b0745997c7dcaae350d35859c9715c71e92ffb7e0f4a8e8a16732150f38"}, + {file = "pillow-11.0.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ae08bd8ffc41aebf578c2af2f9d8749d91f448b3bfd41d7d9ff573d74f2a6b2"}, + {file = "pillow-11.0.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d69bfd8ec3219ae71bcde1f942b728903cad25fafe3100ba2258b973bd2bc1b2"}, + {file = "pillow-11.0.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:61b887f9ddba63ddf62fd02a3ba7add935d053b6dd7d58998c630e6dbade8527"}, + {file = "pillow-11.0.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:c6a660307ca9d4867caa8d9ca2c2658ab685de83792d1876274991adec7b93fa"}, + {file = "pillow-11.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:73e3a0200cdda995c7e43dd47436c1548f87a30bb27fb871f352a22ab8dcf45f"}, + {file = "pillow-11.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fba162b8872d30fea8c52b258a542c5dfd7b235fb5cb352240c8d63b414013eb"}, + {file = "pillow-11.0.0-cp313-cp313-win32.whl", hash = "sha256:f1b82c27e89fffc6da125d5eb0ca6e68017faf5efc078128cfaa42cf5cb38798"}, + {file = "pillow-11.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:8ba470552b48e5835f1d23ecb936bb7f71d206f9dfeee64245f30c3270b994de"}, + {file = "pillow-11.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:846e193e103b41e984ac921b335df59195356ce3f71dcfd155aa79c603873b84"}, + {file = "pillow-11.0.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:4ad70c4214f67d7466bea6a08061eba35c01b1b89eaa098040a35272a8efb22b"}, + {file = "pillow-11.0.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:6ec0d5af64f2e3d64a165f490d96368bb5dea8b8f9ad04487f9ab60dc4bb6003"}, + {file = "pillow-11.0.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c809a70e43c7977c4a42aefd62f0131823ebf7dd73556fa5d5950f5b354087e2"}, + {file = "pillow-11.0.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:4b60c9520f7207aaf2e1d94de026682fc227806c6e1f55bba7606d1c94dd623a"}, + {file = "pillow-11.0.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:1e2688958a840c822279fda0086fec1fdab2f95bf2b717b66871c4ad9859d7e8"}, + {file = "pillow-11.0.0-cp313-cp313t-win32.whl", hash = "sha256:607bbe123c74e272e381a8d1957083a9463401f7bd01287f50521ecb05a313f8"}, + {file = "pillow-11.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:5c39ed17edea3bc69c743a8dd3e9853b7509625c2462532e62baa0732163a904"}, + {file = "pillow-11.0.0-cp313-cp313t-win_arm64.whl", hash = "sha256:75acbbeb05b86bc53cbe7b7e6fe00fbcf82ad7c684b3ad82e3d711da9ba287d3"}, + {file = "pillow-11.0.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:2e46773dc9f35a1dd28bd6981332fd7f27bec001a918a72a79b4133cf5291dba"}, + {file = "pillow-11.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2679d2258b7f1192b378e2893a8a0a0ca472234d4c2c0e6bdd3380e8dfa21b6a"}, + {file = "pillow-11.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eda2616eb2313cbb3eebbe51f19362eb434b18e3bb599466a1ffa76a033fb916"}, + {file = "pillow-11.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20ec184af98a121fb2da42642dea8a29ec80fc3efbaefb86d8fdd2606619045d"}, + {file = "pillow-11.0.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:8594f42df584e5b4bb9281799698403f7af489fba84c34d53d1c4bfb71b7c4e7"}, + {file = "pillow-11.0.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:c12b5ae868897c7338519c03049a806af85b9b8c237b7d675b8c5e089e4a618e"}, + {file = "pillow-11.0.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:70fbbdacd1d271b77b7721fe3cdd2d537bbbd75d29e6300c672ec6bb38d9672f"}, + {file = "pillow-11.0.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:5178952973e588b3f1360868847334e9e3bf49d19e169bbbdfaf8398002419ae"}, + {file = "pillow-11.0.0-cp39-cp39-win32.whl", hash = "sha256:8c676b587da5673d3c75bd67dd2a8cdfeb282ca38a30f37950511766b26858c4"}, + {file = "pillow-11.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:94f3e1780abb45062287b4614a5bc0874519c86a777d4a7ad34978e86428b8dd"}, + {file = "pillow-11.0.0-cp39-cp39-win_arm64.whl", hash = "sha256:290f2cc809f9da7d6d622550bbf4c1e57518212da51b6a30fe8e0a270a5b78bd"}, + {file = "pillow-11.0.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:1187739620f2b365de756ce086fdb3604573337cc28a0d3ac4a01ab6b2d2a6d2"}, + {file = "pillow-11.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:fbbcb7b57dc9c794843e3d1258c0fbf0f48656d46ffe9e09b63bbd6e8cd5d0a2"}, + {file = "pillow-11.0.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d203af30149ae339ad1b4f710d9844ed8796e97fda23ffbc4cc472968a47d0b"}, + {file = "pillow-11.0.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21a0d3b115009ebb8ac3d2ebec5c2982cc693da935f4ab7bb5c8ebe2f47d36f2"}, + {file = "pillow-11.0.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:73853108f56df97baf2bb8b522f3578221e56f646ba345a372c78326710d3830"}, + {file = "pillow-11.0.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e58876c91f97b0952eb766123bfef372792ab3f4e3e1f1a2267834c2ab131734"}, + {file = "pillow-11.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:224aaa38177597bb179f3ec87eeefcce8e4f85e608025e9cfac60de237ba6316"}, + {file = "pillow-11.0.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:5bd2d3bdb846d757055910f0a59792d33b555800813c3b39ada1829c372ccb06"}, + {file = "pillow-11.0.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:375b8dd15a1f5d2feafff536d47e22f69625c1aa92f12b339ec0b2ca40263273"}, + {file = "pillow-11.0.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:daffdf51ee5db69a82dd127eabecce20729e21f7a3680cf7cbb23f0829189790"}, + {file = "pillow-11.0.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7326a1787e3c7b0429659e0a944725e1b03eeaa10edd945a86dead1913383944"}, + {file = "pillow-11.0.0.tar.gz", hash = "sha256:72bacbaf24ac003fea9bff9837d1eedb6088758d41e100c1552930151f677739"}, ] [package.extras] -docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinx-removed-in", "sphinxext-opengraph"] +docs = ["furo", "olefile", "sphinx (>=8.1)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinxext-opengraph"] fpx = ["olefile"] mic = ["olefile"] tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"] @@ -3262,29 +3743,29 @@ xmp = ["defusedxml"] [[package]] name = "platformdirs" -version = "4.2.2" +version = "4.3.6" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false python-versions = ">=3.8" files = [ - {file = "platformdirs-4.2.2-py3-none-any.whl", hash = "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee"}, - {file = "platformdirs-4.2.2.tar.gz", hash = "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3"}, + {file = "platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"}, + {file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"}, ] [package.extras] -docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"] -type = ["mypy (>=1.8)"] +docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.2)", "pytest-cov (>=5)", "pytest-mock (>=3.14)"] +type = ["mypy (>=1.11.2)"] [[package]] name = "plotly" -version = "5.22.0" +version = "5.24.1" description = "An open-source, interactive data visualization library for Python" optional = false python-versions = ">=3.8" files = [ - {file = "plotly-5.22.0-py3-none-any.whl", hash = "sha256:68fc1901f098daeb233cc3dd44ec9dc31fb3ca4f4e53189344199c43496ed006"}, - {file = "plotly-5.22.0.tar.gz", hash = "sha256:859fdadbd86b5770ae2466e542b761b247d1c6b49daed765b95bb8c7063e7469"}, + {file = "plotly-5.24.1-py3-none-any.whl", hash = "sha256:f67073a1e637eb0dc3e46324d9d51e2fe76e9727c892dde64ddf1e1b51f29089"}, + {file = "plotly-5.24.1.tar.gz", hash = "sha256:dbc8ac8339d248a4bcc36e08a5659bacfe1b079390b8953533f4eb22169b4bae"}, ] [package.dependencies] @@ -3308,13 +3789,13 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "portalocker" -version = "2.10.0" +version = "2.10.1" description = "Wraps the portalocker recipe for easy usage" optional = false python-versions = ">=3.8" files = [ - {file = "portalocker-2.10.0-py3-none-any.whl", hash = "sha256:48944147b2cd42520549bc1bb8fe44e220296e56f7c3d551bc6ecce69d9b0de1"}, - {file = "portalocker-2.10.0.tar.gz", hash = "sha256:49de8bc0a2f68ca98bf9e219c81a3e6b27097c7bf505a87c5a112ce1aaeb9b81"}, + {file = "portalocker-2.10.1-py3-none-any.whl", hash = "sha256:53a5984ebc86a025552264b459b46a2086e269b21823cb572f8f28ee759e45bf"}, + {file = "portalocker-2.10.1.tar.gz", hash = "sha256:ef1bf844e878ab08aee7e40184156e1151f228f103aa5c6bd0724cc330960f8f"}, ] [package.dependencies] @@ -3327,13 +3808,13 @@ tests = ["pytest (>=5.4.1)", "pytest-cov (>=2.8.1)", "pytest-mypy (>=0.8.0)", "p [[package]] name = "pre-commit" -version = "4.0.0" +version = "4.0.1" description = "A framework for managing and maintaining multi-language pre-commit hooks." optional = false python-versions = ">=3.9" files = [ - {file = "pre_commit-4.0.0-py2.py3-none-any.whl", hash = "sha256:0ca2341cf94ac1865350970951e54b1a50521e57b7b500403307aed4315a1234"}, - {file = "pre_commit-4.0.0.tar.gz", hash = "sha256:5d9807162cc5537940f94f266cbe2d716a75cfad0d78a317a92cac16287cfed6"}, + {file = "pre_commit-4.0.1-py2.py3-none-any.whl", hash = "sha256:efde913840816312445dc98787724647c65473daefe420785f885e8ed9a06878"}, + {file = "pre_commit-4.0.1.tar.gz", hash = "sha256:80905ac375958c0444c65e9cebebd948b3cdb518f335a091a670a89d652139d2"}, ] [package.dependencies] @@ -3356,27 +3837,134 @@ files = [ [[package]] name = "prompt-toolkit" -version = "3.0.47" +version = "3.0.48" description = "Library for building powerful interactive command lines in Python" optional = false python-versions = ">=3.7.0" files = [ - {file = "prompt_toolkit-3.0.47-py3-none-any.whl", hash = "sha256:0d7bfa67001d5e39d02c224b663abc33687405033a8c422d0d675a5a13361d10"}, - {file = "prompt_toolkit-3.0.47.tar.gz", hash = "sha256:1e1b29cb58080b1e69f207c893a1a7bf16d127a5c30c9d17a25a5d77792e5360"}, + {file = "prompt_toolkit-3.0.48-py3-none-any.whl", hash = "sha256:f49a827f90062e411f1ce1f854f2aedb3c23353244f8108b89283587397ac10e"}, + {file = "prompt_toolkit-3.0.48.tar.gz", hash = "sha256:d6623ab0477a80df74e646bdbc93621143f5caf104206aa29294d53de1a03d90"}, ] [package.dependencies] wcwidth = "*" +[[package]] +name = "propcache" +version = "0.2.0" +description = "Accelerated property cache" +optional = false +python-versions = ">=3.8" +files = [ + {file = "propcache-0.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:c5869b8fd70b81835a6f187c5fdbe67917a04d7e52b6e7cc4e5fe39d55c39d58"}, + {file = "propcache-0.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:952e0d9d07609d9c5be361f33b0d6d650cd2bae393aabb11d9b719364521984b"}, + {file = "propcache-0.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:33ac8f098df0585c0b53009f039dfd913b38c1d2edafed0cedcc0c32a05aa110"}, + {file = "propcache-0.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:97e48e8875e6c13909c800fa344cd54cc4b2b0db1d5f911f840458a500fde2c2"}, + {file = "propcache-0.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:388f3217649d6d59292b722d940d4d2e1e6a7003259eb835724092a1cca0203a"}, + {file = "propcache-0.2.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f571aea50ba5623c308aa146eb650eebf7dbe0fd8c5d946e28343cb3b5aad577"}, + {file = "propcache-0.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3dfafb44f7bb35c0c06eda6b2ab4bfd58f02729e7c4045e179f9a861b07c9850"}, + {file = "propcache-0.2.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a3ebe9a75be7ab0b7da2464a77bb27febcb4fab46a34f9288f39d74833db7f61"}, + {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d2f0d0f976985f85dfb5f3d685697ef769faa6b71993b46b295cdbbd6be8cc37"}, + {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:a3dc1a4b165283bd865e8f8cb5f0c64c05001e0718ed06250d8cac9bec115b48"}, + {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:9e0f07b42d2a50c7dd2d8675d50f7343d998c64008f1da5fef888396b7f84630"}, + {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:e63e3e1e0271f374ed489ff5ee73d4b6e7c60710e1f76af5f0e1a6117cd26394"}, + {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:56bb5c98f058a41bb58eead194b4db8c05b088c93d94d5161728515bd52b052b"}, + {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7665f04d0c7f26ff8bb534e1c65068409bf4687aa2534faf7104d7182debb336"}, + {file = "propcache-0.2.0-cp310-cp310-win32.whl", hash = "sha256:7cf18abf9764746b9c8704774d8b06714bcb0a63641518a3a89c7f85cc02c2ad"}, + {file = "propcache-0.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:cfac69017ef97db2438efb854edf24f5a29fd09a536ff3a992b75990720cdc99"}, + {file = "propcache-0.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:63f13bf09cc3336eb04a837490b8f332e0db41da66995c9fd1ba04552e516354"}, + {file = "propcache-0.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:608cce1da6f2672a56b24a015b42db4ac612ee709f3d29f27a00c943d9e851de"}, + {file = "propcache-0.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:466c219deee4536fbc83c08d09115249db301550625c7fef1c5563a584c9bc87"}, + {file = "propcache-0.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc2db02409338bf36590aa985a461b2c96fce91f8e7e0f14c50c5fcc4f229016"}, + {file = "propcache-0.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a6ed8db0a556343d566a5c124ee483ae113acc9a557a807d439bcecc44e7dfbb"}, + {file = "propcache-0.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:91997d9cb4a325b60d4e3f20967f8eb08dfcb32b22554d5ef78e6fd1dda743a2"}, + {file = "propcache-0.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c7dde9e533c0a49d802b4f3f218fa9ad0a1ce21f2c2eb80d5216565202acab4"}, + {file = "propcache-0.2.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffcad6c564fe6b9b8916c1aefbb37a362deebf9394bd2974e9d84232e3e08504"}, + {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:97a58a28bcf63284e8b4d7b460cbee1edaab24634e82059c7b8c09e65284f178"}, + {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:945db8ee295d3af9dbdbb698cce9bbc5c59b5c3fe328bbc4387f59a8a35f998d"}, + {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:39e104da444a34830751715f45ef9fc537475ba21b7f1f5b0f4d71a3b60d7fe2"}, + {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:c5ecca8f9bab618340c8e848d340baf68bcd8ad90a8ecd7a4524a81c1764b3db"}, + {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:c436130cc779806bdf5d5fae0d848713105472b8566b75ff70048c47d3961c5b"}, + {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:191db28dc6dcd29d1a3e063c3be0b40688ed76434622c53a284e5427565bbd9b"}, + {file = "propcache-0.2.0-cp311-cp311-win32.whl", hash = "sha256:5f2564ec89058ee7c7989a7b719115bdfe2a2fb8e7a4543b8d1c0cc4cf6478c1"}, + {file = "propcache-0.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:6e2e54267980349b723cff366d1e29b138b9a60fa376664a157a342689553f71"}, + {file = "propcache-0.2.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:2ee7606193fb267be4b2e3b32714f2d58cad27217638db98a60f9efb5efeccc2"}, + {file = "propcache-0.2.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:91ee8fc02ca52e24bcb77b234f22afc03288e1dafbb1f88fe24db308910c4ac7"}, + {file = "propcache-0.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2e900bad2a8456d00a113cad8c13343f3b1f327534e3589acc2219729237a2e8"}, + {file = "propcache-0.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f52a68c21363c45297aca15561812d542f8fc683c85201df0bebe209e349f793"}, + {file = "propcache-0.2.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1e41d67757ff4fbc8ef2af99b338bfb955010444b92929e9e55a6d4dcc3c4f09"}, + {file = "propcache-0.2.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a64e32f8bd94c105cc27f42d3b658902b5bcc947ece3c8fe7bc1b05982f60e89"}, + {file = "propcache-0.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:55346705687dbd7ef0d77883ab4f6fabc48232f587925bdaf95219bae072491e"}, + {file = "propcache-0.2.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:00181262b17e517df2cd85656fcd6b4e70946fe62cd625b9d74ac9977b64d8d9"}, + {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6994984550eaf25dd7fc7bd1b700ff45c894149341725bb4edc67f0ffa94efa4"}, + {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:56295eb1e5f3aecd516d91b00cfd8bf3a13991de5a479df9e27dd569ea23959c"}, + {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:439e76255daa0f8151d3cb325f6dd4a3e93043e6403e6491813bcaaaa8733887"}, + {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f6475a1b2ecb310c98c28d271a30df74f9dd436ee46d09236a6b750a7599ce57"}, + {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:3444cdba6628accf384e349014084b1cacd866fbb88433cd9d279d90a54e0b23"}, + {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4a9d9b4d0a9b38d1c391bb4ad24aa65f306c6f01b512e10a8a34a2dc5675d348"}, + {file = "propcache-0.2.0-cp312-cp312-win32.whl", hash = "sha256:69d3a98eebae99a420d4b28756c8ce6ea5a29291baf2dc9ff9414b42676f61d5"}, + {file = "propcache-0.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:ad9c9b99b05f163109466638bd30ada1722abb01bbb85c739c50b6dc11f92dc3"}, + {file = "propcache-0.2.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ecddc221a077a8132cf7c747d5352a15ed763b674c0448d811f408bf803d9ad7"}, + {file = "propcache-0.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0e53cb83fdd61cbd67202735e6a6687a7b491c8742dfc39c9e01e80354956763"}, + {file = "propcache-0.2.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92fe151145a990c22cbccf9ae15cae8ae9eddabfc949a219c9f667877e40853d"}, + {file = "propcache-0.2.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6a21ef516d36909931a2967621eecb256018aeb11fc48656e3257e73e2e247a"}, + {file = "propcache-0.2.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3f88a4095e913f98988f5b338c1d4d5d07dbb0b6bad19892fd447484e483ba6b"}, + {file = "propcache-0.2.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5a5b3bb545ead161be780ee85a2b54fdf7092815995661947812dde94a40f6fb"}, + {file = "propcache-0.2.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67aeb72e0f482709991aa91345a831d0b707d16b0257e8ef88a2ad246a7280bf"}, + {file = "propcache-0.2.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c997f8c44ec9b9b0bcbf2d422cc00a1d9b9c681f56efa6ca149a941e5560da2"}, + {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2a66df3d4992bc1d725b9aa803e8c5a66c010c65c741ad901e260ece77f58d2f"}, + {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:3ebbcf2a07621f29638799828b8d8668c421bfb94c6cb04269130d8de4fb7136"}, + {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1235c01ddaa80da8235741e80815ce381c5267f96cc49b1477fdcf8c047ef325"}, + {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3947483a381259c06921612550867b37d22e1df6d6d7e8361264b6d037595f44"}, + {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:d5bed7f9805cc29c780f3aee05de3262ee7ce1f47083cfe9f77471e9d6777e83"}, + {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e4a91d44379f45f5e540971d41e4626dacd7f01004826a18cb048e7da7e96544"}, + {file = "propcache-0.2.0-cp313-cp313-win32.whl", hash = "sha256:f902804113e032e2cdf8c71015651c97af6418363bea8d78dc0911d56c335032"}, + {file = "propcache-0.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:8f188cfcc64fb1266f4684206c9de0e80f54622c3f22a910cbd200478aeae61e"}, + {file = "propcache-0.2.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:53d1bd3f979ed529f0805dd35ddaca330f80a9a6d90bc0121d2ff398f8ed8861"}, + {file = "propcache-0.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:83928404adf8fb3d26793665633ea79b7361efa0287dfbd372a7e74311d51ee6"}, + {file = "propcache-0.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:77a86c261679ea5f3896ec060be9dc8e365788248cc1e049632a1be682442063"}, + {file = "propcache-0.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:218db2a3c297a3768c11a34812e63b3ac1c3234c3a086def9c0fee50d35add1f"}, + {file = "propcache-0.2.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7735e82e3498c27bcb2d17cb65d62c14f1100b71723b68362872bca7d0913d90"}, + {file = "propcache-0.2.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:20a617c776f520c3875cf4511e0d1db847a076d720714ae35ffe0df3e440be68"}, + {file = "propcache-0.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67b69535c870670c9f9b14a75d28baa32221d06f6b6fa6f77a0a13c5a7b0a5b9"}, + {file = "propcache-0.2.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4569158070180c3855e9c0791c56be3ceeb192defa2cdf6a3f39e54319e56b89"}, + {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:db47514ffdbd91ccdc7e6f8407aac4ee94cc871b15b577c1c324236b013ddd04"}, + {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_armv7l.whl", hash = "sha256:2a60ad3e2553a74168d275a0ef35e8c0a965448ffbc3b300ab3a5bb9956c2162"}, + {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:662dd62358bdeaca0aee5761de8727cfd6861432e3bb828dc2a693aa0471a563"}, + {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:25a1f88b471b3bc911d18b935ecb7115dff3a192b6fef46f0bfaf71ff4f12418"}, + {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:f60f0ac7005b9f5a6091009b09a419ace1610e163fa5deaba5ce3484341840e7"}, + {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:74acd6e291f885678631b7ebc85d2d4aec458dd849b8c841b57ef04047833bed"}, + {file = "propcache-0.2.0-cp38-cp38-win32.whl", hash = "sha256:d9b6ddac6408194e934002a69bcaadbc88c10b5f38fb9307779d1c629181815d"}, + {file = "propcache-0.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:676135dcf3262c9c5081cc8f19ad55c8a64e3f7282a21266d05544450bffc3a5"}, + {file = "propcache-0.2.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:25c8d773a62ce0451b020c7b29a35cfbc05de8b291163a7a0f3b7904f27253e6"}, + {file = "propcache-0.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:375a12d7556d462dc64d70475a9ee5982465fbb3d2b364f16b86ba9135793638"}, + {file = "propcache-0.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1ec43d76b9677637a89d6ab86e1fef70d739217fefa208c65352ecf0282be957"}, + {file = "propcache-0.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f45eec587dafd4b2d41ac189c2156461ebd0c1082d2fe7013571598abb8505d1"}, + {file = "propcache-0.2.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bc092ba439d91df90aea38168e11f75c655880c12782facf5cf9c00f3d42b562"}, + {file = "propcache-0.2.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fa1076244f54bb76e65e22cb6910365779d5c3d71d1f18b275f1dfc7b0d71b4d"}, + {file = "propcache-0.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:682a7c79a2fbf40f5dbb1eb6bfe2cd865376deeac65acf9beb607505dced9e12"}, + {file = "propcache-0.2.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8e40876731f99b6f3c897b66b803c9e1c07a989b366c6b5b475fafd1f7ba3fb8"}, + {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:363ea8cd3c5cb6679f1c2f5f1f9669587361c062e4899fce56758efa928728f8"}, + {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:140fbf08ab3588b3468932974a9331aff43c0ab8a2ec2c608b6d7d1756dbb6cb"}, + {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:e70fac33e8b4ac63dfc4c956fd7d85a0b1139adcfc0d964ce288b7c527537fea"}, + {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:b33d7a286c0dc1a15f5fc864cc48ae92a846df287ceac2dd499926c3801054a6"}, + {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:f6d5749fdd33d90e34c2efb174c7e236829147a2713334d708746e94c4bde40d"}, + {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:22aa8f2272d81d9317ff5756bb108021a056805ce63dd3630e27d042c8092798"}, + {file = "propcache-0.2.0-cp39-cp39-win32.whl", hash = "sha256:73e4b40ea0eda421b115248d7e79b59214411109a5bc47d0d48e4c73e3b8fcf9"}, + {file = "propcache-0.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:9517d5e9e0731957468c29dbfd0f976736a0e55afaea843726e887f36fe017df"}, + {file = "propcache-0.2.0-py3-none-any.whl", hash = "sha256:2ccc28197af5313706511fab3a8b66dcd6da067a1331372c82ea1cb74285e036"}, + {file = "propcache-0.2.0.tar.gz", hash = "sha256:df81779732feb9d01e5d513fad0122efb3d53bbc75f61b2a4f29a020bc985e70"}, +] + [[package]] name = "proto-plus" -version = "1.24.0" +version = "1.25.0" description = "Beautiful, Pythonic protocol buffers." optional = false python-versions = ">=3.7" files = [ - {file = "proto-plus-1.24.0.tar.gz", hash = "sha256:30b72a5ecafe4406b0d339db35b56c4059064e69227b8c3bda7462397f966445"}, - {file = "proto_plus-1.24.0-py3-none-any.whl", hash = "sha256:402576830425e5f6ce4c2a6702400ac79897dab0b4343821aa5188b0fab81a12"}, + {file = "proto_plus-1.25.0-py3-none-any.whl", hash = "sha256:c91fc4a65074ade8e458e95ef8bac34d4008daa7cce4a12d6707066fca648961"}, + {file = "proto_plus-1.25.0.tar.gz", hash = "sha256:fbb17f57f7bd05a68b7707e745e26528b0b3c34e378db91eef93912c54982d91"}, ] [package.dependencies] @@ -3418,32 +4006,33 @@ files = [ [[package]] name = "psutil" -version = "6.0.0" +version = "6.1.0" description = "Cross-platform lib for process and system monitoring in Python." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" files = [ - {file = "psutil-6.0.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a021da3e881cd935e64a3d0a20983bda0bb4cf80e4f74fa9bfcb1bc5785360c6"}, - {file = "psutil-6.0.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:1287c2b95f1c0a364d23bc6f2ea2365a8d4d9b726a3be7294296ff7ba97c17f0"}, - {file = "psutil-6.0.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:a9a3dbfb4de4f18174528d87cc352d1f788b7496991cca33c6996f40c9e3c92c"}, - {file = "psutil-6.0.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:6ec7588fb3ddaec7344a825afe298db83fe01bfaaab39155fa84cf1c0d6b13c3"}, - {file = "psutil-6.0.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:1e7c870afcb7d91fdea2b37c24aeb08f98b6d67257a5cb0a8bc3ac68d0f1a68c"}, - {file = "psutil-6.0.0-cp27-none-win32.whl", hash = "sha256:02b69001f44cc73c1c5279d02b30a817e339ceb258ad75997325e0e6169d8b35"}, - {file = "psutil-6.0.0-cp27-none-win_amd64.whl", hash = "sha256:21f1fb635deccd510f69f485b87433460a603919b45e2a324ad65b0cc74f8fb1"}, - {file = "psutil-6.0.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c588a7e9b1173b6e866756dde596fd4cad94f9399daf99ad8c3258b3cb2b47a0"}, - {file = "psutil-6.0.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ed2440ada7ef7d0d608f20ad89a04ec47d2d3ab7190896cd62ca5fc4fe08bf0"}, - {file = "psutil-6.0.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5fd9a97c8e94059b0ef54a7d4baf13b405011176c3b6ff257c247cae0d560ecd"}, - {file = "psutil-6.0.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2e8d0054fc88153ca0544f5c4d554d42e33df2e009c4ff42284ac9ebdef4132"}, - {file = "psutil-6.0.0-cp36-cp36m-win32.whl", hash = "sha256:fc8c9510cde0146432bbdb433322861ee8c3efbf8589865c8bf8d21cb30c4d14"}, - {file = "psutil-6.0.0-cp36-cp36m-win_amd64.whl", hash = "sha256:34859b8d8f423b86e4385ff3665d3f4d94be3cdf48221fbe476e883514fdb71c"}, - {file = "psutil-6.0.0-cp37-abi3-win32.whl", hash = "sha256:a495580d6bae27291324fe60cea0b5a7c23fa36a7cd35035a16d93bdcf076b9d"}, - {file = "psutil-6.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:33ea5e1c975250a720b3a6609c490db40dae5d83a4eb315170c4fe0d8b1f34b3"}, - {file = "psutil-6.0.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:ffe7fc9b6b36beadc8c322f84e1caff51e8703b88eee1da46d1e3a6ae11b4fd0"}, - {file = "psutil-6.0.0.tar.gz", hash = "sha256:8faae4f310b6d969fa26ca0545338b21f73c6b15db7c4a8d934a5482faa818f2"}, + {file = "psutil-6.1.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:ff34df86226c0227c52f38b919213157588a678d049688eded74c76c8ba4a5d0"}, + {file = "psutil-6.1.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:c0e0c00aa18ca2d3b2b991643b799a15fc8f0563d2ebb6040f64ce8dc027b942"}, + {file = "psutil-6.1.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:000d1d1ebd634b4efb383f4034437384e44a6d455260aaee2eca1e9c1b55f047"}, + {file = "psutil-6.1.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:5cd2bcdc75b452ba2e10f0e8ecc0b57b827dd5d7aaffbc6821b2a9a242823a76"}, + {file = "psutil-6.1.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:045f00a43c737f960d273a83973b2511430d61f283a44c96bf13a6e829ba8fdc"}, + {file = "psutil-6.1.0-cp27-none-win32.whl", hash = "sha256:9118f27452b70bb1d9ab3198c1f626c2499384935aaf55388211ad982611407e"}, + {file = "psutil-6.1.0-cp27-none-win_amd64.whl", hash = "sha256:a8506f6119cff7015678e2bce904a4da21025cc70ad283a53b099e7620061d85"}, + {file = "psutil-6.1.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:6e2dcd475ce8b80522e51d923d10c7871e45f20918e027ab682f94f1c6351688"}, + {file = "psutil-6.1.0-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:0895b8414afafc526712c498bd9de2b063deaac4021a3b3c34566283464aff8e"}, + {file = "psutil-6.1.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9dcbfce5d89f1d1f2546a2090f4fcf87c7f669d1d90aacb7d7582addece9fb38"}, + {file = "psutil-6.1.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:498c6979f9c6637ebc3a73b3f87f9eb1ec24e1ce53a7c5173b8508981614a90b"}, + {file = "psutil-6.1.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d905186d647b16755a800e7263d43df08b790d709d575105d419f8b6ef65423a"}, + {file = "psutil-6.1.0-cp36-cp36m-win32.whl", hash = "sha256:6d3fbbc8d23fcdcb500d2c9f94e07b1342df8ed71b948a2649b5cb060a7c94ca"}, + {file = "psutil-6.1.0-cp36-cp36m-win_amd64.whl", hash = "sha256:1209036fbd0421afde505a4879dee3b2fd7b1e14fee81c0069807adcbbcca747"}, + {file = "psutil-6.1.0-cp37-abi3-win32.whl", hash = "sha256:1ad45a1f5d0b608253b11508f80940985d1d0c8f6111b5cb637533a0e6ddc13e"}, + {file = "psutil-6.1.0-cp37-abi3-win_amd64.whl", hash = "sha256:a8fb3752b491d246034fa4d279ff076501588ce8cbcdbb62c32fd7a377d996be"}, + {file = "psutil-6.1.0.tar.gz", hash = "sha256:353815f59a7f64cdaca1c0307ee13558a0512f6db064e92fe833784f08539c7a"}, ] [package.extras] -test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"] +dev = ["black", "check-manifest", "coverage", "packaging", "pylint", "pyperf", "pypinfo", "pytest-cov", "requests", "rstcheck", "ruff", "sphinx", "sphinx_rtd_theme", "toml-sort", "twine", "virtualenv", "wheel"] +test = ["pytest", "pytest-xdist", "setuptools"] [[package]] name = "ptyprocess" @@ -3458,13 +4047,13 @@ files = [ [[package]] name = "pure-eval" -version = "0.2.2" +version = "0.2.3" description = "Safely evaluate AST nodes without side effects" optional = false python-versions = "*" files = [ - {file = "pure_eval-0.2.2-py3-none-any.whl", hash = "sha256:01eaab343580944bc56080ebe0a674b39ec44a945e6d09ba7db3cb8cec289350"}, - {file = "pure_eval-0.2.2.tar.gz", hash = "sha256:2b45320af6dfaa1750f543d714b6d1c520a1688dec6fd24d339063ce0aaa9ac3"}, + {file = "pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0"}, + {file = "pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42"}, ] [package.extras] @@ -3494,76 +4083,82 @@ files = [ [[package]] name = "pyarrow" -version = "16.1.0" +version = "18.0.0" description = "Python library for Apache Arrow" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "pyarrow-16.1.0-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:17e23b9a65a70cc733d8b738baa6ad3722298fa0c81d88f63ff94bf25eaa77b9"}, - {file = "pyarrow-16.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4740cc41e2ba5d641071d0ab5e9ef9b5e6e8c7611351a5cb7c1d175eaf43674a"}, - {file = "pyarrow-16.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:98100e0268d04e0eec47b73f20b39c45b4006f3c4233719c3848aa27a03c1aef"}, - {file = "pyarrow-16.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f68f409e7b283c085f2da014f9ef81e885d90dcd733bd648cfba3ef265961848"}, - {file = "pyarrow-16.1.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:a8914cd176f448e09746037b0c6b3a9d7688cef451ec5735094055116857580c"}, - {file = "pyarrow-16.1.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:48be160782c0556156d91adbdd5a4a7e719f8d407cb46ae3bb4eaee09b3111bd"}, - {file = "pyarrow-16.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:9cf389d444b0f41d9fe1444b70650fea31e9d52cfcb5f818b7888b91b586efff"}, - {file = "pyarrow-16.1.0-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:d0ebea336b535b37eee9eee31761813086d33ed06de9ab6fc6aaa0bace7b250c"}, - {file = "pyarrow-16.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2e73cfc4a99e796727919c5541c65bb88b973377501e39b9842ea71401ca6c1c"}, - {file = "pyarrow-16.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf9251264247ecfe93e5f5a0cd43b8ae834f1e61d1abca22da55b20c788417f6"}, - {file = "pyarrow-16.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ddf5aace92d520d3d2a20031d8b0ec27b4395cab9f74e07cc95edf42a5cc0147"}, - {file = "pyarrow-16.1.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:25233642583bf658f629eb230b9bb79d9af4d9f9229890b3c878699c82f7d11e"}, - {file = "pyarrow-16.1.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:a33a64576fddfbec0a44112eaf844c20853647ca833e9a647bfae0582b2ff94b"}, - {file = "pyarrow-16.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:185d121b50836379fe012753cf15c4ba9638bda9645183ab36246923875f8d1b"}, - {file = "pyarrow-16.1.0-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:2e51ca1d6ed7f2e9d5c3c83decf27b0d17bb207a7dea986e8dc3e24f80ff7d6f"}, - {file = "pyarrow-16.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:06ebccb6f8cb7357de85f60d5da50e83507954af617d7b05f48af1621d331c9a"}, - {file = "pyarrow-16.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b04707f1979815f5e49824ce52d1dceb46e2f12909a48a6a753fe7cafbc44a0c"}, - {file = "pyarrow-16.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d32000693deff8dc5df444b032b5985a48592c0697cb6e3071a5d59888714e2"}, - {file = "pyarrow-16.1.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:8785bb10d5d6fd5e15d718ee1d1f914fe768bf8b4d1e5e9bf253de8a26cb1628"}, - {file = "pyarrow-16.1.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:e1369af39587b794873b8a307cc6623a3b1194e69399af0efd05bb202195a5a7"}, - {file = "pyarrow-16.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:febde33305f1498f6df85e8020bca496d0e9ebf2093bab9e0f65e2b4ae2b3444"}, - {file = "pyarrow-16.1.0-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:b5f5705ab977947a43ac83b52ade3b881eb6e95fcc02d76f501d549a210ba77f"}, - {file = "pyarrow-16.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0d27bf89dfc2576f6206e9cd6cf7a107c9c06dc13d53bbc25b0bd4556f19cf5f"}, - {file = "pyarrow-16.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d07de3ee730647a600037bc1d7b7994067ed64d0eba797ac74b2bc77384f4c2"}, - {file = "pyarrow-16.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fbef391b63f708e103df99fbaa3acf9f671d77a183a07546ba2f2c297b361e83"}, - {file = "pyarrow-16.1.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:19741c4dbbbc986d38856ee7ddfdd6a00fc3b0fc2d928795b95410d38bb97d15"}, - {file = "pyarrow-16.1.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:f2c5fb249caa17b94e2b9278b36a05ce03d3180e6da0c4c3b3ce5b2788f30eed"}, - {file = "pyarrow-16.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:e6b6d3cd35fbb93b70ade1336022cc1147b95ec6af7d36906ca7fe432eb09710"}, - {file = "pyarrow-16.1.0-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:18da9b76a36a954665ccca8aa6bd9f46c1145f79c0bb8f4f244f5f8e799bca55"}, - {file = "pyarrow-16.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:99f7549779b6e434467d2aa43ab2b7224dd9e41bdde486020bae198978c9e05e"}, - {file = "pyarrow-16.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f07fdffe4fd5b15f5ec15c8b64584868d063bc22b86b46c9695624ca3505b7b4"}, - {file = "pyarrow-16.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ddfe389a08ea374972bd4065d5f25d14e36b43ebc22fc75f7b951f24378bf0b5"}, - {file = "pyarrow-16.1.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:3b20bd67c94b3a2ea0a749d2a5712fc845a69cb5d52e78e6449bbd295611f3aa"}, - {file = "pyarrow-16.1.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:ba8ac20693c0bb0bf4b238751d4409e62852004a8cf031c73b0e0962b03e45e3"}, - {file = "pyarrow-16.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:31a1851751433d89a986616015841977e0a188662fcffd1a5677453f1df2de0a"}, - {file = "pyarrow-16.1.0.tar.gz", hash = "sha256:15fbb22ea96d11f0b5768504a3f961edab25eaf4197c341720c4a387f6c60315"}, + {file = "pyarrow-18.0.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:2333f93260674e185cfbf208d2da3007132572e56871f451ba1a556b45dae6e2"}, + {file = "pyarrow-18.0.0-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:4c381857754da44326f3a49b8b199f7f87a51c2faacd5114352fc78de30d3aba"}, + {file = "pyarrow-18.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:603cd8ad4976568954598ef0a6d4ed3dfb78aff3d57fa8d6271f470f0ce7d34f"}, + {file = "pyarrow-18.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58a62549a3e0bc9e03df32f350e10e1efb94ec6cf63e3920c3385b26663948ce"}, + {file = "pyarrow-18.0.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:bc97316840a349485fbb137eb8d0f4d7057e1b2c1272b1a20eebbbe1848f5122"}, + {file = "pyarrow-18.0.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:2e549a748fa8b8715e734919923f69318c953e077e9c02140ada13e59d043310"}, + {file = "pyarrow-18.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:606e9a3dcb0f52307c5040698ea962685fb1c852d72379ee9412be7de9c5f9e2"}, + {file = "pyarrow-18.0.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:d5795e37c0a33baa618c5e054cd61f586cf76850a251e2b21355e4085def6280"}, + {file = "pyarrow-18.0.0-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:5f0510608ccd6e7f02ca8596962afb8c6cc84c453e7be0da4d85f5f4f7b0328a"}, + {file = "pyarrow-18.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:616ea2826c03c16e87f517c46296621a7c51e30400f6d0a61be645f203aa2b93"}, + {file = "pyarrow-18.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a1824f5b029ddd289919f354bc285992cb4e32da518758c136271cf66046ef22"}, + {file = "pyarrow-18.0.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:6dd1b52d0d58dd8f685ced9971eb49f697d753aa7912f0a8f50833c7a7426319"}, + {file = "pyarrow-18.0.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:320ae9bd45ad7ecc12ec858b3e8e462578de060832b98fc4d671dee9f10d9954"}, + {file = "pyarrow-18.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:2c992716cffb1088414f2b478f7af0175fd0a76fea80841b1706baa8fb0ebaad"}, + {file = "pyarrow-18.0.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:e7ab04f272f98ebffd2a0661e4e126036f6936391ba2889ed2d44c5006237802"}, + {file = "pyarrow-18.0.0-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:03f40b65a43be159d2f97fd64dc998f769d0995a50c00f07aab58b0b3da87e1f"}, + {file = "pyarrow-18.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be08af84808dff63a76860847c48ec0416928a7b3a17c2f49a072cac7c45efbd"}, + {file = "pyarrow-18.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c70c1965cde991b711a98448ccda3486f2a336457cf4ec4dca257a926e149c9"}, + {file = "pyarrow-18.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:00178509f379415a3fcf855af020e3340254f990a8534294ec3cf674d6e255fd"}, + {file = "pyarrow-18.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:a71ab0589a63a3e987beb2bc172e05f000a5c5be2636b4b263c44034e215b5d7"}, + {file = "pyarrow-18.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:fe92efcdbfa0bcf2fa602e466d7f2905500f33f09eb90bf0bcf2e6ca41b574c8"}, + {file = "pyarrow-18.0.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:907ee0aa8ca576f5e0cdc20b5aeb2ad4d3953a3b4769fc4b499e00ef0266f02f"}, + {file = "pyarrow-18.0.0-cp313-cp313-macosx_12_0_x86_64.whl", hash = "sha256:66dcc216ebae2eb4c37b223feaf82f15b69d502821dde2da138ec5a3716e7463"}, + {file = "pyarrow-18.0.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc1daf7c425f58527900876354390ee41b0ae962a73ad0959b9d829def583bb1"}, + {file = "pyarrow-18.0.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:871b292d4b696b09120ed5bde894f79ee2a5f109cb84470546471df264cae136"}, + {file = "pyarrow-18.0.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:082ba62bdcb939824ba1ce10b8acef5ab621da1f4c4805e07bfd153617ac19d4"}, + {file = "pyarrow-18.0.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:2c664ab88b9766413197733c1720d3dcd4190e8fa3bbdc3710384630a0a7207b"}, + {file = "pyarrow-18.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:dc892be34dbd058e8d189b47db1e33a227d965ea8805a235c8a7286f7fd17d3a"}, + {file = "pyarrow-18.0.0-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:28f9c39a56d2c78bf6b87dcc699d520ab850919d4a8c7418cd20eda49874a2ea"}, + {file = "pyarrow-18.0.0-cp313-cp313t-macosx_12_0_x86_64.whl", hash = "sha256:f1a198a50c409ab2d009fbf20956ace84567d67f2c5701511d4dd561fae6f32e"}, + {file = "pyarrow-18.0.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b5bd7fd32e3ace012d43925ea4fc8bd1b02cc6cc1e9813b518302950e89b5a22"}, + {file = "pyarrow-18.0.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:336addb8b6f5208be1b2398442c703a710b6b937b1a046065ee4db65e782ff5a"}, + {file = "pyarrow-18.0.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:45476490dd4adec5472c92b4d253e245258745d0ccaabe706f8d03288ed60a79"}, + {file = "pyarrow-18.0.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:b46591222c864e7da7faa3b19455196416cd8355ff6c2cc2e65726a760a3c420"}, + {file = "pyarrow-18.0.0-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:eb7e3abcda7e1e6b83c2dc2909c8d045881017270a119cc6ee7fdcfe71d02df8"}, + {file = "pyarrow-18.0.0-cp39-cp39-macosx_12_0_x86_64.whl", hash = "sha256:09f30690b99ce34e0da64d20dab372ee54431745e4efb78ac938234a282d15f9"}, + {file = "pyarrow-18.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d5ca5d707e158540312e09fd907f9f49bacbe779ab5236d9699ced14d2293b8"}, + {file = "pyarrow-18.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d6331f280c6e4521c69b201a42dd978f60f7e129511a55da9e0bfe426b4ebb8d"}, + {file = "pyarrow-18.0.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:3ac24b2be732e78a5a3ac0b3aa870d73766dd00beba6e015ea2ea7394f8b4e55"}, + {file = "pyarrow-18.0.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:b30a927c6dff89ee702686596f27c25160dd6c99be5bcc1513a763ae5b1bfc03"}, + {file = "pyarrow-18.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:8f40ec677e942374e3d7f2fad6a67a4c2811a8b975e8703c6fd26d3b168a90e2"}, + {file = "pyarrow-18.0.0.tar.gz", hash = "sha256:a6aa027b1a9d2970cf328ccd6dbe4a996bc13c39fd427f502782f5bdb9ca20f5"}, ] -[package.dependencies] -numpy = ">=1.16.6" +[package.extras] +test = ["cffi", "hypothesis", "pandas", "pytest", "pytz"] [[package]] name = "pyasn1" -version = "0.5.1" +version = "0.6.1" description = "Pure-Python implementation of ASN.1 types and DER/BER/CER codecs (X.208)" optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" +python-versions = ">=3.8" files = [ - {file = "pyasn1-0.5.1-py2.py3-none-any.whl", hash = "sha256:4439847c58d40b1d0a573d07e3856e95333f1976294494c325775aeca506eb58"}, - {file = "pyasn1-0.5.1.tar.gz", hash = "sha256:6d391a96e59b23130a5cfa74d6fd7f388dbbe26cc8f1edf39fdddf08d9d6676c"}, + {file = "pyasn1-0.6.1-py3-none-any.whl", hash = "sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629"}, + {file = "pyasn1-0.6.1.tar.gz", hash = "sha256:6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034"}, ] [[package]] name = "pyasn1-modules" -version = "0.3.0" +version = "0.4.1" description = "A collection of ASN.1-based protocols modules" optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" +python-versions = ">=3.8" files = [ - {file = "pyasn1_modules-0.3.0-py2.py3-none-any.whl", hash = "sha256:d3ccd6ed470d9ffbc716be08bd90efbd44d0734bc9303818f7336070984a162d"}, - {file = "pyasn1_modules-0.3.0.tar.gz", hash = "sha256:5bd01446b736eb9d31512a30d46c1ac3395d676c6f3cafa4c03eb54b9925631c"}, + {file = "pyasn1_modules-0.4.1-py3-none-any.whl", hash = "sha256:49bfa96b45a292b711e986f222502c1c9a5e1f4e568fc30e2574a6c7d07838fd"}, + {file = "pyasn1_modules-0.4.1.tar.gz", hash = "sha256:c28e2dbf9c06ad61c71a075c7e0f9fd0f1b0bb2d2ad4377f240d33ac2ab60a7c"}, ] [package.dependencies] -pyasn1 = ">=0.4.6,<0.6.0" +pyasn1 = ">=0.4.6,<0.7.0" [[package]] name = "pycares" @@ -3633,13 +4228,13 @@ idna = ["idna (>=2.1)"] [[package]] name = "pycodestyle" -version = "2.12.0" +version = "2.12.1" description = "Python style guide checker" optional = false python-versions = ">=3.8" files = [ - {file = "pycodestyle-2.12.0-py2.py3-none-any.whl", hash = "sha256:949a39f6b86c3e1515ba1787c2022131d165a8ad271b11370a8819aa070269e4"}, - {file = "pycodestyle-2.12.0.tar.gz", hash = "sha256:442f950141b4f43df752dd303511ffded3a04c2b6fb7f65980574f0c31e6e79c"}, + {file = "pycodestyle-2.12.1-py2.py3-none-any.whl", hash = "sha256:46f0fb92069a7c28ab7bb558f05bfc0110dac69a0cd23c61ea0040283a9d78b3"}, + {file = "pycodestyle-2.12.1.tar.gz", hash = "sha256:6838eae08bbce4f6accd5d5572075c63626a15ee3e6f842df996bf62f6d73521"}, ] [[package]] @@ -3671,18 +4266,18 @@ setuptools = "*" [[package]] name = "pydoclint" -version = "0.5.1" +version = "0.5.9" description = "A Python docstring linter that checks arguments, returns, yields, and raises sections" optional = false python-versions = ">=3.8" files = [ - {file = "pydoclint-0.5.1-py2.py3-none-any.whl", hash = "sha256:198cc7d80e7701e340466783b5c461d062622832f8ea7b4af66a1901c7df8a95"}, - {file = "pydoclint-0.5.1.tar.gz", hash = "sha256:380fcd5f14ef9781605f81db76a55f5781972cbf2a902282eab0c6566743860b"}, + {file = "pydoclint-0.5.9-py2.py3-none-any.whl", hash = "sha256:089327003cef6fe5605cbaa9887859ea5229ce0c9abb52775ffd57513094c1ae"}, + {file = "pydoclint-0.5.9.tar.gz", hash = "sha256:e200f964a5d9fbbb2ff1078bd7cb5433a0564d2482b6a1ba1be848f66bc4924f"}, ] [package.dependencies] click = ">=8.1.0" -docstring-parser-fork = ">=0.0.8" +docstring-parser-fork = ">=0.0.9" tomli = {version = ">=2.0.1", markers = "python_version < \"3.11\""} [package.extras] @@ -3715,13 +4310,13 @@ windows-terminal = ["colorama (>=0.4.6)"] [[package]] name = "pyjwt" -version = "2.8.0" +version = "2.9.0" description = "JSON Web Token implementation in Python" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "PyJWT-2.8.0-py3-none-any.whl", hash = "sha256:59127c392cc44c2da5bb3192169a91f429924e17aff6534d70fdc02ab3e04320"}, - {file = "PyJWT-2.8.0.tar.gz", hash = "sha256:57e28d156e3d5c10088e0c68abb90bfac3df82b40a71bd0daa20c65ccd5c23de"}, + {file = "PyJWT-2.9.0-py3-none-any.whl", hash = "sha256:3b02fb0f44517787776cf48f2ae25d8e14f300e6d7545a4315cee571a415e850"}, + {file = "pyjwt-2.9.0.tar.gz", hash = "sha256:7e1e5b56cc735432a7369cbfa0efe50fa113ebecdc04ae6922deba8b84582d0c"}, ] [package.dependencies] @@ -3729,8 +4324,8 @@ cryptography = {version = ">=3.4.0", optional = true, markers = "extra == \"cryp [package.extras] crypto = ["cryptography (>=3.4.0)"] -dev = ["coverage[toml] (==5.0.4)", "cryptography (>=3.4.0)", "pre-commit", "pytest (>=6.0.0,<7.0.0)", "sphinx (>=4.5.0,<5.0.0)", "sphinx-rtd-theme", "zope.interface"] -docs = ["sphinx (>=4.5.0,<5.0.0)", "sphinx-rtd-theme", "zope.interface"] +dev = ["coverage[toml] (==5.0.4)", "cryptography (>=3.4.0)", "pre-commit", "pytest (>=6.0.0,<7.0.0)", "sphinx", "sphinx-rtd-theme", "zope.interface"] +docs = ["sphinx", "sphinx-rtd-theme", "zope.interface"] tests = ["coverage[toml] (==5.0.4)", "pytest (>=6.0.0,<7.0.0)"] [[package]] @@ -3746,13 +4341,13 @@ files = [ [[package]] name = "pymdown-extensions" -version = "10.11.2" +version = "10.12" description = "Extension pack for Python Markdown." optional = false python-versions = ">=3.8" files = [ - {file = "pymdown_extensions-10.11.2-py3-none-any.whl", hash = "sha256:41cdde0a77290e480cf53892f5c5e50921a7ee3e5cd60ba91bf19837b33badcf"}, - {file = "pymdown_extensions-10.11.2.tar.gz", hash = "sha256:bc8847ecc9e784a098efd35e20cba772bc5a1b529dfcef9dc1972db9021a1049"}, + {file = "pymdown_extensions-10.12-py3-none-any.whl", hash = "sha256:49f81412242d3527b8b4967b990df395c89563043bc51a3d2d7d500e52123b77"}, + {file = "pymdown_extensions-10.12.tar.gz", hash = "sha256:b0ee1e0b2bef1071a47891ab17003bfe5bf824a398e13f49f8ed653b699369a7"}, ] [package.dependencies] @@ -3797,13 +4392,13 @@ sql = ["pandas (>=1.0.5)", "pyarrow (>=1.0.0)"] [[package]] name = "pytest" -version = "8.3.1" +version = "8.3.3" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.8" files = [ - {file = "pytest-8.3.1-py3-none-any.whl", hash = "sha256:e9600ccf4f563976e2c99fa02c7624ab938296551f280835ee6516df8bc4ae8c"}, - {file = "pytest-8.3.1.tar.gz", hash = "sha256:7e8e5c5abd6e93cb1cc151f23e57adc31fcf8cfd2a3ff2da63e23f732de35db6"}, + {file = "pytest-8.3.3-py3-none-any.whl", hash = "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2"}, + {file = "pytest-8.3.3.tar.gz", hash = "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181"}, ] [package.dependencies] @@ -3901,96 +4496,102 @@ files = [ [[package]] name = "pytz" -version = "2024.1" +version = "2024.2" description = "World timezone definitions, modern and historical" optional = false python-versions = "*" files = [ - {file = "pytz-2024.1-py2.py3-none-any.whl", hash = "sha256:328171f4e3623139da4983451950b28e95ac706e13f3f2630a879749e7a8b319"}, - {file = "pytz-2024.1.tar.gz", hash = "sha256:2a29735ea9c18baf14b448846bde5a48030ed267578472d8955cd0e7443a9812"}, + {file = "pytz-2024.2-py2.py3-none-any.whl", hash = "sha256:31c7c1817eb7fae7ca4b8c7ee50c72f93aa2dd863de768e1ef4245d426aa0725"}, + {file = "pytz-2024.2.tar.gz", hash = "sha256:2aa355083c50a0f93fa581709deac0c9ad65cca8a9e9beac660adcbd493c798a"}, ] [[package]] name = "pywin32" -version = "306" +version = "308" description = "Python for Window Extensions" optional = false python-versions = "*" files = [ - {file = "pywin32-306-cp310-cp310-win32.whl", hash = "sha256:06d3420a5155ba65f0b72f2699b5bacf3109f36acbe8923765c22938a69dfc8d"}, - {file = "pywin32-306-cp310-cp310-win_amd64.whl", hash = "sha256:84f4471dbca1887ea3803d8848a1616429ac94a4a8d05f4bc9c5dcfd42ca99c8"}, - {file = "pywin32-306-cp311-cp311-win32.whl", hash = "sha256:e65028133d15b64d2ed8f06dd9fbc268352478d4f9289e69c190ecd6818b6407"}, - {file = "pywin32-306-cp311-cp311-win_amd64.whl", hash = "sha256:a7639f51c184c0272e93f244eb24dafca9b1855707d94c192d4a0b4c01e1100e"}, - {file = "pywin32-306-cp311-cp311-win_arm64.whl", hash = "sha256:70dba0c913d19f942a2db25217d9a1b726c278f483a919f1abfed79c9cf64d3a"}, - {file = "pywin32-306-cp312-cp312-win32.whl", hash = "sha256:383229d515657f4e3ed1343da8be101000562bf514591ff383ae940cad65458b"}, - {file = "pywin32-306-cp312-cp312-win_amd64.whl", hash = "sha256:37257794c1ad39ee9be652da0462dc2e394c8159dfd913a8a4e8eb6fd346da0e"}, - {file = "pywin32-306-cp312-cp312-win_arm64.whl", hash = "sha256:5821ec52f6d321aa59e2db7e0a35b997de60c201943557d108af9d4ae1ec7040"}, - {file = "pywin32-306-cp37-cp37m-win32.whl", hash = "sha256:1c73ea9a0d2283d889001998059f5eaaba3b6238f767c9cf2833b13e6a685f65"}, - {file = "pywin32-306-cp37-cp37m-win_amd64.whl", hash = "sha256:72c5f621542d7bdd4fdb716227be0dd3f8565c11b280be6315b06ace35487d36"}, - {file = "pywin32-306-cp38-cp38-win32.whl", hash = "sha256:e4c092e2589b5cf0d365849e73e02c391c1349958c5ac3e9d5ccb9a28e017b3a"}, - {file = "pywin32-306-cp38-cp38-win_amd64.whl", hash = "sha256:e8ac1ae3601bee6ca9f7cb4b5363bf1c0badb935ef243c4733ff9a393b1690c0"}, - {file = "pywin32-306-cp39-cp39-win32.whl", hash = "sha256:e25fd5b485b55ac9c057f67d94bc203f3f6595078d1fb3b458c9c28b7153a802"}, - {file = "pywin32-306-cp39-cp39-win_amd64.whl", hash = "sha256:39b61c15272833b5c329a2989999dcae836b1eed650252ab1b7bfbe1d59f30f4"}, + {file = "pywin32-308-cp310-cp310-win32.whl", hash = "sha256:796ff4426437896550d2981b9c2ac0ffd75238ad9ea2d3bfa67a1abd546d262e"}, + {file = "pywin32-308-cp310-cp310-win_amd64.whl", hash = "sha256:4fc888c59b3c0bef905ce7eb7e2106a07712015ea1c8234b703a088d46110e8e"}, + {file = "pywin32-308-cp310-cp310-win_arm64.whl", hash = "sha256:a5ab5381813b40f264fa3495b98af850098f814a25a63589a8e9eb12560f450c"}, + {file = "pywin32-308-cp311-cp311-win32.whl", hash = "sha256:5d8c8015b24a7d6855b1550d8e660d8daa09983c80e5daf89a273e5c6fb5095a"}, + {file = "pywin32-308-cp311-cp311-win_amd64.whl", hash = "sha256:575621b90f0dc2695fec346b2d6302faebd4f0f45c05ea29404cefe35d89442b"}, + {file = "pywin32-308-cp311-cp311-win_arm64.whl", hash = "sha256:100a5442b7332070983c4cd03f2e906a5648a5104b8a7f50175f7906efd16bb6"}, + {file = "pywin32-308-cp312-cp312-win32.whl", hash = "sha256:587f3e19696f4bf96fde9d8a57cec74a57021ad5f204c9e627e15c33ff568897"}, + {file = "pywin32-308-cp312-cp312-win_amd64.whl", hash = "sha256:00b3e11ef09ede56c6a43c71f2d31857cf7c54b0ab6e78ac659497abd2834f47"}, + {file = "pywin32-308-cp312-cp312-win_arm64.whl", hash = "sha256:9b4de86c8d909aed15b7011182c8cab38c8850de36e6afb1f0db22b8959e3091"}, + {file = "pywin32-308-cp313-cp313-win32.whl", hash = "sha256:1c44539a37a5b7b21d02ab34e6a4d314e0788f1690d65b48e9b0b89f31abbbed"}, + {file = "pywin32-308-cp313-cp313-win_amd64.whl", hash = "sha256:fd380990e792eaf6827fcb7e187b2b4b1cede0585e3d0c9e84201ec27b9905e4"}, + {file = "pywin32-308-cp313-cp313-win_arm64.whl", hash = "sha256:ef313c46d4c18dfb82a2431e3051ac8f112ccee1a34f29c263c583c568db63cd"}, + {file = "pywin32-308-cp37-cp37m-win32.whl", hash = "sha256:1f696ab352a2ddd63bd07430080dd598e6369152ea13a25ebcdd2f503a38f1ff"}, + {file = "pywin32-308-cp37-cp37m-win_amd64.whl", hash = "sha256:13dcb914ed4347019fbec6697a01a0aec61019c1046c2b905410d197856326a6"}, + {file = "pywin32-308-cp38-cp38-win32.whl", hash = "sha256:5794e764ebcabf4ff08c555b31bd348c9025929371763b2183172ff4708152f0"}, + {file = "pywin32-308-cp38-cp38-win_amd64.whl", hash = "sha256:3b92622e29d651c6b783e368ba7d6722b1634b8e70bd376fd7610fe1992e19de"}, + {file = "pywin32-308-cp39-cp39-win32.whl", hash = "sha256:7873ca4dc60ab3287919881a7d4f88baee4a6e639aa6962de25a98ba6b193341"}, + {file = "pywin32-308-cp39-cp39-win_amd64.whl", hash = "sha256:71b3322d949b4cc20776436a9c9ba0eeedcbc9c650daa536df63f0ff111bb920"}, ] [[package]] name = "pyyaml" -version = "6.0.1" +version = "6.0.2" description = "YAML parser and emitter for Python" optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" files = [ - {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, - {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, - {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, - {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, - {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, - {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, - {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, - {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, - {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, - {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, - {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, - {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, - {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, - {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, - {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, - {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, - {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, - {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, - {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, - {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, - {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, - {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, - {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, - {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, - {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"}, - {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"}, - {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"}, - {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"}, - {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"}, - {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"}, - {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"}, - {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"}, - {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"}, - {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"}, - {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, - {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, - {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, - {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, - {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, - {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, - {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, - {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"}, - {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, - {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, - {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, - {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, - {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, - {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, - {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, + {file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"}, + {file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed"}, + {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180"}, + {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68"}, + {file = "PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99"}, + {file = "PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e"}, + {file = "PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774"}, + {file = "PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85"}, + {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4"}, + {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e"}, + {file = "PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5"}, + {file = "PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44"}, + {file = "PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab"}, + {file = "PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476"}, + {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48"}, + {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b"}, + {file = "PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4"}, + {file = "PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8"}, + {file = "PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba"}, + {file = "PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5"}, + {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc"}, + {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652"}, + {file = "PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183"}, + {file = "PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563"}, + {file = "PyYAML-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083"}, + {file = "PyYAML-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706"}, + {file = "PyYAML-6.0.2-cp38-cp38-win32.whl", hash = "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a"}, + {file = "PyYAML-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff"}, + {file = "PyYAML-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d"}, + {file = "PyYAML-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19"}, + {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e"}, + {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725"}, + {file = "PyYAML-6.0.2-cp39-cp39-win32.whl", hash = "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631"}, + {file = "PyYAML-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8"}, + {file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"}, ] [[package]] @@ -4009,99 +4610,120 @@ pyyaml = "*" [[package]] name = "pyzmq" -version = "26.0.3" +version = "26.2.0" description = "Python bindings for 0MQ" optional = false python-versions = ">=3.7" files = [ - {file = "pyzmq-26.0.3-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:44dd6fc3034f1eaa72ece33588867df9e006a7303725a12d64c3dff92330f625"}, - {file = "pyzmq-26.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:acb704195a71ac5ea5ecf2811c9ee19ecdc62b91878528302dd0be1b9451cc90"}, - {file = "pyzmq-26.0.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5dbb9c997932473a27afa93954bb77a9f9b786b4ccf718d903f35da3232317de"}, - {file = "pyzmq-26.0.3-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6bcb34f869d431799c3ee7d516554797f7760cb2198ecaa89c3f176f72d062be"}, - {file = "pyzmq-26.0.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:38ece17ec5f20d7d9b442e5174ae9f020365d01ba7c112205a4d59cf19dc38ee"}, - {file = "pyzmq-26.0.3-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:ba6e5e6588e49139a0979d03a7deb9c734bde647b9a8808f26acf9c547cab1bf"}, - {file = "pyzmq-26.0.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3bf8b000a4e2967e6dfdd8656cd0757d18c7e5ce3d16339e550bd462f4857e59"}, - {file = "pyzmq-26.0.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:2136f64fbb86451dbbf70223635a468272dd20075f988a102bf8a3f194a411dc"}, - {file = "pyzmq-26.0.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e8918973fbd34e7814f59143c5f600ecd38b8038161239fd1a3d33d5817a38b8"}, - {file = "pyzmq-26.0.3-cp310-cp310-win32.whl", hash = "sha256:0aaf982e68a7ac284377d051c742610220fd06d330dcd4c4dbb4cdd77c22a537"}, - {file = "pyzmq-26.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:f1a9b7d00fdf60b4039f4455afd031fe85ee8305b019334b72dcf73c567edc47"}, - {file = "pyzmq-26.0.3-cp310-cp310-win_arm64.whl", hash = "sha256:80b12f25d805a919d53efc0a5ad7c0c0326f13b4eae981a5d7b7cc343318ebb7"}, - {file = "pyzmq-26.0.3-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:a72a84570f84c374b4c287183debc776dc319d3e8ce6b6a0041ce2e400de3f32"}, - {file = "pyzmq-26.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7ca684ee649b55fd8f378127ac8462fb6c85f251c2fb027eb3c887e8ee347bcd"}, - {file = "pyzmq-26.0.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e222562dc0f38571c8b1ffdae9d7adb866363134299264a1958d077800b193b7"}, - {file = "pyzmq-26.0.3-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f17cde1db0754c35a91ac00b22b25c11da6eec5746431d6e5092f0cd31a3fea9"}, - {file = "pyzmq-26.0.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b7c0c0b3244bb2275abe255d4a30c050d541c6cb18b870975553f1fb6f37527"}, - {file = "pyzmq-26.0.3-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:ac97a21de3712afe6a6c071abfad40a6224fd14fa6ff0ff8d0c6e6cd4e2f807a"}, - {file = "pyzmq-26.0.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:88b88282e55fa39dd556d7fc04160bcf39dea015f78e0cecec8ff4f06c1fc2b5"}, - {file = "pyzmq-26.0.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:72b67f966b57dbd18dcc7efbc1c7fc9f5f983e572db1877081f075004614fcdd"}, - {file = "pyzmq-26.0.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f4b6cecbbf3b7380f3b61de3a7b93cb721125dc125c854c14ddc91225ba52f83"}, - {file = "pyzmq-26.0.3-cp311-cp311-win32.whl", hash = "sha256:eed56b6a39216d31ff8cd2f1d048b5bf1700e4b32a01b14379c3b6dde9ce3aa3"}, - {file = "pyzmq-26.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:3191d312c73e3cfd0f0afdf51df8405aafeb0bad71e7ed8f68b24b63c4f36500"}, - {file = "pyzmq-26.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:b6907da3017ef55139cf0e417c5123a84c7332520e73a6902ff1f79046cd3b94"}, - {file = "pyzmq-26.0.3-cp312-cp312-macosx_10_15_universal2.whl", hash = "sha256:068ca17214038ae986d68f4a7021f97e187ed278ab6dccb79f837d765a54d753"}, - {file = "pyzmq-26.0.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:7821d44fe07335bea256b9f1f41474a642ca55fa671dfd9f00af8d68a920c2d4"}, - {file = "pyzmq-26.0.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eeb438a26d87c123bb318e5f2b3d86a36060b01f22fbdffd8cf247d52f7c9a2b"}, - {file = "pyzmq-26.0.3-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:69ea9d6d9baa25a4dc9cef5e2b77b8537827b122214f210dd925132e34ae9b12"}, - {file = "pyzmq-26.0.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7daa3e1369355766dea11f1d8ef829905c3b9da886ea3152788dc25ee6079e02"}, - {file = "pyzmq-26.0.3-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:6ca7a9a06b52d0e38ccf6bca1aeff7be178917893f3883f37b75589d42c4ac20"}, - {file = "pyzmq-26.0.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1b7d0e124948daa4d9686d421ef5087c0516bc6179fdcf8828b8444f8e461a77"}, - {file = "pyzmq-26.0.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:e746524418b70f38550f2190eeee834db8850088c834d4c8406fbb9bc1ae10b2"}, - {file = "pyzmq-26.0.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:6b3146f9ae6af82c47a5282ac8803523d381b3b21caeae0327ed2f7ecb718798"}, - {file = "pyzmq-26.0.3-cp312-cp312-win32.whl", hash = "sha256:2b291d1230845871c00c8462c50565a9cd6026fe1228e77ca934470bb7d70ea0"}, - {file = "pyzmq-26.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:926838a535c2c1ea21c903f909a9a54e675c2126728c21381a94ddf37c3cbddf"}, - {file = "pyzmq-26.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:5bf6c237f8c681dfb91b17f8435b2735951f0d1fad10cc5dfd96db110243370b"}, - {file = "pyzmq-26.0.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0c0991f5a96a8e620f7691e61178cd8f457b49e17b7d9cfa2067e2a0a89fc1d5"}, - {file = "pyzmq-26.0.3-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:dbf012d8fcb9f2cf0643b65df3b355fdd74fc0035d70bb5c845e9e30a3a4654b"}, - {file = "pyzmq-26.0.3-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:01fbfbeb8249a68d257f601deb50c70c929dc2dfe683b754659569e502fbd3aa"}, - {file = "pyzmq-26.0.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c8eb19abe87029c18f226d42b8a2c9efdd139d08f8bf6e085dd9075446db450"}, - {file = "pyzmq-26.0.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:5344b896e79800af86ad643408ca9aa303a017f6ebff8cee5a3163c1e9aec987"}, - {file = "pyzmq-26.0.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:204e0f176fd1d067671157d049466869b3ae1fc51e354708b0dc41cf94e23a3a"}, - {file = "pyzmq-26.0.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a42db008d58530efa3b881eeee4991146de0b790e095f7ae43ba5cc612decbc5"}, - {file = "pyzmq-26.0.3-cp37-cp37m-win32.whl", hash = "sha256:8d7a498671ca87e32b54cb47c82a92b40130a26c5197d392720a1bce1b3c77cf"}, - {file = "pyzmq-26.0.3-cp37-cp37m-win_amd64.whl", hash = "sha256:3b4032a96410bdc760061b14ed6a33613ffb7f702181ba999df5d16fb96ba16a"}, - {file = "pyzmq-26.0.3-cp38-cp38-macosx_10_15_universal2.whl", hash = "sha256:2cc4e280098c1b192c42a849de8de2c8e0f3a84086a76ec5b07bfee29bda7d18"}, - {file = "pyzmq-26.0.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5bde86a2ed3ce587fa2b207424ce15b9a83a9fa14422dcc1c5356a13aed3df9d"}, - {file = "pyzmq-26.0.3-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:34106f68e20e6ff253c9f596ea50397dbd8699828d55e8fa18bd4323d8d966e6"}, - {file = "pyzmq-26.0.3-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ebbbd0e728af5db9b04e56389e2299a57ea8b9dd15c9759153ee2455b32be6ad"}, - {file = "pyzmq-26.0.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f6b1d1c631e5940cac5a0b22c5379c86e8df6a4ec277c7a856b714021ab6cfad"}, - {file = "pyzmq-26.0.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:e891ce81edd463b3b4c3b885c5603c00141151dd9c6936d98a680c8c72fe5c67"}, - {file = "pyzmq-26.0.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:9b273ecfbc590a1b98f014ae41e5cf723932f3b53ba9367cfb676f838038b32c"}, - {file = "pyzmq-26.0.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b32bff85fb02a75ea0b68f21e2412255b5731f3f389ed9aecc13a6752f58ac97"}, - {file = "pyzmq-26.0.3-cp38-cp38-win32.whl", hash = "sha256:f6c21c00478a7bea93caaaef9e7629145d4153b15a8653e8bb4609d4bc70dbfc"}, - {file = "pyzmq-26.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:3401613148d93ef0fd9aabdbddb212de3db7a4475367f49f590c837355343972"}, - {file = "pyzmq-26.0.3-cp39-cp39-macosx_10_15_universal2.whl", hash = "sha256:2ed8357f4c6e0daa4f3baf31832df8a33334e0fe5b020a61bc8b345a3db7a606"}, - {file = "pyzmq-26.0.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c1c8f2a2ca45292084c75bb6d3a25545cff0ed931ed228d3a1810ae3758f975f"}, - {file = "pyzmq-26.0.3-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:b63731993cdddcc8e087c64e9cf003f909262b359110070183d7f3025d1c56b5"}, - {file = "pyzmq-26.0.3-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b3cd31f859b662ac5d7f4226ec7d8bd60384fa037fc02aee6ff0b53ba29a3ba8"}, - {file = "pyzmq-26.0.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:115f8359402fa527cf47708d6f8a0f8234f0e9ca0cab7c18c9c189c194dbf620"}, - {file = "pyzmq-26.0.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:715bdf952b9533ba13dfcf1f431a8f49e63cecc31d91d007bc1deb914f47d0e4"}, - {file = "pyzmq-26.0.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:e1258c639e00bf5e8a522fec6c3eaa3e30cf1c23a2f21a586be7e04d50c9acab"}, - {file = "pyzmq-26.0.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:15c59e780be8f30a60816a9adab900c12a58d79c1ac742b4a8df044ab2a6d920"}, - {file = "pyzmq-26.0.3-cp39-cp39-win32.whl", hash = "sha256:d0cdde3c78d8ab5b46595054e5def32a755fc028685add5ddc7403e9f6de9879"}, - {file = "pyzmq-26.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:ce828058d482ef860746bf532822842e0ff484e27f540ef5c813d516dd8896d2"}, - {file = "pyzmq-26.0.3-cp39-cp39-win_arm64.whl", hash = "sha256:788f15721c64109cf720791714dc14afd0f449d63f3a5487724f024345067381"}, - {file = "pyzmq-26.0.3-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2c18645ef6294d99b256806e34653e86236eb266278c8ec8112622b61db255de"}, - {file = "pyzmq-26.0.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7e6bc96ebe49604df3ec2c6389cc3876cabe475e6bfc84ced1bf4e630662cb35"}, - {file = "pyzmq-26.0.3-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:971e8990c5cc4ddcff26e149398fc7b0f6a042306e82500f5e8db3b10ce69f84"}, - {file = "pyzmq-26.0.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8416c23161abd94cc7da80c734ad7c9f5dbebdadfdaa77dad78244457448223"}, - {file = "pyzmq-26.0.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:082a2988364b60bb5de809373098361cf1dbb239623e39e46cb18bc035ed9c0c"}, - {file = "pyzmq-26.0.3-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d57dfbf9737763b3a60d26e6800e02e04284926329aee8fb01049635e957fe81"}, - {file = "pyzmq-26.0.3-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:77a85dca4c2430ac04dc2a2185c2deb3858a34fe7f403d0a946fa56970cf60a1"}, - {file = "pyzmq-26.0.3-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4c82a6d952a1d555bf4be42b6532927d2a5686dd3c3e280e5f63225ab47ac1f5"}, - {file = "pyzmq-26.0.3-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4496b1282c70c442809fc1b151977c3d967bfb33e4e17cedbf226d97de18f709"}, - {file = "pyzmq-26.0.3-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:e4946d6bdb7ba972dfda282f9127e5756d4f299028b1566d1245fa0d438847e6"}, - {file = "pyzmq-26.0.3-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:03c0ae165e700364b266876d712acb1ac02693acd920afa67da2ebb91a0b3c09"}, - {file = "pyzmq-26.0.3-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:3e3070e680f79887d60feeda051a58d0ac36622e1759f305a41059eff62c6da7"}, - {file = "pyzmq-26.0.3-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6ca08b840fe95d1c2bd9ab92dac5685f949fc6f9ae820ec16193e5ddf603c3b2"}, - {file = "pyzmq-26.0.3-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e76654e9dbfb835b3518f9938e565c7806976c07b37c33526b574cc1a1050480"}, - {file = "pyzmq-26.0.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:871587bdadd1075b112e697173e946a07d722459d20716ceb3d1bd6c64bd08ce"}, - {file = "pyzmq-26.0.3-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d0a2d1bd63a4ad79483049b26514e70fa618ce6115220da9efdff63688808b17"}, - {file = "pyzmq-26.0.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0270b49b6847f0d106d64b5086e9ad5dc8a902413b5dbbb15d12b60f9c1747a4"}, - {file = "pyzmq-26.0.3-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:703c60b9910488d3d0954ca585c34f541e506a091a41930e663a098d3b794c67"}, - {file = "pyzmq-26.0.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:74423631b6be371edfbf7eabb02ab995c2563fee60a80a30829176842e71722a"}, - {file = "pyzmq-26.0.3-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:4adfbb5451196842a88fda3612e2c0414134874bffb1c2ce83ab4242ec9e027d"}, - {file = "pyzmq-26.0.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:3516119f4f9b8671083a70b6afaa0a070f5683e431ab3dc26e9215620d7ca1ad"}, - {file = "pyzmq-26.0.3.tar.gz", hash = "sha256:dba7d9f2e047dfa2bca3b01f4f84aa5246725203d6284e3790f2ca15fba6b40a"}, + {file = "pyzmq-26.2.0-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:ddf33d97d2f52d89f6e6e7ae66ee35a4d9ca6f36eda89c24591b0c40205a3629"}, + {file = "pyzmq-26.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dacd995031a01d16eec825bf30802fceb2c3791ef24bcce48fa98ce40918c27b"}, + {file = "pyzmq-26.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:89289a5ee32ef6c439086184529ae060c741334b8970a6855ec0b6ad3ff28764"}, + {file = "pyzmq-26.2.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5506f06d7dc6ecf1efacb4a013b1f05071bb24b76350832c96449f4a2d95091c"}, + {file = "pyzmq-26.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8ea039387c10202ce304af74def5021e9adc6297067f3441d348d2b633e8166a"}, + {file = "pyzmq-26.2.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:a2224fa4a4c2ee872886ed00a571f5e967c85e078e8e8c2530a2fb01b3309b88"}, + {file = "pyzmq-26.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:28ad5233e9c3b52d76196c696e362508959741e1a005fb8fa03b51aea156088f"}, + {file = "pyzmq-26.2.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:1c17211bc037c7d88e85ed8b7d8f7e52db6dc8eca5590d162717c654550f7282"}, + {file = "pyzmq-26.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b8f86dd868d41bea9a5f873ee13bf5551c94cf6bc51baebc6f85075971fe6eea"}, + {file = "pyzmq-26.2.0-cp310-cp310-win32.whl", hash = "sha256:46a446c212e58456b23af260f3d9fb785054f3e3653dbf7279d8f2b5546b21c2"}, + {file = "pyzmq-26.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:49d34ab71db5a9c292a7644ce74190b1dd5a3475612eefb1f8be1d6961441971"}, + {file = "pyzmq-26.2.0-cp310-cp310-win_arm64.whl", hash = "sha256:bfa832bfa540e5b5c27dcf5de5d82ebc431b82c453a43d141afb1e5d2de025fa"}, + {file = "pyzmq-26.2.0-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:8f7e66c7113c684c2b3f1c83cdd3376103ee0ce4c49ff80a648643e57fb22218"}, + {file = "pyzmq-26.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3a495b30fc91db2db25120df5847d9833af237546fd59170701acd816ccc01c4"}, + {file = "pyzmq-26.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77eb0968da535cba0470a5165468b2cac7772cfb569977cff92e240f57e31bef"}, + {file = "pyzmq-26.2.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ace4f71f1900a548f48407fc9be59c6ba9d9aaf658c2eea6cf2779e72f9f317"}, + {file = "pyzmq-26.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:92a78853d7280bffb93df0a4a6a2498cba10ee793cc8076ef797ef2f74d107cf"}, + {file = "pyzmq-26.2.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:689c5d781014956a4a6de61d74ba97b23547e431e9e7d64f27d4922ba96e9d6e"}, + {file = "pyzmq-26.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0aca98bc423eb7d153214b2df397c6421ba6373d3397b26c057af3c904452e37"}, + {file = "pyzmq-26.2.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:1f3496d76b89d9429a656293744ceca4d2ac2a10ae59b84c1da9b5165f429ad3"}, + {file = "pyzmq-26.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5c2b3bfd4b9689919db068ac6c9911f3fcb231c39f7dd30e3138be94896d18e6"}, + {file = "pyzmq-26.2.0-cp311-cp311-win32.whl", hash = "sha256:eac5174677da084abf378739dbf4ad245661635f1600edd1221f150b165343f4"}, + {file = "pyzmq-26.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:5a509df7d0a83a4b178d0f937ef14286659225ef4e8812e05580776c70e155d5"}, + {file = "pyzmq-26.2.0-cp311-cp311-win_arm64.whl", hash = "sha256:c0e6091b157d48cbe37bd67233318dbb53e1e6327d6fc3bb284afd585d141003"}, + {file = "pyzmq-26.2.0-cp312-cp312-macosx_10_15_universal2.whl", hash = "sha256:ded0fc7d90fe93ae0b18059930086c51e640cdd3baebdc783a695c77f123dcd9"}, + {file = "pyzmq-26.2.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:17bf5a931c7f6618023cdacc7081f3f266aecb68ca692adac015c383a134ca52"}, + {file = "pyzmq-26.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55cf66647e49d4621a7e20c8d13511ef1fe1efbbccf670811864452487007e08"}, + {file = "pyzmq-26.2.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4661c88db4a9e0f958c8abc2b97472e23061f0bc737f6f6179d7a27024e1faa5"}, + {file = "pyzmq-26.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ea7f69de383cb47522c9c208aec6dd17697db7875a4674c4af3f8cfdac0bdeae"}, + {file = "pyzmq-26.2.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:7f98f6dfa8b8ccaf39163ce872bddacca38f6a67289116c8937a02e30bbe9711"}, + {file = "pyzmq-26.2.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:e3e0210287329272539eea617830a6a28161fbbd8a3271bf4150ae3e58c5d0e6"}, + {file = "pyzmq-26.2.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:6b274e0762c33c7471f1a7471d1a2085b1a35eba5cdc48d2ae319f28b6fc4de3"}, + {file = "pyzmq-26.2.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:29c6a4635eef69d68a00321e12a7d2559fe2dfccfa8efae3ffb8e91cd0b36a8b"}, + {file = "pyzmq-26.2.0-cp312-cp312-win32.whl", hash = "sha256:989d842dc06dc59feea09e58c74ca3e1678c812a4a8a2a419046d711031f69c7"}, + {file = "pyzmq-26.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:2a50625acdc7801bc6f74698c5c583a491c61d73c6b7ea4dee3901bb99adb27a"}, + {file = "pyzmq-26.2.0-cp312-cp312-win_arm64.whl", hash = "sha256:4d29ab8592b6ad12ebbf92ac2ed2bedcfd1cec192d8e559e2e099f648570e19b"}, + {file = "pyzmq-26.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9dd8cd1aeb00775f527ec60022004d030ddc51d783d056e3e23e74e623e33726"}, + {file = "pyzmq-26.2.0-cp313-cp313-macosx_10_15_universal2.whl", hash = "sha256:28c812d9757fe8acecc910c9ac9dafd2ce968c00f9e619db09e9f8f54c3a68a3"}, + {file = "pyzmq-26.2.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d80b1dd99c1942f74ed608ddb38b181b87476c6a966a88a950c7dee118fdf50"}, + {file = "pyzmq-26.2.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8c997098cc65e3208eca09303630e84d42718620e83b733d0fd69543a9cab9cb"}, + {file = "pyzmq-26.2.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ad1bc8d1b7a18497dda9600b12dc193c577beb391beae5cd2349184db40f187"}, + {file = "pyzmq-26.2.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:bea2acdd8ea4275e1278350ced63da0b166421928276c7c8e3f9729d7402a57b"}, + {file = "pyzmq-26.2.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:23f4aad749d13698f3f7b64aad34f5fc02d6f20f05999eebc96b89b01262fb18"}, + {file = "pyzmq-26.2.0-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:a4f96f0d88accc3dbe4a9025f785ba830f968e21e3e2c6321ccdfc9aef755115"}, + {file = "pyzmq-26.2.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ced65e5a985398827cc9276b93ef6dfabe0273c23de8c7931339d7e141c2818e"}, + {file = "pyzmq-26.2.0-cp313-cp313-win32.whl", hash = "sha256:31507f7b47cc1ead1f6e86927f8ebb196a0bab043f6345ce070f412a59bf87b5"}, + {file = "pyzmq-26.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:70fc7fcf0410d16ebdda9b26cbd8bf8d803d220a7f3522e060a69a9c87bf7bad"}, + {file = "pyzmq-26.2.0-cp313-cp313-win_arm64.whl", hash = "sha256:c3789bd5768ab5618ebf09cef6ec2b35fed88709b104351748a63045f0ff9797"}, + {file = "pyzmq-26.2.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:034da5fc55d9f8da09015d368f519478a52675e558c989bfcb5cf6d4e16a7d2a"}, + {file = "pyzmq-26.2.0-cp313-cp313t-macosx_10_15_universal2.whl", hash = "sha256:c92d73464b886931308ccc45b2744e5968cbaade0b1d6aeb40d8ab537765f5bc"}, + {file = "pyzmq-26.2.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:794a4562dcb374f7dbbfb3f51d28fb40123b5a2abadee7b4091f93054909add5"}, + {file = "pyzmq-26.2.0-cp313-cp313t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aee22939bb6075e7afededabad1a56a905da0b3c4e3e0c45e75810ebe3a52672"}, + {file = "pyzmq-26.2.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ae90ff9dad33a1cfe947d2c40cb9cb5e600d759ac4f0fd22616ce6540f72797"}, + {file = "pyzmq-26.2.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:43a47408ac52647dfabbc66a25b05b6a61700b5165807e3fbd40063fcaf46386"}, + {file = "pyzmq-26.2.0-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:25bf2374a2a8433633c65ccb9553350d5e17e60c8eb4de4d92cc6bd60f01d306"}, + {file = "pyzmq-26.2.0-cp313-cp313t-musllinux_1_1_i686.whl", hash = "sha256:007137c9ac9ad5ea21e6ad97d3489af654381324d5d3ba614c323f60dab8fae6"}, + {file = "pyzmq-26.2.0-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:470d4a4f6d48fb34e92d768b4e8a5cc3780db0d69107abf1cd7ff734b9766eb0"}, + {file = "pyzmq-26.2.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3b55a4229ce5da9497dd0452b914556ae58e96a4381bb6f59f1305dfd7e53fc8"}, + {file = "pyzmq-26.2.0-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:9cb3a6460cdea8fe8194a76de8895707e61ded10ad0be97188cc8463ffa7e3a8"}, + {file = "pyzmq-26.2.0-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8ab5cad923cc95c87bffee098a27856c859bd5d0af31bd346035aa816b081fe1"}, + {file = "pyzmq-26.2.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9ed69074a610fad1c2fda66180e7b2edd4d31c53f2d1872bc2d1211563904cd9"}, + {file = "pyzmq-26.2.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:cccba051221b916a4f5e538997c45d7d136a5646442b1231b916d0164067ea27"}, + {file = "pyzmq-26.2.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:0eaa83fc4c1e271c24eaf8fb083cbccef8fde77ec8cd45f3c35a9a123e6da097"}, + {file = "pyzmq-26.2.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:9edda2df81daa129b25a39b86cb57dfdfe16f7ec15b42b19bfac503360d27a93"}, + {file = "pyzmq-26.2.0-cp37-cp37m-win32.whl", hash = "sha256:ea0eb6af8a17fa272f7b98d7bebfab7836a0d62738e16ba380f440fceca2d951"}, + {file = "pyzmq-26.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:4ff9dc6bc1664bb9eec25cd17506ef6672d506115095411e237d571e92a58231"}, + {file = "pyzmq-26.2.0-cp38-cp38-macosx_10_15_universal2.whl", hash = "sha256:2eb7735ee73ca1b0d71e0e67c3739c689067f055c764f73aac4cc8ecf958ee3f"}, + {file = "pyzmq-26.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1a534f43bc738181aa7cbbaf48e3eca62c76453a40a746ab95d4b27b1111a7d2"}, + {file = "pyzmq-26.2.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:aedd5dd8692635813368e558a05266b995d3d020b23e49581ddd5bbe197a8ab6"}, + {file = "pyzmq-26.2.0-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8be4700cd8bb02cc454f630dcdf7cfa99de96788b80c51b60fe2fe1dac480289"}, + {file = "pyzmq-26.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fcc03fa4997c447dce58264e93b5aa2d57714fbe0f06c07b7785ae131512732"}, + {file = "pyzmq-26.2.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:402b190912935d3db15b03e8f7485812db350d271b284ded2b80d2e5704be780"}, + {file = "pyzmq-26.2.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8685fa9c25ff00f550c1fec650430c4b71e4e48e8d852f7ddcf2e48308038640"}, + {file = "pyzmq-26.2.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:76589c020680778f06b7e0b193f4b6dd66d470234a16e1df90329f5e14a171cd"}, + {file = "pyzmq-26.2.0-cp38-cp38-win32.whl", hash = "sha256:8423c1877d72c041f2c263b1ec6e34360448decfb323fa8b94e85883043ef988"}, + {file = "pyzmq-26.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:76589f2cd6b77b5bdea4fca5992dc1c23389d68b18ccc26a53680ba2dc80ff2f"}, + {file = "pyzmq-26.2.0-cp39-cp39-macosx_10_15_universal2.whl", hash = "sha256:b1d464cb8d72bfc1a3adc53305a63a8e0cac6bc8c5a07e8ca190ab8d3faa43c2"}, + {file = "pyzmq-26.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4da04c48873a6abdd71811c5e163bd656ee1b957971db7f35140a2d573f6949c"}, + {file = "pyzmq-26.2.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:d049df610ac811dcffdc147153b414147428567fbbc8be43bb8885f04db39d98"}, + {file = "pyzmq-26.2.0-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:05590cdbc6b902101d0e65d6a4780af14dc22914cc6ab995d99b85af45362cc9"}, + {file = "pyzmq-26.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c811cfcd6a9bf680236c40c6f617187515269ab2912f3d7e8c0174898e2519db"}, + {file = "pyzmq-26.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:6835dd60355593de10350394242b5757fbbd88b25287314316f266e24c61d073"}, + {file = "pyzmq-26.2.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc6bee759a6bddea5db78d7dcd609397449cb2d2d6587f48f3ca613b19410cfc"}, + {file = "pyzmq-26.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c530e1eecd036ecc83c3407f77bb86feb79916d4a33d11394b8234f3bd35b940"}, + {file = "pyzmq-26.2.0-cp39-cp39-win32.whl", hash = "sha256:367b4f689786fca726ef7a6c5ba606958b145b9340a5e4808132cc65759abd44"}, + {file = "pyzmq-26.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:e6fa2e3e683f34aea77de8112f6483803c96a44fd726d7358b9888ae5bb394ec"}, + {file = "pyzmq-26.2.0-cp39-cp39-win_arm64.whl", hash = "sha256:7445be39143a8aa4faec43b076e06944b8f9d0701b669df4af200531b21e40bb"}, + {file = "pyzmq-26.2.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:706e794564bec25819d21a41c31d4df2d48e1cc4b061e8d345d7fb4dd3e94072"}, + {file = "pyzmq-26.2.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b435f2753621cd36e7c1762156815e21c985c72b19135dac43a7f4f31d28dd1"}, + {file = "pyzmq-26.2.0-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:160c7e0a5eb178011e72892f99f918c04a131f36056d10d9c1afb223fc952c2d"}, + {file = "pyzmq-26.2.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c4a71d5d6e7b28a47a394c0471b7e77a0661e2d651e7ae91e0cab0a587859ca"}, + {file = "pyzmq-26.2.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:90412f2db8c02a3864cbfc67db0e3dcdbda336acf1c469526d3e869394fe001c"}, + {file = "pyzmq-26.2.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2ea4ad4e6a12e454de05f2949d4beddb52460f3de7c8b9d5c46fbb7d7222e02c"}, + {file = "pyzmq-26.2.0-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:fc4f7a173a5609631bb0c42c23d12c49df3966f89f496a51d3eb0ec81f4519d6"}, + {file = "pyzmq-26.2.0-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:878206a45202247781472a2d99df12a176fef806ca175799e1c6ad263510d57c"}, + {file = "pyzmq-26.2.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:17c412bad2eb9468e876f556eb4ee910e62d721d2c7a53c7fa31e643d35352e6"}, + {file = "pyzmq-26.2.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:0d987a3ae5a71c6226b203cfd298720e0086c7fe7c74f35fa8edddfbd6597eed"}, + {file = "pyzmq-26.2.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:39887ac397ff35b7b775db7201095fc6310a35fdbae85bac4523f7eb3b840e20"}, + {file = "pyzmq-26.2.0-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:fdb5b3e311d4d4b0eb8b3e8b4d1b0a512713ad7e6a68791d0923d1aec433d919"}, + {file = "pyzmq-26.2.0-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:226af7dcb51fdb0109f0016449b357e182ea0ceb6b47dfb5999d569e5db161d5"}, + {file = "pyzmq-26.2.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0bed0e799e6120b9c32756203fb9dfe8ca2fb8467fed830c34c877e25638c3fc"}, + {file = "pyzmq-26.2.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:29c7947c594e105cb9e6c466bace8532dc1ca02d498684128b339799f5248277"}, + {file = "pyzmq-26.2.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:cdeabcff45d1c219636ee2e54d852262e5c2e085d6cb476d938aee8d921356b3"}, + {file = "pyzmq-26.2.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:35cffef589bcdc587d06f9149f8d5e9e8859920a071df5a2671de2213bef592a"}, + {file = "pyzmq-26.2.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:18c8dc3b7468d8b4bdf60ce9d7141897da103c7a4690157b32b60acb45e333e6"}, + {file = "pyzmq-26.2.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7133d0a1677aec369d67dd78520d3fa96dd7f3dcec99d66c1762870e5ea1a50a"}, + {file = "pyzmq-26.2.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:6a96179a24b14fa6428cbfc08641c779a53f8fcec43644030328f44034c7f1f4"}, + {file = "pyzmq-26.2.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:4f78c88905461a9203eac9faac157a2a0dbba84a0fd09fd29315db27be40af9f"}, + {file = "pyzmq-26.2.0.tar.gz", hash = "sha256:070672c258581c8e4f640b5159297580a9974b026043bd4ab0470be9ed324f1f"}, ] [package.dependencies] @@ -4109,90 +4731,105 @@ cffi = {version = "*", markers = "implementation_name == \"pypy\""} [[package]] name = "regex" -version = "2024.5.15" +version = "2024.9.11" description = "Alternative regular expression module, to replace re." optional = false python-versions = ">=3.8" files = [ - {file = "regex-2024.5.15-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a81e3cfbae20378d75185171587cbf756015ccb14840702944f014e0d93ea09f"}, - {file = "regex-2024.5.15-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7b59138b219ffa8979013be7bc85bb60c6f7b7575df3d56dc1e403a438c7a3f6"}, - {file = "regex-2024.5.15-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a0bd000c6e266927cb7a1bc39d55be95c4b4f65c5be53e659537537e019232b1"}, - {file = "regex-2024.5.15-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5eaa7ddaf517aa095fa8da0b5015c44d03da83f5bd49c87961e3c997daed0de7"}, - {file = "regex-2024.5.15-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ba68168daedb2c0bab7fd7e00ced5ba90aebf91024dea3c88ad5063c2a562cca"}, - {file = "regex-2024.5.15-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6e8d717bca3a6e2064fc3a08df5cbe366369f4b052dcd21b7416e6d71620dca1"}, - {file = "regex-2024.5.15-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1337b7dbef9b2f71121cdbf1e97e40de33ff114801263b275aafd75303bd62b5"}, - {file = "regex-2024.5.15-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f9ebd0a36102fcad2f03696e8af4ae682793a5d30b46c647eaf280d6cfb32796"}, - {file = "regex-2024.5.15-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:9efa1a32ad3a3ea112224897cdaeb6aa00381627f567179c0314f7b65d354c62"}, - {file = "regex-2024.5.15-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:1595f2d10dff3d805e054ebdc41c124753631b6a471b976963c7b28543cf13b0"}, - {file = "regex-2024.5.15-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:b802512f3e1f480f41ab5f2cfc0e2f761f08a1f41092d6718868082fc0d27143"}, - {file = "regex-2024.5.15-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:a0981022dccabca811e8171f913de05720590c915b033b7e601f35ce4ea7019f"}, - {file = "regex-2024.5.15-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:19068a6a79cf99a19ccefa44610491e9ca02c2be3305c7760d3831d38a467a6f"}, - {file = "regex-2024.5.15-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:1b5269484f6126eee5e687785e83c6b60aad7663dafe842b34691157e5083e53"}, - {file = "regex-2024.5.15-cp310-cp310-win32.whl", hash = "sha256:ada150c5adfa8fbcbf321c30c751dc67d2f12f15bd183ffe4ec7cde351d945b3"}, - {file = "regex-2024.5.15-cp310-cp310-win_amd64.whl", hash = "sha256:ac394ff680fc46b97487941f5e6ae49a9f30ea41c6c6804832063f14b2a5a145"}, - {file = "regex-2024.5.15-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f5b1dff3ad008dccf18e652283f5e5339d70bf8ba7c98bf848ac33db10f7bc7a"}, - {file = "regex-2024.5.15-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c6a2b494a76983df8e3d3feea9b9ffdd558b247e60b92f877f93a1ff43d26656"}, - {file = "regex-2024.5.15-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a32b96f15c8ab2e7d27655969a23895eb799de3665fa94349f3b2fbfd547236f"}, - {file = "regex-2024.5.15-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:10002e86e6068d9e1c91eae8295ef690f02f913c57db120b58fdd35a6bb1af35"}, - {file = "regex-2024.5.15-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ec54d5afa89c19c6dd8541a133be51ee1017a38b412b1321ccb8d6ddbeb4cf7d"}, - {file = "regex-2024.5.15-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:10e4ce0dca9ae7a66e6089bb29355d4432caed736acae36fef0fdd7879f0b0cb"}, - {file = "regex-2024.5.15-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3e507ff1e74373c4d3038195fdd2af30d297b4f0950eeda6f515ae3d84a1770f"}, - {file = "regex-2024.5.15-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d1f059a4d795e646e1c37665b9d06062c62d0e8cc3c511fe01315973a6542e40"}, - {file = "regex-2024.5.15-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0721931ad5fe0dda45d07f9820b90b2148ccdd8e45bb9e9b42a146cb4f695649"}, - {file = "regex-2024.5.15-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:833616ddc75ad595dee848ad984d067f2f31be645d603e4d158bba656bbf516c"}, - {file = "regex-2024.5.15-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:287eb7f54fc81546346207c533ad3c2c51a8d61075127d7f6d79aaf96cdee890"}, - {file = "regex-2024.5.15-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:19dfb1c504781a136a80ecd1fff9f16dddf5bb43cec6871778c8a907a085bb3d"}, - {file = "regex-2024.5.15-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:119af6e56dce35e8dfb5222573b50c89e5508d94d55713c75126b753f834de68"}, - {file = "regex-2024.5.15-cp311-cp311-win32.whl", hash = "sha256:1c1c174d6ec38d6c8a7504087358ce9213d4332f6293a94fbf5249992ba54efa"}, - {file = "regex-2024.5.15-cp311-cp311-win_amd64.whl", hash = "sha256:9e717956dcfd656f5055cc70996ee2cc82ac5149517fc8e1b60261b907740201"}, - {file = "regex-2024.5.15-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:632b01153e5248c134007209b5c6348a544ce96c46005d8456de1d552455b014"}, - {file = "regex-2024.5.15-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:e64198f6b856d48192bf921421fdd8ad8eb35e179086e99e99f711957ffedd6e"}, - {file = "regex-2024.5.15-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:68811ab14087b2f6e0fc0c2bae9ad689ea3584cad6917fc57be6a48bbd012c49"}, - {file = "regex-2024.5.15-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8ec0c2fea1e886a19c3bee0cd19d862b3aa75dcdfb42ebe8ed30708df64687a"}, - {file = "regex-2024.5.15-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d0c0c0003c10f54a591d220997dd27d953cd9ccc1a7294b40a4be5312be8797b"}, - {file = "regex-2024.5.15-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2431b9e263af1953c55abbd3e2efca67ca80a3de8a0437cb58e2421f8184717a"}, - {file = "regex-2024.5.15-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a605586358893b483976cffc1723fb0f83e526e8f14c6e6614e75919d9862cf"}, - {file = "regex-2024.5.15-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:391d7f7f1e409d192dba8bcd42d3e4cf9e598f3979cdaed6ab11288da88cb9f2"}, - {file = "regex-2024.5.15-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9ff11639a8d98969c863d4617595eb5425fd12f7c5ef6621a4b74b71ed8726d5"}, - {file = "regex-2024.5.15-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4eee78a04e6c67e8391edd4dad3279828dd66ac4b79570ec998e2155d2e59fd5"}, - {file = "regex-2024.5.15-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:8fe45aa3f4aa57faabbc9cb46a93363edd6197cbc43523daea044e9ff2fea83e"}, - {file = "regex-2024.5.15-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:d0a3d8d6acf0c78a1fff0e210d224b821081330b8524e3e2bc5a68ef6ab5803d"}, - {file = "regex-2024.5.15-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c486b4106066d502495b3025a0a7251bf37ea9540433940a23419461ab9f2a80"}, - {file = "regex-2024.5.15-cp312-cp312-win32.whl", hash = "sha256:c49e15eac7c149f3670b3e27f1f28a2c1ddeccd3a2812cba953e01be2ab9b5fe"}, - {file = "regex-2024.5.15-cp312-cp312-win_amd64.whl", hash = "sha256:673b5a6da4557b975c6c90198588181029c60793835ce02f497ea817ff647cb2"}, - {file = "regex-2024.5.15-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:87e2a9c29e672fc65523fb47a90d429b70ef72b901b4e4b1bd42387caf0d6835"}, - {file = "regex-2024.5.15-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c3bea0ba8b73b71b37ac833a7f3fd53825924165da6a924aec78c13032f20850"}, - {file = "regex-2024.5.15-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:bfc4f82cabe54f1e7f206fd3d30fda143f84a63fe7d64a81558d6e5f2e5aaba9"}, - {file = "regex-2024.5.15-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e5bb9425fe881d578aeca0b2b4b3d314ec88738706f66f219c194d67179337cb"}, - {file = "regex-2024.5.15-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:64c65783e96e563103d641760664125e91bd85d8e49566ee560ded4da0d3e704"}, - {file = "regex-2024.5.15-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cf2430df4148b08fb4324b848672514b1385ae3807651f3567871f130a728cc3"}, - {file = "regex-2024.5.15-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5397de3219a8b08ae9540c48f602996aa6b0b65d5a61683e233af8605c42b0f2"}, - {file = "regex-2024.5.15-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:455705d34b4154a80ead722f4f185b04c4237e8e8e33f265cd0798d0e44825fa"}, - {file = "regex-2024.5.15-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b2b6f1b3bb6f640c1a92be3bbfbcb18657b125b99ecf141fb3310b5282c7d4ed"}, - {file = "regex-2024.5.15-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:3ad070b823ca5890cab606c940522d05d3d22395d432f4aaaf9d5b1653e47ced"}, - {file = "regex-2024.5.15-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:5b5467acbfc153847d5adb21e21e29847bcb5870e65c94c9206d20eb4e99a384"}, - {file = "regex-2024.5.15-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:e6662686aeb633ad65be2a42b4cb00178b3fbf7b91878f9446075c404ada552f"}, - {file = "regex-2024.5.15-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:2b4c884767504c0e2401babe8b5b7aea9148680d2e157fa28f01529d1f7fcf67"}, - {file = "regex-2024.5.15-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:3cd7874d57f13bf70078f1ff02b8b0aa48d5b9ed25fc48547516c6aba36f5741"}, - {file = "regex-2024.5.15-cp38-cp38-win32.whl", hash = "sha256:e4682f5ba31f475d58884045c1a97a860a007d44938c4c0895f41d64481edbc9"}, - {file = "regex-2024.5.15-cp38-cp38-win_amd64.whl", hash = "sha256:d99ceffa25ac45d150e30bd9ed14ec6039f2aad0ffa6bb87a5936f5782fc1569"}, - {file = "regex-2024.5.15-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:13cdaf31bed30a1e1c2453ef6015aa0983e1366fad2667657dbcac7b02f67133"}, - {file = "regex-2024.5.15-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:cac27dcaa821ca271855a32188aa61d12decb6fe45ffe3e722401fe61e323cd1"}, - {file = "regex-2024.5.15-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7dbe2467273b875ea2de38ded4eba86cbcbc9a1a6d0aa11dcf7bd2e67859c435"}, - {file = "regex-2024.5.15-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:64f18a9a3513a99c4bef0e3efd4c4a5b11228b48aa80743be822b71e132ae4f5"}, - {file = "regex-2024.5.15-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d347a741ea871c2e278fde6c48f85136c96b8659b632fb57a7d1ce1872547600"}, - {file = "regex-2024.5.15-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1878b8301ed011704aea4c806a3cadbd76f84dece1ec09cc9e4dc934cfa5d4da"}, - {file = "regex-2024.5.15-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4babf07ad476aaf7830d77000874d7611704a7fcf68c9c2ad151f5d94ae4bfc4"}, - {file = "regex-2024.5.15-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:35cb514e137cb3488bce23352af3e12fb0dbedd1ee6e60da053c69fb1b29cc6c"}, - {file = "regex-2024.5.15-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:cdd09d47c0b2efee9378679f8510ee6955d329424c659ab3c5e3a6edea696294"}, - {file = "regex-2024.5.15-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:72d7a99cd6b8f958e85fc6ca5b37c4303294954eac1376535b03c2a43eb72629"}, - {file = "regex-2024.5.15-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:a094801d379ab20c2135529948cb84d417a2169b9bdceda2a36f5f10977ebc16"}, - {file = "regex-2024.5.15-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:c0c18345010870e58238790a6779a1219b4d97bd2e77e1140e8ee5d14df071aa"}, - {file = "regex-2024.5.15-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:16093f563098448ff6b1fa68170e4acbef94e6b6a4e25e10eae8598bb1694b5d"}, - {file = "regex-2024.5.15-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:e38a7d4e8f633a33b4c7350fbd8bad3b70bf81439ac67ac38916c4a86b465456"}, - {file = "regex-2024.5.15-cp39-cp39-win32.whl", hash = "sha256:71a455a3c584a88f654b64feccc1e25876066c4f5ef26cd6dd711308aa538694"}, - {file = "regex-2024.5.15-cp39-cp39-win_amd64.whl", hash = "sha256:cab12877a9bdafde5500206d1020a584355a97884dfd388af3699e9137bf7388"}, - {file = "regex-2024.5.15.tar.gz", hash = "sha256:d3ee02d9e5f482cc8309134a91eeaacbdd2261ba111b0fef3748eeb4913e6a2c"}, + {file = "regex-2024.9.11-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:1494fa8725c285a81d01dc8c06b55287a1ee5e0e382d8413adc0a9197aac6408"}, + {file = "regex-2024.9.11-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0e12c481ad92d129c78f13a2a3662317e46ee7ef96c94fd332e1c29131875b7d"}, + {file = "regex-2024.9.11-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:16e13a7929791ac1216afde26f712802e3df7bf0360b32e4914dca3ab8baeea5"}, + {file = "regex-2024.9.11-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:46989629904bad940bbec2106528140a218b4a36bb3042d8406980be1941429c"}, + {file = "regex-2024.9.11-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a906ed5e47a0ce5f04b2c981af1c9acf9e8696066900bf03b9d7879a6f679fc8"}, + {file = "regex-2024.9.11-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e9a091b0550b3b0207784a7d6d0f1a00d1d1c8a11699c1a4d93db3fbefc3ad35"}, + {file = "regex-2024.9.11-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ddcd9a179c0a6fa8add279a4444015acddcd7f232a49071ae57fa6e278f1f71"}, + {file = "regex-2024.9.11-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6b41e1adc61fa347662b09398e31ad446afadff932a24807d3ceb955ed865cc8"}, + {file = "regex-2024.9.11-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ced479f601cd2f8ca1fd7b23925a7e0ad512a56d6e9476f79b8f381d9d37090a"}, + {file = "regex-2024.9.11-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:635a1d96665f84b292e401c3d62775851aedc31d4f8784117b3c68c4fcd4118d"}, + {file = "regex-2024.9.11-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:c0256beda696edcf7d97ef16b2a33a8e5a875affd6fa6567b54f7c577b30a137"}, + {file = "regex-2024.9.11-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:3ce4f1185db3fbde8ed8aa223fc9620f276c58de8b0d4f8cc86fd1360829edb6"}, + {file = "regex-2024.9.11-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:09d77559e80dcc9d24570da3745ab859a9cf91953062e4ab126ba9d5993688ca"}, + {file = "regex-2024.9.11-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7a22ccefd4db3f12b526eccb129390942fe874a3a9fdbdd24cf55773a1faab1a"}, + {file = "regex-2024.9.11-cp310-cp310-win32.whl", hash = "sha256:f745ec09bc1b0bd15cfc73df6fa4f726dcc26bb16c23a03f9e3367d357eeedd0"}, + {file = "regex-2024.9.11-cp310-cp310-win_amd64.whl", hash = "sha256:01c2acb51f8a7d6494c8c5eafe3d8e06d76563d8a8a4643b37e9b2dd8a2ff623"}, + {file = "regex-2024.9.11-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2cce2449e5927a0bf084d346da6cd5eb016b2beca10d0013ab50e3c226ffc0df"}, + {file = "regex-2024.9.11-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3b37fa423beefa44919e009745ccbf353d8c981516e807995b2bd11c2c77d268"}, + {file = "regex-2024.9.11-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:64ce2799bd75039b480cc0360907c4fb2f50022f030bf9e7a8705b636e408fad"}, + {file = "regex-2024.9.11-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a4cc92bb6db56ab0c1cbd17294e14f5e9224f0cc6521167ef388332604e92679"}, + {file = "regex-2024.9.11-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d05ac6fa06959c4172eccd99a222e1fbf17b5670c4d596cb1e5cde99600674c4"}, + {file = "regex-2024.9.11-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:040562757795eeea356394a7fb13076ad4f99d3c62ab0f8bdfb21f99a1f85664"}, + {file = "regex-2024.9.11-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6113c008a7780792efc80f9dfe10ba0cd043cbf8dc9a76ef757850f51b4edc50"}, + {file = "regex-2024.9.11-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8e5fb5f77c8745a60105403a774fe2c1759b71d3e7b4ca237a5e67ad066c7199"}, + {file = "regex-2024.9.11-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:54d9ff35d4515debf14bc27f1e3b38bfc453eff3220f5bce159642fa762fe5d4"}, + {file = "regex-2024.9.11-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:df5cbb1fbc74a8305b6065d4ade43b993be03dbe0f8b30032cced0d7740994bd"}, + {file = "regex-2024.9.11-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:7fb89ee5d106e4a7a51bce305ac4efb981536301895f7bdcf93ec92ae0d91c7f"}, + {file = "regex-2024.9.11-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:a738b937d512b30bf75995c0159c0ddf9eec0775c9d72ac0202076c72f24aa96"}, + {file = "regex-2024.9.11-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e28f9faeb14b6f23ac55bfbbfd3643f5c7c18ede093977f1df249f73fd22c7b1"}, + {file = "regex-2024.9.11-cp311-cp311-win32.whl", hash = "sha256:18e707ce6c92d7282dfce370cd205098384b8ee21544e7cb29b8aab955b66fa9"}, + {file = "regex-2024.9.11-cp311-cp311-win_amd64.whl", hash = "sha256:313ea15e5ff2a8cbbad96ccef6be638393041b0a7863183c2d31e0c6116688cf"}, + {file = "regex-2024.9.11-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b0d0a6c64fcc4ef9c69bd5b3b3626cc3776520a1637d8abaa62b9edc147a58f7"}, + {file = "regex-2024.9.11-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:49b0e06786ea663f933f3710a51e9385ce0cba0ea56b67107fd841a55d56a231"}, + {file = "regex-2024.9.11-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5b513b6997a0b2f10e4fd3a1313568e373926e8c252bd76c960f96fd039cd28d"}, + {file = "regex-2024.9.11-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ee439691d8c23e76f9802c42a95cfeebf9d47cf4ffd06f18489122dbb0a7ad64"}, + {file = "regex-2024.9.11-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a8f877c89719d759e52783f7fe6e1c67121076b87b40542966c02de5503ace42"}, + {file = "regex-2024.9.11-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:23b30c62d0f16827f2ae9f2bb87619bc4fba2044911e2e6c2eb1af0161cdb766"}, + {file = "regex-2024.9.11-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85ab7824093d8f10d44330fe1e6493f756f252d145323dd17ab6b48733ff6c0a"}, + {file = "regex-2024.9.11-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8dee5b4810a89447151999428fe096977346cf2f29f4d5e29609d2e19e0199c9"}, + {file = "regex-2024.9.11-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:98eeee2f2e63edae2181c886d7911ce502e1292794f4c5ee71e60e23e8d26b5d"}, + {file = "regex-2024.9.11-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:57fdd2e0b2694ce6fc2e5ccf189789c3e2962916fb38779d3e3521ff8fe7a822"}, + {file = "regex-2024.9.11-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:d552c78411f60b1fdaafd117a1fca2f02e562e309223b9d44b7de8be451ec5e0"}, + {file = "regex-2024.9.11-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:a0b2b80321c2ed3fcf0385ec9e51a12253c50f146fddb2abbb10f033fe3d049a"}, + {file = "regex-2024.9.11-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:18406efb2f5a0e57e3a5881cd9354c1512d3bb4f5c45d96d110a66114d84d23a"}, + {file = "regex-2024.9.11-cp312-cp312-win32.whl", hash = "sha256:e464b467f1588e2c42d26814231edecbcfe77f5ac414d92cbf4e7b55b2c2a776"}, + {file = "regex-2024.9.11-cp312-cp312-win_amd64.whl", hash = "sha256:9e8719792ca63c6b8340380352c24dcb8cd7ec49dae36e963742a275dfae6009"}, + {file = "regex-2024.9.11-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:c157bb447303070f256e084668b702073db99bbb61d44f85d811025fcf38f784"}, + {file = "regex-2024.9.11-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4db21ece84dfeefc5d8a3863f101995de646c6cb0536952c321a2650aa202c36"}, + {file = "regex-2024.9.11-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:220e92a30b426daf23bb67a7962900ed4613589bab80382be09b48896d211e92"}, + {file = "regex-2024.9.11-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eb1ae19e64c14c7ec1995f40bd932448713d3c73509e82d8cd7744dc00e29e86"}, + {file = "regex-2024.9.11-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f47cd43a5bfa48f86925fe26fbdd0a488ff15b62468abb5d2a1e092a4fb10e85"}, + {file = "regex-2024.9.11-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9d4a76b96f398697fe01117093613166e6aa8195d63f1b4ec3f21ab637632963"}, + {file = "regex-2024.9.11-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ea51dcc0835eea2ea31d66456210a4e01a076d820e9039b04ae8d17ac11dee6"}, + {file = "regex-2024.9.11-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b7aaa315101c6567a9a45d2839322c51c8d6e81f67683d529512f5bcfb99c802"}, + {file = "regex-2024.9.11-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c57d08ad67aba97af57a7263c2d9006d5c404d721c5f7542f077f109ec2a4a29"}, + {file = "regex-2024.9.11-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:f8404bf61298bb6f8224bb9176c1424548ee1181130818fcd2cbffddc768bed8"}, + {file = "regex-2024.9.11-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:dd4490a33eb909ef5078ab20f5f000087afa2a4daa27b4c072ccb3cb3050ad84"}, + {file = "regex-2024.9.11-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:eee9130eaad130649fd73e5cd92f60e55708952260ede70da64de420cdcad554"}, + {file = "regex-2024.9.11-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6a2644a93da36c784e546de579ec1806bfd2763ef47babc1b03d765fe560c9f8"}, + {file = "regex-2024.9.11-cp313-cp313-win32.whl", hash = "sha256:e997fd30430c57138adc06bba4c7c2968fb13d101e57dd5bb9355bf8ce3fa7e8"}, + {file = "regex-2024.9.11-cp313-cp313-win_amd64.whl", hash = "sha256:042c55879cfeb21a8adacc84ea347721d3d83a159da6acdf1116859e2427c43f"}, + {file = "regex-2024.9.11-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:35f4a6f96aa6cb3f2f7247027b07b15a374f0d5b912c0001418d1d55024d5cb4"}, + {file = "regex-2024.9.11-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:55b96e7ce3a69a8449a66984c268062fbaa0d8ae437b285428e12797baefce7e"}, + {file = "regex-2024.9.11-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cb130fccd1a37ed894824b8c046321540263013da72745d755f2d35114b81a60"}, + {file = "regex-2024.9.11-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:323c1f04be6b2968944d730e5c2091c8c89767903ecaa135203eec4565ed2b2b"}, + {file = "regex-2024.9.11-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:be1c8ed48c4c4065ecb19d882a0ce1afe0745dfad8ce48c49586b90a55f02366"}, + {file = "regex-2024.9.11-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b5b029322e6e7b94fff16cd120ab35a253236a5f99a79fb04fda7ae71ca20ae8"}, + {file = "regex-2024.9.11-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6fff13ef6b5f29221d6904aa816c34701462956aa72a77f1f151a8ec4f56aeb"}, + {file = "regex-2024.9.11-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:587d4af3979376652010e400accc30404e6c16b7df574048ab1f581af82065e4"}, + {file = "regex-2024.9.11-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:079400a8269544b955ffa9e31f186f01d96829110a3bf79dc338e9910f794fca"}, + {file = "regex-2024.9.11-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:f9268774428ec173654985ce55fc6caf4c6d11ade0f6f914d48ef4719eb05ebb"}, + {file = "regex-2024.9.11-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:23f9985c8784e544d53fc2930fc1ac1a7319f5d5332d228437acc9f418f2f168"}, + {file = "regex-2024.9.11-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:ae2941333154baff9838e88aa71c1d84f4438189ecc6021a12c7573728b5838e"}, + {file = "regex-2024.9.11-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:e93f1c331ca8e86fe877a48ad64e77882c0c4da0097f2212873a69bbfea95d0c"}, + {file = "regex-2024.9.11-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:846bc79ee753acf93aef4184c040d709940c9d001029ceb7b7a52747b80ed2dd"}, + {file = "regex-2024.9.11-cp38-cp38-win32.whl", hash = "sha256:c94bb0a9f1db10a1d16c00880bdebd5f9faf267273b8f5bd1878126e0fbde771"}, + {file = "regex-2024.9.11-cp38-cp38-win_amd64.whl", hash = "sha256:2b08fce89fbd45664d3df6ad93e554b6c16933ffa9d55cb7e01182baaf971508"}, + {file = "regex-2024.9.11-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:07f45f287469039ffc2c53caf6803cd506eb5f5f637f1d4acb37a738f71dd066"}, + {file = "regex-2024.9.11-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4838e24ee015101d9f901988001038f7f0d90dc0c3b115541a1365fb439add62"}, + {file = "regex-2024.9.11-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6edd623bae6a737f10ce853ea076f56f507fd7726bee96a41ee3d68d347e4d16"}, + {file = "regex-2024.9.11-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c69ada171c2d0e97a4b5aa78fbb835e0ffbb6b13fc5da968c09811346564f0d3"}, + {file = "regex-2024.9.11-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:02087ea0a03b4af1ed6ebab2c54d7118127fee8d71b26398e8e4b05b78963199"}, + {file = "regex-2024.9.11-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:69dee6a020693d12a3cf892aba4808fe168d2a4cef368eb9bf74f5398bfd4ee8"}, + {file = "regex-2024.9.11-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:297f54910247508e6e5cae669f2bc308985c60540a4edd1c77203ef19bfa63ca"}, + {file = "regex-2024.9.11-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ecea58b43a67b1b79805f1a0255730edaf5191ecef84dbc4cc85eb30bc8b63b9"}, + {file = "regex-2024.9.11-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:eab4bb380f15e189d1313195b062a6aa908f5bd687a0ceccd47c8211e9cf0d4a"}, + {file = "regex-2024.9.11-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0cbff728659ce4bbf4c30b2a1be040faafaa9eca6ecde40aaff86f7889f4ab39"}, + {file = "regex-2024.9.11-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:54c4a097b8bc5bb0dfc83ae498061d53ad7b5762e00f4adaa23bee22b012e6ba"}, + {file = "regex-2024.9.11-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:73d6d2f64f4d894c96626a75578b0bf7d9e56dcda8c3d037a2118fdfe9b1c664"}, + {file = "regex-2024.9.11-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:e53b5fbab5d675aec9f0c501274c467c0f9a5d23696cfc94247e1fb56501ed89"}, + {file = "regex-2024.9.11-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:0ffbcf9221e04502fc35e54d1ce9567541979c3fdfb93d2c554f0ca583a19b35"}, + {file = "regex-2024.9.11-cp39-cp39-win32.whl", hash = "sha256:e4c22e1ac1f1ec1e09f72e6c44d8f2244173db7eb9629cc3a346a8d7ccc31142"}, + {file = "regex-2024.9.11-cp39-cp39-win_amd64.whl", hash = "sha256:faa3c142464efec496967359ca99696c896c591c56c53506bac1ad465f66e919"}, + {file = "regex-2024.9.11.tar.gz", hash = "sha256:6c188c307e8433bcb63dc1915022deb553b4203a70722fc542c363bf120a01fd"}, ] [[package]] @@ -4268,40 +4905,40 @@ pyasn1 = ">=0.1.3" [[package]] name = "ruff" -version = "0.7.0" +version = "0.7.1" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.7.0-py3-none-linux_armv6l.whl", hash = "sha256:0cdf20c2b6ff98e37df47b2b0bd3a34aaa155f59a11182c1303cce79be715628"}, - {file = "ruff-0.7.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:496494d350c7fdeb36ca4ef1c9f21d80d182423718782222c29b3e72b3512737"}, - {file = "ruff-0.7.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:214b88498684e20b6b2b8852c01d50f0651f3cc6118dfa113b4def9f14faaf06"}, - {file = "ruff-0.7.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:630fce3fefe9844e91ea5bbf7ceadab4f9981f42b704fae011bb8efcaf5d84be"}, - {file = "ruff-0.7.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:211d877674e9373d4bb0f1c80f97a0201c61bcd1e9d045b6e9726adc42c156aa"}, - {file = "ruff-0.7.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:194d6c46c98c73949a106425ed40a576f52291c12bc21399eb8f13a0f7073495"}, - {file = "ruff-0.7.0-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:82c2579b82b9973a110fab281860403b397c08c403de92de19568f32f7178598"}, - {file = "ruff-0.7.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9af971fe85dcd5eaed8f585ddbc6bdbe8c217fb8fcf510ea6bca5bdfff56040e"}, - {file = "ruff-0.7.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b641c7f16939b7d24b7bfc0be4102c56562a18281f84f635604e8a6989948914"}, - {file = "ruff-0.7.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d71672336e46b34e0c90a790afeac8a31954fd42872c1f6adaea1dff76fd44f9"}, - {file = "ruff-0.7.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:ab7d98c7eed355166f367597e513a6c82408df4181a937628dbec79abb2a1fe4"}, - {file = "ruff-0.7.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:1eb54986f770f49edb14f71d33312d79e00e629a57387382200b1ef12d6a4ef9"}, - {file = "ruff-0.7.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:dc452ba6f2bb9cf8726a84aa877061a2462afe9ae0ea1d411c53d226661c601d"}, - {file = "ruff-0.7.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:4b406c2dce5be9bad59f2de26139a86017a517e6bcd2688da515481c05a2cb11"}, - {file = "ruff-0.7.0-py3-none-win32.whl", hash = "sha256:f6c968509f767776f524a8430426539587d5ec5c662f6addb6aa25bc2e8195ec"}, - {file = "ruff-0.7.0-py3-none-win_amd64.whl", hash = "sha256:ff4aabfbaaba880e85d394603b9e75d32b0693152e16fa659a3064a85df7fce2"}, - {file = "ruff-0.7.0-py3-none-win_arm64.whl", hash = "sha256:10842f69c245e78d6adec7e1db0a7d9ddc2fff0621d730e61657b64fa36f207e"}, - {file = "ruff-0.7.0.tar.gz", hash = "sha256:47a86360cf62d9cd53ebfb0b5eb0e882193fc191c6d717e8bef4462bc3b9ea2b"}, + {file = "ruff-0.7.1-py3-none-linux_armv6l.whl", hash = "sha256:cb1bc5ed9403daa7da05475d615739cc0212e861b7306f314379d958592aaa89"}, + {file = "ruff-0.7.1-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:27c1c52a8d199a257ff1e5582d078eab7145129aa02721815ca8fa4f9612dc35"}, + {file = "ruff-0.7.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:588a34e1ef2ea55b4ddfec26bbe76bc866e92523d8c6cdec5e8aceefeff02d99"}, + {file = "ruff-0.7.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94fc32f9cdf72dc75c451e5f072758b118ab8100727168a3df58502b43a599ca"}, + {file = "ruff-0.7.1-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:985818742b833bffa543a84d1cc11b5e6871de1b4e0ac3060a59a2bae3969250"}, + {file = "ruff-0.7.1-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:32f1e8a192e261366c702c5fb2ece9f68d26625f198a25c408861c16dc2dea9c"}, + {file = "ruff-0.7.1-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:699085bf05819588551b11751eff33e9ca58b1b86a6843e1b082a7de40da1565"}, + {file = "ruff-0.7.1-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:344cc2b0814047dc8c3a8ff2cd1f3d808bb23c6658db830d25147339d9bf9ea7"}, + {file = "ruff-0.7.1-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4316bbf69d5a859cc937890c7ac7a6551252b6a01b1d2c97e8fc96e45a7c8b4a"}, + {file = "ruff-0.7.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:79d3af9dca4c56043e738a4d6dd1e9444b6d6c10598ac52d146e331eb155a8ad"}, + {file = "ruff-0.7.1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:c5c121b46abde94a505175524e51891f829414e093cd8326d6e741ecfc0a9112"}, + {file = "ruff-0.7.1-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:8422104078324ea250886954e48f1373a8fe7de59283d747c3a7eca050b4e378"}, + {file = "ruff-0.7.1-py3-none-musllinux_1_2_i686.whl", hash = "sha256:56aad830af8a9db644e80098fe4984a948e2b6fc2e73891538f43bbe478461b8"}, + {file = "ruff-0.7.1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:658304f02f68d3a83c998ad8bf91f9b4f53e93e5412b8f2388359d55869727fd"}, + {file = "ruff-0.7.1-py3-none-win32.whl", hash = "sha256:b517a2011333eb7ce2d402652ecaa0ac1a30c114fbbd55c6b8ee466a7f600ee9"}, + {file = "ruff-0.7.1-py3-none-win_amd64.whl", hash = "sha256:f38c41fcde1728736b4eb2b18850f6d1e3eedd9678c914dede554a70d5241307"}, + {file = "ruff-0.7.1-py3-none-win_arm64.whl", hash = "sha256:19aa200ec824c0f36d0c9114c8ec0087082021732979a359d6f3c390a6ff2a37"}, + {file = "ruff-0.7.1.tar.gz", hash = "sha256:9d8a41d4aa2dad1575adb98a82870cf5db5f76b2938cf2206c22c940034a36f4"}, ] [[package]] name = "s3transfer" -version = "0.10.1" +version = "0.10.3" description = "An Amazon S3 Transfer Manager" optional = false -python-versions = ">= 3.8" +python-versions = ">=3.8" files = [ - {file = "s3transfer-0.10.1-py3-none-any.whl", hash = "sha256:ceb252b11bcf87080fb7850a224fb6e05c8a776bab8f2b64b7f25b969464839d"}, - {file = "s3transfer-0.10.1.tar.gz", hash = "sha256:5683916b4c724f799e600f41dd9e10a9ff19871bf87623cc8f491cb4f5fa0a19"}, + {file = "s3transfer-0.10.3-py3-none-any.whl", hash = "sha256:263ed587a5803c6c708d3ce44dc4dfedaab4c1a32e8329bab818933d79ddcf5d"}, + {file = "s3transfer-0.10.3.tar.gz", hash = "sha256:4f50ed74ab84d474ce614475e0b8d5047ff080810aac5d01ea25231cfc944b0c"}, ] [package.dependencies] @@ -4312,32 +4949,37 @@ crt = ["botocore[crt] (>=1.33.2,<2.0a.0)"] [[package]] name = "scikit-learn" -version = "1.5.0" +version = "1.5.2" description = "A set of python modules for machine learning and data mining" optional = false python-versions = ">=3.9" files = [ - {file = "scikit_learn-1.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:12e40ac48555e6b551f0a0a5743cc94cc5a765c9513fe708e01f0aa001da2801"}, - {file = "scikit_learn-1.5.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:f405c4dae288f5f6553b10c4ac9ea7754d5180ec11e296464adb5d6ac68b6ef5"}, - {file = "scikit_learn-1.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df8ccabbf583315f13160a4bb06037bde99ea7d8211a69787a6b7c5d4ebb6fc3"}, - {file = "scikit_learn-1.5.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c75ea812cd83b1385bbfa94ae971f0d80adb338a9523f6bbcb5e0b0381151d4"}, - {file = "scikit_learn-1.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:a90c5da84829a0b9b4bf00daf62754b2be741e66b5946911f5bdfaa869fcedd6"}, - {file = "scikit_learn-1.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2a65af2d8a6cce4e163a7951a4cfbfa7fceb2d5c013a4b593686c7f16445cf9d"}, - {file = "scikit_learn-1.5.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:4c0c56c3005f2ec1db3787aeaabefa96256580678cec783986836fc64f8ff622"}, - {file = "scikit_learn-1.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f77547165c00625551e5c250cefa3f03f2fc92c5e18668abd90bfc4be2e0bff"}, - {file = "scikit_learn-1.5.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:118a8d229a41158c9f90093e46b3737120a165181a1b58c03461447aa4657415"}, - {file = "scikit_learn-1.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:a03b09f9f7f09ffe8c5efffe2e9de1196c696d811be6798ad5eddf323c6f4d40"}, - {file = "scikit_learn-1.5.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:460806030c666addee1f074788b3978329a5bfdc9b7d63e7aad3f6d45c67a210"}, - {file = "scikit_learn-1.5.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:1b94d6440603752b27842eda97f6395f570941857456c606eb1d638efdb38184"}, - {file = "scikit_learn-1.5.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d82c2e573f0f2f2f0be897e7a31fcf4e73869247738ab8c3ce7245549af58ab8"}, - {file = "scikit_learn-1.5.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a3a10e1d9e834e84d05e468ec501a356226338778769317ee0b84043c0d8fb06"}, - {file = "scikit_learn-1.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:855fc5fa8ed9e4f08291203af3d3e5fbdc4737bd617a371559aaa2088166046e"}, - {file = "scikit_learn-1.5.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:40fb7d4a9a2db07e6e0cae4dc7bdbb8fada17043bac24104d8165e10e4cff1a2"}, - {file = "scikit_learn-1.5.0-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:47132440050b1c5beb95f8ba0b2402bbd9057ce96ec0ba86f2f445dd4f34df67"}, - {file = "scikit_learn-1.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:174beb56e3e881c90424e21f576fa69c4ffcf5174632a79ab4461c4c960315ac"}, - {file = "scikit_learn-1.5.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:261fe334ca48f09ed64b8fae13f9b46cc43ac5f580c4a605cbb0a517456c8f71"}, - {file = "scikit_learn-1.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:057b991ac64b3e75c9c04b5f9395eaf19a6179244c089afdebaad98264bff37c"}, - {file = "scikit_learn-1.5.0.tar.gz", hash = "sha256:789e3db01c750ed6d496fa2db7d50637857b451e57bcae863bff707c1247bef7"}, + {file = "scikit_learn-1.5.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:299406827fb9a4f862626d0fe6c122f5f87f8910b86fe5daa4c32dcd742139b6"}, + {file = "scikit_learn-1.5.2-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:2d4cad1119c77930b235579ad0dc25e65c917e756fe80cab96aa3b9428bd3fb0"}, + {file = "scikit_learn-1.5.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c412ccc2ad9bf3755915e3908e677b367ebc8d010acbb3f182814524f2e5540"}, + {file = "scikit_learn-1.5.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a686885a4b3818d9e62904d91b57fa757fc2bed3e465c8b177be652f4dd37c8"}, + {file = "scikit_learn-1.5.2-cp310-cp310-win_amd64.whl", hash = "sha256:c15b1ca23d7c5f33cc2cb0a0d6aaacf893792271cddff0edbd6a40e8319bc113"}, + {file = "scikit_learn-1.5.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:03b6158efa3faaf1feea3faa884c840ebd61b6484167c711548fce208ea09445"}, + {file = "scikit_learn-1.5.2-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:1ff45e26928d3b4eb767a8f14a9a6efbf1cbff7c05d1fb0f95f211a89fd4f5de"}, + {file = "scikit_learn-1.5.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f763897fe92d0e903aa4847b0aec0e68cadfff77e8a0687cabd946c89d17e675"}, + {file = "scikit_learn-1.5.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8b0ccd4a902836493e026c03256e8b206656f91fbcc4fde28c57a5b752561f1"}, + {file = "scikit_learn-1.5.2-cp311-cp311-win_amd64.whl", hash = "sha256:6c16d84a0d45e4894832b3c4d0bf73050939e21b99b01b6fd59cbb0cf39163b6"}, + {file = "scikit_learn-1.5.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f932a02c3f4956dfb981391ab24bda1dbd90fe3d628e4b42caef3e041c67707a"}, + {file = "scikit_learn-1.5.2-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:3b923d119d65b7bd555c73be5423bf06c0105678ce7e1f558cb4b40b0a5502b1"}, + {file = "scikit_learn-1.5.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f60021ec1574e56632be2a36b946f8143bf4e5e6af4a06d85281adc22938e0dd"}, + {file = "scikit_learn-1.5.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:394397841449853c2290a32050382edaec3da89e35b3e03d6cc966aebc6a8ae6"}, + {file = "scikit_learn-1.5.2-cp312-cp312-win_amd64.whl", hash = "sha256:57cc1786cfd6bd118220a92ede80270132aa353647684efa385a74244a41e3b1"}, + {file = "scikit_learn-1.5.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e9a702e2de732bbb20d3bad29ebd77fc05a6b427dc49964300340e4c9328b3f5"}, + {file = "scikit_learn-1.5.2-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:b0768ad641981f5d3a198430a1d31c3e044ed2e8a6f22166b4d546a5116d7908"}, + {file = "scikit_learn-1.5.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:178ddd0a5cb0044464fc1bfc4cca5b1833bfc7bb022d70b05db8530da4bb3dd3"}, + {file = "scikit_learn-1.5.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f7284ade780084d94505632241bf78c44ab3b6f1e8ccab3d2af58e0e950f9c12"}, + {file = "scikit_learn-1.5.2-cp313-cp313-win_amd64.whl", hash = "sha256:b7b0f9a0b1040830d38c39b91b3a44e1b643f4b36e36567b80b7c6bd2202a27f"}, + {file = "scikit_learn-1.5.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:757c7d514ddb00ae249832fe87100d9c73c6ea91423802872d9e74970a0e40b9"}, + {file = "scikit_learn-1.5.2-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:52788f48b5d8bca5c0736c175fa6bdaab2ef00a8f536cda698db61bd89c551c1"}, + {file = "scikit_learn-1.5.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:643964678f4b5fbdc95cbf8aec638acc7aa70f5f79ee2cdad1eec3df4ba6ead8"}, + {file = "scikit_learn-1.5.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca64b3089a6d9b9363cd3546f8978229dcbb737aceb2c12144ee3f70f95684b7"}, + {file = "scikit_learn-1.5.2-cp39-cp39-win_amd64.whl", hash = "sha256:3bed4909ba187aca80580fe2ef370d9180dcf18e621a27c4cf2ef10d279a7efe"}, + {file = "scikit_learn-1.5.2.tar.gz", hash = "sha256:b4237ed7b3fdd0a4882792e68ef2545d5baa50aca3bb45aa7df468138ad8f94d"}, ] [package.dependencies] @@ -4348,12 +4990,12 @@ threadpoolctl = ">=3.1.0" [package.extras] benchmark = ["matplotlib (>=3.3.4)", "memory_profiler (>=0.57.0)", "pandas (>=1.1.5)"] -build = ["cython (>=3.0.10)", "meson-python (>=0.15.0)", "numpy (>=1.19.5)", "scipy (>=1.6.0)"] -docs = ["Pillow (>=7.1.2)", "matplotlib (>=3.3.4)", "memory_profiler (>=0.57.0)", "numpydoc (>=1.2.0)", "pandas (>=1.1.5)", "plotly (>=5.14.0)", "polars (>=0.20.23)", "pooch (>=1.6.0)", "scikit-image (>=0.17.2)", "seaborn (>=0.9.0)", "sphinx (>=6.0.0)", "sphinx-copybutton (>=0.5.2)", "sphinx-gallery (>=0.15.0)", "sphinx-prompt (>=1.3.0)", "sphinxext-opengraph (>=0.4.2)"] +build = ["cython (>=3.0.10)", "meson-python (>=0.16.0)", "numpy (>=1.19.5)", "scipy (>=1.6.0)"] +docs = ["Pillow (>=7.1.2)", "matplotlib (>=3.3.4)", "memory_profiler (>=0.57.0)", "numpydoc (>=1.2.0)", "pandas (>=1.1.5)", "plotly (>=5.14.0)", "polars (>=0.20.30)", "pooch (>=1.6.0)", "pydata-sphinx-theme (>=0.15.3)", "scikit-image (>=0.17.2)", "seaborn (>=0.9.0)", "sphinx (>=7.3.7)", "sphinx-copybutton (>=0.5.2)", "sphinx-design (>=0.5.0)", "sphinx-design (>=0.6.0)", "sphinx-gallery (>=0.16.0)", "sphinx-prompt (>=1.4.0)", "sphinx-remove-toctrees (>=1.0.0.post1)", "sphinxcontrib-sass (>=0.3.4)", "sphinxext-opengraph (>=0.9.1)"] examples = ["matplotlib (>=3.3.4)", "pandas (>=1.1.5)", "plotly (>=5.14.0)", "pooch (>=1.6.0)", "scikit-image (>=0.17.2)", "seaborn (>=0.9.0)"] install = ["joblib (>=1.2.0)", "numpy (>=1.19.5)", "scipy (>=1.6.0)", "threadpoolctl (>=3.1.0)"] maintenance = ["conda-lock (==2.5.6)"] -tests = ["black (>=24.3.0)", "matplotlib (>=3.3.4)", "mypy (>=1.9)", "numpydoc (>=1.2.0)", "pandas (>=1.1.5)", "polars (>=0.20.23)", "pooch (>=1.6.0)", "pyamg (>=4.0.0)", "pyarrow (>=12.0.0)", "pytest (>=7.1.2)", "pytest-cov (>=2.9.0)", "ruff (>=0.2.1)", "scikit-image (>=0.17.2)"] +tests = ["black (>=24.3.0)", "matplotlib (>=3.3.4)", "mypy (>=1.9)", "numpydoc (>=1.2.0)", "pandas (>=1.1.5)", "polars (>=0.20.30)", "pooch (>=1.6.0)", "pyamg (>=4.0.0)", "pyarrow (>=12.0.0)", "pytest (>=7.1.2)", "pytest-cov (>=2.9.0)", "ruff (>=0.2.1)", "scikit-image (>=0.17.2)"] [[package]] name = "scipy" @@ -4399,13 +5041,13 @@ test = ["asv", "gmpy2", "mpmath", "pooch", "pytest", "pytest-cov", "pytest-timeo [[package]] name = "sentry-sdk" -version = "2.6.0" +version = "2.17.0" description = "Python client for Sentry (https://sentry.io)" optional = false python-versions = ">=3.6" files = [ - {file = "sentry_sdk-2.6.0-py2.py3-none-any.whl", hash = "sha256:422b91cb49378b97e7e8d0e8d5a1069df23689d45262b86f54988a7db264e874"}, - {file = "sentry_sdk-2.6.0.tar.gz", hash = "sha256:65cc07e9c6995c5e316109f138570b32da3bd7ff8d0d0ee4aaf2628c3dd8127d"}, + {file = "sentry_sdk-2.17.0-py2.py3-none-any.whl", hash = "sha256:625955884b862cc58748920f9e21efdfb8e0d4f98cca4ab0d3918576d5b606ad"}, + {file = "sentry_sdk-2.17.0.tar.gz", hash = "sha256:dd0a05352b78ffeacced73a94e86f38b32e2eae15fff5f30ca5abb568a72eacf"}, ] [package.dependencies] @@ -4428,14 +5070,16 @@ falcon = ["falcon (>=1.4)"] fastapi = ["fastapi (>=0.79.0)"] flask = ["blinker (>=1.1)", "flask (>=0.11)", "markupsafe"] grpcio = ["grpcio (>=1.21.1)", "protobuf (>=3.8.0)"] +http2 = ["httpcore[http2] (==1.*)"] httpx = ["httpx (>=0.16.0)"] huey = ["huey (>=2)"] huggingface-hub = ["huggingface-hub (>=0.22)"] langchain = ["langchain (>=0.0.210)"] +litestar = ["litestar (>=2.0.0)"] loguru = ["loguru (>=0.5)"] openai = ["openai (>=1.0.0)", "tiktoken (>=0.3.0)"] opentelemetry = ["opentelemetry-distro (>=0.35b0)"] -opentelemetry-experimental = ["opentelemetry-distro (>=0.40b0,<1.0)", "opentelemetry-instrumentation-aiohttp-client (>=0.40b0,<1.0)", "opentelemetry-instrumentation-django (>=0.40b0,<1.0)", "opentelemetry-instrumentation-fastapi (>=0.40b0,<1.0)", "opentelemetry-instrumentation-flask (>=0.40b0,<1.0)", "opentelemetry-instrumentation-requests (>=0.40b0,<1.0)", "opentelemetry-instrumentation-sqlite3 (>=0.40b0,<1.0)", "opentelemetry-instrumentation-urllib (>=0.40b0,<1.0)"] +opentelemetry-experimental = ["opentelemetry-distro"] pure-eval = ["asttokens", "executing", "pure-eval"] pymongo = ["pymongo (>=3.1)"] pyspark = ["pyspark (>=2.4.4)"] @@ -4445,7 +5089,7 @@ sanic = ["sanic (>=0.8)"] sqlalchemy = ["sqlalchemy (>=1.2)"] starlette = ["starlette (>=0.19.1)"] starlite = ["starlite (>=1.48)"] -tornado = ["tornado (>=5)"] +tornado = ["tornado (>=6)"] [[package]] name = "setproctitle" @@ -4549,19 +5193,97 @@ test = ["pytest"] [[package]] name = "setuptools" -version = "66.1.1" +version = "75.3.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" +files = [ + {file = "setuptools-75.3.0-py3-none-any.whl", hash = "sha256:f2504966861356aa38616760c0f66568e535562374995367b4e69c7143cf6bcd"}, + {file = "setuptools-75.3.0.tar.gz", hash = "sha256:fba5dd4d766e97be1b1681d98712680ae8f2f26d7881245f2ce9e40714f1a686"}, +] + +[package.extras] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)", "ruff (>=0.5.2)"] +core = ["importlib-metadata (>=6)", "importlib-resources (>=5.10.2)", "jaraco.collections", "jaraco.functools", "jaraco.text (>=3.7)", "more-itertools", "more-itertools (>=8.8)", "packaging", "packaging (>=24)", "platformdirs (>=4.2.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier", "towncrier (<24.7)"] +enabler = ["pytest-enabler (>=2.2)"] +test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test (>=5.5)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-home (>=0.5)", "pytest-perf", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"] +type = ["importlib-metadata (>=7.0.2)", "jaraco.develop (>=7.21)", "mypy (==1.12.*)", "pytest-mypy"] + +[[package]] +name = "setuptools-scm" +version = "8.1.0" +description = "the blessed package to manage your versions by scm tags" +optional = false +python-versions = ">=3.8" +files = [ + {file = "setuptools_scm-8.1.0-py3-none-any.whl", hash = "sha256:897a3226a6fd4a6eb2f068745e49733261a21f70b1bb28fce0339feb978d9af3"}, + {file = "setuptools_scm-8.1.0.tar.gz", hash = "sha256:42dea1b65771cba93b7a515d65a65d8246e560768a66b9106a592c8e7f26c8a7"}, +] + +[package.dependencies] +packaging = ">=20" +setuptools = "*" +tomli = {version = ">=1", markers = "python_version < \"3.11\""} + +[package.extras] +docs = ["entangled-cli (>=2.0,<3.0)", "mkdocs", "mkdocs-entangled-plugin", "mkdocs-material", "mkdocstrings[python]", "pygments"] +rich = ["rich"] +test = ["build", "pytest", "rich", "typing-extensions", "wheel"] + +[[package]] +name = "shap" +version = "0.46.0" +description = "A unified approach to explain the output of any machine learning model." +optional = false +python-versions = ">=3.9" files = [ - {file = "setuptools-66.1.1-py3-none-any.whl", hash = "sha256:6f590d76b713d5de4e49fe4fbca24474469f53c83632d5d0fd056f7ff7e8112b"}, - {file = "setuptools-66.1.1.tar.gz", hash = "sha256:ac4008d396bc9cd983ea483cb7139c0240a07bbc74ffb6232fceffedc6cf03a8"}, + {file = "shap-0.46.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:905b2d7a0262ef820785a7c0e3c7f24c9d281e6f934edb65cbe811fe0e971187"}, + {file = "shap-0.46.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:bccbb30ffbf8b9ed53e476d0c1319fdfcbeac455fe9df277fb0d570d92790e80"}, + {file = "shap-0.46.0-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9633d3d7174acc01455538169ca6e6344f570530384548631aeadcf7bfdaaaea"}, + {file = "shap-0.46.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c6097eb2ab7e8c194254bac3e462266490fbdd43bfe35a1014e9ee21c4ef10ee"}, + {file = "shap-0.46.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:0cf7c6e3f056cf3bfd16bcfd5744d0cc25b851555b1e750a3ab889b3077d2d05"}, + {file = "shap-0.46.0-cp310-cp310-win_amd64.whl", hash = "sha256:949bd7fa40371c3f1885a30ae0611dd481bf4ac90066ff726c73cb5bb393032b"}, + {file = "shap-0.46.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f18217c98f39fd485d541f6aab0b860b3be74b69b21d4faf11959e3fcba765c5"}, + {file = "shap-0.46.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5bbdae4489577c6fce1cfe2d9d8f3d5b96d69284d29645fe651f78f6e965aeb4"}, + {file = "shap-0.46.0-cp311-cp311-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13d36dc58d1e8c010feb4e7da71c77d23626a52d12d16b02869e793b11be4695"}, + {file = "shap-0.46.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:70e06fdfdf53d5fb932c82f4529397552b262e0ccce734f5226fb1e1eab2bc3e"}, + {file = "shap-0.46.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:943f0806fa00b4fafb174f172a73d88de2d8600e6d69c2e2bff833f00e6c4c21"}, + {file = "shap-0.46.0-cp311-cp311-win_amd64.whl", hash = "sha256:c972a2efdc9fc00d543efaa55805eca947b8c418d065962d967824c2d5d295d0"}, + {file = "shap-0.46.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a9cc9be191562bea1a782baff912854d267c6f4831bbf454d8d7bb7df7ddb214"}, + {file = "shap-0.46.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ab1fecfb43604605be17e26ae12bde4406c451c46b54b980d9570cec03fbc239"}, + {file = "shap-0.46.0-cp312-cp312-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b216adf2a17b0e0694f17965ac29354ca8c4f27ac3c66f68bf6fc4cb2aa28207"}, + {file = "shap-0.46.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b6e5dc5257b747a784f7a9b3acb64216a9011f01734f3c96b27fe5e15ae5f99f"}, + {file = "shap-0.46.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1230bf973463041dfa15734f290fbf3ab9c6e4e8222339c76f68fc355b940d80"}, + {file = "shap-0.46.0-cp312-cp312-win_amd64.whl", hash = "sha256:0cbbf996537b2a42d3bc7f2a13492988822ee1bfd7220700989408dfb9e1c5ad"}, + {file = "shap-0.46.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3c7d0c53a8cbefb2260ce28a98fa866c1a287770981f95c40a54f9d1082cbb31"}, + {file = "shap-0.46.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0726f8c63f09dde586c9859ad315641f5a080e9aecf123a0cabc336b61703d66"}, + {file = "shap-0.46.0-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:99edc28daac4cbb98cd9f02febf4e9fbc6b9e3d24519c22ed59a98c68c47336c"}, + {file = "shap-0.46.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85a6ff9c9e15abd9a332360cff8d105165a600466167d6274dab468a050d005a"}, + {file = "shap-0.46.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:9f9f9727839e2459dfa4b4fbc190224e87f7b4b2a29f0e2a438500215921192b"}, + {file = "shap-0.46.0-cp39-cp39-win_amd64.whl", hash = "sha256:b169b485a69f7d32e32fa64ad77be00129436c4455b9d0997b21b553f0becc8c"}, + {file = "shap-0.46.0.tar.gz", hash = "sha256:bdaa5b098be5a958348015e940f6fd264339b5db1e651f9898a3117be95b05a0"}, ] +[package.dependencies] +cloudpickle = "*" +numba = "*" +numpy = "*" +packaging = ">20.9" +pandas = "*" +scikit-learn = "*" +scipy = "*" +slicer = "0.0.8" +tqdm = ">=4.27.0" + [package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8 (<5)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] -testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] +docs = ["ipython", "matplotlib", "myst-parser (==2.0.0)", "nbsphinx (==0.9.3)", "numpydoc", "requests", "sphinx (==7.2.6)", "sphinx-github-changelog (==1.2.1)", "sphinx-rtd-theme (==2.0.0)"] +others = ["lime"] +plots = ["ipython", "matplotlib"] +test = ["catboost", "gpboost", "lightgbm", "ngboost", "opencv-python", "protobuf (==3.20.3)", "pyod", "pyspark", "pytest", "pytest-cov", "pytest-mpl", "sentencepiece", "tensorflow", "tf-keras", "torch", "torch (==2.2.0)", "torchvision", "transformers", "xgboost"] +test-core = ["pytest", "pytest-cov", "pytest-mpl"] +test-notebooks = ["datasets", "jupyter", "keras", "nbconvert", "nbformat", "nlp", "transformers"] [[package]] name = "shellingham" @@ -4607,6 +5329,17 @@ docs = ["fairlearn (>=0.7.0)", "matplotlib (>=3.3)", "numpydoc (>=1.0.0)", "pand rich = ["rich (>=12)"] tests = ["catboost (>=1.0)", "fairlearn (>=0.7.0)", "flake8 (>=3.8.2)", "flaky (>=3.7.0)", "lightgbm (>=3)", "matplotlib (>=3.3)", "pandas (>=1)", "pytest (>=7)", "pytest-cov (>=2.9.0)", "quantile-forest (>=1.0.0)", "rich (>=12)", "types-requests (>=2.28.5)", "xgboost (>=1.6)"] +[[package]] +name = "slicer" +version = "0.0.8" +description = "A small package for big slicing." +optional = false +python-versions = ">=3.6" +files = [ + {file = "slicer-0.0.8-py3-none-any.whl", hash = "sha256:6c206258543aecd010d497dc2eca9d2805860a0b3758673903456b7df7934dc3"}, + {file = "slicer-0.0.8.tar.gz", hash = "sha256:2e7553af73f0c0c2d355f4afcc3ecf97c6f2156fcf4593955c3f56cf6c4d6eb7"}, +] + [[package]] name = "smmap" version = "5.0.1" @@ -4631,13 +5364,13 @@ files = [ [[package]] name = "soupsieve" -version = "2.5" +version = "2.6" description = "A modern CSS selector implementation for Beautiful Soup." optional = false python-versions = ">=3.8" files = [ - {file = "soupsieve-2.5-py3-none-any.whl", hash = "sha256:eaa337ff55a1579b6549dc679565eac1e3d000563bcb1c8ab0d0fefbc0c2cdc7"}, - {file = "soupsieve-2.5.tar.gz", hash = "sha256:5663d5a7b3bfaeee0bc4372e7fc48f9cff4940b3eec54a6451cc5299f1097690"}, + {file = "soupsieve-2.6-py3-none-any.whl", hash = "sha256:e72c4ff06e4fb6e4b5a9f0f55fe6e81514581fca1515028625d0f299c602ccc9"}, + {file = "soupsieve-2.6.tar.gz", hash = "sha256:e2e68417777af359ec65daac1057404a3c8a5455bb8abc36f1a9866ab1a51abb"}, ] [[package]] @@ -4675,13 +5408,13 @@ widechars = ["wcwidth"] [[package]] name = "tenacity" -version = "8.4.1" +version = "9.0.0" description = "Retry code until it succeeds" optional = false python-versions = ">=3.8" files = [ - {file = "tenacity-8.4.1-py3-none-any.whl", hash = "sha256:28522e692eda3e1b8f5e99c51464efcc0b9fc86933da92415168bc1c4e2308fa"}, - {file = "tenacity-8.4.1.tar.gz", hash = "sha256:54b1412b878ddf7e1f1577cd49527bad8cdef32421bd599beac0c6c3f10582fd"}, + {file = "tenacity-9.0.0-py3-none-any.whl", hash = "sha256:93de0c98785b27fcf659856aa9f54bfbd399e29969b0621bc7f762bd441b4539"}, + {file = "tenacity-9.0.0.tar.gz", hash = "sha256:807f37ca97d62aa361264d497b0e31e92b8027044942bfa756160d908320d73b"}, ] [package.extras] @@ -4690,13 +5423,13 @@ test = ["pytest", "tornado (>=4.5)", "typeguard"] [[package]] name = "termcolor" -version = "2.4.0" +version = "2.5.0" description = "ANSI color formatting for output in terminal" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "termcolor-2.4.0-py3-none-any.whl", hash = "sha256:9297c0df9c99445c2412e832e882a7884038a25617c60cea2ad69488d4040d63"}, - {file = "termcolor-2.4.0.tar.gz", hash = "sha256:aab9e56047c8ac41ed798fa36d892a37aca6b3e9159f3e0c24bc64a9b3ac7b7a"}, + {file = "termcolor-2.5.0-py3-none-any.whl", hash = "sha256:37b17b5fc1e604945c2642c872a3764b5d547a48009871aea3edd3afa180afb8"}, + {file = "termcolor-2.5.0.tar.gz", hash = "sha256:998d8d27da6d48442e8e1f016119076b690d962507531df4890fcd2db2ef8a6f"}, ] [package.extras] @@ -4715,13 +5448,13 @@ files = [ [[package]] name = "tomli" -version = "2.0.1" +version = "2.0.2" description = "A lil' TOML parser" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, - {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, + {file = "tomli-2.0.2-py3-none-any.whl", hash = "sha256:2ebe24485c53d303f690b0ec092806a085f07af5a5aa1464f3931eec36caaa38"}, + {file = "tomli-2.0.2.tar.gz", hash = "sha256:d46d457a85337051c36524bc5349dd91b1877838e2979ac5ced3e710ed8a60ed"}, ] [[package]] @@ -4746,13 +5479,13 @@ files = [ [[package]] name = "tqdm" -version = "4.66.4" +version = "4.66.6" description = "Fast, Extensible Progress Meter" optional = false python-versions = ">=3.7" files = [ - {file = "tqdm-4.66.4-py3-none-any.whl", hash = "sha256:b75ca56b413b030bc3f00af51fd2c1a1a5eac6a0c1cca83cbb37a5c52abce644"}, - {file = "tqdm-4.66.4.tar.gz", hash = "sha256:e4d936c9de8727928f3be6079590e97d9abfe8d39a590be678eb5919ffc186bb"}, + {file = "tqdm-4.66.6-py3-none-any.whl", hash = "sha256:223e8b5359c2efc4b30555531f09e9f2f3589bcd7fdd389271191031b49b7a63"}, + {file = "tqdm-4.66.6.tar.gz", hash = "sha256:4bdd694238bef1485ce839d67967ab50af8f9272aab687c0d7702a01da0be090"}, ] [package.dependencies] @@ -4781,13 +5514,13 @@ test = ["argcomplete (>=3.0.3)", "mypy (>=1.7.0)", "pre-commit", "pytest (>=7.0, [[package]] name = "typer" -version = "0.12.3" +version = "0.12.5" description = "Typer, build great CLIs. Easy to code. Based on Python type hints." optional = false python-versions = ">=3.7" files = [ - {file = "typer-0.12.3-py3-none-any.whl", hash = "sha256:070d7ca53f785acbccba8e7d28b08dcd88f79f1fbda035ade0aecec71ca5c914"}, - {file = "typer-0.12.3.tar.gz", hash = "sha256:49e73131481d804288ef62598d97a1ceef3058905aa536a1134f90891ba35482"}, + {file = "typer-0.12.5-py3-none-any.whl", hash = "sha256:62fe4e471711b147e3365034133904df3e235698399bc4de2b36c8579298d52b"}, + {file = "typer-0.12.5.tar.gz", hash = "sha256:f592f089bedcc8ec1b974125d64851029c3b1af145f04aca64d69410f0c9b722"}, ] [package.dependencies] @@ -4809,24 +5542,24 @@ files = [ [[package]] name = "tzdata" -version = "2024.1" +version = "2024.2" description = "Provider of IANA time zone data" optional = false python-versions = ">=2" files = [ - {file = "tzdata-2024.1-py2.py3-none-any.whl", hash = "sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252"}, - {file = "tzdata-2024.1.tar.gz", hash = "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd"}, + {file = "tzdata-2024.2-py2.py3-none-any.whl", hash = "sha256:a48093786cdcde33cad18c2555e8532f34422074448fbc874186f0abd79565cd"}, + {file = "tzdata-2024.2.tar.gz", hash = "sha256:7d85cc416e9382e69095b7bdf4afd9e3880418a2413feec7069d533d6b4e31cc"}, ] [[package]] name = "urllib3" -version = "2.2.2" +version = "2.2.3" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.8" files = [ - {file = "urllib3-2.2.2-py3-none-any.whl", hash = "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472"}, - {file = "urllib3-2.2.2.tar.gz", hash = "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168"}, + {file = "urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac"}, + {file = "urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9"}, ] [package.extras] @@ -4837,57 +5570,64 @@ zstd = ["zstandard (>=0.18.0)"] [[package]] name = "uvloop" -version = "0.19.0" +version = "0.21.0" description = "Fast implementation of asyncio event loop on top of libuv" optional = false python-versions = ">=3.8.0" files = [ - {file = "uvloop-0.19.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:de4313d7f575474c8f5a12e163f6d89c0a878bc49219641d49e6f1444369a90e"}, - {file = "uvloop-0.19.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5588bd21cf1fcf06bded085f37e43ce0e00424197e7c10e77afd4bbefffef428"}, - {file = "uvloop-0.19.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b1fd71c3843327f3bbc3237bedcdb6504fd50368ab3e04d0410e52ec293f5b8"}, - {file = "uvloop-0.19.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5a05128d315e2912791de6088c34136bfcdd0c7cbc1cf85fd6fd1bb321b7c849"}, - {file = "uvloop-0.19.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:cd81bdc2b8219cb4b2556eea39d2e36bfa375a2dd021404f90a62e44efaaf957"}, - {file = "uvloop-0.19.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:5f17766fb6da94135526273080f3455a112f82570b2ee5daa64d682387fe0dcd"}, - {file = "uvloop-0.19.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4ce6b0af8f2729a02a5d1575feacb2a94fc7b2e983868b009d51c9a9d2149bef"}, - {file = "uvloop-0.19.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:31e672bb38b45abc4f26e273be83b72a0d28d074d5b370fc4dcf4c4eb15417d2"}, - {file = "uvloop-0.19.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:570fc0ed613883d8d30ee40397b79207eedd2624891692471808a95069a007c1"}, - {file = "uvloop-0.19.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5138821e40b0c3e6c9478643b4660bd44372ae1e16a322b8fc07478f92684e24"}, - {file = "uvloop-0.19.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:91ab01c6cd00e39cde50173ba4ec68a1e578fee9279ba64f5221810a9e786533"}, - {file = "uvloop-0.19.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:47bf3e9312f63684efe283f7342afb414eea4d3011542155c7e625cd799c3b12"}, - {file = "uvloop-0.19.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:da8435a3bd498419ee8c13c34b89b5005130a476bda1d6ca8cfdde3de35cd650"}, - {file = "uvloop-0.19.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:02506dc23a5d90e04d4f65c7791e65cf44bd91b37f24cfc3ef6cf2aff05dc7ec"}, - {file = "uvloop-0.19.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2693049be9d36fef81741fddb3f441673ba12a34a704e7b4361efb75cf30befc"}, - {file = "uvloop-0.19.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7010271303961c6f0fe37731004335401eb9075a12680738731e9c92ddd96ad6"}, - {file = "uvloop-0.19.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:5daa304d2161d2918fa9a17d5635099a2f78ae5b5960e742b2fcfbb7aefaa593"}, - {file = "uvloop-0.19.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:7207272c9520203fea9b93843bb775d03e1cf88a80a936ce760f60bb5add92f3"}, - {file = "uvloop-0.19.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:78ab247f0b5671cc887c31d33f9b3abfb88d2614b84e4303f1a63b46c046c8bd"}, - {file = "uvloop-0.19.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:472d61143059c84947aa8bb74eabbace30d577a03a1805b77933d6bd13ddebbd"}, - {file = "uvloop-0.19.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45bf4c24c19fb8a50902ae37c5de50da81de4922af65baf760f7c0c42e1088be"}, - {file = "uvloop-0.19.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:271718e26b3e17906b28b67314c45d19106112067205119dddbd834c2b7ce797"}, - {file = "uvloop-0.19.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:34175c9fd2a4bc3adc1380e1261f60306344e3407c20a4d684fd5f3be010fa3d"}, - {file = "uvloop-0.19.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e27f100e1ff17f6feeb1f33968bc185bf8ce41ca557deee9d9bbbffeb72030b7"}, - {file = "uvloop-0.19.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:13dfdf492af0aa0a0edf66807d2b465607d11c4fa48f4a1fd41cbea5b18e8e8b"}, - {file = "uvloop-0.19.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6e3d4e85ac060e2342ff85e90d0c04157acb210b9ce508e784a944f852a40e67"}, - {file = "uvloop-0.19.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8ca4956c9ab567d87d59d49fa3704cf29e37109ad348f2d5223c9bf761a332e7"}, - {file = "uvloop-0.19.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f467a5fd23b4fc43ed86342641f3936a68ded707f4627622fa3f82a120e18256"}, - {file = "uvloop-0.19.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:492e2c32c2af3f971473bc22f086513cedfc66a130756145a931a90c3958cb17"}, - {file = "uvloop-0.19.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2df95fca285a9f5bfe730e51945ffe2fa71ccbfdde3b0da5772b4ee4f2e770d5"}, - {file = "uvloop-0.19.0.tar.gz", hash = "sha256:0246f4fd1bf2bf702e06b0d45ee91677ee5c31242f39aab4ea6fe0c51aedd0fd"}, + {file = "uvloop-0.21.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ec7e6b09a6fdded42403182ab6b832b71f4edaf7f37a9a0e371a01db5f0cb45f"}, + {file = "uvloop-0.21.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:196274f2adb9689a289ad7d65700d37df0c0930fd8e4e743fa4834e850d7719d"}, + {file = "uvloop-0.21.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f38b2e090258d051d68a5b14d1da7203a3c3677321cf32a95a6f4db4dd8b6f26"}, + {file = "uvloop-0.21.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87c43e0f13022b998eb9b973b5e97200c8b90823454d4bc06ab33829e09fb9bb"}, + {file = "uvloop-0.21.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:10d66943def5fcb6e7b37310eb6b5639fd2ccbc38df1177262b0640c3ca68c1f"}, + {file = "uvloop-0.21.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:67dd654b8ca23aed0a8e99010b4c34aca62f4b7fce88f39d452ed7622c94845c"}, + {file = "uvloop-0.21.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c0f3fa6200b3108919f8bdabb9a7f87f20e7097ea3c543754cabc7d717d95cf8"}, + {file = "uvloop-0.21.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0878c2640cf341b269b7e128b1a5fed890adc4455513ca710d77d5e93aa6d6a0"}, + {file = "uvloop-0.21.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9fb766bb57b7388745d8bcc53a359b116b8a04c83a2288069809d2b3466c37e"}, + {file = "uvloop-0.21.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a375441696e2eda1c43c44ccb66e04d61ceeffcd76e4929e527b7fa401b90fb"}, + {file = "uvloop-0.21.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:baa0e6291d91649c6ba4ed4b2f982f9fa165b5bbd50a9e203c416a2797bab3c6"}, + {file = "uvloop-0.21.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4509360fcc4c3bd2c70d87573ad472de40c13387f5fda8cb58350a1d7475e58d"}, + {file = "uvloop-0.21.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:359ec2c888397b9e592a889c4d72ba3d6befba8b2bb01743f72fffbde663b59c"}, + {file = "uvloop-0.21.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f7089d2dc73179ce5ac255bdf37c236a9f914b264825fdaacaded6990a7fb4c2"}, + {file = "uvloop-0.21.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:baa4dcdbd9ae0a372f2167a207cd98c9f9a1ea1188a8a526431eef2f8116cc8d"}, + {file = "uvloop-0.21.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86975dca1c773a2c9864f4c52c5a55631038e387b47eaf56210f873887b6c8dc"}, + {file = "uvloop-0.21.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:461d9ae6660fbbafedd07559c6a2e57cd553b34b0065b6550685f6653a98c1cb"}, + {file = "uvloop-0.21.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:183aef7c8730e54c9a3ee3227464daed66e37ba13040bb3f350bc2ddc040f22f"}, + {file = "uvloop-0.21.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:bfd55dfcc2a512316e65f16e503e9e450cab148ef11df4e4e679b5e8253a5281"}, + {file = "uvloop-0.21.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:787ae31ad8a2856fc4e7c095341cccc7209bd657d0e71ad0dc2ea83c4a6fa8af"}, + {file = "uvloop-0.21.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ee4d4ef48036ff6e5cfffb09dd192c7a5027153948d85b8da7ff705065bacc6"}, + {file = "uvloop-0.21.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3df876acd7ec037a3d005b3ab85a7e4110422e4d9c1571d4fc89b0fc41b6816"}, + {file = "uvloop-0.21.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bd53ecc9a0f3d87ab847503c2e1552b690362e005ab54e8a48ba97da3924c0dc"}, + {file = "uvloop-0.21.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a5c39f217ab3c663dc699c04cbd50c13813e31d917642d459fdcec07555cc553"}, + {file = "uvloop-0.21.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:17df489689befc72c39a08359efac29bbee8eee5209650d4b9f34df73d22e414"}, + {file = "uvloop-0.21.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bc09f0ff191e61c2d592a752423c767b4ebb2986daa9ed62908e2b1b9a9ae206"}, + {file = "uvloop-0.21.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f0ce1b49560b1d2d8a2977e3ba4afb2414fb46b86a1b64056bc4ab929efdafbe"}, + {file = "uvloop-0.21.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e678ad6fe52af2c58d2ae3c73dc85524ba8abe637f134bf3564ed07f555c5e79"}, + {file = "uvloop-0.21.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:460def4412e473896ef179a1671b40c039c7012184b627898eea5072ef6f017a"}, + {file = "uvloop-0.21.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:10da8046cc4a8f12c91a1c39d1dd1585c41162a15caaef165c2174db9ef18bdc"}, + {file = "uvloop-0.21.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c097078b8031190c934ed0ebfee8cc5f9ba9642e6eb88322b9958b649750f72b"}, + {file = "uvloop-0.21.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:46923b0b5ee7fc0020bef24afe7836cb068f5050ca04caf6b487c513dc1a20b2"}, + {file = "uvloop-0.21.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:53e420a3afe22cdcf2a0f4846e377d16e718bc70103d7088a4f7623567ba5fb0"}, + {file = "uvloop-0.21.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88cb67cdbc0e483da00af0b2c3cdad4b7c61ceb1ee0f33fe00e09c81e3a6cb75"}, + {file = "uvloop-0.21.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:221f4f2a1f46032b403bf3be628011caf75428ee3cc204a22addf96f586b19fd"}, + {file = "uvloop-0.21.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2d1f581393673ce119355d56da84fe1dd9d2bb8b3d13ce792524e1607139feff"}, + {file = "uvloop-0.21.0.tar.gz", hash = "sha256:3bf12b0fda68447806a7ad847bfa591613177275d35b6724b1ee573faa3704e3"}, ] [package.extras] +dev = ["Cython (>=3.0,<4.0)", "setuptools (>=60)"] docs = ["Sphinx (>=4.1.2,<4.2.0)", "sphinx-rtd-theme (>=0.5.2,<0.6.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)"] -test = ["Cython (>=0.29.36,<0.30.0)", "aiohttp (==3.9.0b0)", "aiohttp (>=3.8.1)", "flake8 (>=5.0,<6.0)", "mypy (>=0.800)", "psutil", "pyOpenSSL (>=23.0.0,<23.1.0)", "pycodestyle (>=2.9.0,<2.10.0)"] +test = ["aiohttp (>=3.10.5)", "flake8 (>=5.0,<6.0)", "mypy (>=0.800)", "psutil", "pyOpenSSL (>=23.0.0,<23.1.0)", "pycodestyle (>=2.9.0,<2.10.0)"] [[package]] name = "virtualenv" -version = "20.26.3" +version = "20.27.1" description = "Virtual Python Environment builder" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "virtualenv-20.26.3-py3-none-any.whl", hash = "sha256:8cc4a31139e796e9a7de2cd5cf2489de1217193116a8fd42328f1bd65f434589"}, - {file = "virtualenv-20.26.3.tar.gz", hash = "sha256:4c43a2a236279d9ea36a0d76f98d84bd6ca94ac4e0f4a3b9d46d05e10fea542a"}, + {file = "virtualenv-20.27.1-py3-none-any.whl", hash = "sha256:f11f1b8a29525562925f745563bfd48b189450f61fb34c4f9cc79dd5aa32a1f4"}, + {file = "virtualenv-20.27.1.tar.gz", hash = "sha256:142c6be10212543b32c6c45d3d3893dff89112cc588b7d0879ae5a1ec03a47ba"}, ] [package.dependencies] @@ -4901,19 +5641,21 @@ test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess [[package]] name = "wandb" -version = "0.18.0" +version = "0.18.5" description = "A CLI and library for interacting with the Weights & Biases API." optional = false python-versions = ">=3.7" files = [ - {file = "wandb-0.18.0-py3-none-any.whl", hash = "sha256:a176af0d51b55a363dac3c54a8b7aa1cfd5a89cad6fc6574237232f37c779965"}, - {file = "wandb-0.18.0-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:2bc7f18becda9a566a63723666390f941e8b115b9e7746e0e5d73dc9ea9714c6"}, - {file = "wandb-0.18.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:e14a385c95e61e77b0b5c4cbc6c5a0b47ac0d9e66730ca8c17b84eba374e35d1"}, - {file = "wandb-0.18.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0764ad8911a70cdb7cb339567c4170b860e8f5f523447b2f748d7e0e6224e29"}, - {file = "wandb-0.18.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d2ffea43710e3482168a2d89b2770aa9a14007ba16e717b176428f2a50765f2"}, - {file = "wandb-0.18.0-py3-none-win32.whl", hash = "sha256:b209840a9499bf687e8b5b20117341e7722f86a85f986c422501eb1a709dc721"}, - {file = "wandb-0.18.0-py3-none-win_amd64.whl", hash = "sha256:25aa8ee1808eae0c0e4818b81bc43fd6461e4f3603d7918e5eab2f9afca00715"}, - {file = "wandb-0.18.0.tar.gz", hash = "sha256:872dfd7298c053ca861352196bc422452caff105d3bc66b90e7bc86f17ad8bdd"}, + {file = "wandb-0.18.5-py3-none-any.whl", hash = "sha256:49ba7bafff0cecff2159bc6fb68176d6e5561d744a9bd6a63753e7077a74e26d"}, + {file = "wandb-0.18.5-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:c9d903dbff9517843881d9a0d561d82bcf0e949d8b8c03aafa35aceef31ea7e0"}, + {file = "wandb-0.18.5-py3-none-macosx_11_0_arm64.whl", hash = "sha256:33d3e5765a9bb305558af4f291338cf8723856d2b3a3c377414cd8f8b711baa4"}, + {file = "wandb-0.18.5-py3-none-macosx_11_0_x86_64.whl", hash = "sha256:9ff72e7a45e998e2a7ff42645ec76bedabf17ea51fd112ae2837dce5023ac0cc"}, + {file = "wandb-0.18.5-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:136a79c06c114c225add8f977acec23d53df5e2a4d2803700a5eb5501ae40160"}, + {file = "wandb-0.18.5-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:350fc0f6f5bc23f4baeef12ccfea6daa89d1a5b84948d72d48249cbb652ab22a"}, + {file = "wandb-0.18.5-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:4e31741eefa2b2a83aa9f69ef27ce6112fee6f4c792a9e2996cf374a74465276"}, + {file = "wandb-0.18.5-py3-none-win32.whl", hash = "sha256:b2a25e9caf63c12e5de1cbdb30b13f76553c04754f9ff404080f70386adb8384"}, + {file = "wandb-0.18.5-py3-none-win_amd64.whl", hash = "sha256:83b619167eb2ffdd1188cba3805ccad158f6fd7fc06bef43daf6d2729a787fa0"}, + {file = "wandb-0.18.5.tar.gz", hash = "sha256:75ef47ba7fc709b787be05e558f1635d99246afeacc9369031c1be6e5b620ce6"}, ] [package.dependencies] @@ -4925,9 +5667,10 @@ protobuf = {version = ">=3.19.0,<4.21.0 || >4.21.0,<5.28.0 || >5.28.0,<6", marke psutil = ">=5.0.0" pyyaml = "*" requests = ">=2.0.0,<3" -sentry-sdk = ">=1.0.0" +sentry-sdk = ">=2.0.0" setproctitle = "*" setuptools = "*" +typing-extensions = {version = ">=4.4,<5", markers = "python_version < \"3.12\""} [package.extras] aws = ["boto3"] @@ -4936,7 +5679,7 @@ gcp = ["google-cloud-storage"] importers = ["filelock", "mlflow", "polars (<=1.2.1)", "rich", "tenacity"] kubeflow = ["google-cloud-storage", "kubernetes", "minio", "sh"] launch = ["awscli", "azure-containerregistry", "azure-identity", "azure-storage-blob", "boto3", "botocore", "chardet", "google-auth", "google-cloud-aiplatform", "google-cloud-artifact-registry", "google-cloud-compute", "google-cloud-storage", "iso8601", "jsonschema", "kubernetes", "kubernetes-asyncio", "nbconvert", "nbformat", "optuna", "pydantic", "pyyaml (>=6.0.0)", "tomli", "typing-extensions"] -media = ["bokeh", "moviepy", "numpy", "pillow", "plotly (>=5.18.0)", "rdkit-pypi", "soundfile"] +media = ["bokeh", "imageio", "moviepy", "numpy", "pillow", "plotly (>=5.18.0)", "rdkit", "soundfile"] models = ["cloudpickle"] perf = ["orjson"] sweeps = ["sweeps (>=0.2.0)"] @@ -4944,43 +5687,41 @@ workspaces = ["wandb-workspaces"] [[package]] name = "watchdog" -version = "4.0.1" +version = "5.0.3" description = "Filesystem events monitoring" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "watchdog-4.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:da2dfdaa8006eb6a71051795856bedd97e5b03e57da96f98e375682c48850645"}, - {file = "watchdog-4.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e93f451f2dfa433d97765ca2634628b789b49ba8b504fdde5837cdcf25fdb53b"}, - {file = "watchdog-4.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ef0107bbb6a55f5be727cfc2ef945d5676b97bffb8425650dadbb184be9f9a2b"}, - {file = "watchdog-4.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:17e32f147d8bf9657e0922c0940bcde863b894cd871dbb694beb6704cfbd2fb5"}, - {file = "watchdog-4.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:03e70d2df2258fb6cb0e95bbdbe06c16e608af94a3ffbd2b90c3f1e83eb10767"}, - {file = "watchdog-4.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:123587af84260c991dc5f62a6e7ef3d1c57dfddc99faacee508c71d287248459"}, - {file = "watchdog-4.0.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:093b23e6906a8b97051191a4a0c73a77ecc958121d42346274c6af6520dec175"}, - {file = "watchdog-4.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:611be3904f9843f0529c35a3ff3fd617449463cb4b73b1633950b3d97fa4bfb7"}, - {file = "watchdog-4.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:62c613ad689ddcb11707f030e722fa929f322ef7e4f18f5335d2b73c61a85c28"}, - {file = "watchdog-4.0.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:d4925e4bf7b9bddd1c3de13c9b8a2cdb89a468f640e66fbfabaf735bd85b3e35"}, - {file = "watchdog-4.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cad0bbd66cd59fc474b4a4376bc5ac3fc698723510cbb64091c2a793b18654db"}, - {file = "watchdog-4.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a3c2c317a8fb53e5b3d25790553796105501a235343f5d2bf23bb8649c2c8709"}, - {file = "watchdog-4.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c9904904b6564d4ee8a1ed820db76185a3c96e05560c776c79a6ce5ab71888ba"}, - {file = "watchdog-4.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:667f3c579e813fcbad1b784db7a1aaa96524bed53437e119f6a2f5de4db04235"}, - {file = "watchdog-4.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d10a681c9a1d5a77e75c48a3b8e1a9f2ae2928eda463e8d33660437705659682"}, - {file = "watchdog-4.0.1-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0144c0ea9997b92615af1d94afc0c217e07ce2c14912c7b1a5731776329fcfc7"}, - {file = "watchdog-4.0.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:998d2be6976a0ee3a81fb8e2777900c28641fb5bfbd0c84717d89bca0addcdc5"}, - {file = "watchdog-4.0.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:e7921319fe4430b11278d924ef66d4daa469fafb1da679a2e48c935fa27af193"}, - {file = "watchdog-4.0.1-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:f0de0f284248ab40188f23380b03b59126d1479cd59940f2a34f8852db710625"}, - {file = "watchdog-4.0.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:bca36be5707e81b9e6ce3208d92d95540d4ca244c006b61511753583c81c70dd"}, - {file = "watchdog-4.0.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:ab998f567ebdf6b1da7dc1e5accfaa7c6992244629c0fdaef062f43249bd8dee"}, - {file = "watchdog-4.0.1-py3-none-manylinux2014_aarch64.whl", hash = "sha256:dddba7ca1c807045323b6af4ff80f5ddc4d654c8bce8317dde1bd96b128ed253"}, - {file = "watchdog-4.0.1-py3-none-manylinux2014_armv7l.whl", hash = "sha256:4513ec234c68b14d4161440e07f995f231be21a09329051e67a2118a7a612d2d"}, - {file = "watchdog-4.0.1-py3-none-manylinux2014_i686.whl", hash = "sha256:4107ac5ab936a63952dea2a46a734a23230aa2f6f9db1291bf171dac3ebd53c6"}, - {file = "watchdog-4.0.1-py3-none-manylinux2014_ppc64.whl", hash = "sha256:6e8c70d2cd745daec2a08734d9f63092b793ad97612470a0ee4cbb8f5f705c57"}, - {file = "watchdog-4.0.1-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:f27279d060e2ab24c0aa98363ff906d2386aa6c4dc2f1a374655d4e02a6c5e5e"}, - {file = "watchdog-4.0.1-py3-none-manylinux2014_s390x.whl", hash = "sha256:f8affdf3c0f0466e69f5b3917cdd042f89c8c63aebdb9f7c078996f607cdb0f5"}, - {file = "watchdog-4.0.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:ac7041b385f04c047fcc2951dc001671dee1b7e0615cde772e84b01fbf68ee84"}, - {file = "watchdog-4.0.1-py3-none-win32.whl", hash = "sha256:206afc3d964f9a233e6ad34618ec60b9837d0582b500b63687e34011e15bb429"}, - {file = "watchdog-4.0.1-py3-none-win_amd64.whl", hash = "sha256:7577b3c43e5909623149f76b099ac49a1a01ca4e167d1785c76eb52fa585745a"}, - {file = "watchdog-4.0.1-py3-none-win_ia64.whl", hash = "sha256:d7b9f5f3299e8dd230880b6c55504a1f69cf1e4316275d1b215ebdd8187ec88d"}, - {file = "watchdog-4.0.1.tar.gz", hash = "sha256:eebaacf674fa25511e8867028d281e602ee6500045b57f43b08778082f7f8b44"}, + {file = "watchdog-5.0.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:85527b882f3facda0579bce9d743ff7f10c3e1e0db0a0d0e28170a7d0e5ce2ea"}, + {file = "watchdog-5.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:53adf73dcdc0ef04f7735066b4a57a4cd3e49ef135daae41d77395f0b5b692cb"}, + {file = "watchdog-5.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e25adddab85f674acac303cf1f5835951345a56c5f7f582987d266679979c75b"}, + {file = "watchdog-5.0.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f01f4a3565a387080dc49bdd1fefe4ecc77f894991b88ef927edbfa45eb10818"}, + {file = "watchdog-5.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:91b522adc25614cdeaf91f7897800b82c13b4b8ac68a42ca959f992f6990c490"}, + {file = "watchdog-5.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d52db5beb5e476e6853da2e2d24dbbbed6797b449c8bf7ea118a4ee0d2c9040e"}, + {file = "watchdog-5.0.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:94d11b07c64f63f49876e0ab8042ae034674c8653bfcdaa8c4b32e71cfff87e8"}, + {file = "watchdog-5.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:349c9488e1d85d0a58e8cb14222d2c51cbc801ce11ac3936ab4c3af986536926"}, + {file = "watchdog-5.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:53a3f10b62c2d569e260f96e8d966463dec1a50fa4f1b22aec69e3f91025060e"}, + {file = "watchdog-5.0.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:950f531ec6e03696a2414b6308f5c6ff9dab7821a768c9d5788b1314e9a46ca7"}, + {file = "watchdog-5.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ae6deb336cba5d71476caa029ceb6e88047fc1dc74b62b7c4012639c0b563906"}, + {file = "watchdog-5.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1021223c08ba8d2d38d71ec1704496471ffd7be42cfb26b87cd5059323a389a1"}, + {file = "watchdog-5.0.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:752fb40efc7cc8d88ebc332b8f4bcbe2b5cc7e881bccfeb8e25054c00c994ee3"}, + {file = "watchdog-5.0.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a2e8f3f955d68471fa37b0e3add18500790d129cc7efe89971b8a4cc6fdeb0b2"}, + {file = "watchdog-5.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b8ca4d854adcf480bdfd80f46fdd6fb49f91dd020ae11c89b3a79e19454ec627"}, + {file = "watchdog-5.0.3-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:90a67d7857adb1d985aca232cc9905dd5bc4803ed85cfcdcfcf707e52049eda7"}, + {file = "watchdog-5.0.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:720ef9d3a4f9ca575a780af283c8fd3a0674b307651c1976714745090da5a9e8"}, + {file = "watchdog-5.0.3-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:223160bb359281bb8e31c8f1068bf71a6b16a8ad3d9524ca6f523ac666bb6a1e"}, + {file = "watchdog-5.0.3-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:560135542c91eaa74247a2e8430cf83c4342b29e8ad4f520ae14f0c8a19cfb5b"}, + {file = "watchdog-5.0.3-py3-none-manylinux2014_aarch64.whl", hash = "sha256:dd021efa85970bd4824acacbb922066159d0f9e546389a4743d56919b6758b91"}, + {file = "watchdog-5.0.3-py3-none-manylinux2014_armv7l.whl", hash = "sha256:78864cc8f23dbee55be34cc1494632a7ba30263951b5b2e8fc8286b95845f82c"}, + {file = "watchdog-5.0.3-py3-none-manylinux2014_i686.whl", hash = "sha256:1e9679245e3ea6498494b3028b90c7b25dbb2abe65c7d07423ecfc2d6218ff7c"}, + {file = "watchdog-5.0.3-py3-none-manylinux2014_ppc64.whl", hash = "sha256:9413384f26b5d050b6978e6fcd0c1e7f0539be7a4f1a885061473c5deaa57221"}, + {file = "watchdog-5.0.3-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:294b7a598974b8e2c6123d19ef15de9abcd282b0fbbdbc4d23dfa812959a9e05"}, + {file = "watchdog-5.0.3-py3-none-manylinux2014_s390x.whl", hash = "sha256:26dd201857d702bdf9d78c273cafcab5871dd29343748524695cecffa44a8d97"}, + {file = "watchdog-5.0.3-py3-none-manylinux2014_x86_64.whl", hash = "sha256:0f9332243355643d567697c3e3fa07330a1d1abf981611654a1f2bf2175612b7"}, + {file = "watchdog-5.0.3-py3-none-win32.whl", hash = "sha256:c66f80ee5b602a9c7ab66e3c9f36026590a0902db3aea414d59a2f55188c1f49"}, + {file = "watchdog-5.0.3-py3-none-win_amd64.whl", hash = "sha256:f00b4cf737f568be9665563347a910f8bdc76f88c2970121c86243c8cfdf90e9"}, + {file = "watchdog-5.0.3-py3-none-win_ia64.whl", hash = "sha256:49f4d36cb315c25ea0d946e018c01bb028048023b9e103d3d3943f58e109dd45"}, + {file = "watchdog-5.0.3.tar.gz", hash = "sha256:108f42a7f0345042a854d4d0ad0834b741d421330d5f575b81cb27b883500176"}, ] [package.extras] @@ -4988,13 +5729,13 @@ watchmedo = ["PyYAML (>=3.10)"] [[package]] name = "wcmatch" -version = "8.5.2" +version = "10.0" description = "Wildcard/glob file name matcher." optional = false python-versions = ">=3.8" files = [ - {file = "wcmatch-8.5.2-py3-none-any.whl", hash = "sha256:17d3ad3758f9d0b5b4dedc770b65420d4dac62e680229c287bf24c9db856a478"}, - {file = "wcmatch-8.5.2.tar.gz", hash = "sha256:a70222b86dea82fb382dd87b73278c10756c138bd6f8f714e2183128887b9eb2"}, + {file = "wcmatch-10.0-py3-none-any.whl", hash = "sha256:0dd927072d03c0a6527a20d2e6ad5ba8d0380e60870c383bc533b71744df7b7a"}, + {file = "wcmatch-10.0.tar.gz", hash = "sha256:e72f0de09bba6a04e0de70937b0cf06e55f36f37b3deb422dfaf854b867b840a"}, ] [package.dependencies] @@ -5092,13 +5833,13 @@ files = [ [[package]] name = "xyzservices" -version = "2024.6.0" +version = "2024.9.0" description = "Source of XYZ tiles providers" optional = false python-versions = ">=3.8" files = [ - {file = "xyzservices-2024.6.0-py3-none-any.whl", hash = "sha256:fecb2508f0f2b71c819aecf5df2c03cef001c56a4b49302e640f3b34710d25e4"}, - {file = "xyzservices-2024.6.0.tar.gz", hash = "sha256:58c1bdab4257d2551b9ef91cd48571f77b7c4d2bc45bf5e3c05ac97b3a4d7282"}, + {file = "xyzservices-2024.9.0-py3-none-any.whl", hash = "sha256:776ae82b78d6e5ca63dd6a94abb054df8130887a4a308473b54a6bd364de8644"}, + {file = "xyzservices-2024.9.0.tar.gz", hash = "sha256:68fb8353c9dbba4f1ff6c0f2e5e4e596bb9e1db7f94f4f7dfbcb26e25aa66fde"}, ] [[package]] @@ -5121,108 +5862,101 @@ dev = ["doc8", "flake8", "flake8-import-order", "rstcheck[sphinx]", "sphinx"] [[package]] name = "yarl" -version = "1.9.4" +version = "1.17.0" description = "Yet another URL library" optional = false -python-versions = ">=3.7" +python-versions = ">=3.9" files = [ - {file = "yarl-1.9.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a8c1df72eb746f4136fe9a2e72b0c9dc1da1cbd23b5372f94b5820ff8ae30e0e"}, - {file = "yarl-1.9.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a3a6ed1d525bfb91b3fc9b690c5a21bb52de28c018530ad85093cc488bee2dd2"}, - {file = "yarl-1.9.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c38c9ddb6103ceae4e4498f9c08fac9b590c5c71b0370f98714768e22ac6fa66"}, - {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d9e09c9d74f4566e905a0b8fa668c58109f7624db96a2171f21747abc7524234"}, - {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8477c1ee4bd47c57d49621a062121c3023609f7a13b8a46953eb6c9716ca392"}, - {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d5ff2c858f5f6a42c2a8e751100f237c5e869cbde669a724f2062d4c4ef93551"}, - {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:357495293086c5b6d34ca9616a43d329317feab7917518bc97a08f9e55648455"}, - {file = "yarl-1.9.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:54525ae423d7b7a8ee81ba189f131054defdb122cde31ff17477951464c1691c"}, - {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:801e9264d19643548651b9db361ce3287176671fb0117f96b5ac0ee1c3530d53"}, - {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e516dc8baf7b380e6c1c26792610230f37147bb754d6426462ab115a02944385"}, - {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:7d5aaac37d19b2904bb9dfe12cdb08c8443e7ba7d2852894ad448d4b8f442863"}, - {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:54beabb809ffcacbd9d28ac57b0db46e42a6e341a030293fb3185c409e626b8b"}, - {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bac8d525a8dbc2a1507ec731d2867025d11ceadcb4dd421423a5d42c56818541"}, - {file = "yarl-1.9.4-cp310-cp310-win32.whl", hash = "sha256:7855426dfbddac81896b6e533ebefc0af2f132d4a47340cee6d22cac7190022d"}, - {file = "yarl-1.9.4-cp310-cp310-win_amd64.whl", hash = "sha256:848cd2a1df56ddbffeb375535fb62c9d1645dde33ca4d51341378b3f5954429b"}, - {file = "yarl-1.9.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:35a2b9396879ce32754bd457d31a51ff0a9d426fd9e0e3c33394bf4b9036b099"}, - {file = "yarl-1.9.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c7d56b293cc071e82532f70adcbd8b61909eec973ae9d2d1f9b233f3d943f2c"}, - {file = "yarl-1.9.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d8a1c6c0be645c745a081c192e747c5de06e944a0d21245f4cf7c05e457c36e0"}, - {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4b3c1ffe10069f655ea2d731808e76e0f452fc6c749bea04781daf18e6039525"}, - {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:549d19c84c55d11687ddbd47eeb348a89df9cb30e1993f1b128f4685cd0ebbf8"}, - {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a7409f968456111140c1c95301cadf071bd30a81cbd7ab829169fb9e3d72eae9"}, - {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e23a6d84d9d1738dbc6e38167776107e63307dfc8ad108e580548d1f2c587f42"}, - {file = "yarl-1.9.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d8b889777de69897406c9fb0b76cdf2fd0f31267861ae7501d93003d55f54fbe"}, - {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:03caa9507d3d3c83bca08650678e25364e1843b484f19986a527630ca376ecce"}, - {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4e9035df8d0880b2f1c7f5031f33f69e071dfe72ee9310cfc76f7b605958ceb9"}, - {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:c0ec0ed476f77db9fb29bca17f0a8fcc7bc97ad4c6c1d8959c507decb22e8572"}, - {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:ee04010f26d5102399bd17f8df8bc38dc7ccd7701dc77f4a68c5b8d733406958"}, - {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:49a180c2e0743d5d6e0b4d1a9e5f633c62eca3f8a86ba5dd3c471060e352ca98"}, - {file = "yarl-1.9.4-cp311-cp311-win32.whl", hash = "sha256:81eb57278deb6098a5b62e88ad8281b2ba09f2f1147c4767522353eaa6260b31"}, - {file = "yarl-1.9.4-cp311-cp311-win_amd64.whl", hash = "sha256:d1d2532b340b692880261c15aee4dc94dd22ca5d61b9db9a8a361953d36410b1"}, - {file = "yarl-1.9.4-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0d2454f0aef65ea81037759be5ca9947539667eecebca092733b2eb43c965a81"}, - {file = "yarl-1.9.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:44d8ffbb9c06e5a7f529f38f53eda23e50d1ed33c6c869e01481d3fafa6b8142"}, - {file = "yarl-1.9.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:aaaea1e536f98754a6e5c56091baa1b6ce2f2700cc4a00b0d49eca8dea471074"}, - {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3777ce5536d17989c91696db1d459574e9a9bd37660ea7ee4d3344579bb6f129"}, - {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fc5fc1eeb029757349ad26bbc5880557389a03fa6ada41703db5e068881e5f2"}, - {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ea65804b5dc88dacd4a40279af0cdadcfe74b3e5b4c897aa0d81cf86927fee78"}, - {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa102d6d280a5455ad6a0f9e6d769989638718e938a6a0a2ff3f4a7ff8c62cc4"}, - {file = "yarl-1.9.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09efe4615ada057ba2d30df871d2f668af661e971dfeedf0c159927d48bbeff0"}, - {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:008d3e808d03ef28542372d01057fd09168419cdc8f848efe2804f894ae03e51"}, - {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:6f5cb257bc2ec58f437da2b37a8cd48f666db96d47b8a3115c29f316313654ff"}, - {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:992f18e0ea248ee03b5a6e8b3b4738850ae7dbb172cc41c966462801cbf62cf7"}, - {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:0e9d124c191d5b881060a9e5060627694c3bdd1fe24c5eecc8d5d7d0eb6faabc"}, - {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3986b6f41ad22988e53d5778f91855dc0399b043fc8946d4f2e68af22ee9ff10"}, - {file = "yarl-1.9.4-cp312-cp312-win32.whl", hash = "sha256:4b21516d181cd77ebd06ce160ef8cc2a5e9ad35fb1c5930882baff5ac865eee7"}, - {file = "yarl-1.9.4-cp312-cp312-win_amd64.whl", hash = "sha256:a9bd00dc3bc395a662900f33f74feb3e757429e545d831eef5bb280252631984"}, - {file = "yarl-1.9.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:63b20738b5aac74e239622d2fe30df4fca4942a86e31bf47a81a0e94c14df94f"}, - {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7d7f7de27b8944f1fee2c26a88b4dabc2409d2fea7a9ed3df79b67277644e17"}, - {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c74018551e31269d56fab81a728f683667e7c28c04e807ba08f8c9e3bba32f14"}, - {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ca06675212f94e7a610e85ca36948bb8fc023e458dd6c63ef71abfd482481aa5"}, - {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5aef935237d60a51a62b86249839b51345f47564208c6ee615ed2a40878dccdd"}, - {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2b134fd795e2322b7684155b7855cc99409d10b2e408056db2b93b51a52accc7"}, - {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d25039a474c4c72a5ad4b52495056f843a7ff07b632c1b92ea9043a3d9950f6e"}, - {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:f7d6b36dd2e029b6bcb8a13cf19664c7b8e19ab3a58e0fefbb5b8461447ed5ec"}, - {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:957b4774373cf6f709359e5c8c4a0af9f6d7875db657adb0feaf8d6cb3c3964c"}, - {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:d7eeb6d22331e2fd42fce928a81c697c9ee2d51400bd1a28803965883e13cead"}, - {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:6a962e04b8f91f8c4e5917e518d17958e3bdee71fd1d8b88cdce74dd0ebbf434"}, - {file = "yarl-1.9.4-cp37-cp37m-win32.whl", hash = "sha256:f3bc6af6e2b8f92eced34ef6a96ffb248e863af20ef4fde9448cc8c9b858b749"}, - {file = "yarl-1.9.4-cp37-cp37m-win_amd64.whl", hash = "sha256:ad4d7a90a92e528aadf4965d685c17dacff3df282db1121136c382dc0b6014d2"}, - {file = "yarl-1.9.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ec61d826d80fc293ed46c9dd26995921e3a82146feacd952ef0757236fc137be"}, - {file = "yarl-1.9.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8be9e837ea9113676e5754b43b940b50cce76d9ed7d2461df1af39a8ee674d9f"}, - {file = "yarl-1.9.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:bef596fdaa8f26e3d66af846bbe77057237cb6e8efff8cd7cc8dff9a62278bbf"}, - {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d47552b6e52c3319fede1b60b3de120fe83bde9b7bddad11a69fb0af7db32f1"}, - {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84fc30f71689d7fc9168b92788abc977dc8cefa806909565fc2951d02f6b7d57"}, - {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4aa9741085f635934f3a2583e16fcf62ba835719a8b2b28fb2917bb0537c1dfa"}, - {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:206a55215e6d05dbc6c98ce598a59e6fbd0c493e2de4ea6cc2f4934d5a18d130"}, - {file = "yarl-1.9.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07574b007ee20e5c375a8fe4a0789fad26db905f9813be0f9fef5a68080de559"}, - {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5a2e2433eb9344a163aced6a5f6c9222c0786e5a9e9cac2c89f0b28433f56e23"}, - {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:6ad6d10ed9b67a382b45f29ea028f92d25bc0bc1daf6c5b801b90b5aa70fb9ec"}, - {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:6fe79f998a4052d79e1c30eeb7d6c1c1056ad33300f682465e1b4e9b5a188b78"}, - {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:a825ec844298c791fd28ed14ed1bffc56a98d15b8c58a20e0e08c1f5f2bea1be"}, - {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8619d6915b3b0b34420cf9b2bb6d81ef59d984cb0fde7544e9ece32b4b3043c3"}, - {file = "yarl-1.9.4-cp38-cp38-win32.whl", hash = "sha256:686a0c2f85f83463272ddffd4deb5e591c98aac1897d65e92319f729c320eece"}, - {file = "yarl-1.9.4-cp38-cp38-win_amd64.whl", hash = "sha256:a00862fb23195b6b8322f7d781b0dc1d82cb3bcac346d1e38689370cc1cc398b"}, - {file = "yarl-1.9.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:604f31d97fa493083ea21bd9b92c419012531c4e17ea6da0f65cacdcf5d0bd27"}, - {file = "yarl-1.9.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8a854227cf581330ffa2c4824d96e52ee621dd571078a252c25e3a3b3d94a1b1"}, - {file = "yarl-1.9.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ba6f52cbc7809cd8d74604cce9c14868306ae4aa0282016b641c661f981a6e91"}, - {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a6327976c7c2f4ee6816eff196e25385ccc02cb81427952414a64811037bbc8b"}, - {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8397a3817d7dcdd14bb266283cd1d6fc7264a48c186b986f32e86d86d35fbac5"}, - {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e0381b4ce23ff92f8170080c97678040fc5b08da85e9e292292aba67fdac6c34"}, - {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:23d32a2594cb5d565d358a92e151315d1b2268bc10f4610d098f96b147370136"}, - {file = "yarl-1.9.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ddb2a5c08a4eaaba605340fdee8fc08e406c56617566d9643ad8bf6852778fc7"}, - {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:26a1dc6285e03f3cc9e839a2da83bcbf31dcb0d004c72d0730e755b33466c30e"}, - {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:18580f672e44ce1238b82f7fb87d727c4a131f3a9d33a5e0e82b793362bf18b4"}, - {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:29e0f83f37610f173eb7e7b5562dd71467993495e568e708d99e9d1944f561ec"}, - {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:1f23e4fe1e8794f74b6027d7cf19dc25f8b63af1483d91d595d4a07eca1fb26c"}, - {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:db8e58b9d79200c76956cefd14d5c90af54416ff5353c5bfd7cbe58818e26ef0"}, - {file = "yarl-1.9.4-cp39-cp39-win32.whl", hash = "sha256:c7224cab95645c7ab53791022ae77a4509472613e839dab722a72abe5a684575"}, - {file = "yarl-1.9.4-cp39-cp39-win_amd64.whl", hash = "sha256:824d6c50492add5da9374875ce72db7a0733b29c2394890aef23d533106e2b15"}, - {file = "yarl-1.9.4-py3-none-any.whl", hash = "sha256:928cecb0ef9d5a7946eb6ff58417ad2fe9375762382f1bf5c55e61645f2c43ad"}, - {file = "yarl-1.9.4.tar.gz", hash = "sha256:566db86717cf8080b99b58b083b773a908ae40f06681e87e589a976faf8246bf"}, + {file = "yarl-1.17.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2d8715edfe12eee6f27f32a3655f38d6c7410deb482158c0b7d4b7fad5d07628"}, + {file = "yarl-1.17.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1803bf2a7a782e02db746d8bd18f2384801bc1d108723840b25e065b116ad726"}, + {file = "yarl-1.17.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e66589110e20c2951221a938fa200c7aa134a8bdf4e4dc97e6b21539ff026d4"}, + {file = "yarl-1.17.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7069d411cfccf868e812497e0ec4acb7c7bf8d684e93caa6c872f1e6f5d1664d"}, + {file = "yarl-1.17.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cbf70ba16118db3e4b0da69dcde9d4d4095d383c32a15530564c283fa38a7c52"}, + {file = "yarl-1.17.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0bc53cc349675b32ead83339a8de79eaf13b88f2669c09d4962322bb0f064cbc"}, + {file = "yarl-1.17.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d6aa18a402d1c80193ce97c8729871f17fd3e822037fbd7d9b719864018df746"}, + {file = "yarl-1.17.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d89c5bc701861cfab357aa0cd039bc905fe919997b8c312b4b0c358619c38d4d"}, + {file = "yarl-1.17.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b728bdf38ca58f2da1d583e4af4ba7d4cd1a58b31a363a3137a8159395e7ecc7"}, + {file = "yarl-1.17.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:5542e57dc15d5473da5a39fbde14684b0cc4301412ee53cbab677925e8497c11"}, + {file = "yarl-1.17.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e564b57e5009fb150cb513804d7e9e9912fee2e48835638f4f47977f88b4a39c"}, + {file = "yarl-1.17.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:eb3c4cff524b4c1c1dba3a6da905edb1dfd2baf6f55f18a58914bbb2d26b59e1"}, + {file = "yarl-1.17.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:05e13f389038842da930d439fbed63bdce3f7644902714cb68cf527c971af804"}, + {file = "yarl-1.17.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:153c38ee2b4abba136385af4467459c62d50f2a3f4bde38c7b99d43a20c143ef"}, + {file = "yarl-1.17.0-cp310-cp310-win32.whl", hash = "sha256:4065b4259d1ae6f70fd9708ffd61e1c9c27516f5b4fae273c41028afcbe3a094"}, + {file = "yarl-1.17.0-cp310-cp310-win_amd64.whl", hash = "sha256:abf366391a02a8335c5c26163b5fe6f514cc1d79e74d8bf3ffab13572282368e"}, + {file = "yarl-1.17.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:19a4fe0279626c6295c5b0c8c2bb7228319d2e985883621a6e87b344062d8135"}, + {file = "yarl-1.17.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cadd0113f4db3c6b56868d6a19ca6286f5ccfa7bc08c27982cf92e5ed31b489a"}, + {file = "yarl-1.17.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:60d6693eef43215b1ccfb1df3f6eae8db30a9ff1e7989fb6b2a6f0b468930ee8"}, + {file = "yarl-1.17.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5bb8bf3843e1fa8cf3fe77813c512818e57368afab7ebe9ef02446fe1a10b492"}, + {file = "yarl-1.17.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d2a5b35fd1d8d90443e061d0c8669ac7600eec5c14c4a51f619e9e105b136715"}, + {file = "yarl-1.17.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c5bf17b32f392df20ab5c3a69d37b26d10efaa018b4f4e5643c7520d8eee7ac7"}, + {file = "yarl-1.17.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:48f51b529b958cd06e78158ff297a8bf57b4021243c179ee03695b5dbf9cb6e1"}, + {file = "yarl-1.17.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5fcaa06bf788e19f913d315d9c99a69e196a40277dc2c23741a1d08c93f4d430"}, + {file = "yarl-1.17.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:32f3ee19ff0f18a7a522d44e869e1ebc8218ad3ae4ebb7020445f59b4bbe5897"}, + {file = "yarl-1.17.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:a4fb69a81ae2ec2b609574ae35420cf5647d227e4d0475c16aa861dd24e840b0"}, + {file = "yarl-1.17.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:7bacc8b77670322132a1b2522c50a1f62991e2f95591977455fd9a398b4e678d"}, + {file = "yarl-1.17.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:437bf6eb47a2d20baaf7f6739895cb049e56896a5ffdea61a4b25da781966e8b"}, + {file = "yarl-1.17.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:30534a03c87484092080e3b6e789140bd277e40f453358900ad1f0f2e61fc8ec"}, + {file = "yarl-1.17.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b30df4ff98703649915144be6f0df3b16fd4870ac38a09c56d5d9e54ff2d5f96"}, + {file = "yarl-1.17.0-cp311-cp311-win32.whl", hash = "sha256:263b487246858e874ab53e148e2a9a0de8465341b607678106829a81d81418c6"}, + {file = "yarl-1.17.0-cp311-cp311-win_amd64.whl", hash = "sha256:07055a9e8b647a362e7d4810fe99d8f98421575e7d2eede32e008c89a65a17bd"}, + {file = "yarl-1.17.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:84095ab25ba69a8fa3fb4936e14df631b8a71193fe18bd38be7ecbe34d0f5512"}, + {file = "yarl-1.17.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:02608fb3f6df87039212fc746017455ccc2a5fc96555ee247c45d1e9f21f1d7b"}, + {file = "yarl-1.17.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:13468d291fe8c12162b7cf2cdb406fe85881c53c9e03053ecb8c5d3523822cd9"}, + {file = "yarl-1.17.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8da3f8f368fb7e2f052fded06d5672260c50b5472c956a5f1bd7bf474ae504ab"}, + {file = "yarl-1.17.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ec0507ab6523980bed050137007c76883d941b519aca0e26d4c1ec1f297dd646"}, + {file = "yarl-1.17.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08fc76df7fd8360e9ff30e6ccc3ee85b8dbd6ed5d3a295e6ec62bcae7601b932"}, + {file = "yarl-1.17.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d522f390686acb6bab2b917dd9ca06740c5080cd2eaa5aef8827b97e967319d"}, + {file = "yarl-1.17.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:147c527a80bb45b3dcd6e63401af8ac574125d8d120e6afe9901049286ff64ef"}, + {file = "yarl-1.17.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:24cf43bcd17a0a1f72284e47774f9c60e0bf0d2484d5851f4ddf24ded49f33c6"}, + {file = "yarl-1.17.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:c28a44b9e0fba49c3857360e7ad1473fc18bc7f6659ca08ed4f4f2b9a52c75fa"}, + {file = "yarl-1.17.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:350cacb2d589bc07d230eb995d88fcc646caad50a71ed2d86df533a465a4e6e1"}, + {file = "yarl-1.17.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:fd1ab1373274dea1c6448aee420d7b38af163b5c4732057cd7ee9f5454efc8b1"}, + {file = "yarl-1.17.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:4934e0f96dadc567edc76d9c08181633c89c908ab5a3b8f698560124167d9488"}, + {file = "yarl-1.17.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8d0a278170d75c88e435a1ce76557af6758bfebc338435b2eba959df2552163e"}, + {file = "yarl-1.17.0-cp312-cp312-win32.whl", hash = "sha256:61584f33196575a08785bb56db6b453682c88f009cd9c6f338a10f6737ce419f"}, + {file = "yarl-1.17.0-cp312-cp312-win_amd64.whl", hash = "sha256:9987a439ad33a7712bd5bbd073f09ad10d38640425fa498ecc99d8aa064f8fc4"}, + {file = "yarl-1.17.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8deda7b8eb15a52db94c2014acdc7bdd14cb59ec4b82ac65d2ad16dc234a109e"}, + {file = "yarl-1.17.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:56294218b348dcbd3d7fce0ffd79dd0b6c356cb2a813a1181af730b7c40de9e7"}, + {file = "yarl-1.17.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1fab91292f51c884b290ebec0b309a64a5318860ccda0c4940e740425a67b6b7"}, + {file = "yarl-1.17.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5cf93fa61ff4d9c7d40482ce1a2c9916ca435e34a1b8451e17f295781ccc034f"}, + {file = "yarl-1.17.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:261be774a0d71908c8830c33bacc89eef15c198433a8cc73767c10eeeb35a7d0"}, + {file = "yarl-1.17.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:deec9693b67f6af856a733b8a3e465553ef09e5e8ead792f52c25b699b8f9e6e"}, + {file = "yarl-1.17.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c804b07622ba50a765ca7fb8145512836ab65956de01307541def869e4a456c9"}, + {file = "yarl-1.17.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d013a7c9574e98c14831a8f22d27277688ec3b2741d0188ac01a910b009987a"}, + {file = "yarl-1.17.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e2cfcba719bd494c7413dcf0caafb51772dec168c7c946e094f710d6aa70494e"}, + {file = "yarl-1.17.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:c068aba9fc5b94dfae8ea1cedcbf3041cd4c64644021362ffb750f79837e881f"}, + {file = "yarl-1.17.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:3616df510ffac0df3c9fa851a40b76087c6c89cbcea2de33a835fc80f9faac24"}, + {file = "yarl-1.17.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:755d6176b442fba9928a4df787591a6a3d62d4969f05c406cad83d296c5d4e05"}, + {file = "yarl-1.17.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:c18f6e708d1cf9ff5b1af026e697ac73bea9cb70ee26a2b045b112548579bed2"}, + {file = "yarl-1.17.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5b937c216b6dee8b858c6afea958de03c5ff28406257d22b55c24962a2baf6fd"}, + {file = "yarl-1.17.0-cp313-cp313-win32.whl", hash = "sha256:d0131b14cb545c1a7bd98f4565a3e9bdf25a1bd65c83fc156ee5d8a8499ec4a3"}, + {file = "yarl-1.17.0-cp313-cp313-win_amd64.whl", hash = "sha256:01c96efa4313c01329e88b7e9e9e1b2fc671580270ddefdd41129fa8d0db7696"}, + {file = "yarl-1.17.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:0d44f67e193f0a7acdf552ecb4d1956a3a276c68e7952471add9f93093d1c30d"}, + {file = "yarl-1.17.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:16ea0aa5f890cdcb7ae700dffa0397ed6c280840f637cd07bffcbe4b8d68b985"}, + {file = "yarl-1.17.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:cf5469dc7dcfa65edf5cc3a6add9f84c5529c6b556729b098e81a09a92e60e51"}, + {file = "yarl-1.17.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e662bf2f6e90b73cf2095f844e2bc1fda39826472a2aa1959258c3f2a8500a2f"}, + {file = "yarl-1.17.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8260e88f1446904ba20b558fa8ce5d0ab9102747238e82343e46d056d7304d7e"}, + {file = "yarl-1.17.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5dc16477a4a2c71e64c5d3d15d7ae3d3a6bb1e8b955288a9f73c60d2a391282f"}, + {file = "yarl-1.17.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46027e326cecd55e5950184ec9d86c803f4f6fe4ba6af9944a0e537d643cdbe0"}, + {file = "yarl-1.17.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fc95e46c92a2b6f22e70afe07e34dbc03a4acd07d820204a6938798b16f4014f"}, + {file = "yarl-1.17.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:16ca76c7ac9515320cd09d6cc083d8d13d1803f6ebe212b06ea2505fd66ecff8"}, + {file = "yarl-1.17.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:eb1a5b97388f2613f9305d78a3473cdf8d80c7034e554d8199d96dcf80c62ac4"}, + {file = "yarl-1.17.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:41fd5498975418cdc34944060b8fbeec0d48b2741068077222564bea68daf5a6"}, + {file = "yarl-1.17.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:146ca582ed04a5664ad04b0e0603934281eaab5c0115a5a46cce0b3c061a56a1"}, + {file = "yarl-1.17.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:6abb8c06107dbec97481b2392dafc41aac091a5d162edf6ed7d624fe7da0587a"}, + {file = "yarl-1.17.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:4d14be4613dd4f96c25feb4bd8c0d8ce0f529ab0ae555a17df5789e69d8ec0c5"}, + {file = "yarl-1.17.0-cp39-cp39-win32.whl", hash = "sha256:174d6a6cad1068f7850702aad0c7b1bca03bcac199ca6026f84531335dfc2646"}, + {file = "yarl-1.17.0-cp39-cp39-win_amd64.whl", hash = "sha256:6af417ca2c7349b101d3fd557ad96b4cd439fdb6ab0d288e3f64a068eea394d0"}, + {file = "yarl-1.17.0-py3-none-any.whl", hash = "sha256:62dd42bb0e49423f4dd58836a04fcf09c80237836796025211bbe913f1524993"}, + {file = "yarl-1.17.0.tar.gz", hash = "sha256:d3f13583f378930377e02002b4085a3d025b00402d5a80911726d43a67911cd9"}, ] [package.dependencies] idna = ">=2.0" multidict = ">=4.0" +propcache = ">=0.2.0" [metadata] lock-version = "2.0" python-versions = "^3.10, <3.11" -content-hash = "9caf73143d9e3b6d71389d7fce3b554c619492bff8567de39847129ed7309af2" +content-hash = "c22ab3de1b76f7549448f4204d52fe0a2d9e68cbbd4d4e873fad667a075dffe3" diff --git a/pyproject.toml b/pyproject.toml index 4985c6709..54b5a20ca 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -34,6 +34,8 @@ scikit-learn = "^1.3.2" pandas = { extras = ["gcp", "parquet"], version = "^2.2.2" } skops = ">=0.9,<0.11" google-cloud-secret-manager = "^2.20.0" +shap = "^0.46.0" +matplotlib = "3.7.3" [tool.poetry.dev-dependencies] pre-commit = "^4.0.0" diff --git a/src/gentropy/method/l2g/model.py b/src/gentropy/method/l2g/model.py index 45d90f90d..e35e255a2 100644 --- a/src/gentropy/method/l2g/model.py +++ b/src/gentropy/method/l2g/model.py @@ -2,10 +2,12 @@ from __future__ import annotations +import json from dataclasses import dataclass, field from pathlib import Path from typing import TYPE_CHECKING, Any, Type +import pandas as pd import skops.io as sio from pandas import DataFrame as pd_dataframe from pandas import to_numeric as pd_to_numeric @@ -148,6 +150,23 @@ def save(self: LocusToGeneModel, path: str) -> None: else: sio.dump(self.model, path) + @staticmethod + def load_feature_matrix_from_wandb(wandb_run_name: str) -> pd.DataFrame: + """Loads dataset of feature matrix used during a wandb run. + + Args: + wandb_run_name (str): Name of the wandb run to load the feature matrix from + + Returns: + pd.DataFrame: Feature matrix used during the wandb run + """ + with open(wandb_run_name) as f: + raw_data = json.load(f) + + data = raw_data["data"] + columns = raw_data["columns"] + return pd.DataFrame(data, columns=columns) + def _create_hugging_face_model_card( self: LocusToGeneModel, local_repo: str, diff --git a/src/gentropy/method/l2g/trainer.py b/src/gentropy/method/l2g/trainer.py index 1c4088462..fe56b3f42 100644 --- a/src/gentropy/method/l2g/trainer.py +++ b/src/gentropy/method/l2g/trainer.py @@ -2,11 +2,14 @@ from __future__ import annotations +import os from dataclasses import dataclass from functools import partial -from typing import Any +from typing import TYPE_CHECKING, Any +import matplotlib.pyplot as plt import pandas as pd +import shap from sklearn.metrics import ( accuracy_score, f1_score, @@ -15,7 +18,8 @@ roc_auc_score, ) from sklearn.model_selection import train_test_split -from wandb.data_types import Table +from wandb.data_types import Image, Table +from wandb.errors.term import termlog as wandb_termlog from wandb.sdk.wandb_init import init as wandb_init from wandb.sdk.wandb_sweep import sweep as wandb_sweep from wandb.sklearn import plot_classifier @@ -24,6 +28,11 @@ from gentropy.dataset.l2g_feature_matrix import L2GFeatureMatrix from gentropy.method.l2g.model import LocusToGeneModel +if TYPE_CHECKING: + from matplotlib.axes._axes import Axes + from shap._explanation import Explanation + from wandb.sdk.wandb_run import Run + @dataclass class LocusToGeneTrainer: @@ -34,13 +43,22 @@ class LocusToGeneTrainer: # Initialise vars features_list: list[str] | None = None - target_labels: list[str] | None = None + label_col: str = "goldStandardSet" x_train: pd.DataFrame | None = None y_train: pd.Series | None = None x_test: pd.DataFrame | None = None y_test: pd.Series | None = None + run: Run | None = None wandb_l2g_project_name: str = "gentropy-locus-to-gene" + def __post_init__(self) -> None: + """Set default features_list to feature_matrix's features_list if not provided.""" + self.features_list = ( + self.feature_matrix.features_list + if self.features_list is None + else self.features_list + ) + def fit( self: LocusToGeneTrainer, ) -> LocusToGeneModel: @@ -65,6 +83,54 @@ def fit( return self.model raise ValueError("Train data not set, nothing to fit.") + def _get_shap_explanation( + self: LocusToGeneTrainer, + model: LocusToGeneModel, + ) -> Explanation: + """Get the SHAP values for the given model and data. We pass the full X matrix (without the labels) to interpret their shap values. + + Args: + model (LocusToGeneModel): Model to explain. + + Returns: + Explanation: SHAP values for the given model and data. + + Raises: + ValueError: Train data not set, cannot get SHAP values. + """ + if self.x_train is not None and self.x_test is not None: + training_data = pd.concat([self.x_train, self.x_test], ignore_index=True) + explainer = shap.TreeExplainer( + model.model, + data=training_data, + feature_perturbation="interventional", + ) + return explainer(training_data) + raise ValueError("Train data not set.") + + def log_plot_image_to_wandb( + self: LocusToGeneTrainer, title: str, plot: Axes + ) -> None: + """Accepts a plot object, and saves the fig to PNG to then log it in W&B. + + Args: + title (str): Title of the plot. + plot (Axes): Shap plot to log. + + Raises: + ValueError: Run not set, cannot log to W&B. + """ + if self.run is None: + raise ValueError("Run not set, cannot log to W&B.") + if not plot: + # Scatter plot returns none, so we need to handle this case + plt.savefig("tmp.png", bbox_inches="tight") + else: + plot.figure.savefig("tmp.png", bbox_inches="tight") + self.run.log({title: Image("tmp.png")}) + plt.close() + os.remove("tmp.png") + def log_to_wandb( self: LocusToGeneTrainer, wandb_run_name: str, @@ -76,12 +142,16 @@ def log_to_wandb( Args: wandb_run_name (str): Name of the W&B run + + Raises: + ValueError: If dependencies are not available. """ if ( self.x_train is not None and self.x_test is not None and self.y_train is not None and self.y_test is not None + and self.features_list is not None ): assert ( not self.x_train.empty and not self.y_train.empty @@ -89,7 +159,7 @@ def log_to_wandb( fitted_classifier = self.model.model y_predicted = fitted_classifier.predict(self.x_test.values) y_probas = fitted_classifier.predict_proba(self.x_test.values) - run = wandb_init( + self.run = wandb_init( project=self.wandb_l2g_project_name, name=wandb_run_name, config=fitted_classifier.get_params(), @@ -109,39 +179,66 @@ def log_to_wandb( is_binary=True, ) # Track evaluation metrics - run.log( + self.run.log( { "areaUnderROC": roc_auc_score( self.y_test, y_probas[:, 1], average="weighted" ) } ) - run.log({"accuracy": accuracy_score(self.y_test, y_predicted)}) - run.log( + self.run.log({"accuracy": accuracy_score(self.y_test, y_predicted)}) + self.run.log( { "weightedPrecision": precision_score( self.y_test, y_predicted, average="weighted" ) } ) - run.log( + self.run.log( { "weightedRecall": recall_score( self.y_test, y_predicted, average="weighted" ) } ) - run.log({"f1": f1_score(self.y_test, y_predicted, average="weighted")}) + self.run.log({"f1": f1_score(self.y_test, y_predicted, average="weighted")}) # Track gold standards and their features - run.log( + self.run.log( {"featureMatrix": Table(dataframe=self.feature_matrix._df.toPandas())} ) # Log feature missingness - run.log( + self.run.log( { "missingnessRates": self.feature_matrix.calculate_feature_missingness_rate() } ) + # Plot marginal contribution of each feature + explanation = self._get_shap_explanation(self.model) + self.log_plot_image_to_wandb( + "Feature Contribution", + shap.plots.bar( + explanation, max_display=len(self.x_train.columns), show=False + ), + ) + self.log_plot_image_to_wandb( + "Beeswarm Plot", + shap.plots.beeswarm( + explanation, max_display=len(self.x_train.columns), show=False + ), + ) + # Plot correlation between feature values and their importance + for feature in self.features_list: + self.log_plot_image_to_wandb( + f"Effect of {feature} on the predictions", + shap.plots.scatter( + explanation[:, feature], + show=False, + ), + ) + wandb_termlog("Logged Shapley contributions.") + self.run.finish() + else: + raise ValueError("Something went wrong, couldn't log to W&B.") def train( self: LocusToGeneTrainer, @@ -158,20 +255,12 @@ def train( data_df = self.feature_matrix._df.drop("geneId", "studyLocusId").toPandas() # Encode labels in `goldStandardSet` to a numeric value - data_df["goldStandardSet"] = data_df["goldStandardSet"].map( - self.model.label_encoder - ) + data_df[self.label_col] = data_df[self.label_col].map(self.model.label_encoder) # Ensure all columns are numeric and split data_df = data_df.apply(pd.to_numeric) - self.feature_cols = [ - col - for col in data_df.columns - if col not in ["studyLocusId", "goldStandardSet"] - ] - label_col = "goldStandardSet" - X = data_df[self.feature_cols].copy() - y = data_df[label_col].copy() + X = data_df[self.features_list].copy() + y = data_df[self.label_col].copy() self.x_train, self.x_test, self.y_train, self.y_test = train_test_split( X, y, test_size=0.2, random_state=42 ) diff --git a/utils/install_dependencies_on_cluster.sh b/utils/install_dependencies_on_cluster.sh index b0a165c04..849dee0c3 100644 --- a/utils/install_dependencies_on_cluster.sh +++ b/utils/install_dependencies_on_cluster.sh @@ -62,7 +62,7 @@ function main() { echo "Install package..." # NOTE: ensure the gentropy is reinstalled each time without version cache # see https://pip.pypa.io/en/stable/cli/pip_install/#cmdoption-force-reinstall - run_with_retry pip install --force-reinstall ${PACKAGENAME} + run_with_retry pip install --force-reinstall --ignore-installed ${PACKAGENAME} } From 7bb74a5056c98b76344525ef96f864ef2fb22c4d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 31 Oct 2024 16:15:35 +0000 Subject: [PATCH 144/188] chore: pre-commit autoupdate (#885) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.7.0 → v0.7.1](https://github.com/astral-sh/ruff-pre-commit/compare/v0.7.0...v0.7.1) - [github.com/pre-commit/mirrors-mypy: v1.12.1 → v1.13.0](https://github.com/pre-commit/mirrors-mypy/compare/v1.12.1...v1.13.0) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 7d2d55fc2..e62a9d790 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -6,7 +6,7 @@ ci: skip: [poetry-lock] repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.7.0 + rev: v0.7.1 hooks: - id: ruff args: @@ -65,7 +65,7 @@ repos: stages: [commit-msg] - repo: https://github.com/pre-commit/mirrors-mypy - rev: "v1.12.1" + rev: "v1.13.0" hooks: - id: mypy args: From fa38ca67d75c3064691120a93a89b0c208ade818 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Irene=20L=C3=B3pez=20Santiago?= <45119610+ireneisdoomed@users.noreply.github.com> Date: Thu, 31 Oct 2024 17:56:10 +0000 Subject: [PATCH 145/188] fix(distance_features): correct mean distance equation and correct rows with negative values (#889) * fix(distance_features): hack to set to null negative values * fix(distance_features): correct mean distance equation --- src/gentropy/dataset/l2g_features/distance.py | 37 +++++++++++-------- tests/gentropy/dataset/test_l2g_feature.py | 2 +- 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/src/gentropy/dataset/l2g_features/distance.py b/src/gentropy/dataset/l2g_features/distance.py index 2149dc339..08ffc7c5e 100644 --- a/src/gentropy/dataset/l2g_features/distance.py +++ b/src/gentropy/dataset/l2g_features/distance.py @@ -42,10 +42,6 @@ def common_distance_feature_logic( distances_dataset = variant_index.get_distance_to_gene(distance_type=distance_type) if "Mean" in feature_name: # Weighting by the SNP contribution is only applied when we are averaging all distances - distance_score_expr = ( - f.lit(genomic_window) - f.col(distance_type) + f.lit(1) - ) * f.col("posteriorProbability") - agg_expr = f.mean(f.col("distance_score")) df = study_loci_to_annotate.df.withColumn( "variantInLocus", f.explode_outer("locus") ).select( @@ -53,11 +49,15 @@ def common_distance_feature_logic( f.col("variantInLocus.variantId").alias("variantId"), f.col("variantInLocus.posteriorProbability").alias("posteriorProbability"), ) + distance_score_expr = ( + f.lit(genomic_window) - f.col(distance_type) + f.lit(1) + ) * f.col("posteriorProbability") + agg_expr = f.sum(f.col("distance_score")) elif "Sentinel" in feature_name: + df = study_loci_to_annotate.df.select("studyLocusId", "variantId") # For minimum distances we calculate the unweighted distance between the sentinel (lead) and the gene. This distance_score_expr = f.lit(genomic_window) - f.col(distance_type) + f.lit(1) agg_expr = f.first(f.col("distance_score")) - df = study_loci_to_annotate.df.select("studyLocusId", "variantId") return ( df.join( distances_dataset.withColumnRenamed("targetId", "geneId"), @@ -66,10 +66,15 @@ def common_distance_feature_logic( ) .withColumn( "distance_score", - f.log10(distance_score_expr) / f.log10(f.lit(genomic_window + 1)), + distance_score_expr, ) .groupBy("studyLocusId", "geneId") - .agg(agg_expr.alias(feature_name)) + .agg(agg_expr.alias("distance_score_agg")) + .withColumn( + feature_name, + f.log10(f.col("distance_score_agg")) / f.log10(f.lit(genomic_window + 1)), + ) + .drop("distance_score_agg") ) @@ -120,7 +125,6 @@ def common_neighbourhood_distance_feature_logic( class DistanceTssMeanFeature(L2GFeature): """Average distance of all tagging variants to gene TSS.""" - fill_na_value = 500_000 feature_dependency_type = VariantIndex feature_name = "distanceTssMean" @@ -147,6 +151,11 @@ def compute( feature_name=cls.feature_name, distance_type=distance_type, **feature_dependency, + ).withColumn( + cls.feature_name, + f.when(f.col(cls.feature_name) < 0, f.lit(0.0)).otherwise( + f.col(cls.feature_name) + ), ), id_vars=("studyLocusId", "geneId"), var_name="featureName", @@ -159,7 +168,6 @@ def compute( class DistanceTssMeanNeighbourhoodFeature(L2GFeature): """Minimum mean distance to TSS for all genes in the vicinity of a studyLocus.""" - fill_na_value = 500_000 feature_dependency_type = VariantIndex feature_name = "distanceTssMeanNeighbourhood" @@ -198,7 +206,6 @@ def compute( class DistanceSentinelTssFeature(L2GFeature): """Distance of the sentinel variant to gene TSS. This is not weighted by the causal probability.""" - fill_na_value = 500_000 feature_dependency_type = VariantIndex feature_name = "distanceSentinelTss" @@ -237,7 +244,6 @@ def compute( class DistanceSentinelTssNeighbourhoodFeature(L2GFeature): """Distance between the sentinel variant and a gene TSS as a relation of the distnace with all the genes in the vicinity of a studyLocus. This is not weighted by the causal probability.""" - fill_na_value = 500_000 feature_dependency_type = VariantIndex feature_name = "distanceSentinelTssNeighbourhood" @@ -276,7 +282,6 @@ def compute( class DistanceFootprintMeanFeature(L2GFeature): """Average distance of all tagging variants to the footprint of a gene.""" - fill_na_value = 500_000 feature_dependency_type = VariantIndex feature_name = "distanceFootprintMean" @@ -303,6 +308,11 @@ def compute( feature_name=cls.feature_name, distance_type=distance_type, **feature_dependency, + ).withColumn( + cls.feature_name, + f.when(f.col(cls.feature_name) < 0, f.lit(0.0)).otherwise( + f.col(cls.feature_name) + ), ), id_vars=("studyLocusId", "geneId"), var_name="featureName", @@ -315,7 +325,6 @@ def compute( class DistanceFootprintMeanNeighbourhoodFeature(L2GFeature): """Minimum mean distance to footprint for all genes in the vicinity of a studyLocus.""" - fill_na_value = 500_000 feature_dependency_type = VariantIndex feature_name = "distanceFootprintMeanNeighbourhood" @@ -354,7 +363,6 @@ def compute( class DistanceSentinelFootprintFeature(L2GFeature): """Distance between the sentinel variant and the footprint of a gene.""" - fill_na_value = 500_000 feature_dependency_type = VariantIndex feature_name = "distanceSentinelFootprint" @@ -393,7 +401,6 @@ def compute( class DistanceSentinelFootprintNeighbourhoodFeature(L2GFeature): """Distance between the sentinel variant and a gene footprint as a relation of the distnace with all the genes in the vicinity of a studyLocus. This is not weighted by the causal probability.""" - fill_na_value = 500_000 feature_dependency_type = VariantIndex feature_name = "distanceSentinelFootprintNeighbourhood" diff --git a/tests/gentropy/dataset/test_l2g_feature.py b/tests/gentropy/dataset/test_l2g_feature.py index c6019cefc..0637b4a86 100644 --- a/tests/gentropy/dataset/test_l2g_feature.py +++ b/tests/gentropy/dataset/test_l2g_feature.py @@ -513,7 +513,7 @@ class TestCommonDistanceFeatureLogic: ( "distanceTssMean", [ - {"studyLocusId": "1", "geneId": "gene1", "distanceTssMean": 0.08}, + {"studyLocusId": "1", "geneId": "gene1", "distanceTssMean": 0.52}, {"studyLocusId": "1", "geneId": "gene2", "distanceTssMean": 0.63}, ], ), From b812f67a486ff3fc0f7b272048820227443321f1 Mon Sep 17 00:00:00 2001 From: Vivien Ho <56025826+vivienho@users.noreply.github.com> Date: Fri, 1 Nov 2024 11:08:51 +0000 Subject: [PATCH 146/188] feat: add step to generate association data (#888) * feat: add step to generate association data * fix: evidence input file is json * feat: changed maximum theoretical harmonic sum formula * test: add test for calculate_harmonic_sum function * chore: move calculate_harmonic_sum function to spark_helpers.py * chore: update import statement --- docs/python_api/steps/l2g.md | 2 + src/gentropy/common/spark_helpers.py | 35 +++++++++++++++++ src/gentropy/config.py | 14 +++++++ src/gentropy/l2g.py | 59 ++++++++++++++++++++++++++++ 4 files changed, 110 insertions(+) diff --git a/docs/python_api/steps/l2g.md b/docs/python_api/steps/l2g.md index 5594f1605..e6aeb0ebb 100644 --- a/docs/python_api/steps/l2g.md +++ b/docs/python_api/steps/l2g.md @@ -7,3 +7,5 @@ title: Locus to Gene (L2G) ::: gentropy.l2g.LocusToGeneStep ::: gentropy.l2g.LocusToGeneEvidenceStep + +::: gentropy.l2g.LocusToGeneAssociationsStep diff --git a/src/gentropy/common/spark_helpers.py b/src/gentropy/common/spark_helpers.py index 4e40ac4f1..a1bf9670a 100644 --- a/src/gentropy/common/spark_helpers.py +++ b/src/gentropy/common/spark_helpers.py @@ -847,3 +847,38 @@ def get_struct_field_schema(schema: t.StructType, name: str) -> t.DataType: if not matching_fields: raise ValueError("Provided name %s is not present in the schema.", name) return matching_fields[0].dataType + +def calculate_harmonic_sum(input_array: Column) -> Column: + """Calculate the harmonic sum of an array. + + Args: + input_array (Column): input array of doubles + + Returns: + Column: column of harmonic sums + + Examples: + >>> from pyspark.sql import Row + >>> df = spark.createDataFrame([ + ... Row([0.3, 0.8, 1.0]), + ... Row([0.7, 0.2, 0.9]), + ... ], ["input_array"] + ... ) + >>> df.select("*", calculate_harmonic_sum(f.col("input_array")).alias("harmonic_sum")).show() + +---------------+------------------+ + | input_array| harmonic_sum| + +---------------+------------------+ + |[0.3, 0.8, 1.0]|0.7502326177269538| + |[0.7, 0.2, 0.9]|0.6674366756805108| + +---------------+------------------+ + + """ + return f.aggregate( + f.arrays_zip( + f.sort_array(input_array, False).alias("score"), + f.sequence(f.lit(1), f.size(input_array)).alias("pos") + ), + f.lit(0.0), + lambda acc, x: acc + + x["score"]/f.pow(x["pos"], 2)/f.lit(sum(1 / ((i + 1)**2) for i in range(1000))) + ) diff --git a/src/gentropy/config.py b/src/gentropy/config.py index c5889dbab..e9bf26f31 100644 --- a/src/gentropy/config.py +++ b/src/gentropy/config.py @@ -632,6 +632,15 @@ class LocusToGeneEvidenceStepConfig(StepConfig): locus_to_gene_threshold: float = 0.05 _target_: str = "gentropy.l2g.LocusToGeneEvidenceStep" +@dataclass +class LocusToGeneAssociationsStepConfig(StepConfig): + """Configuration of the locus to gene association step.""" + + evidence_input_path: str = MISSING + disease_index_path: str = MISSING + direct_associations_output_path: str = MISSING + indirect_associations_output_path: str = MISSING + _target_: str = "gentropy.l2g.LocusToGeneAssociationsStep" @dataclass class StudyLocusValidationStepConfig(StepConfig): @@ -733,5 +742,10 @@ def register_config() -> None: name="locus_to_gene_evidence", node=LocusToGeneEvidenceStepConfig, ) + cs.store( + group="step", + name="locus_to_gene_associations", + node=LocusToGeneAssociationsStepConfig, + ) cs.store(group="step", name="finngen_ukb_meta_ingestion", node=FinngenUkbMetaConfig) cs.store(group="step", name="credible_set_qc", node=CredibleSetQCStepConfig) diff --git a/src/gentropy/l2g.py b/src/gentropy/l2g.py index ca52fbf04..1004fa0fb 100644 --- a/src/gentropy/l2g.py +++ b/src/gentropy/l2g.py @@ -9,6 +9,7 @@ from wandb import login as wandb_login from gentropy.common.session import Session +from gentropy.common.spark_helpers import calculate_harmonic_sum from gentropy.common.utils import access_gcp_secret from gentropy.dataset.colocalisation import Colocalisation from gentropy.dataset.gene_index import GeneIndex @@ -320,3 +321,61 @@ def __init__( .write.mode(session.write_mode) .json(evidence_output_path) ) + +class LocusToGeneAssociationsStep: + """Locus to gene associations step.""" + + def __init__( + self, + session: Session, + evidence_input_path: str, + disease_index_path: str, + direct_associations_output_path: str, + indirect_associations_output_path: str, + ) -> None: + """Create direct and indirect association datasets. + + Args: + session (Session): Session object that contains the Spark session + evidence_input_path (str): Path to the L2G evidence input dataset + disease_index_path (str): Path to disease index file + direct_associations_output_path (str): Path to the direct associations output dataset + indirect_associations_output_path (str): Path to the indirect associations output dataset + """ + # Read in the disease index + disease_index = ( + session.spark.read.parquet(disease_index_path) + .select( + f.col("id").alias("diseaseId"), + f.explode("ancestors").alias("ancestorDiseaseId") + ) + ) + + # Read in the L2G evidence + disease_target_evidence = ( + session.spark.read.json(evidence_input_path) + .select( + f.col("targetFromSourceId").alias("targetId"), + f.col("diseaseFromSourceMappedId").alias("diseaseId"), + f.col("resourceScore") + ) + ) + + # Generate direct assocations and save file + ( + disease_target_evidence + .groupBy("targetId", "diseaseId") + .agg(f.collect_set("resourceScore").alias("scores")) + .select("targetId", "diseaseId", calculate_harmonic_sum(f.col("scores")).alias("harmonicSum")) + .write.mode(session.write_mode).parquet(direct_associations_output_path) + ) + + # Generate indirect assocations and save file + ( + disease_target_evidence + .join(disease_index, on="diseaseId", how="inner") + .groupBy("targetId", "ancestorDiseaseId") + .agg(f.collect_set("resourceScore").alias("scores")) + .select("targetId", "ancestorDiseaseId", calculate_harmonic_sum(f.col("scores")).alias("harmonicSum")) + .write.mode(session.write_mode).parquet(indirect_associations_output_path) + ) From c5998569841160e665d75b306f0b52292c5d47b8 Mon Sep 17 00:00:00 2001 From: Vivien Ho <56025826+vivienho@users.noreply.github.com> Date: Fri, 1 Nov 2024 11:18:09 +0000 Subject: [PATCH 147/188] fix: revert distinct for associations input file (#871) * fix: revert distinct for associations input file * refactor: rename the temporary studyLocusId to rowId * refactor: rename the temporary studyLocusId to rowId in test * revert: add back assign_study_locus_id in window_baased_clumping as required for SummaryStatistics --------- Co-authored-by: Daniel Suveges --- .../datasource/gwas_catalog/associations.py | 32 +++++++++++-------- .../test_gwas_catalog_associations.py | 2 +- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/src/gentropy/datasource/gwas_catalog/associations.py b/src/gentropy/datasource/gwas_catalog/associations.py index da2bcc6df..31238e425 100644 --- a/src/gentropy/datasource/gwas_catalog/associations.py +++ b/src/gentropy/datasource/gwas_catalog/associations.py @@ -209,7 +209,7 @@ def _map_variants_to_gnomad_variants( """ # Subset of GWAS Catalog associations required for resolving variant IDs: gwas_associations_subset = gwas_associations.select( - "studyLocusId", + "rowId", f.col("CHR_ID").alias("chromosome"), # The positions from GWAS Catalog are from ensembl that causes discrepancy for indels: f.col("CHR_POS").cast(IntegerType()).alias("ensemblPosition"), @@ -258,7 +258,7 @@ def _map_variants_to_gnomad_variants( .withColumn( "rsIdFilter", GWASCatalogCuratedAssociationsParser._flag_mappings_to_retain( - f.col("studyLocusId"), + f.col("rowId"), GWASCatalogCuratedAssociationsParser._compare_rsids( f.col("rsIdsGnomad"), f.col("rsIdsGwasCatalog") ), @@ -267,7 +267,7 @@ def _map_variants_to_gnomad_variants( .withColumn( "concordanceFilter", GWASCatalogCuratedAssociationsParser._flag_mappings_to_retain( - f.col("studyLocusId"), + f.col("rowId"), GWASCatalogCuratedAssociationsParser._check_concordance( f.col("riskAllele"), f.col("referenceAllele"), @@ -285,11 +285,11 @@ def _map_variants_to_gnomad_variants( ) ) - # Keep only highest maxMaf variant per studyLocusId + # Keep only highest maxMaf variant per rowId fully_mapped_associations = get_record_with_maximum_value( - filtered_associations, grouping_col="studyLocusId", sorting_col="maxMaf" + filtered_associations, grouping_col="rowId", sorting_col="maxMaf" ).select( - "studyLocusId", + "rowId", "variantId", "referenceAllele", "alternateAllele", @@ -298,7 +298,7 @@ def _map_variants_to_gnomad_variants( ) return gwas_associations.join( - fully_mapped_associations, on="studyLocusId", how="left" + fully_mapped_associations, on="rowId", how="left" ) @staticmethod @@ -1106,11 +1106,9 @@ def from_source( pvalue_threshold is keeped in sync with the WindowBasedClumpingStep gwas_significance. """ return StudyLocusGWASCatalog( - _df=gwas_associations - # drop duplicate rows - .distinct() - .withColumn( - "studyLocusId", f.monotonically_increasing_id().cast(StringType()) + _df=gwas_associations.withColumn( + # temporary column + "rowId", f.monotonically_increasing_id().cast(StringType()) ) .transform( # Map/harmonise variants to variant annotation dataset: @@ -1138,6 +1136,14 @@ def from_source( ) # Harmonising effect to beta value and flip effect if needed: .transform(cls.harmonise_association_effect_to_beta) + .withColumnRenamed("STUDY ACCESSION", "studyId") + # Adding study-locus id: + .withColumn( + "studyLocusId", + StudyLocus.assign_study_locus_id( + ["studyId", "variantId"] + ), + ) .select( # INSIDE STUDY-LOCUS SCHEMA: "studyLocusId", @@ -1145,7 +1151,7 @@ def from_source( # Mapped genomic location of the variant (; separated list) "chromosome", "position", - f.col("STUDY ACCESSION").alias("studyId"), + "studyId", # p-value of the association, string: split into exponent and mantissa. *GWASCatalogCuratedAssociationsParser._parse_pvalue(f.col("P-VALUE")), # Capturing phenotype granularity at the association level diff --git a/tests/gentropy/datasource/gwas_catalog/test_gwas_catalog_associations.py b/tests/gentropy/datasource/gwas_catalog/test_gwas_catalog_associations.py index fe9608bf0..147f6c067 100644 --- a/tests/gentropy/datasource/gwas_catalog/test_gwas_catalog_associations.py +++ b/tests/gentropy/datasource/gwas_catalog/test_gwas_catalog_associations.py @@ -71,7 +71,7 @@ def test_map_variants_to_variant_index( assert isinstance( GWASCatalogCuratedAssociationsParser._map_variants_to_gnomad_variants( sample_gwas_catalog_associations.withColumn( - "studyLocusId", f.monotonically_increasing_id().cast(StringType()) + "rowId", f.monotonically_increasing_id().cast(StringType()) ), mock_variant_index, ), From 9295d5850a2b03bf7cff8df4f7cccbf11299cfc6 Mon Sep 17 00:00:00 2001 From: Tobi Alegbe Date: Fri, 1 Nov 2024 14:24:50 +0000 Subject: [PATCH 148/188] feat: add effect size direction to coloc output (#854) * feat(coloc effect sizes): add calculate beta ratio method * feat(coloc effect sizes): update schema and coloc code * fix(coloc effect sizes): tweak beta ratio return * chore: tweak colocalisation schema * feat(coloc_effect_sizes): add simple test * fix(coloc_effect_sizes): change variable to camel case * fix: test broken * feat: remove zero betas too * chore: stylistic changes --------- Co-authored-by: Daniel Suveges --- .../assets/schemas/colocalisation.json | 6 ++ src/gentropy/dataset/study_locus_overlap.py | 34 ++++++++ src/gentropy/method/colocalisation.py | 10 +++ .../method/test_colocalisation_method.py | 86 ++++++++++++++++++- 4 files changed, 133 insertions(+), 3 deletions(-) diff --git a/src/gentropy/assets/schemas/colocalisation.json b/src/gentropy/assets/schemas/colocalisation.json index 0bfb66816..a065dc947 100644 --- a/src/gentropy/assets/schemas/colocalisation.json +++ b/src/gentropy/assets/schemas/colocalisation.json @@ -72,6 +72,12 @@ "type": "double", "nullable": true, "metadata": {} + }, + { + "name": "betaRatioSignAverage", + "type": "double", + "nullable": true, + "metadata": {} } ] } diff --git a/src/gentropy/dataset/study_locus_overlap.py b/src/gentropy/dataset/study_locus_overlap.py index a6288a5e8..d4faea4cc 100644 --- a/src/gentropy/dataset/study_locus_overlap.py +++ b/src/gentropy/dataset/study_locus_overlap.py @@ -5,10 +5,13 @@ from dataclasses import dataclass from typing import TYPE_CHECKING +import pyspark.sql.functions as f + from gentropy.common.schemas import parse_spark_schema from gentropy.dataset.dataset import Dataset if TYPE_CHECKING: + from pyspark.sql import DataFrame from pyspark.sql.types import StructType from gentropy.dataset.study_locus import StudyLocus @@ -48,6 +51,37 @@ def from_associations( """ return study_locus.find_overlaps() + + def calculate_beta_ratio(self: StudyLocusOverlap) -> DataFrame: + """Calculate the beta ratio for the overlapping signals. + + Returns: + DataFrame: A dataframe containing left and right loci IDs, chromosome + and the average sign of the beta ratio + """ + return ( + # Unpack statistics column: + self.df.select("*", "statistics.*") + .drop("statistics") + # Drop any rows where the beta is null or zero + .filter( + f.col("left_beta").isNotNull() & + f.col("right_beta").isNotNull() & + (f.col("left_beta") != 0) & + (f.col("right_beta") != 0) + ) + # Calculate the beta ratio and get the sign, then calculate the average sign across all variants in the locus + .withColumn( + "betaRatioSign", + f.signum(f.col("left_beta") / f.col("right_beta")) + ) + # Aggregate beta signs: + .groupBy("leftStudyLocusId","rightStudyLocusId","chromosome") + .agg( + f.avg("betaRatioSign").alias("betaRatioSignAverage") + ) + ) + def _convert_to_square_matrix(self: StudyLocusOverlap) -> StudyLocusOverlap: """Convert the dataset to a square matrix. diff --git a/src/gentropy/method/colocalisation.py b/src/gentropy/method/colocalisation.py index 2867e700c..c20f4909c 100644 --- a/src/gentropy/method/colocalisation.py +++ b/src/gentropy/method/colocalisation.py @@ -179,6 +179,11 @@ def colocalise( f.sum(f.col("clpp")).alias("clpp"), ) .withColumn("colocalisationMethod", f.lit(cls.METHOD_NAME)) + .join( + overlapping_signals.calculate_beta_ratio(), + on=["leftStudyLocusId", "rightStudyLocusId","chromosome"], + how="left" + ) ), _schema=Colocalisation.get_schema(), ) @@ -379,6 +384,11 @@ def colocalise( "lH4bf", ) .withColumn("colocalisationMethod", f.lit(cls.METHOD_NAME)) + .join( + overlapping_signals.calculate_beta_ratio(), + on=["leftStudyLocusId", "rightStudyLocusId","chromosome"], + how="left" + ) ), _schema=Colocalisation.get_schema(), ) diff --git a/tests/gentropy/method/test_colocalisation_method.py b/tests/gentropy/method/test_colocalisation_method.py index d44652fbb..5b05d724b 100644 --- a/tests/gentropy/method/test_colocalisation_method.py +++ b/tests/gentropy/method/test_colocalisation_method.py @@ -38,7 +38,12 @@ def test_coloc(mock_study_locus_overlap: StudyLocusOverlap) -> None: "rightStudyType": "eqtl", "chromosome": "1", "tagVariantId": "snp", - "statistics": {"left_logBF": 10.3, "right_logBF": 10.5}, + "statistics": { + "left_logBF": 10.3, + "right_logBF": 10.5, + "left_beta": 0.1, + "right_beta": 0.2, + }, }, ], # expected coloc @@ -62,7 +67,12 @@ def test_coloc(mock_study_locus_overlap: StudyLocusOverlap) -> None: "rightStudyType": "eqtl", "chromosome": "1", "tagVariantId": "snp1", - "statistics": {"left_logBF": 10.3, "right_logBF": 10.5}, + "statistics": { + "left_logBF": 10.3, + "right_logBF": 10.5, + "left_beta": 0.1, + "right_beta": 0.2, + }, }, { "leftStudyLocusId": "1", @@ -70,7 +80,12 @@ def test_coloc(mock_study_locus_overlap: StudyLocusOverlap) -> None: "rightStudyType": "eqtl", "chromosome": "1", "tagVariantId": "snp2", - "statistics": {"left_logBF": 10.3, "right_logBF": 10.5}, + "statistics": { + "left_logBF": 10.3, + "right_logBF": 10.5, + "left_beta": 0.3, + "right_beta": 0.5, + }, }, ], # expected coloc @@ -134,6 +149,8 @@ def test_coloc_no_logbf( "statistics": { "left_logBF": None, "right_logBF": None, + "left_beta": 0.1, + "right_beta": 0.2, "left_posteriorProbability": None, "right_posteriorProbability": None, }, # irrelevant for COLOC @@ -152,6 +169,8 @@ def test_coloc_no_logbf( [ StructField("left_logBF", DoubleType(), True), StructField("right_logBF", DoubleType(), True), + StructField("left_beta", DoubleType(), False), + StructField("right_beta", DoubleType(), False), StructField( "left_posteriorProbability", DoubleType(), True ), @@ -176,6 +195,67 @@ def test_coloc_no_logbf( ), "COLOC should return a low h4 (traits are associated) when the input data has irrelevant logBF." +def test_coloc_no_betas(spark: SparkSession) -> None: + """Test COLOC output when the input data has no betas.""" + observed_overlap = StudyLocusOverlap( + ( + spark.createDataFrame( + [ + { + "leftStudyLocusId": "1", + "rightStudyLocusId": "2", + "rightStudyType": "eqtl", + "chromosome": "1", + "tagVariantId": "snp", + "statistics": { + "left_logBF": 10.5, + "right_logBF": 10.3, + "left_beta": None, + "right_beta": None, + "left_posteriorProbability": None, + "right_posteriorProbability": None, + }, # irrelevant for COLOC + } + ], + schema=StructType( + [ + StructField("leftStudyLocusId", StringType(), False), + StructField("rightStudyLocusId", StringType(), False), + StructField("rightStudyType", StringType(), False), + StructField("chromosome", StringType(), False), + StructField("tagVariantId", StringType(), False), + StructField( + "statistics", + StructType( + [ + StructField("left_logBF", DoubleType(), False), + StructField("right_logBF", DoubleType(), False), + StructField("left_beta", DoubleType(), True), + StructField("right_beta", DoubleType(), True), + StructField( + "left_posteriorProbability", DoubleType(), True + ), + StructField( + "right_posteriorProbability", DoubleType(), True + ), + ] + ), + ), + ] + ), + ) + ), + StudyLocusOverlap.get_schema(), + ) + observed_coloc_df = Coloc.colocalise(observed_overlap).df + assert ( + observed_coloc_df.select("betaRatioSignAverage").collect()[0][ + "betaRatioSignAverage" + ] + is None + ), "No betas results in None type." + + def test_ecaviar(mock_study_locus_overlap: StudyLocusOverlap) -> None: """Test eCAVIAR.""" assert isinstance(ECaviar.colocalise(mock_study_locus_overlap), Colocalisation) From 9237d73edfcc108665f44284a733f154983c303e Mon Sep 17 00:00:00 2001 From: Szymon Szyszkowski <69353402+project-defiant@users.noreply.github.com> Date: Mon, 4 Nov 2024 14:44:02 +0000 Subject: [PATCH 149/188] refactor(convert to vcf): allow multiple input sources (#891) * refactor(convert to vcf step): parse variants from multiple data sources * chore(config): align config * fix: pass write mode from session * feat: allow for 2 columns to create partitions --------- Co-authored-by: Szymon Szyszkowski --- src/gentropy/config.py | 7 +- src/gentropy/variant_index.py | 55 +++++-- .../credible-sets-extended/._SUCCESS.crc | Bin 0 -> 8 bytes ...-b24d-7ed798f8860f-c000.snappy.parquet.crc | Bin 0 -> 560 bytes .../credible-sets-extended/_SUCCESS | 0 ...4437-b24d-7ed798f8860f-c000.snappy.parquet | Bin 0 -> 70519 bytes .../credible-sets/._SUCCESS.crc | Bin 0 -> 8 bytes ...-911e-4d61475173d0-c000.snappy.parquet.crc | Bin 0 -> 168 bytes .../variant_sources/credible-sets/_SUCCESS | 0 ...4bf4-911e-4d61475173d0-c000.snappy.parquet | Bin 0 -> 20452 bytes .../variant_sources/eva-test.jsonl | 50 ++++++ .../pharmacogenomics-test.jsonl | 46 ++++++ .../variant_sources/uniprot-test-sort.jsonl | 9 + .../variant_sources/uniprot-test.jsonl | 50 ++++++ .../gentropy/step/test_convert_to_vcf_step.py | 154 ++++++++++++++++++ 15 files changed, 358 insertions(+), 13 deletions(-) create mode 100644 tests/gentropy/data_samples/variant_sources/credible-sets-extended/._SUCCESS.crc create mode 100644 tests/gentropy/data_samples/variant_sources/credible-sets-extended/.part-00000-aed9d229-0baa-4437-b24d-7ed798f8860f-c000.snappy.parquet.crc create mode 100644 tests/gentropy/data_samples/variant_sources/credible-sets-extended/_SUCCESS create mode 100644 tests/gentropy/data_samples/variant_sources/credible-sets-extended/part-00000-aed9d229-0baa-4437-b24d-7ed798f8860f-c000.snappy.parquet create mode 100644 tests/gentropy/data_samples/variant_sources/credible-sets/._SUCCESS.crc create mode 100644 tests/gentropy/data_samples/variant_sources/credible-sets/.part-00000-a9a641da-3820-4bf4-911e-4d61475173d0-c000.snappy.parquet.crc create mode 100644 tests/gentropy/data_samples/variant_sources/credible-sets/_SUCCESS create mode 100644 tests/gentropy/data_samples/variant_sources/credible-sets/part-00000-a9a641da-3820-4bf4-911e-4d61475173d0-c000.snappy.parquet create mode 100644 tests/gentropy/data_samples/variant_sources/eva-test.jsonl create mode 100644 tests/gentropy/data_samples/variant_sources/pharmacogenomics-test.jsonl create mode 100644 tests/gentropy/data_samples/variant_sources/uniprot-test-sort.jsonl create mode 100644 tests/gentropy/data_samples/variant_sources/uniprot-test.jsonl create mode 100644 tests/gentropy/step/test_convert_to_vcf_step.py diff --git a/src/gentropy/config.py b/src/gentropy/config.py index e9bf26f31..82ead9ed0 100644 --- a/src/gentropy/config.py +++ b/src/gentropy/config.py @@ -506,9 +506,10 @@ class _ConsequenceToPathogenicityScoreMap(TypedDict): class ConvertToVcfStepConfig(StepConfig): """Variant to VCF step configuration.""" - source_path: str = MISSING - source_format: str = MISSING - vcf_path: str = MISSING + source_paths: list[str] = MISSING + source_formats: list[str] = MISSING + output_path: str = MISSING + partition_size: int = 2000 _target_: str = "gentropy.variant_index.ConvertToVcfStep" diff --git a/src/gentropy/variant_index.py b/src/gentropy/variant_index.py index b50b470b2..4843553e8 100644 --- a/src/gentropy/variant_index.py +++ b/src/gentropy/variant_index.py @@ -2,6 +2,11 @@ from __future__ import annotations +import math +from functools import reduce + +from pyspark.sql import functions as f + from gentropy.common.session import Session from gentropy.dataset.variant_index import VariantIndex from gentropy.datasource.ensembl.vep_parser import VariantEffectPredictorParser @@ -29,7 +34,7 @@ def __init__( session (Session): Session object. vep_output_json_path (str): Variant effect predictor output path (in json format). variant_index_path (str): Variant index dataset path to save resulting data. - hash_threshold (int): Hash threshold for variant identifier lenght. + hash_threshold (int): Hash threshold for variant identifier length. gnomad_variant_annotations_path (str | None): Path to extra variant annotation dataset. """ # Extract variant annotations from VEP output: @@ -64,21 +69,51 @@ class ConvertToVcfStep: def __init__( self, session: Session, - source_path: str, - source_format: str, - vcf_path: str, + source_paths: list[str], + source_formats: list[str], + output_path: str, + partition_size: int, ) -> None: """Initialize step. Args: session (Session): Session object. - source_path (str): Input dataset path. - source_format(str): Format of the input dataset. - vcf_path (str): Output VCF file path. + source_paths (list[str]): Input dataset path. + source_formats (list[str]): Format of the input dataset. + output_path (str): Output VCF file path. + partition_size (int): Approximate number of variants in each output partition. """ + assert len(source_formats) == len( + source_paths + ), "Must provide format for each source path." + # Load - df = session.load_data(source_path, source_format) + raw_variants = [ + session.load_data(p, f) + for p, f in zip(source_paths, source_formats, strict=True) + ] + # Extract - vcf_df = OpenTargetsVariant.as_vcf_df(session, df) + processed_variants = [ + OpenTargetsVariant.as_vcf_df(session, df) for df in raw_variants + ] + + # Merge + merged_variants = reduce( + lambda x, y: x.unionByName(y), processed_variants + ).drop_duplicates(["#CHROM", "POS", "REF", "ALT"]) + + variant_count = merged_variants.count() + n_partitions = int(math.ceil(variant_count / partition_size)) + partitioned_variants = ( + merged_variants.repartitionByRange( + n_partitions, f.col("#CHROM"), f.col("POS") + ) + .sortWithinPartitions(f.col("#CHROM").asc(), f.col("POS").asc()) + # Due to the large number of partitions ensure we do not lose the partitions before saving them + .persist() + ) # Write - vcf_df.write.csv(vcf_path, sep="\t", header=True) + partitioned_variants.write.mode(session.write_mode).csv( + output_path, sep="\t", header=True + ) diff --git a/tests/gentropy/data_samples/variant_sources/credible-sets-extended/._SUCCESS.crc b/tests/gentropy/data_samples/variant_sources/credible-sets-extended/._SUCCESS.crc new file mode 100644 index 0000000000000000000000000000000000000000..3b7b044936a890cd8d651d349a752d819d71d22c GIT binary patch literal 8 PcmYc;N@ieSU}69O2$TUk literal 0 HcmV?d00001 diff --git a/tests/gentropy/data_samples/variant_sources/credible-sets-extended/.part-00000-aed9d229-0baa-4437-b24d-7ed798f8860f-c000.snappy.parquet.crc b/tests/gentropy/data_samples/variant_sources/credible-sets-extended/.part-00000-aed9d229-0baa-4437-b24d-7ed798f8860f-c000.snappy.parquet.crc new file mode 100644 index 0000000000000000000000000000000000000000..751da3705151000702b9f8929e42b4337b71aab6 GIT binary patch literal 560 zcmV-00?++pa$^7h00ICSBDeX|e{(}5>O(Iet8q<=i7_e?%kVRy&?NRlQ&)+c1&*+b zny7}BQy_sjYu;!$l$-B);j8O3t%_8P!S|{WK!7Tr?H!mDH~PI)vVd}TP2E{q7U+8} zcK0|^-fNc(r6Y^^397G}4Yx5HgZUZfQtI_)Jj0v~j+#%Y4%`l^AF%B5zSV;5!PBY7 zCDbeFFrRVN$!oBn)I)b zojdO(!8O5%$9)eQ2b!Wt z%NI{EzaM(YcLW}q&nwJ2TiMOBk&cC2Vif91!OoLU63!1TF9;D}$ZT6>4b#5n&!6)B z0E>Bw)3p%6gT?M4^rtGJrSL@r{1I(ESkBLyCJ9GFVhU1io18sH9w!B8CU)J*X*56A ydX?$A7|q7Kw5TXZ3;g=3_)g}9Tu)F&juRCv^!w##CcH{05GV`I7{MNavb8TQ>kJbB literal 0 HcmV?d00001 diff --git a/tests/gentropy/data_samples/variant_sources/credible-sets-extended/_SUCCESS b/tests/gentropy/data_samples/variant_sources/credible-sets-extended/_SUCCESS new file mode 100644 index 000000000..e69de29bb diff --git a/tests/gentropy/data_samples/variant_sources/credible-sets-extended/part-00000-aed9d229-0baa-4437-b24d-7ed798f8860f-c000.snappy.parquet b/tests/gentropy/data_samples/variant_sources/credible-sets-extended/part-00000-aed9d229-0baa-4437-b24d-7ed798f8860f-c000.snappy.parquet new file mode 100644 index 0000000000000000000000000000000000000000..634dbbaacb582279e61a75c216b1bcba8e85d1c6 GIT binary patch literal 70519 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͍> zCd7reQClN{Z?e8Vwj~m@KODCnsEma1`K8-FJ&y$PiOt`%N+N-BahteYK_n>ebQ|Zm z9SNG{BBIhhk??T1{5akDNH}&!Mp8&Q68JkA8S<1O;q>|kk9H_TLd+JW9cwm3E{58ouT1^3;^`L0#aYgw^6-1RxAWTX=B)@Q=g z;%9bc7qVb4uVO;z$4uy5D^enul?BPB_sYKE`bXx#nd_#g-#PUoZ08SWf%U_u%PP-h zLGZ1T(tOh_Ai|{ehitOo^ZCjHx0SLW?lMat=jJRBjnL)1B!vC2t=TH!fa{}OKV}5h z(8^ocI4Yk7x}6py+N-kQt7Q^jCDPyOow*12vLHNAvFsuCM|#VTJ3K3KebV{mumn=4 zW!#+;nC^lQs-3b~Ab(oqOUlbk__`Z*Hz#C4-`ex;x9GFsk(oy_V3)!Pg*I5;~E+-GZ>D%Spd6fq=%XdC{)BSpXFewMAmd2+K#p?MWc*8{cyk#D6 z2MlrR%ICq2j%7Q4Y{-MuHT@RW2lF5&_UI*dq-B}Gl5B_b;8tbF$LXW_kb6yQZ_&9t z^pe|c&SjhrP7B7dJg~fTa&Papd@#;1m`%Q%2deq+LcSlybp=z4C;N$f@RN}`VQHEV z4a|e|f>rqtlI6UHyDuM(y*MPWttTIzajlXH^1yWx=PxA+IUg2G>PTr8*XI5CfDdCn zn-1gyXYIlMDb;+q$=ukGn}qG`aiYA`&xcbMQXh`s`sU1}RdAEqK%qnrSRw5o>B;9SaR}JSt;1ZN_;leF9m@cDY>D~OF?<;=EobmO2O@8 zU&z3oQkbyb0Rl+9q-Y;^l)@K!uLcTI&4rIVOM&)9hZ!Clrz+QLV7}L)k>_3TSXlG2 zb4y$)Fr1P(vS(W<%*CI|9d#{*$L61+%4zjcdSwQY%C24dN-44g)Y;UJwuKY}?aOb; zuwpPc_`Y8NuWt*T+u1`Yh4d2nWy{(M!Qf0*$mqRzn6y%n=)M~d9@cBtj-H8!FO!#R z_b0@|hsRQbKCua~EcU>A+0+CmyZ-X_wxk4j^qS>qNmv5Z?GDr_&qx5}sF!96R}w(x zdr+C}k_0G@e`d8OJOPaCSxiq2$3x$}+Z2j_0>m?oAF0}s0423L7uQ(h`IqaGPkAQ5 zoi&rf?;R2VZJpOwk*=;Hy%?R#_zzxO75~HG2>+cI*Lt*d{%0>PzN-v>ytbBpRb?JV zColBan)(-at^ePRo&T4`Dtsw?w)4zO;e~*O3+^slo^-4ire6DtUZLZ;F6P6v|GK!p zSjhF&Hx!z$OWY=-XA*A+9b>5B{s5_P6Es|Lh12my&@tY($)Q;`(Y(nOO~)N`?lb$^ zgzKvV*Ct;7A2N2z{NG^g{Mv-Z=s(6zn&I)E#!i|amY*crIPcPon#q)AecAlM=3NSv zk}U>G|8TrgAEAWqS*uRZtnsNebT818798Htg^y;(=GjiaT!$acrn*uz7ZaMh)ox{K z>j6U@sWu~{g9q;(JZ$PtI<#QVG(A5}LJKFlOIZXTyoXjut9wUICEUG7b3l1>l-Hh~ z(ILO>&@o5apMWF1{ep$_OeM__TBE$m)Vk7qumZ{H*`Eu*4iu;j{o)f>uZ&xVpFYGxheqB6Jb#;JLG7k$^-;gVw zU43)oD^-ag<@e_#ZmEqHO5E1`J}YrYi$hH^SV!QzWQg9nBFWI*>T{A|`}EbM?jAgP zUh3WvyCSJ@Q_nf62(v&n>HAiZ=cOZU9~MbRITp`-_$y!`EkfrTTGYbsfK#!alQpN} zF8^Y;iTCEzw@J7r5@?ecDF4bP>DE>bbluZeABp)-0SniSrc&;qx%l4(EbNbb^!VxL z_m46O2Ep{Kg)p1=C!1XEC?DvS#5k7DmQ*PaL}$7`HO1GBQfmIHoW#G7dg*JjpoDz$A|;MUMRpjGgG+EChEU;=On}eDe)U=60*!5={%&Lgpp(I6{epi zKv87oOv?BKsK{ondhvb&T4#GiB41Cyy1u8!IBO>0L=B6w{i6v;i~3<>k~9I*ahoKj zq9;HqCI zuZ%vzmQo>)CjO7GBPH&u&g)4yUZ!NpH#Y$$x`kJ4h9}_pMmp2>_6eB$HOkSRIsta6 z)rX~mk;*&COW03m&7{r7ESCS&NAQ_j<{oh5Bi!0_vVX4~ z73f9SFb|21j)j@~YYp=hc({J>YRkb^&6wG&*Zc^6=MJ4^?w$mFE2>;h$t3K3Xs$FE zISJ;x_tjq@HRJB0Se}`LQ#-TE-$7fb zxS}x%Xr@9b8_voQo&K!HWVevzj71;w%_|S&OHjzlUvQUGLFI~tKHHa^CR&4 zWrys$*%1)>&VSf^W(0O;3?FUyJOYA4<=!t_MnFzz@{;$H5%9{9oTp0}ff7BzJh_Mw zC~mYXUI3`EQMYLdNFT174c5A-dyl~JuSwY}k$SM$XWzO! z0$eHM=*}_%Byriv*X|?WR#e&a)@=l$61qcIBCS%qGWPA%2uMU-h36L79>>1Y;S(cJ zu{STbYW)bXYjxN@Tr&bYRCCOPSB*f>*&}`rmydu+%J(g!J;QMPDBpBQ_Aq38J}W#E zISke(8&){nAI5mpk^;41!_c{M%{-6)Fwo6sh5a}+3~3(3DI@7&AkKDpKH(jPY>hC- zV~oSlXBwt?^v4jaWpdBi_hksWi`*)MJ`cgYF8(Z&@gXP~{Ti!3Is|=v-d)c-hTyfW zk;ujOL!dM0^q9GE2)b6U9Nt$q1d}3@4jgZ(kT+pDJ^Y#q+taVaCpA!kcXH!v&u3Iv zB|9xMTS|q}bNkXua;czqEGM~=LIn=J@eSHhR7hmrCqEiag`U{XFIVrOAXZ=baVUfe zj}p|+zYeAXSJMf<*qc-k%E+oVM7mnKzmasE3ROI@S9yJ@VBgv)wcd*gZPk_GSy!nL z!2PmAQeX2(+^b|Q6bgHRHt@773$V*j#o3J!p=P>$Br0a z{b~CW19nkidQAF>FVZ8E(y}{{S{tml_SC0BrozxbsU8*L`C$1nq~*j+I9UhFyLjQ& z=IvD2cltej0+|Z4*6jHgk?QfeBtOugLO8$eRyK7i++KR4%|?|9bkmmO<|yVDFWi~#(h6)>g?o%%op~5D&5sOh_DkM~vO#kMj zLUioJ@2yLyz^eY5_xO)N$b2_hoI5iJz7B5O)*l98+D+o@`o2N9Qy`R4*E0yeZ+Jv* zeLn~qv3VQ5w+%wF`6;dDra`#b__e;aVG!EG+q`$z4}y%6yA^ZYAcUwSI1J_vLhs&t zKl3ES4}!YsF|WvIY{&K&t=o_eFpkHcj~E0gWq*m9aID9DWOmKnLAY{9 znfqt(AQTR9Na)@kgbke=zm)n7f=DIP?kB#3a4o5l|FHKU#LS$ys&ruxR>ZxCOmQCs zwLa}S1!v4hZ8|J!j1Wd|d)$QYG=u58HFE#||N8HLt zqA-xE3*)2Ek9fh2c$B_L0k1mXe!x~o%-Yt;O3u;j^l2+gF$)(fOIvdXD=}9qH?gy} zZZ=}JPI9hhj;ArnV7pSJ5*?qjyPKS|wH!%R2w_?14E3}RSliQGw>szMVrJonMOeEy zJBqowJ35-VoELL-Gjp?bb+ff_-As2`o9?8!nJZ>-b`o>3I_>O2%kJiUTFl1Q4WAF! zl4MD96ORIx3Xx7?t6A`7M8|7DTW6f4XIMtZ#YXo@l`H=Fb_P0rZU%lnF$D#)O%~<~ zR+bo3Q%T8EWut|;nX0*hf~uKOn z*ti(0Z$#K<1YK5EmfNU|p)Y8Aw2OKEv{YGJ%kYGQm6^4LyPKPp%LxN*gA)sUb~>S? zj`-II|EZ41jcN*;)GZv`5icA|J0ZuT4EG8!fVu z2G@g~rXgPatxzT!2mvPJ|L?yie@RMI!(=xJW1uA;`cnwoa(8O0{;VMu#3r)0cDV_) zbKx`>o~GyLL#EQva-aN@n{2RM%-q4*!d}eM*~(SS$=OZJ!r95q%+^WF!_39j%*oAF z%*;*9&Bh8P?~J=Gin-YS|n{yCw}Np#)XTmo!y-*QT9>j@d9fr7b_c?ovg9tr%}BB-XVGvSxja{LQ7s8Ha2c;PX_BGHZpeTm;81m-OPXm zru}ugf+SV>v~`TuU%U{1Qw#lFDF^qk*x2H!Gb$RDOOwP8ymlMkByDPJc=IocW3Mn9QaRTLmWuQ7k8%|NS~P&_p4nKHxgG5g}dwCGb!vZ{tWuDkjno$Q!>Xw%KNK?sXMHsXCjNm{m5qh({CKLA9A`& zT~C|2*q?BawIwQ*8}uTQ{T<8{_QE+wG*Y^VT;rZdMUmS;UHn1Sz)2A|V6`l8QC56}w5TwOebK zu!w(z5X3)h2_lO~C?cWXJ@>tL@9aMJXJ{KF$-D2p?>qP0bI(2Jd&^oXS91MZ>};j9 zIk(c-g1_QJ-dI34Uh40)sz%)mSp950P8z$%F4;Z)!(m{@dhJraoVSY-vCgr&aiPOS zi9~_ba*5k$>~05}ptg?%>8ZdhMcBEXyaK zwYs{jZ29>@!75mrM2<$r?cW3wJM4;+1)c!^3eLG=F5~1jI*#o~6Teofban`be9tOn zoqVq_-nF+SY%bbU$rSSC{ugi>ICcSfI$pP>9S&=Wn2`cXlXzIdM8VqwbM&cxRg^}e zGRhabw_4?&*}k{MJQjP!QioOET+CT-NE?@E!v(v$am{x($r}rMD-JB#YGsPso8-__ z?ogga1ZX`Du}Z09gd}%|=3vSg2Q`G2&s!_3e0Pgmju@rHJ z;w5i8KXUBOOlMv!k~DL{qQ_{0$yU z#1}TS7_qvB>Ma)!v)%0SGwj4N9&2wkQqz{1)7PrV$*6#_#D>9!{~C=mcI$jJJ{U6i znP450e)&(0%pk4)uck!XjqLBIwFEw{3am*dy`-v{yrLCWAI}M zH89cgCoKZUjQ#@@JHWFAS24f@N*QQ4cD-1HMrj{t89}>Zf2yY=9X8wl_!B} zveWNJ<7tC`m{x9ZQypQBEoSd7#NGDRC8;Ntj55#dM#NG|zE;zg{!t`4U_EIWfROk3Naoms`_je@X zF?SXdP95TsQF4C=qC~VMCY6LDO4OB(ef)1CN{;-2qU7ibGm=8LsiLi}5 z$H%PpRy1=e4c;S*#{je3;Ais!W@V(VVg1AtolbH8s1vDqFv1Q;@CrZPm1y0Rn!d3! z=iNRAEbhVUVsXb||84BD&tE4$Pz+5jE658&AvP4kgZ$*{A}vx|X{tsufZ`-kd~`V) zUvKa?3o1${l_o@RGQ>`Y@Erf>=ZI6$o|+NStFk32?J9uhJ>oh1N7@bJ;PHYdpw=O# zOSSAlgpU^xL0+qC`u#8H0!HYcp`RVzsecN2S&-`NXPAuq^(vt23eN=F?6Dq}Y!>e)Wpzx6=~5#Y%mUie{Ywxt3_10vuq%vi?8KBNdh_lfM+uu@K6)ZkUq zpIB+bm}^VewFo;`!|`f6XZG&4Z(8!PgF>ut(}fVuiPceRj`CPUX?5% zmjx=1%GbXomh+MY{j%oLNpq2%fW$uc3cK_Q#|!+}BjHX@3^IL%h+U~k1q=uH^8(p$ z6E=Lu;AqpQvLUboktW^kXXE|ieLiwCT(!qNQA$)mViU@=;*ADaG)fkoxI!xotw0O# zNnWWc#Id#m{|qxo3mmVtw}!o9+!wg~V%*cf^wszmcoS?4yeP(@N{HIR4e&|4lj|jr zpIFO&y;i)*@BOkC$A!?&+^XqTO-j2AnDoFuM8KW>GqoB}K}4>YhTKyFRrtD;7)dUC&%-Aa2S*^Pxn*xE#$vcz;M9) zhscDZS1Amk^-N{Lr1}fCjP$YVeH<_HcYad`TRe@?jCsN%J>BfrhW;Y}3 zOby2){Jq~rMfEc$rPG|NvKrvHL!;sly$;(SBC8HwS-^Jl7#lqwT?zqpwQ1T;cRJIX zfiRaQjV=uVr3C58tZhy=r}3R^)ubm%dkSgDd62fsX~*tM_dqnuWy%@zeYQVYhH95= zOP0z`C0kCePIl$3Lavl-+qpkk%=E}xO7+77>IJA%xGq)-g$zF3CEEaDtxkIA$+rCm z4y>+55fb6tA$)yi?hs0RoI8f6R4Rmgv21l)4hClE45@A^0C<1)&fJ`vJAlwl)!R9{ zA{KDQ=1Zw{?(bKtvkIrHU}r=O&d`ez#>?OeX4cCwjRvfcXK7%SYOGLZ>+S%dS%J+q zbSCK1K9HXYGLDn!$FQqQ)0UM7x`yaJ3te=Nds3% zvtE4-%GJ#k*ld?dm)hrzBGmc0gD62?Va(b$UgI_o2=(D$9w79&!GC}1SoQBtai-}l zoew+fAoM?9D2SN_%&XWl^VvwWEIz3};lQoy-<`r86F#Q+$jMII#!q|{F)+iN3?#jc zn+Fnov{CQR%(1H82>Q-5ceF2|^!R@}^yXIrd`U;!|7-`Tk8dg{W_AX>dcZJWbj#^) z^*Afs`g=uVy0IzUv?A46$ro}f)~&Oe*JRhP*?^y@YPGU0P1)vbSEe=FytZ?l)z#eG f)Y#nAl-;m)6+ZakJNkd^k8%51{P5iK+Z+D_tu)gC literal 0 HcmV?d00001 diff --git a/tests/gentropy/data_samples/variant_sources/credible-sets/._SUCCESS.crc b/tests/gentropy/data_samples/variant_sources/credible-sets/._SUCCESS.crc new file mode 100644 index 0000000000000000000000000000000000000000..3b7b044936a890cd8d651d349a752d819d71d22c GIT binary patch literal 8 PcmYc;N@ieSU}69O2$TUk literal 0 HcmV?d00001 diff --git a/tests/gentropy/data_samples/variant_sources/credible-sets/.part-00000-a9a641da-3820-4bf4-911e-4d61475173d0-c000.snappy.parquet.crc b/tests/gentropy/data_samples/variant_sources/credible-sets/.part-00000-a9a641da-3820-4bf4-911e-4d61475173d0-c000.snappy.parquet.crc new file mode 100644 index 0000000000000000000000000000000000000000..881413c1519d66412a717b231d6dc96adfea7b28 GIT binary patch literal 168 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 R|JVK_wg=(QA>jM{{vQ;-oNfRB literal 0 HcmV?d00001 diff --git a/tests/gentropy/data_samples/variant_sources/eva-test.jsonl b/tests/gentropy/data_samples/variant_sources/eva-test.jsonl new file mode 100644 index 000000000..e83f7dcd7 --- /dev/null +++ b/tests/gentropy/data_samples/variant_sources/eva-test.jsonl @@ -0,0 +1,50 @@ +{"alleleOrigins":["germline"],"datasourceId":"eva","datatypeId":"genetic_association","clinicalSignificances":["uncertain significance"],"confidence":"criteria provided, single submitter","studyId":"RCV001281540","releaseDate":"2021-01-17","targetFromSourceId":"ENSG00000061455","variantFunctionalConsequenceId":"SO_0001583","variantId":"5_123159516_C_T","variantRsId":"rs1333586171","cohortPhenotypes":["Heart, malformation of"],"diseaseFromSource":"Heart, malformation of","diseaseFromSourceId":"CN130023","diseaseFromSourceMappedId":"HP_0001627","variantHgvsId":"NC_000005.10:g.123159516C>T"} +{"alleleOrigins":["germline"],"datasourceId":"eva","datatypeId":"genetic_association","clinicalSignificances":["uncertain significance"],"confidence":"criteria provided, single submitter","studyId":"RCV002030146","releaseDate":"2022-03-28","targetFromSourceId":"ENSG00000160200","variantFunctionalConsequenceId":"SO_0001583","variantId":"21_43063980_T_C","variantRsId":"rs777884368","cohortPhenotypes":["HYPERHOMOCYSTEINEMIA, THROMBOTIC, CBS-RELATED"],"diseaseFromSource":"HYPERHOMOCYSTEINEMIA, THROMBOTIC, CBS-RELATED","diseaseFromSourceId":"C3150344","diseaseFromSourceMappedId":"Orphanet_394","variantHgvsId":"NC_000021.9:g.43063980T>C"} +{"alleleOrigins":["germline"],"datasourceId":"eva","datatypeId":"genetic_association","clinicalSignificances":["pathogenic"],"confidence":"no assertion criteria provided","studyId":"RCV000412534","releaseDate":"2017-01-09","targetFromSourceId":"ENSG00000139324","variantFunctionalConsequenceId":"SO_0001587","variantId":"12_88195521_C_T","variantRsId":"rs1057517697","cohortPhenotypes":["Lissencephaly 8"],"diseaseFromSource":"Lissencephaly 8","diseaseFromSourceId":"C4310646","diseaseFromSourceMappedId":"MONDO_0018838","variantHgvsId":"NC_000012.12:g.88195521C>T"} +{"alleleOrigins":null,"datasourceId":"eva","datatypeId":"genetic_association","clinicalSignificances":["pathogenic"],"confidence":"criteria provided, single submitter","studyId":"RCV000987058","releaseDate":"2020-01-11","targetFromSourceId":"ENSG00000130561","variantFunctionalConsequenceId":"SO_0001587","variantId":"2_233328536_C_T","variantRsId":"rs1574942567","cohortPhenotypes":["Oguchi disease","Oguchi's disease","Stationary night blindness, Oguchi type"],"diseaseFromSource":"Oguchi disease","diseaseFromSourceId":"C1306122","diseaseFromSourceMappedId":"MONDO_0019152","variantHgvsId":"NC_000002.12:g.233328536C>T"} +{"alleleOrigins":["germline"],"datasourceId":"eva","datatypeId":"genetic_association","clinicalSignificances":["uncertain significance"],"confidence":"criteria provided, single submitter","studyId":"RCV000850771","releaseDate":"2019-09-22","targetFromSourceId":"ENSG00000198804","variantFunctionalConsequenceId":"SO_0001631","variantId":"MT_4456_C_T","variantRsId":"rs1603219465","cohortPhenotypes":["Juvenile myopathy, encephalopathy, lactic acidosis AND stroke","MELAS syndrome","Mitochondrial encephalomyopathy lactic acidosis and stroke-like episodes"],"diseaseFromSource":"Juvenile myopathy, encephalopathy, lactic acidosis AND stroke","diseaseFromSourceId":"C0162671","diseaseFromSourceMappedId":"Orphanet_550","variantHgvsId":"NC_012920.1:m.4456C>T"} +{"alleleOrigins":["germline"],"datasourceId":"eva","datatypeId":"genetic_association","clinicalSignificances":["uncertain significance"],"confidence":"criteria provided, multiple submitters, no conflicts","studyId":"RCV001223098","releaseDate":"2020-07-16","targetFromSourceId":"ENSG00000104133","variantFunctionalConsequenceId":"SO_0001583","variantId":"15_44598352_G_C","variantRsId":"rs746116309","cohortPhenotypes":["Autosomal recessive hereditary spastic paraplegia, mental impairment, and thin corpus callosum","Hereditary spastic paraplegia 11","Hereditary spastic paraplegia mental impairment and thin corpus callosum","Nakamura Osame syndrome","SPASTIC PARAPLEGIA, AUTOSOMAL RECESSIVE, COMPLICATED, WITH THIN CORPUS CALLOSUM","SPASTIC PARAPLEGIA, AUTOSOMAL RECESSIVE, WITH MENTAL IMPAIRMENT AND THIN CORPUS CALLOSUM","Spastic paraplegia 11","Spastic paraplegia 11, autosomal recessive","Spastic paraplegia, mental retardation and thin corpus callosum"],"diseaseFromSource":"Hereditary spastic paraplegia 11","diseaseFromSourceId":"C1858479","diseaseFromSourceMappedId":"MONDO_0011445","variantHgvsId":"NC_000015.10:g.44598352G>C"} +{"alleleOrigins":["germline"],"datasourceId":"eva","datatypeId":"genetic_association","clinicalSignificances":["uncertain significance"],"confidence":"criteria provided, single submitter","studyId":"RCV000279062","releaseDate":"2016-12-06","targetFromSourceId":"ENSG00000175294","variantFunctionalConsequenceId":"SO_0001819","variantId":"11_66025978_C_T","variantRsId":"rs370953416","cohortPhenotypes":["CATSPER-Related Male Infertility","MALE INFERTILITY, NONSYNDROMIC, AUTOSOMAL RECESSIVE","Spermatogenic failure 7"],"diseaseFromSource":"Spermatogenic failure 7","diseaseFromSourceId":"C2751811","diseaseFromSourceMappedId":"MONDO_0013070","variantHgvsId":"NC_000011.10:g.66025978C>T"} +{"alleleOrigins":["germline"],"datasourceId":"eva","datatypeId":"genetic_association","clinicalSignificances":["likely pathogenic"],"confidence":"criteria provided, single submitter","studyId":"RCV003236645","releaseDate":"2023-06-24","targetFromSourceId":"ENSG00000184895","variantFunctionalConsequenceId":"SO_0001583","variantId":"Y_2787299_G_A","variantRsId":null,"cohortPhenotypes":["46,XX SEX REVERSAL, SRY-POSITIVE","46,XX sex reversal 1","SRY-positive 46,XX testicular disorder of sex development"],"diseaseFromSource":"46,XX sex reversal 1","diseaseFromSourceId":"C2748895","diseaseFromSourceMappedId":"MONDO_0100250","variantHgvsId":"NC_000024.10:g.2787299G>A"} +{"alleleOrigins":null,"datasourceId":"eva","datatypeId":"genetic_association","clinicalSignificances":["uncertain significance"],"confidence":"criteria provided, single submitter","studyId":"RCV000671195","releaseDate":"2018-08-05","targetFromSourceId":"ENSG00000170927","variantFunctionalConsequenceId":"SO_0001822","variantId":"6_51748030_CTTT_C","variantRsId":"rs1554218479","cohortPhenotypes":["AR polycystic kidney disease","Autosomal recessive polycystic kidney disease","POLYCYSTIC KIDNEY AND HEPATIC DISEASE 1","POLYCYSTIC KIDNEY DISEASE, INFANTILE, TYPE I","Polycystic kidney disease, infantile type"],"diseaseFromSource":"Autosomal recessive polycystic kidney disease","diseaseFromSourceId":"C0085548","diseaseFromSourceMappedId":"MONDO_0009889","variantHgvsId":"NC_000006.12:g.51748034_51748036del"} +{"alleleOrigins":["germline"],"datasourceId":"eva","datatypeId":"genetic_association","clinicalSignificances":["uncertain significance"],"confidence":"no assertion criteria provided","studyId":"RCV003389101","releaseDate":"2023-11-11","targetFromSourceId":"ENSG00000114374","variantFunctionalConsequenceId":"SO_0001583","variantId":"Y_12842370_G_T","variantRsId":null,"cohortPhenotypes":["AZOOSPERMIA, NONOBSTRUCTIVE, Y-LINKED","OLIGOSPERMIA, NONOBSTRUCTIVE, Y-LINKED","OLIGOZOOSPERMIA, NONOBSTRUCTIVE, Y-LINKED","SPERMATOGENIC ARREST, Y-LINKED","SPERMATOGENIC FAILURE, NONOBSTRUCTIVE, Y-LINKED","Spermatogenic failure, Y-linked, 2"],"diseaseFromSource":"Spermatogenic failure, Y-linked, 2","diseaseFromSourceId":"C1839071","diseaseFromSourceMappedId":"MONDO_0015607","variantHgvsId":"NC_000024.10:g.12842370G>T"} +{"alleleOrigins":["germline"],"datasourceId":"eva","datatypeId":"genetic_association","clinicalSignificances":["likely benign"],"confidence":"criteria provided, single submitter","studyId":"RCV002083386","releaseDate":"2022-04-08","targetFromSourceId":"ENSG00000072778","variantFunctionalConsequenceId":"SO_0002169","variantId":"17_7224135_T_C","variantRsId":"rs745620433","cohortPhenotypes":["VLCAD deficiency","Very long chain acyl-CoA dehydrogenase deficiency"],"diseaseFromSource":"Very long chain acyl-CoA dehydrogenase deficiency","diseaseFromSourceId":"C3887523","diseaseFromSourceMappedId":"MONDO_0008723","variantHgvsId":"NC_000017.11:g.7224135T>C"} +{"alleleOrigins":["germline"],"datasourceId":"eva","datatypeId":"genetic_association","clinicalSignificances":["likely benign"],"confidence":"criteria provided, single submitter","studyId":"RCV002203969","releaseDate":"2022-04-12","targetFromSourceId":"ENSG00000125741","variantFunctionalConsequenceId":"SO_0001819","variantId":"19_45584735_C_T","variantRsId":"rs1131692018","cohortPhenotypes":["3-Methylglutaconic aciduria type 3","3-alpha methylglutaconic aciduria type III","3-methylglutaconic aciduria type III","Costeff optic atrophy syndrome","Iraqi Jewish optic atrophy plus","MGA type III","OPA3, AUTOSOMAL RECESSIVE","OPA3-Related 3-Methylglutaconic Aciduria","OPTIC ATROPHY 3, AUTOSOMAL DOMINANT","OPTIC ATROPHY 3, AUTOSOMAL RECESSIVE","Optic atrophy 3","Optic atrophy and cataract, autosomal dominant","Optic atrophy infantile with chorea and spastic paraplegia","Optic atrophy, cataract, and neurologic disorder"],"diseaseFromSource":"Optic atrophy 3","diseaseFromSourceId":"C1833809","diseaseFromSourceMappedId":"Orphanet_67036","variantHgvsId":"NC_000019.10:g.45584735C>T"} +{"alleleOrigins":["germline"],"datasourceId":"eva","datatypeId":"genetic_association","clinicalSignificances":["uncertain significance"],"confidence":"criteria provided, single submitter","studyId":"RCV002676812","releaseDate":"2023-02-07","targetFromSourceId":"ENSG00000125826","variantFunctionalConsequenceId":"SO_0001583","variantId":"20_419394_C_A","variantRsId":null,"cohortPhenotypes":["POLYGLUCOSAN BODY MYOPATHY WITHOUT IMMUNODEFICIENCY","Polyglucosan body myopathy 1 with or without immunodeficiency","Polyglucosan body myopathy type 1"],"diseaseFromSource":"Polyglucosan body myopathy type 1","diseaseFromSourceId":"C4014605","diseaseFromSourceMappedId":"Orphanet_397937","variantHgvsId":"NC_000020.11:g.419394C>A"} +{"alleleOrigins":["germline"],"datasourceId":"eva","datatypeId":"genetic_association","clinicalSignificances":["uncertain significance"],"confidence":"criteria provided, single submitter","studyId":"RCV002680839","releaseDate":"2023-02-07","targetFromSourceId":"ENSG00000160789","variantFunctionalConsequenceId":"SO_0001583","variantId":"1_156137732_C_T","variantRsId":null,"cohortPhenotypes":["Charcot-Marie-Tooth disease type 2","Charcot-Marie-Tooth, Type 2"],"diseaseFromSource":"Charcot-Marie-Tooth disease type 2","diseaseFromSourceId":"C0270914","diseaseFromSourceMappedId":"MONDO_0018993","variantHgvsId":"NC_000001.11:g.156137732C>T"} +{"alleleOrigins":["germline"],"datasourceId":"eva","datatypeId":"genetic_association","clinicalSignificances":["pathogenic"],"confidence":"criteria provided, single submitter","studyId":"RCV002847567","releaseDate":"2023-02-07","targetFromSourceId":"ENSG00000075891","variantFunctionalConsequenceId":"SO_0001589","variantId":"10_100750706_C_CG","variantRsId":null,"cohortPhenotypes":["CAKUT WITH OR WITHOUT OCULAR ABNORMALITIES","CONGENITAL ANOMALIES OF THE KIDNEY AND URINARY TRACT WITH OR WITHOUT OCULAR ABNORMALITIES","Coloboma of optic nerve with renal disease","Focal segmental glomerulosclerosis 7","Optic coloboma, vesicoureteral reflux, and renal anomalies","Optic nerve coloboma with renal disease","PAPILLORENAL SYNDROME WITH MILD OCULAR ABNORMALITIES","Papillorenal syndrome","RENAL-COLOBOMA SYNDROME WITH MACULAR ABNORMALITIES","Renal coloboma syndrome"],"diseaseFromSource":"Focal segmental glomerulosclerosis 7","diseaseFromSourceId":"C4014925","diseaseFromSourceMappedId":"MONDO_0014451","variantHgvsId":"NC_000010.11:g.100750708dup"} +{"alleleOrigins":["germline"],"datasourceId":"eva","datatypeId":"genetic_association","clinicalSignificances":["benign"],"confidence":"criteria provided, single submitter","studyId":"RCV003621924","releaseDate":"2024-02-20","targetFromSourceId":"ENSG00000008056","variantFunctionalConsequenceId":"SO_0001819","variantId":"X_47619585_G_C","variantRsId":null,"cohortPhenotypes":["Epilepsy, X-linked 1, with variable learning disabilities and behavior disorders","Epilepsy, X-linked, with variable learning disabilities and behavior disorders","X-linked epilepsy-learning disabilities-behavior disorders syndrome"],"diseaseFromSource":"Epilepsy, X-linked 1, with variable learning disabilities and behavior disorders","diseaseFromSourceId":"C5774177","diseaseFromSourceMappedId":"Orphanet_85294","variantHgvsId":"NC_000023.11:g.47619585G>C"} +{"alleleOrigins":["germline"],"datasourceId":"eva","datatypeId":"genetic_association","clinicalSignificances":["likely benign"],"confidence":"criteria provided, single submitter","studyId":"RCV003636240","releaseDate":"2024-02-20","targetFromSourceId":"ENSG00000143669","variantFunctionalConsequenceId":"SO_0001819","variantId":"1_235744114_A_G","variantRsId":null,"cohortPhenotypes":["Chediak-Higashi Syndrome","Chédiak-Higashi syndrome"],"diseaseFromSource":"Chédiak-Higashi syndrome","diseaseFromSourceId":"C0007965","diseaseFromSourceMappedId":"Orphanet_167","variantHgvsId":"NC_000001.11:g.235744114A>G"} +{"alleleOrigins":["germline"],"datasourceId":"eva","datatypeId":"genetic_association","clinicalSignificances":["likely pathogenic"],"confidence":"criteria provided, single submitter","studyId":"RCV003735165","releaseDate":"2024-02-20","targetFromSourceId":"ENSG00000196569","variantFunctionalConsequenceId":"SO_0001575","variantId":"6_129453132_G_C","variantRsId":null,"cohortPhenotypes":["LAMA2-related muscular dystrophy","Laminin alpha 2-related dystrophy"],"diseaseFromSource":"LAMA2-related muscular dystrophy","diseaseFromSourceId":"C5679788","diseaseFromSourceMappedId":"MONDO_0100228","variantHgvsId":"NC_000006.12:g.129453132G>C"} +{"alleleOrigins":["germline"],"datasourceId":"eva","datatypeId":"genetic_association","clinicalSignificances":["uncertain significance"],"confidence":"criteria provided, single submitter","studyId":"RCV000797080","releaseDate":"2019-08-14","targetFromSourceId":"ENSG00000179348","variantFunctionalConsequenceId":"SO_0001583","variantId":"3_128485795_C_A","variantRsId":"rs1576748419","cohortPhenotypes":["COMBINED IMMUNODEFICIENCY WITH SUSCEPTIBILITY TO MYCOBACTERIAL, VIRAL, AND FUNGAL INFECTIONS","Deafness-lymphedema-leukemia syndrome","Dendritic cell, monocyte, B lymphocyte, and natural killer lymphocyte deficiency","Emberger syndrome","GATA2 DEFICIENCY","IMMUNODEFICIENCY 21","Lymphedema, primary, with myelodysplasia","MONOCYTOPENIA AND MYCOBACTERIAL INFECTION SYNDROME","MONOCYTOPENIA WITH SUSCEPTIBILITY TO MYCOBACTERIAL, FUNGAL, AND PAPILLOMAVIRUS INFECTIONS AND MYELODYSPLASIA","Monocytopenia with susceptibility to infections"],"diseaseFromSource":"Monocytopenia with susceptibility to infections","diseaseFromSourceId":"C3280030","diseaseFromSourceMappedId":"MONDO_0013607","variantHgvsId":"NC_000003.12:g.128485795C>A"} +{"alleleOrigins":["germline"],"datasourceId":"eva","datatypeId":"genetic_association","clinicalSignificances":["likely benign"],"confidence":"criteria provided, single submitter","studyId":"RCV001500249","releaseDate":"2021-06-08","targetFromSourceId":"ENSG00000159082","variantFunctionalConsequenceId":"SO_0001819","variantId":"21_32694306_C_T","variantRsId":"rs780954414","cohortPhenotypes":["Developmental and epileptic encephalopathy, 53","Early-onset Parkinson disease 20","Epileptic encephalopathy, early infantile, 53"],"diseaseFromSource":"Developmental and epileptic encephalopathy, 53","diseaseFromSourceId":"C4479313","diseaseFromSourceMappedId":"Orphanet_1934","variantHgvsId":"NC_000021.9:g.32694306C>T"} +{"alleleOrigins":["germline"],"datasourceId":"eva","datatypeId":"genetic_association","clinicalSignificances":["likely benign"],"confidence":"criteria provided, single submitter","studyId":"RCV002392200","releaseDate":"2022-11-29","targetFromSourceId":"ENSG00000184058","variantFunctionalConsequenceId":"SO_0001819","variantId":"22_19766420_C_T","variantRsId":null,"cohortPhenotypes":["Cardiovascular phenotype"],"diseaseFromSource":"Cardiovascular phenotype","diseaseFromSourceId":"CN230736","diseaseFromSourceMappedId":"HP_0001626","variantHgvsId":"NC_000022.11:g.19766420C>T"} +{"alleleOrigins":["germline"],"datasourceId":"eva","datatypeId":"genetic_association","clinicalSignificances":["uncertain significance"],"confidence":"criteria provided, single submitter","studyId":"RCV003774575","releaseDate":"2024-02-28","targetFromSourceId":"ENSG00000128591","variantFunctionalConsequenceId":"SO_0001583","variantId":"7_128841305_G_A","variantRsId":null,"cohortPhenotypes":["Cardiomyopathy, familial hypertrophic, 26","Dilated Cardiomyopathy, Dominant","Distal myopathy with posterior leg and anterior hand involvement","FILAMINOPATHY, AUTOSOMAL DOMINANT","Filaminopathy (type)","Hypertrophic cardiomyopathy 26","Myofibrillar myopathy 5","Myofibrillar myopathy, filamin C-related","Myopathy, distal, 4","WILLIAMS DISTAL MYOPATHY"],"diseaseFromSource":"Hypertrophic cardiomyopathy 26","diseaseFromSourceId":"C4310749","diseaseFromSourceMappedId":"EFO_0000538","variantHgvsId":"NC_000007.14:g.128841305G>A"} +{"alleleOrigins":["germline"],"datasourceId":"eva","datatypeId":"genetic_association","clinicalSignificances":["uncertain significance"],"confidence":"criteria provided, single submitter","studyId":"RCV003779225","releaseDate":"2024-02-28","targetFromSourceId":"ENSG00000151929","variantFunctionalConsequenceId":"SO_0001821","variantId":"10_119670132_G_GGCA","variantRsId":null,"cohortPhenotypes":["Dilated cardiomyopathy 1HH","Myofibrillar myopathy 6","Myofibrillar myopathy, BAG3-related"],"diseaseFromSource":"Dilated cardiomyopathy 1HH","diseaseFromSourceId":"C3151293","diseaseFromSourceMappedId":"MONDO_0013479","variantHgvsId":"NC_000010.11:g.119670135_119670137dup"} +{"alleleOrigins":["germline"],"datasourceId":"eva","datatypeId":"genetic_association","clinicalSignificances":["likely benign"],"confidence":"criteria provided, single submitter","studyId":"RCV001490387","releaseDate":"2021-06-08","targetFromSourceId":"ENSG00000134853","variantFunctionalConsequenceId":"SO_0001627","variantId":"4_54287551_T_C","variantRsId":"rs2110341918","cohortPhenotypes":["Gastrointestinal Stromal Sarcoma","Gastrointestinal stroma tumor","Gastrointestinal stromal tumor","Gastrointestinal stromal tumor, somatic"],"diseaseFromSource":"Gastrointestinal stromal tumor","diseaseFromSourceId":"C0238198","diseaseFromSourceMappedId":"MONDO_0011719","variantHgvsId":"NC_000004.12:g.54287551T>C"} +{"alleleOrigins":["germline"],"datasourceId":"eva","datatypeId":"genetic_association","clinicalSignificances":["uncertain significance"],"confidence":"criteria provided, single submitter","studyId":"RCV003041098","releaseDate":"2023-02-07","targetFromSourceId":"ENSG00000007314","variantFunctionalConsequenceId":"SO_0001583","variantId":"17_63948745_A_T","variantRsId":null,"cohortPhenotypes":["Adynamia episodica hereditaria with or without myotonia","Familial hyperkalemic periodic paralysis","Gamstorp disease","Gamstorp episodic adynamy","Hyperkalemic periodic paralysis"],"diseaseFromSource":"Hyperkalemic periodic paralysis","diseaseFromSourceId":"C0238357","diseaseFromSourceMappedId":"MONDO_0008224","variantHgvsId":"NC_000017.11:g.63948745A>T"} +{"alleleOrigins":["germline"],"datasourceId":"eva","datatypeId":"genetic_association","clinicalSignificances":["likely benign"],"confidence":"criteria provided, single submitter","studyId":"RCV003966094","releaseDate":"2024-03-16","targetFromSourceId":"ENSG00000164818","variantFunctionalConsequenceId":"SO_0001819","variantId":"7_756970_C_G","variantRsId":"rs571248637","cohortPhenotypes":["DNAAF5-related condition","DNAAF5-related disorder"],"diseaseFromSource":"DNAAF5-related disorder","diseaseFromSourceId":null,"diseaseFromSourceMappedId":null,"variantHgvsId":"NC_000007.14:g.756970C>G"} +{"alleleOrigins":["germline"],"datasourceId":"eva","datatypeId":"genetic_association","clinicalSignificances":["likely benign"],"confidence":"criteria provided, single submitter","studyId":"RCV003921540","releaseDate":"2024-03-16","targetFromSourceId":"ENSG00000134982","variantFunctionalConsequenceId":"SO_0001623","variantId":"5_112738418_A_G","variantRsId":null,"cohortPhenotypes":["APC-related condition","APC-related disorder"],"diseaseFromSource":"APC-related disorder","diseaseFromSourceId":null,"diseaseFromSourceMappedId":null,"variantHgvsId":"NC_000005.10:g.112738418A>G"} +{"alleleOrigins":["germline"],"datasourceId":"eva","datatypeId":"genetic_association","clinicalSignificances":["uncertain significance"],"confidence":"criteria provided, single submitter","studyId":"RCV001340631","releaseDate":"2021-03-22","targetFromSourceId":"ENSG00000139618","variantFunctionalConsequenceId":"SO_0001583","variantId":"13_32340936_T_C","variantRsId":"rs876660049","cohortPhenotypes":["Breast and ovarian cancer","Hereditary breast and ovarian cancer","Hereditary breast and ovarian cancer syndrome","Hereditary breast and ovarian cancer syndrome (HBOC)","Hereditary breast ovarian cancer syndrome"],"diseaseFromSource":"Hereditary breast ovarian cancer syndrome","diseaseFromSourceId":"C0677776","diseaseFromSourceMappedId":"MONDO_0003582","variantHgvsId":"NC_000013.11:g.32340936T>C"} +{"alleleOrigins":["germline"],"datasourceId":"eva","datatypeId":"genetic_association","clinicalSignificances":["conflicting interpretations of pathogenicity"],"confidence":"no assertion criteria provided","studyId":"RCV000056173","releaseDate":"2013-10-01","targetFromSourceId":"ENSG00000196218","variantFunctionalConsequenceId":"SO_0001583","variantId":"19_38585013_C_T","variantRsId":"rs118192153","cohortPhenotypes":["Central core disease","Central core disease of muscle","Central core myopathy","Muscle core disease","Muscular central core disease","Myopathy, central fibrillar","Shy-Magee syndrome"],"diseaseFromSource":"Central core myopathy","diseaseFromSourceId":"C0751951","diseaseFromSourceMappedId":"EFO_1000855","variantHgvsId":"NC_000019.10:g.38585013C>T"} +{"alleleOrigins":["germline"],"datasourceId":"eva","datatypeId":"genetic_association","clinicalSignificances":["uncertain significance"],"confidence":"criteria provided, single submitter","studyId":"RCV002249476","releaseDate":"2022-05-28","targetFromSourceId":"ENSG00000228253","variantFunctionalConsequenceId":"SO_0001631","variantId":"MT_7462_C_T","variantRsId":"rs1569484151","cohortPhenotypes":["COX deficiency","Complex 4 mitochondrial respiratory chain deficiency","Complex IV deficiency","Deficiency of mitochondrial respiratory chain complex4","Mitochondrial complex IV deficiency","Mitochondrial complex IV deficiency, nuclear type 1"],"diseaseFromSource":"Mitochondrial complex IV deficiency, nuclear type 1","diseaseFromSourceId":"C5435656","diseaseFromSourceMappedId":"MONDO_0859160","variantHgvsId":"NC_012920.1:m.7462C>T"} +{"alleleOrigins":["germline"],"datasourceId":"eva","datatypeId":"genetic_association","clinicalSignificances":["likely benign"],"confidence":"criteria provided, single submitter","studyId":"RCV003093847","releaseDate":"2023-02-07","targetFromSourceId":"ENSG00000130294","variantFunctionalConsequenceId":"SO_0001630","variantId":"2_240767028_G_C","variantRsId":"rs748724769","cohortPhenotypes":["Hereditary sensory and autonomic neuropathy type IIC","Hereditary spastic paraplegia 30","Intellectual disability, autosomal dominant 9","Mental retardation, autosomal dominant 9","NESCAV SYNDROME","Neuropathy, hereditary sensory, type 2C","SPASTIC PARAPLEGIA 30, AUTOSOMAL DOMINANT","Spastic paraplegia 30, autosomal recessive"],"diseaseFromSource":"Neuropathy, hereditary sensory, type 2C","diseaseFromSourceId":"C3280168","diseaseFromSourceMappedId":"Orphanet_970","variantHgvsId":"NC_000002.12:g.240767028G>C"} +{"alleleOrigins":["germline"],"datasourceId":"eva","datatypeId":"genetic_association","clinicalSignificances":["uncertain significance"],"confidence":"criteria provided, single submitter","studyId":"RCV002016427","releaseDate":"2022-03-28","targetFromSourceId":"ENSG00000159884","variantFunctionalConsequenceId":"SO_0001631","variantId":"9_35657840_C_G","variantRsId":"rs1287720442","cohortPhenotypes":["Anauxetic dysplasia","SPONDYLOMETAEPIPHYSEAL DYSPLASIA, ANAUXETIC TYPE"],"diseaseFromSource":"Anauxetic dysplasia","diseaseFromSourceId":"C1846796","diseaseFromSourceMappedId":"MONDO_0011773","variantHgvsId":"NC_000009.12:g.35657840C>G"} +{"alleleOrigins":["germline"],"datasourceId":"eva","datatypeId":"genetic_association","clinicalSignificances":["uncertain significance"],"confidence":"criteria provided, single submitter","studyId":"RCV002625025","releaseDate":"2023-02-07","targetFromSourceId":"ENSG00000054983","variantFunctionalConsequenceId":"SO_0001583","variantId":"14_87976417_C_A","variantRsId":null,"cohortPhenotypes":["Galactocerebrosidase deficiency","Galactosylceramide beta-galactosidase deficiency","Globoid cell leukoencephalopathy","Krabbe leukodystrophy","Leukodystrophy, Globoid Cell"],"diseaseFromSource":"Galactosylceramide beta-galactosidase deficiency","diseaseFromSourceId":"C0023521","diseaseFromSourceMappedId":"MONDO_0009499","variantHgvsId":"NC_000014.9:g.87976417C>A"} +{"alleleOrigins":["germline"],"datasourceId":"eva","datatypeId":"genetic_association","clinicalSignificances":["uncertain significance"],"confidence":"criteria provided, single submitter","studyId":"RCV003516889","releaseDate":"2024-02-14","targetFromSourceId":"ENSG00000046604","variantFunctionalConsequenceId":"SO_0001583","variantId":"18_31520935_C_A","variantRsId":null,"cohortPhenotypes":["ARRHYTHMOGENIC RIGHT VENTRICULAR DYSPLASIA, FAMILIAL, 10","Arrhythmogenic Right Ventricular Dysplasia/Cardiomyopathy10","Arrhythmogenic right ventricular cardiomyopathy, type 10","Arrhythmogenic right ventricular dysplasia 10","Arrhythmogenic right ventricular dysplasia/cardiomyopathy, type 10"],"diseaseFromSource":"Arrhythmogenic right ventricular dysplasia 10","diseaseFromSourceId":"C1857777","diseaseFromSourceMappedId":"Orphanet_247","variantHgvsId":"NC_000018.10:g.31520935C>A"} +{"alleleOrigins":["germline"],"datasourceId":"eva","datatypeId":"genetic_association","clinicalSignificances":["uncertain significance"],"confidence":"criteria provided, single submitter","studyId":"RCV003583433","releaseDate":"2024-02-14","targetFromSourceId":"ENSG00000163932","variantFunctionalConsequenceId":"SO_0001583","variantId":"3_53186260_A_G","variantRsId":null,"cohortPhenotypes":["Autoimmune lymphoproliferative syndrome, type III","Autoimmune lymphoproliferative syndrome, type III caused by mutation in PRKCD"],"diseaseFromSource":"Autoimmune lymphoproliferative syndrome, type III caused by mutation in PRKCD","diseaseFromSourceId":"C3809928","diseaseFromSourceMappedId":"Orphanet_3261","variantHgvsId":"NC_000003.12:g.53186260A>G"} +{"alleleOrigins":["germline"],"datasourceId":"eva","datatypeId":"genetic_association","clinicalSignificances":["likely benign"],"confidence":"criteria provided, single submitter","studyId":"RCV001419044","releaseDate":"2021-05-16","targetFromSourceId":"ENSG00000171759","variantFunctionalConsequenceId":"SO_0001819","variantId":"12_102912824_A_C","variantRsId":"rs773425620","cohortPhenotypes":["Folling disease","Oligophrenia phenylpyruvica","Phenylketonuria","Phenylketonurias"],"diseaseFromSource":"Phenylketonuria","diseaseFromSourceId":"C0031485","diseaseFromSourceMappedId":"MONDO_0009861","variantHgvsId":"NC_000012.12:g.102912824A>C"} +{"alleleOrigins":["germline"],"datasourceId":"eva","datatypeId":"genetic_association","clinicalSignificances":["uncertain significance"],"confidence":"criteria provided, single submitter","studyId":"RCV001861075","releaseDate":"2022-03-28","targetFromSourceId":"ENSG00000138622","variantFunctionalConsequenceId":"SO_0001583","variantId":"15_73324179_T_G","variantRsId":"rs1161776375","cohortPhenotypes":["Brugada syndrome 8"],"diseaseFromSource":"Brugada syndrome 8","diseaseFromSourceId":"C2751083","diseaseFromSourceMappedId":"MONDO_0013148","variantHgvsId":"NC_000015.10:g.73324179T>G"} +{"alleleOrigins":["germline"],"datasourceId":"eva","datatypeId":"genetic_association","clinicalSignificances":["likely benign"],"confidence":"criteria provided, single submitter","studyId":"RCV002138447","releaseDate":"2022-04-08","targetFromSourceId":"ENSG00000162065","variantFunctionalConsequenceId":"SO_0001627","variantId":"16_2499947_G_A","variantRsId":"rs1173044946","cohortPhenotypes":["Autosomal dominant nonsyndromic hearing loss 65","Caused by mutation in the TBC1 domain family, member 24","Deafness, autosomal dominant 65","Developmental and epileptic encephalopathy, 1","Epileptic encephalopathy, early infantile, 1","INFANTILE SPASM SYNDROME, X-LINKED 1","OHTAHARA SYNDROME, X-LINKED","Tonic spasms with clustering, arrest of psychomotor development and hypsarrhythmia on EEG","West's syndrome","X-Linked Infantile Spasm Syndrome","X-linked infantile spasms"],"diseaseFromSource":"Developmental and epileptic encephalopathy, 1","diseaseFromSourceId":"C3463992","diseaseFromSourceMappedId":"Orphanet_364063","variantHgvsId":"NC_000016.10:g.2499947G>A"} +{"alleleOrigins":["germline"],"datasourceId":"eva","datatypeId":"genetic_association","clinicalSignificances":["likely benign"],"confidence":"criteria provided, single submitter","studyId":"RCV002933690","releaseDate":"2023-02-07","targetFromSourceId":"ENSG00000165280","variantFunctionalConsequenceId":"SO_0001819","variantId":"9_35063060_A_C","variantRsId":null,"cohortPhenotypes":["Amyotrophic lateral sclerosis 14, with or without frontotemporal dementia","Frontotemporal dementia and/or amyotrophic lateral sclerosis 6","Inclusion body myopathy with Paget disease of bone and frontotemporal dementia","Inclusion body myopathy with early-onset Paget disease and frontotemporal dementia","VCP-Related Amyotrophic Lateral Sclerosis","VCP-Related Amyotrophic Lateral Sclerosis/Frontotemporal Dementia"],"diseaseFromSource":"Inclusion body myopathy with Paget disease of bone and frontotemporal dementia","diseaseFromSourceId":"C1833662","diseaseFromSourceMappedId":"Orphanet_52430","variantHgvsId":"NC_000009.12:g.35063060A>C"} +{"alleleOrigins":["germline"],"datasourceId":"eva","datatypeId":"genetic_association","clinicalSignificances":["likely benign"],"confidence":"criteria provided, single submitter","studyId":"RCV003804888","releaseDate":"2024-02-28","targetFromSourceId":"ENSG00000178209","variantFunctionalConsequenceId":"SO_0001819","variantId":"8_143920449_G_A","variantRsId":null,"cohortPhenotypes":["Autosomal recessive limb-girdle muscular dystrophy type 2Q","EPIDERMOLYSIS BULLOSA SIMPLEX 5A, OGNA TYPE","EPIDERMOLYSIS BULLOSA SIMPLEX AND LIMB-GIRDLE MUSCULAR DYSTROPHY","Epidermolysa bullosa simplex and limb girdle muscular dystrophy","Epidermolysis bullosa simplex 5B, with muscular dystrophy","Epidermolysis bullosa simplex 5C, with pyloric atresia","Epidermolysis bullosa simplex with muscular dystrophy","Epidermolysis bullosa simplex with nail dystrophy","Epidermolysis bullosa simplex with pyloric atresia","Epidermolysis bullosa simplex, Ogna type","Limb-girdle muscular dystrophy, type 2Q","MUSCULAR DYSTROPHY, LIMB-GIRDLE, AUTOSOMAL RECESSIVE 17","PLEC1-Related Epidermolysis Bullosa with Pyloric Atresia","Pidermolysis bullosa simplex 5A, Ogna type"],"diseaseFromSource":"Epidermolysis bullosa simplex 5B, with muscular dystrophy","diseaseFromSourceId":"C2931072","diseaseFromSourceMappedId":"Orphanet_257","variantHgvsId":"NC_000008.11:g.143920449G>A"} +{"alleleOrigins":["germline"],"datasourceId":"eva","datatypeId":"genetic_association","clinicalSignificances":["likely benign"],"confidence":"criteria provided, single submitter","studyId":"RCV003805362","releaseDate":"2024-02-28","targetFromSourceId":"ENSG00000101310","variantFunctionalConsequenceId":"SO_0002169","variantId":"20_18515639_C_T","variantRsId":null,"cohortPhenotypes":["CDA 2","Congenital dyserythropoietic anemia, type II","Cowden syndrome 7","Dyserythropoietic anemia, congenital type 2","HEMPAS anemia","Hereditary Erythroblastic Multinuclearity with Positive Acidified-Serum test'"],"diseaseFromSource":"Cowden syndrome 7","diseaseFromSourceId":"C4225179","diseaseFromSourceMappedId":"MONDO_0014802","variantHgvsId":"NC_000020.11:g.18515639C>T"} +{"alleleOrigins":["germline"],"datasourceId":"eva","datatypeId":"genetic_association","clinicalSignificances":["likely pathogenic"],"confidence":"criteria provided, single submitter","studyId":"RCV003806863","releaseDate":"2024-02-28","targetFromSourceId":"ENSG00000134569","variantFunctionalConsequenceId":"SO_0001574","variantId":"11_46883977_C_T","variantRsId":null,"cohortPhenotypes":["Cenani syndactylism","Cenani-Lenz syndactyly syndrome","Congenital myasthenic syndrome 17","SYNDACTYLY, TYPE VII","Sclerosteosis 2","Syndactyly Cenani Lenz type","Syndactyly type 7"],"diseaseFromSource":"Sclerosteosis 2","diseaseFromSourceId":"C3280402","diseaseFromSourceMappedId":"MONDO_0013679","variantHgvsId":"NC_000011.10:g.46883977C>T"} +{"alleleOrigins":["germline"],"datasourceId":"eva","datatypeId":"genetic_association","clinicalSignificances":["likely benign"],"confidence":"criteria provided, single submitter","studyId":"RCV003850101","releaseDate":"2024-02-28","targetFromSourceId":"ENSG00000054983","variantFunctionalConsequenceId":"SO_0002169","variantId":"14_87988221_T_C","variantRsId":null,"cohortPhenotypes":["Galactocerebrosidase deficiency","Galactosylceramide beta-galactosidase deficiency","Globoid cell leukoencephalopathy","Krabbe leukodystrophy","Leukodystrophy, Globoid Cell"],"diseaseFromSource":"Galactosylceramide beta-galactosidase deficiency","diseaseFromSourceId":"C0023521","diseaseFromSourceMappedId":"MONDO_0009499","variantHgvsId":"NC_000014.9:g.87988221T>C"} +{"alleleOrigins":["germline"],"datasourceId":"eva","datatypeId":"genetic_association","clinicalSignificances":["uncertain significance"],"confidence":"criteria provided, single submitter","studyId":"RCV001944434","releaseDate":"2022-03-28","targetFromSourceId":"ENSG00000178209","variantFunctionalConsequenceId":"SO_0001583","variantId":"8_143917391_C_T","variantRsId":"rs541897170","cohortPhenotypes":["Autosomal recessive limb-girdle muscular dystrophy type 2Q","EPIDERMOLYSIS BULLOSA SIMPLEX 5A, OGNA TYPE","EPIDERMOLYSIS BULLOSA SIMPLEX AND LIMB-GIRDLE MUSCULAR DYSTROPHY","Epidermolysa bullosa simplex and limb girdle muscular dystrophy","Epidermolysis bullosa simplex 5B, with muscular dystrophy","Epidermolysis bullosa simplex 5C, with pyloric atresia","Epidermolysis bullosa simplex with muscular dystrophy","Epidermolysis bullosa simplex with nail dystrophy","Epidermolysis bullosa simplex with pyloric atresia","Epidermolysis bullosa simplex, Ogna type","Limb-girdle muscular dystrophy, type 2Q","MUSCULAR DYSTROPHY, LIMB-GIRDLE, AUTOSOMAL RECESSIVE 17","PLEC1-Related Epidermolysis Bullosa with Pyloric Atresia","Pidermolysis bullosa simplex 5A, Ogna type"],"diseaseFromSource":"Autosomal recessive limb-girdle muscular dystrophy type 2Q","diseaseFromSourceId":"C3150989","diseaseFromSourceMappedId":"Orphanet_254361","variantHgvsId":"NC_000008.11:g.143917391C>T"} +{"alleleOrigins":["germline"],"datasourceId":"eva","datatypeId":"genetic_association","clinicalSignificances":["likely benign"],"confidence":"criteria provided, single submitter","studyId":"RCV000547369","releaseDate":"2017-12-26","targetFromSourceId":"ENSG00000008056","variantFunctionalConsequenceId":"SO_0001819","variantId":"X_47574166_C_T","variantRsId":"rs967215240","cohortPhenotypes":["Epilepsy, X-linked 1, with variable learning disabilities and behavior disorders","Epilepsy, X-linked, with variable learning disabilities and behavior disorders","X-linked epilepsy-learning disabilities-behavior disorders syndrome"],"diseaseFromSource":"Epilepsy, X-linked 1, with variable learning disabilities and behavior disorders","diseaseFromSourceId":"C5774177","diseaseFromSourceMappedId":"MONDO_0010339","variantHgvsId":"NC_000023.11:g.47574166C>T"} +{"alleleOrigins":["germline"],"datasourceId":"eva","datatypeId":"genetic_association","clinicalSignificances":["uncertain significance"],"confidence":"criteria provided, single submitter","studyId":"RCV002912729","releaseDate":"2023-02-07","targetFromSourceId":"ENSG00000173040","variantFunctionalConsequenceId":"SO_0001583","variantId":"4_5640686_T_C","variantRsId":null,"cohortPhenotypes":["Acrofacial dysostosis of Weyers","Chondroectodermal dysplasia","Curry-Hall syndrome","Ellis-van Creveld syndrome","Mesoectodermal dysplasia","WEYERS ACRODENTAL DYSOSTOSIS"],"diseaseFromSource":"Ellis-van Creveld syndrome","diseaseFromSourceId":"C0013903","diseaseFromSourceMappedId":"Orphanet_289","variantHgvsId":"NC_000004.12:g.5640686T>C"} +{"alleleOrigins":["germline"],"datasourceId":"eva","datatypeId":"genetic_association","clinicalSignificances":["likely benign"],"confidence":"criteria provided, single submitter","studyId":"RCV002933106","releaseDate":"2023-02-07","targetFromSourceId":"ENSG00000187535","variantFunctionalConsequenceId":"SO_0001819","variantId":"16_1523551_C_T","variantRsId":null,"cohortPhenotypes":["Conorenal syndrome","Renal dysplasia, retinal pigmentary dystrophy, cerebellar ataxia and skeletal dysplasia","SHORT-RIB THORACIC DYSPLASIA 9 WITH OR WITHOUT POLYDACTYLY","SHORT-RIB THORACIC DYSPLASIA 9 WITHOUT POLYDACTYLY","Saldino-Mainzer syndrome"],"diseaseFromSource":"Saldino-Mainzer syndrome","diseaseFromSourceId":"C1849437","diseaseFromSourceMappedId":"Orphanet_140969","variantHgvsId":"NC_000016.10:g.1523551C>T"} +{"alleleOrigins":["germline"],"datasourceId":"eva","datatypeId":"genetic_association","clinicalSignificances":["pathogenic"],"confidence":"criteria provided, single submitter","studyId":"RCV003398441","releaseDate":"2023-11-20","targetFromSourceId":"ENSG00000123191","variantFunctionalConsequenceId":"SO_0001583","variantId":"13_51958333_C_A","variantRsId":"rs28942074","cohortPhenotypes":["ATP7B-related condition","ATP7B-related disorder"],"diseaseFromSource":"ATP7B-related disorder","diseaseFromSourceId":null,"diseaseFromSourceMappedId":null,"variantHgvsId":"NC_000013.11:g.51958333C>A"} +{"alleleOrigins":["germline"],"datasourceId":"eva","datatypeId":"genetic_association","clinicalSignificances":["likely pathogenic","pathogenic"],"confidence":"criteria provided, multiple submitters, no conflicts","studyId":"RCV000116005","releaseDate":"2014-05-17","targetFromSourceId":"ENSG00000183765","variantFunctionalConsequenceId":"SO_0001587","variantId":"22_28687974_G_A","variantRsId":"rs200432447","cohortPhenotypes":["Cancer predisposition","Hereditary Cancer Syndrome","Hereditary cancer-predisposing syndrome","Hereditary neoplastic syndrome","Neoplastic Syndromes, Hereditary","Tumor predisposition"],"diseaseFromSource":"Hereditary cancer-predisposing syndrome","diseaseFromSourceId":"C0027672","diseaseFromSourceMappedId":"MONDO_0015356","variantHgvsId":"NC_000022.11:g.28687974G>A"} +{"alleleOrigins":["de novo"],"datasourceId":"eva","datatypeId":"genetic_association","clinicalSignificances":["pathogenic"],"confidence":"criteria provided, single submitter","studyId":"RCV000855501","releaseDate":"2019-11-08","targetFromSourceId":"ENSG00000152217","variantFunctionalConsequenceId":"SO_0001583","variantId":"18_44951952_T_C","variantRsId":"rs267607038","cohortPhenotypes":["Arthrogryposis multiplex congenita","Congenital arthromyodysplasia","Congenital multiple arthrogryposis","Fetal akinesia deformation sequence 1","Fetal akinesia sequence","Fibrous ankylosis of multiple joints","Guerin-Stern syndrome","Guérin-Stern syndrome","Lethal Pena-Shokeir 1 syndrome","Myodystrophia fetalis deformans","Otto syndrome","Pena Shokeir syndrome, type 1","Pena-Shokeir syndrome type I","Rocher-Sheldon syndrome","Rossi syndrome"],"diseaseFromSource":"Fetal akinesia deformation sequence 1","diseaseFromSourceId":"C1276035","diseaseFromSourceMappedId":"Orphanet_994","variantHgvsId":"NC_000018.10:g.44951952T>C"} diff --git a/tests/gentropy/data_samples/variant_sources/pharmacogenomics-test.jsonl b/tests/gentropy/data_samples/variant_sources/pharmacogenomics-test.jsonl new file mode 100644 index 000000000..b5cbb5dca --- /dev/null +++ b/tests/gentropy/data_samples/variant_sources/pharmacogenomics-test.jsonl @@ -0,0 +1,46 @@ +{"genotypeId":"7_87531302_A_A,C","variantId":"7_87531302_A_C","genotypeAnnotationText":"Patients with the AC genotype may have an increased risk of biopsy-proven acute rejection at 12 month post-transplant when treated with cyclosporine and mycophenolate mofetil as compared to patients with the CC genotype. Other genetic and clinical factors may also influence a patient's response to mycophenolate mofetil.","datasourceId":"pharmgkb","datasourceVersion":"2024-07-05","datatypeId":"clinical_annotation","drugs":[{"drugFromSource":"cyclosporine"}],"evidenceLevel":"3","genotype":"AC","literature":["18444945"],"pgxCategory":"efficacy","studyId":"982040619","targetFromSourceId":"ENSG00000085563","variantFunctionalConsequenceId":"SO_0001583","variantRsId":"rs2032582","phenotypeText":"increased risk of biopsy-proven acute rejection at 12 month post-transplant"} +{"genotypeId":"3_41237949_A_G,G","variantId":"3_41237949_A_G","genotypeAnnotationText":"Patients with the GG genotype and multiple myeloma may have a decreased response to cyclophosphamide, dexamethasone, and thalidomide as compared to patients with the AA genotypes. However, they may also be at decreased risk for neutropenia when treated with lenalidomide. Other genetic and clinical factors may also influence a patient's response to cyclophosphamide, dexamethasone, and thalidomide, and risk of neutropenia when treated with lenalidomide.","datasourceId":"pharmgkb","datasourceVersion":"2024-07-05","datatypeId":"clinical_annotation","drugs":[{"drugFromSource":"cyclophosphamide"}],"evidenceLevel":"3","genotype":"GG","literature":["26521987","26521987"],"pgxCategory":"toxicity","studyId":"1447953328","targetFromSourceId":"ENSG00000168036","variantFunctionalConsequenceId":"SO_0001627","variantRsId":"rs4135385","phenotypeText":null} +{"genotypeId":"18_63312127_C_T,T","variantId":"18_63312127_C_T","genotypeAnnotationText":"Patients with the TT genotype and ovarian cancer may have an increased risk of neurotoxicity when treated with carboplatin in combination with either docetaxel or paclitaxel, as compared to patients with the CC or CT genotype. Other genetic and clinical factors may also influence risk of neurotoxicity.","datasourceId":"pharmgkb","datasourceVersion":"2024-07-05","datatypeId":"clinical_annotation","drugs":[{"drugFromSource":"docetaxel"}],"evidenceLevel":"3","genotype":"TT","literature":["23963862"],"pgxCategory":"toxicity","studyId":"1183631554","targetFromSourceId":"ENSG00000171791","variantFunctionalConsequenceId":"SO_0001627","variantRsId":"rs2849380","phenotypeText":"increased risk of neurotoxicity"} +{"genotypeId":"20_34927985_A_T,T","variantId":"20_34927985_A_T","genotypeAnnotationText":"No patients with the TT genotype were available for analysis, but patients with the AT genotype and non-small-cell lung cancer may have shorter overall survival times when treated with platinum agents in combination with gemcitabine or taxanes, as compared to patients with the AA genotype. Other genetic and clinical factors may also influence overall survival times in non-small-cell lung cancer patients.","datasourceId":"pharmgkb","datasourceVersion":"2024-07-05","datatypeId":"clinical_annotation","drugs":[{"drugFromSource":"carboplatin"}],"evidenceLevel":"3","genotype":"TT","literature":["21636554"],"pgxCategory":"efficacy","studyId":"1447960379","targetFromSourceId":"ENSG00000100983","variantFunctionalConsequenceId":"SO_0001632","variantRsId":"rs17309872","phenotypeText":"shorter overall survival times"} +{"genotypeId":"9_84948455_T_C,T","variantId":"9_84948455_T_C","genotypeAnnotationText":"Patients with the CT genotype and heroin addiction may require a higher dose of methadone when undergoing methadone maintenance treatment as compared to patients with the TT genotype. Other genetic and clinical factors may also influence methadone dose required for effective treatment.","datasourceId":"pharmgkb","datasourceVersion":"2024-07-05","datatypeId":"clinical_annotation","drugs":[{"drugFromSource":"methadone"}],"evidenceLevel":"3","genotype":"CT","literature":["23651024"],"pgxCategory":"dosage","studyId":"982032396","targetFromSourceId":"ENSG00000148053","variantFunctionalConsequenceId":"SO_0001630","variantRsId":"rs2289658","phenotypeText":"require a higher dose of methadone"} +{"genotypeId":"21_36135203_G_A,A","variantId":"21_36135203_G_A","genotypeAnnotationText":"Patients with the AA genotype and breast cancer who are treated with doxorubicin: 1) may have decreased metabolism of doxorubicin 2) may have greater tumor reduction 3) may have increased severity of neutropenia as compared to patients with the GG genotype. Other genetic and clinical factors may also influence a patient's response to doxorubicin treatment and risk of toxicity.","datasourceId":"pharmgkb","datasourceVersion":"2024-07-05","datatypeId":"clinical_annotation","drugs":[{"drugFromSource":"doxorubicin"}],"evidenceLevel":"3","genotype":"AA","literature":["18551042","18551042","18551042","18551042"],"pgxCategory":"toxicity","studyId":"652882846","targetFromSourceId":"ENSG00000159231","variantFunctionalConsequenceId":"SO_0001583","variantRsId":"rs8133052","phenotypeText":"greater tumor reduction"} +{"genotypeId":"14_47546779_A_A,C","variantId":"14_47546779_A_C","genotypeAnnotationText":"Patients with the AC genotype and major depression who are treated with fluvoxamine, milnacipran or paroxetine may have an increased risk of sexual dysfunction as compared to patients with the CC genotype or may have a decreased, but not absent, risk of sexual dysfunction as compared to patients with the AA genotype. Other genetic and clinical factors may also affect patients' response to fluvoxamine, milnacipran or paroxetine.","datasourceId":"pharmgkb","datasourceVersion":"2024-07-05","datatypeId":"clinical_annotation","drugs":[{"drugFromSource":"paroxetine"}],"evidenceLevel":"3","genotype":"AC","literature":["22445761"],"pgxCategory":"toxicity","studyId":"1444700688","targetFromSourceId":"ENSG00000139915","variantFunctionalConsequenceId":"SO_0001627","variantRsId":"rs1160351","phenotypeText":"increased risk of sexual dysfunction"} +{"genotypeId":"15_78590583_G_A,A","variantId":"15_78590583_G_A","genotypeAnnotationText":"Patients with the AA genotype who are in chronic pain and receive opioid medications for treatment may be at increased risk for addiction as compared to patients with the GG genotype. Other genetic and clinical factors may also influence risk of opiate addiction.","datasourceId":"pharmgkb","datasourceVersion":"2024-07-05","datatypeId":"clinical_annotation","drugs":[{"drugFromSource":"Opium alkaloids and derivatives"}],"evidenceLevel":"3","genotype":"AA","literature":["20725741"],"pgxCategory":"toxicity","studyId":"1448101149","targetFromSourceId":"ENSG00000169684","variantFunctionalConsequenceId":"SO_0001583","variantRsId":"rs16969968","phenotypeText":"increased risk for addiction"} +{"genotypeId":"11_113475530_G_G,GG","variantId":"11_113475530_G_GG","genotypeAnnotationText":"Patients with the G/del genotype and Schizophrenia who are treated with antipsychotics 1) may have decreased response 2) may have increased time until response, compared to patients with the GG genotype. Please note that there is contradictory evidence from studies that report no association with these alleles and response to antipsychotics. Other genetic and clinical factors may also influence a patient's response to antipsychotics.","datasourceId":"pharmgkb","datasourceVersion":"2024-07-05","datatypeId":"clinical_annotation","drugs":[{"drugFromSource":"antipsychotics"}],"evidenceLevel":"3","genotype":"G/del","literature":["18926547","16513877","15830237","9858029","9858029","9918131","17105675","15694263","11505224","20194480","28673279"],"pgxCategory":"efficacy","studyId":"655388510","targetFromSourceId":"ENSG00000149295","variantFunctionalConsequenceId":"SO_0001631","variantRsId":"rs1799732","phenotypeText":"increased time until response"} +{"genotypeId":"15_78601997_G_A,A","variantId":"15_78601997_G_A","genotypeAnnotationText":"Patients with the AA genotype may be less likely to remain abstinent from smoking when treated with placebo as compared to patients with the GG genotype. Other genetic and clinical factors may also affect a patient's success at smoking cessation.","datasourceId":"pharmgkb","datasourceVersion":"2024-07-05","datatypeId":"clinical_annotation","drugs":[{"drugFromSource":"Drugs used in nicotine dependence"}],"evidenceLevel":"3","genotype":"AA","literature":["23249876"],"pgxCategory":"other","studyId":"1450929137","targetFromSourceId":"ENSG00000080644","variantFunctionalConsequenceId":"SO_0001819","variantRsId":"rs1051730","phenotypeText":"less likely to remain abstinent from smoking"} +{"genotypeId":"1_46405089_C_A,C","variantId":"1_46405089_C_A","genotypeAnnotationText":"Patients with the AC genotype and Psychotic Disorders who are treated with aripiprazole, clozapine, haloperidol, olanzapine, quetiapine or risperidone may have an increased likelihood of weight gain of more than 7% of baseline body weight as compared to patients with the CC genotype. However, this is contradicted in one study with risperidone. Other genetic and clinical factors may also influence a patient's risk for treatment-induced weight gain.","datasourceId":"pharmgkb","datasourceVersion":"2024-07-05","datatypeId":"clinical_annotation","drugs":[{"drugFromSource":"haloperidol"}],"evidenceLevel":"3","genotype":"AC","literature":["20631561","23799528"],"pgxCategory":"toxicity","studyId":"1043880750","targetFromSourceId":"ENSG00000117480","variantFunctionalConsequenceId":"SO_0001583","variantRsId":"rs324420","phenotypeText":"increased likelihood of weight gain of more than 7% of baseline body weight"} +{"genotypeId":"4_88174909_G_A,G","variantId":"4_88174909_G_A","genotypeAnnotationText":"Patients with the AG genotype may have increased tumor response rate and increased risk of grade 3-4 nonhematological toxicity when treated with fluorouracil, irinotecan and leucovorin as compared to patients with the GG genotype or may have decreased tumor response rate and decreased risk of grade 3-4 nonhematological toxicity when treated with fluorouracil, irinotecan and leucovorin as compared to patients with the AA genotype. Other genetic and clinical factors may also influence a patient's response to fluorouracil, irinotecan and leucovorin.","datasourceId":"pharmgkb","datasourceVersion":"2024-07-05","datatypeId":"clinical_annotation","drugs":[{"drugFromSource":"leucovorin"}],"evidenceLevel":"3","genotype":"AG","literature":["24018773","24018773"],"pgxCategory":"efficacy","studyId":"1444700860","targetFromSourceId":"ENSG00000118777","variantFunctionalConsequenceId":"SO_0001627","variantRsId":"rs7699188","phenotypeText":"increased tumor response rate"} +{"genotypeId":"X_154536002_C_T,T","variantId":"X_154536002_C_T","genotypeAnnotationText":"Patients with the TT genotype with Malaria who are treated with artesunate, chlorproguanil and dapsone may have an increased risk of hemolysis and severe/unsafe hemoglobin decreases as compared to patients with the CC genotype. Other genetic and clinical factors may also influence a patient's response to artesunate, chlorproguanil and dapsone.","datasourceId":"pharmgkb","datasourceVersion":"2024-07-05","datatypeId":"clinical_annotation","drugs":[{"drugFromSource":"artesunate"}],"evidenceLevel":"4","genotype":"TT","literature":["19112496","19690618","19690618"],"pgxCategory":"toxicity","studyId":"981352141","targetFromSourceId":"ENSG00000160211","variantFunctionalConsequenceId":"SO_0001583","variantRsId":"rs1050828","phenotypeText":"increased risk of hemolysis and severe/unsafe hemoglobin decreases"} +{"genotypeId":"17_18328782_G_A,A","variantId":"17_18328782_G_A","genotypeAnnotationText":"Pediatric patients with the AA genotype and with Precursor Cell Lymphoblastic Leukemia-Lymphoma who are treated with methotrexate may have increased catalytic activity of TYMS as compared to pediatric patients with the AG and GG genotype. Patients with the AA genotype and with Precursor Cell Lymphoblastic Leukemia-Lymphoma who are treated with methotrexate may have increased likelihood of Toxic liver disease as compared to patients with the AG genotype. However, this association is contradicted in other studies. Other genetic and clinical factors may also influence a patient's response to methotrexate.","datasourceId":"pharmgkb","datasourceVersion":"2024-07-05","datatypeId":"clinical_annotation","drugs":[{"drugFromSource":"methotrexate"}],"evidenceLevel":"3","genotype":"AA","literature":["22838948","18368069","15797993"],"pgxCategory":"toxicity","studyId":"981238370","targetFromSourceId":"ENSG00000176974","variantFunctionalConsequenceId":"SO_0001583","variantRsId":"rs1979277","phenotypeText":"increased catalytic activity of TYMS"} +{"genotypeId":"4_88131171_G_T,T","variantId":"4_88131171_G_T","genotypeAnnotationText":"Patients with the TT genotype and HIV infection who are treated with efavirenz may have an increased risk of abnormal dreams as compared to patients with the GG genotype. Other genetic and clinical factors may also influence a patient's risk of efavirenz-induced side effects.","datasourceId":"pharmgkb","datasourceVersion":"2024-07-05","datatypeId":"clinical_annotation","drugs":[{"drugFromSource":"efavirenz"}],"evidenceLevel":"3","genotype":"TT","literature":["23859571"],"pgxCategory":"toxicity","studyId":"1183614716","targetFromSourceId":"ENSG00000118777","variantFunctionalConsequenceId":"SO_0001583","variantRsId":"rs2231142","phenotypeText":"increased risk of abnormal dreams"} +{"genotypeId":"19_45351661_T_G,G","variantId":"19_45351661_T_G","genotypeAnnotationText":"Patients with the GG genotype and Colorectal Neoplasms who are treated with fluorouracil and leucovorin or fluorouracil, leucovorin and oxaliplatin may have 1) an increased risk of Drug Toxicity 2) an increased risk of early relapse and 3) decreased progression free survival as compared to patients with the TT genotype. Other genetic and clinical factors may also influence a patient's response to fluorouracil, leucovorin and oxaliplatin.","datasourceId":"pharmgkb","datasourceVersion":"2024-07-05","datatypeId":"clinical_annotation","drugs":[{"drugFromSource":"fluorouracil"}],"evidenceLevel":"3","genotype":"GG","literature":["20385995","18267032","20078613"],"pgxCategory":"efficacy","studyId":"981237959","targetFromSourceId":"ENSG00000104884","variantFunctionalConsequenceId":"SO_0001583","variantRsId":"rs13181","phenotypeText":"increased risk of Drug Toxicity"} +{"genotypeId":"6_35639794_T_C,C","variantId":"6_35639794_T_C","genotypeAnnotationText":"Patients with the CC genotype may 1) have decreased response to antidepressants 2) have decreased, but not absent, risk for suicide ideation with paroxetine, venlafaxine, clomipramine, lithium, liothyronine or nefazodone as compared to patients with the CT or TT genotype. However, contradictory findings regarding an association of the opposite allele or no association with response have been reported. Other genetic and clinical factors may also influence a patient's response to antidepressants.","datasourceId":"pharmgkb","datasourceVersion":"2024-07-05","datatypeId":"clinical_annotation","drugs":[{"drugFromSource":"antidepressants"}],"evidenceLevel":"3","genotype":"CC","literature":["20709156","17467808","23733030","23733030","18597649","21449676","21449676","19676097","15565110"],"pgxCategory":"efficacy","studyId":"655384568","targetFromSourceId":"ENSG00000096060","variantFunctionalConsequenceId":"SO_0001627","variantRsId":"rs1360780","phenotypeText":"decreased response to antidepressants"} +{"genotypeId":"5_112865397_A_A,G","variantId":"5_112865397_A_G","genotypeAnnotationText":"Patients with the AG genotype and major depressive disorder may be less likely to respond when treated with citalopram, fluoxetine, paroxetine or sertraline as compared to patients with the GG genotype, or more likely to respond when treated with citalopram, fluoxetine, paroxetine or sertraline as compared to patients with the AA genotype. Other genetic and clinical factors may also influence response to citalopram, fluoxetine, paroxetine or sertraline.","datasourceId":"pharmgkb","datasourceVersion":"2024-07-05","datatypeId":"clinical_annotation","drugs":[{"drugFromSource":"citalopram"}],"evidenceLevel":"3","genotype":"AG","literature":["22795047"],"pgxCategory":"efficacy","studyId":"1183590959","targetFromSourceId":"ENSG00000153037","variantFunctionalConsequenceId":"SO_0001627","variantRsId":"rs495794","phenotypeText":"less likely to respond"} +{"genotypeId":"22_19963748_G_A,G","variantId":"22_19963748_G_A","genotypeAnnotationText":"Patients with the AG genotype and major Depressive Disorder may have an increased response to fluvoxamine treatment as compared to patients with the GG genotype. Other genetic and clinical factors may also influence a patient's response to fluvoxamine.","datasourceId":"pharmgkb","datasourceVersion":"2024-07-05","datatypeId":"clinical_annotation","drugs":[{"drugFromSource":"fluvoxamine"}],"evidenceLevel":"3","genotype":"AG","literature":["20619611"],"pgxCategory":"efficacy","studyId":"1043880039","targetFromSourceId":"ENSG00000093010","variantFunctionalConsequenceId":"SO_0001583","variantRsId":"rs4680","phenotypeText":"increased response"} +{"genotypeId":"10_94761900_C_T,T","variantId":"10_94761900_C_T","genotypeAnnotationText":"Patients with the TT genotype and breast cancer may have a decreased risk for leukopenia when treated with cyclophosphamide, doxorubicin and fluorouracil (FAC) as compared to patients with CC genotype. Other genetic and clinical factors may also influence risk for leukopenia in patients taking FAC chemotherapy.","datasourceId":"pharmgkb","datasourceVersion":"2024-07-05","datatypeId":"clinical_annotation","drugs":[{"drugFromSource":"cyclophosphamide"}],"evidenceLevel":"3","genotype":"TT","literature":["29507678"],"pgxCategory":"toxicity","studyId":"1449718265","targetFromSourceId":"ENSG00000165841","variantFunctionalConsequenceId":"SO_0001631","variantRsId":"rs12248560","phenotypeText":"decreased risk for leukopenia"} +{"genotypeId":"3_114171968_C_T,T","variantId":"3_114171968_C_T","genotypeAnnotationText":"Patients with the TT genotype and Schizophrenia who are treated with clozapine may have a better response to treatment as compared to patients with the CC or CT genotype. Please note; this association was not found in a meta-analysis. Other genetic and clinical factors may also influence a patient's response to clozapine treatment.","datasourceId":"pharmgkb","datasourceVersion":"2024-07-05","datatypeId":"clinical_annotation","drugs":[{"drugFromSource":"clozapine"}],"evidenceLevel":"3","genotype":"TT","literature":["21332319","20029384"],"pgxCategory":"efficacy","studyId":"981203578","targetFromSourceId":"ENSG00000151577","variantFunctionalConsequenceId":"SO_0001583","variantRsId":"rs6280","phenotypeText":"better response to treatment"} +{"genotypeId":"19_45409478_C_A,G","variantId":"19_45409478_C_A","genotypeAnnotationText":"Patients with Mesothelioma and the AC genotype may have worse overall and progression-free survival when treated with cisplatin and gemcitabine as compared to patients with the CC genotype. Other clinical and genetic factors may also influence response to cisplatin and gemcitabine in patients with mesothelioma.","datasourceId":"pharmgkb","datasourceVersion":"2024-07-05","datatypeId":"clinical_annotation","drugs":[{"drugFromSource":"cisplatin"}],"evidenceLevel":"3","genotype":"AG","literature":["28422153"],"pgxCategory":"efficacy","studyId":"1449004745","targetFromSourceId":"ENSG00000012061","variantFunctionalConsequenceId":"SO_0001624","variantRsId":"rs3212986","phenotypeText":"worse overall and progression-free survival"} +{"genotypeId":"2_233671807_A_A,AT","variantId":"2_233671807_A_AT","genotypeAnnotationText":"Patients with the rs3832043 T/del genotype and non-small cell lung cancer may have decreased glucuronidation of SN-38 as compared to patients with the TT genotype, or increased glucuronidation of SN-38 as compared to patients with the del/del genotype. SN-38 is the active metabolite of irinotecan, and is glucuronidated by UGT1A9 into an inactive form (SN-38G). This annotation only covers the pharmacokinetic relationship between rs3832043 and SN-38 and does not include evidence about clinical outcomes. Other genetic and clinical factors may also influence SN-38 metabolism.","datasourceId":"pharmgkb","datasourceVersion":"2024-07-05","datatypeId":"clinical_annotation","drugs":[{"drugFromSource":"SN-38"}],"evidenceLevel":"3","genotype":"T/del","literature":["24897286","18221820","16636344"],"pgxCategory":"metabolism/pk","studyId":"1183615199","targetFromSourceId":"ENSG00000242515","variantFunctionalConsequenceId":"SO_0001627","variantRsId":"rs3832043","phenotypeText":"decreased glucuronidation"} +{"genotypeId":"18_673016_C_T,T","variantId":"18_673016_C_T","genotypeAnnotationText":"Patients with the TT genotype and cancer who are treated with Capecitabine may have an increased risk of of nausea and vomiting as compared to patients with the CC or CT genotypes and a decreased likelihood of asthenia as compared to the CC genotype. Other clinical and genetic factors may also influence nausea and vomiting in patients with cancer who are treated with Capecitabine.","datasourceId":"pharmgkb","datasourceVersion":"2024-07-05","datatypeId":"clinical_annotation","drugs":[{"drugFromSource":"capecitabine"}],"evidenceLevel":"3","genotype":"TT","literature":["28347776","28347776"],"pgxCategory":"toxicity","studyId":"1448616922","targetFromSourceId":"ENSG00000132199","variantFunctionalConsequenceId":"SO_0001624","variantRsId":"rs699517","phenotypeText":"decreased likelihood of asthenia"} +{"genotypeId":"17_5379957_A_G,G","variantId":"17_5379957_A_G","genotypeAnnotationText":"Patients with bipolar, depressive, psychotic, or schizoaffective disorders and the GG genotype who are administered amisulpride, aripiprazole, clozapine, olanzapine, quetiapine, paliperidone, risperidone, lithium, valproate or/and mirtazapine may have smaller elevations of fasting glucose concentrations as compared to patients with the AA genotype. Other clinical and genetic factors may also influence fasting glucose concentrations in patients administered these medications.","datasourceId":"pharmgkb","datasourceVersion":"2024-07-05","datatypeId":"clinical_annotation","drugs":[{"drugFromSource":"valproic acid"}],"evidenceLevel":"3","genotype":"GG","literature":["28694205"],"pgxCategory":"other","studyId":"1449005382","targetFromSourceId":"ENSG00000108559","variantFunctionalConsequenceId":"SO_0001627","variantRsId":"rs1000940","phenotypeText":"smaller elevations of fasting glucose concentrations"} +{"genotypeId":"20_54684529_G_A,G","variantId":"20_54684529_G_A","genotypeAnnotationText":"Pediatric patients with acute lymphoblastic leukemia (ALL) and the AG genotype may have an increased risk of developing osteonecrosis when treated with cyclophosphamide, cytarabine, daunorubicin, dexamethasone, doxorubicin, methotrexate, pegaspargase, prednisone, thioguanine and vincristine as compared to pediatric ALL patients with the GG genotypes and a decreased risk of osteonecrosis as compared to pediatric patients with the AA genotype. Other clinical and genetic factors may also influence the risk of developing osteonecrosis in pediatric ALL patients.","datasourceId":"pharmgkb","datasourceVersion":"2024-07-05","datatypeId":"clinical_annotation","drugs":[{"drugFromSource":"pegaspargase"}],"evidenceLevel":"3","genotype":"AG","literature":["26590194"],"pgxCategory":"toxicity","studyId":"1448099093","targetFromSourceId":null,"variantFunctionalConsequenceId":null,"variantRsId":"rs117532069","phenotypeText":"increased risk of developing osteonecrosis"} +{"genotypeId":"8_18390208_T_A,A","variantId":"8_18390208_T_A","genotypeAnnotationText":"Patients with the AA genotype and tuberculosis (TB) may have an increased risk for anti-TB drug-induced hepatitis as compared to patients with the TT genotype. Cells with the A allele have been shown to result in decreased transcription of the NAT2 gene as compared to those with the T allele. Other genetic and clinical factors may also influence risk of hepatitis in patients taking anti-TB drugs.","datasourceId":"pharmgkb","datasourceVersion":"2024-07-05","datatypeId":"clinical_annotation","drugs":[{"drugFromSource":"rifampin"}],"evidenceLevel":"3","genotype":"AA","literature":["19891553","19891553","19891553"],"pgxCategory":"metabolism/pk","studyId":"1447964123","targetFromSourceId":"ENSG00000156006","variantFunctionalConsequenceId":"SO_0001631","variantRsId":"rs4646244","phenotypeText":"increased risk for anti-TB drug-induced hepatitis"} +{"genotypeId":"21_45537880_T_C,T","variantId":"21_45537880_T_C","genotypeAnnotationText":"Patients with the rs1051266 CT genotype and rheumatoid arthritis may have decreased response when treated with methotrexate as compared to patients with the TT genotype. However, conflicting evidence has been reported. Other genetic and clinical factors may also influence methotrexate response.","datasourceId":"pharmgkb","datasourceVersion":"2024-07-05","datatypeId":"clinical_annotation","drugs":[{"drugFromSource":"methotrexate"}],"evidenceLevel":"2A","genotype":"CT","literature":["19827168","15677700","22450926","15457444","18322994","17325736","17325736","31099054","26616421","27992285"],"pgxCategory":"efficacy","studyId":"1451245360","targetFromSourceId":"ENSG00000173638","variantFunctionalConsequenceId":"SO_0001583","variantRsId":"rs1051266","phenotypeText":"decreased response"} +{"genotypeId":"9_9687487_C_T,T","variantId":"9_9687487_C_T","genotypeAnnotationText":"Patients with the TT genotype may have higher risk for resistant hypertension in whites and Hispanics patients treated with verapamil and trandolapril as compared to patients with genotype CC. Other genetic and clinical factors may also influence the response to verapamil.","datasourceId":"pharmgkb","datasourceVersion":"2024-07-05","datatypeId":"clinical_annotation","drugs":[{"drugFromSource":"trandolapril"}],"evidenceLevel":"3","genotype":"TT","literature":["26425837"],"pgxCategory":"efficacy","studyId":"1446902927","targetFromSourceId":"ENSG00000153707","variantFunctionalConsequenceId":"SO_0001627","variantRsId":"rs4742610","phenotypeText":"higher risk for resistant hypertension"} +{"genotypeId":"12_21178615_T_C,C","variantId":"12_21178615_T_C","genotypeAnnotationText":"Patients with precursor cell lymphoblastic leukemia-lymphoma and the rs4149056 CC genotype may have a decreased response to methotrexate as compared to patients with the CT and TT genotypes. However, conflicting evidence has been reported. Other clinical and genetic factors may also influence response to methotrexate.","datasourceId":"pharmgkb","datasourceVersion":"2024-07-05","datatypeId":"clinical_annotation","drugs":[{"drugFromSource":"methotrexate"}],"evidenceLevel":"3","genotype":"CC","literature":["24386571","28525903"],"pgxCategory":"efficacy","studyId":"1449004841","targetFromSourceId":"ENSG00000134538","variantFunctionalConsequenceId":"SO_0001583","variantRsId":"rs4149056","phenotypeText":"decreased response to methotrexate"} +{"genotypeId":"X_114584047_C_T","variantId":"X_114584047_C_T","genotypeAnnotationText":"Patients with one X-chromosome, the T genotype and psychiatric disorders who are treated with olanzapine may have a decreased risk of weight gain as compared to patients with the C genotype. This gene is on the X chromosome and males have only one allele. However, some studies find no association with weight gain. Other genetic and clinical factors may also influence a patient's risk for weight gain with antipsychotic treatment.","datasourceId":"pharmgkb","datasourceVersion":"2024-07-05","datatypeId":"clinical_annotation","drugs":[{"drugFromSource":"olanzapine"}],"evidenceLevel":"3","genotype":"T","literature":["17702092","22967772","21121776","19636338","15666332","19434072","25152019","18718676","17016522","20504252","19193342"],"pgxCategory":"toxicity","studyId":"1451256440","targetFromSourceId":"ENSG00000147246","variantFunctionalConsequenceId":"SO_0001631","variantRsId":"rs3813929","phenotypeText":"decreased risk of weight gain"} +{"genotypeId":"5_148826877_G_A,G","variantId":"5_148826877_G_A","genotypeAnnotationText":"Patients with the AG genotype and hypertension may have a greater decrease in diastolic blood pressure when treated with benazepril as compared to patients with the AA genotype. No significant results have been seen for systolic blood pressure. Additionally, the same study reported no significant differences in systolic or diastolic blood pressure between genotypes in a different cohort. Other genetic and clinical factors may also influence change in diastolic or systolic blood pressure.","datasourceId":"pharmgkb","datasourceVersion":"2024-07-05","datatypeId":"clinical_annotation","drugs":[{"drugFromSource":"benazepril"}],"evidenceLevel":"4","genotype":"AG","literature":["15554460","15554460","15554460"],"pgxCategory":"efficacy","studyId":"1183614850","targetFromSourceId":"ENSG00000169252","variantFunctionalConsequenceId":"SO_0001583","variantRsId":"rs1042713","phenotypeText":"greater decrease in diastolic blood pressure"} +{"genotypeId":"16_28606193_C_C,T","variantId":"16_28606193_C_T","genotypeAnnotationText":"Patients with the CT genotype may have a decreased response to acetaminophen (paracetamol) as compared to patients with the CC genotype. Other genetic and clinical factors may also affect a patient's response to acetaminophen.","datasourceId":"pharmgkb","datasourceVersion":"2024-07-05","datatypeId":"clinical_annotation","drugs":[{"drugFromSource":"acetaminophen"}],"evidenceLevel":"3","genotype":"CT","literature":["30908574"],"pgxCategory":"efficacy","studyId":"1450374089","targetFromSourceId":"ENSG00000196502","variantFunctionalConsequenceId":"SO_0001583","variantRsId":"rs1042028","phenotypeText":"decreased response to acetaminophen (paracetamol)"} +{"genotypeId":"13_46834899_G_A,A","variantId":"13_46834899_G_A","genotypeAnnotationText":"Patients with the AA genotype and major depressive disorder who are treated with antidepressants and other treatments may have a reduced response and reduced likelihood of remission as compared to patients with the AG or GG genotype. Other genetic and clinical factors may also influence a patient's response to treatment for major depressive disorder and likelihood of remission.","datasourceId":"pharmgkb","datasourceVersion":"2024-07-05","datatypeId":"clinical_annotation","drugs":[{"drugFromSource":"antidepressants"}],"evidenceLevel":"3","genotype":"AA","literature":["11311507","18253134","18253134","20075642"],"pgxCategory":"efficacy","studyId":"1183618924","targetFromSourceId":"ENSG00000102468","variantFunctionalConsequenceId":"SO_0001583","variantRsId":"rs6314","phenotypeText":"reduced response and reduced likelihood of remission"} +{"genotypeId":"16_55810697_G_G,T","variantId":"16_55810697_G_T","genotypeAnnotationText":"Patients with the GT genotype and Atrial Fibrillation who are treated with dabigatran may have 1) a decreased adjusted trough concentrations of dabigatran, 2) a decreased, but not absent, risk for bleeding when treated with dabigatran as compared to patients with the TT genotype. Other genetic and clinical factors may also influence a patient's risk for bleeding.","datasourceId":"pharmgkb","datasourceVersion":"2024-07-05","datatypeId":"clinical_annotation","drugs":[{"drugFromSource":"dabigatran"}],"evidenceLevel":"3","genotype":"GT","literature":["23467860","23467860","27261537"],"pgxCategory":"toxicity","studyId":"1183490952","targetFromSourceId":"ENSG00000198848","variantFunctionalConsequenceId":"SO_0001627","variantRsId":"rs2244613","phenotypeText":"decreased, but not absent, risk for bleeding"} +{"genotypeId":"22_19963748_G_A,A","variantId":"22_19963748_G_A","genotypeAnnotationText":"Patients with the AA genotype with substance withdrawal syndrome may have a decreased likelihood of headache when discontinuing the use of analgesics (such as opioids, NSAIDs, triptans, ergot) as compared to patients with the AG and GG genotypes. Other clinical and genetic factors may also influence likelihood of headache in patients with withdrawal syndrome who discontinue the use of analgesics.","datasourceId":"pharmgkb","datasourceVersion":"2024-07-05","datatypeId":"clinical_annotation","drugs":[{"drugFromSource":"sumatriptan"}],"evidenceLevel":"3","genotype":"AA","literature":["25096645"],"pgxCategory":"other","studyId":"1184987573","targetFromSourceId":"ENSG00000093010","variantFunctionalConsequenceId":"SO_0001583","variantRsId":"rs4680","phenotypeText":"decreased likelihood of headache"} +{"genotypeId":"10_99804058_G_A,A","variantId":"10_99804058_G_A","genotypeAnnotationText":"Patients with the AA genotype and gastrointestinal stromal tumors may have increased progression-free survival times when treated with imatinib as compared to patients with the GG genotype. Other genetic and clinical factors may also influence progression-free survival tumes in patients receiving imatinib.","datasourceId":"pharmgkb","datasourceVersion":"2024-07-05","datatypeId":"clinical_annotation","drugs":[{"drugFromSource":"imatinib"}],"evidenceLevel":"3","genotype":"AA","literature":["30237583"],"pgxCategory":"efficacy","studyId":"1450373604","targetFromSourceId":"ENSG00000023839","variantFunctionalConsequenceId":"SO_0001583","variantRsId":"rs2273697","phenotypeText":"increased progression-free survival times"} +{"genotypeId":"6_154039662_A_G,G","variantId":"6_154039662_A_G","genotypeAnnotationText":"Patients with the rs1799971 GG genotype may have increased alfentanil dose requirements as compared to patients with the AA genotype. This drug-variant pair has been assigned a “no recommendation” by CPIC, as it was determined to be not clinically actionable. Other genetic or clinical factors may also affect a alfentanil dose requirements.","datasourceId":"pharmgkb","datasourceVersion":"2024-07-05","datatypeId":"clinical_annotation","drugs":[{"drugFromSource":"alfentanil"}],"evidenceLevel":"3","genotype":"GG","literature":["19605407"],"pgxCategory":"dosage","studyId":"1450826899","targetFromSourceId":"ENSG00000112038","variantFunctionalConsequenceId":"SO_0001583","variantRsId":"rs1799971","phenotypeText":"increased alfentanil dose requirements"} +{"genotypeId":"14_103699416_G_A,A","variantId":"14_103699416_G_A","genotypeAnnotationText":"Patients with the AA genotype and non-small cell lung cancer may have an improved response when treated with platinum compounds as compared to patients with the GG genotype, although this is contradicted in one study. Other clinical or genetic factors may also influence a patient's response to platinum compounds in people with non-small cell lung cancer.","datasourceId":"pharmgkb","datasourceVersion":"2024-07-05","datatypeId":"clinical_annotation","drugs":[{"drugFromSource":"Platinum compounds"}],"evidenceLevel":"3","genotype":"AA","literature":["23940523","23940523","27248474"],"pgxCategory":"efficacy","studyId":"1043872993","targetFromSourceId":"ENSG00000126215","variantFunctionalConsequenceId":"SO_0001583","variantRsId":"rs861539","phenotypeText":"improved response"} +{"genotypeId":"11_67585218_A_A,G","variantId":"11_67585218_A_G","genotypeAnnotationText":"Patients with the AG genotype and Ovarian Neoplasms who are treated with cisplatin and cyclophosphamide may have a decreased likelihood of progression free survival as compared to patients with the AA genotype. However, this association was contradicted in other studies. Other genetic and clinical factors may also influence a patient's response to cisplatin and cyclophosphamide treatment.","datasourceId":"pharmgkb","datasourceVersion":"2024-07-05","datatypeId":"clinical_annotation","drugs":[{"drugFromSource":"cyclophosphamide"}],"evidenceLevel":"3","genotype":"AG","literature":["22188361","19786980"],"pgxCategory":"efficacy","studyId":"981237950","targetFromSourceId":"ENSG00000084207","variantFunctionalConsequenceId":"SO_0001583","variantRsId":"rs1695","phenotypeText":"decreased likelihood of progression free survival"} +{"genotypeId":"7_87509329_A_A,G","variantId":"7_87509329_A_G","genotypeAnnotationText":"Patients with the AG genotype and schizophrenia who responded to treatment with antipsychotics may require a decreased dose of antipsychotics as compared to patients with the GG genotype, or an increased dose as compared to patients with the AA genotype. Other genetic and clinical factors may also influence dose of antipsychotics.","datasourceId":"pharmgkb","datasourceVersion":"2024-07-05","datatypeId":"clinical_annotation","drugs":[{"drugFromSource":"antipsychotics"}],"evidenceLevel":"3","genotype":"AG","literature":["22909202"],"pgxCategory":"dosage","studyId":"1447983818","targetFromSourceId":"ENSG00000085563","variantFunctionalConsequenceId":"SO_0001819","variantRsId":"rs1045642","phenotypeText":"require a decreased dose of antipsychotics"} +{"genotypeId":"12_21178615_T_C,C","variantId":"12_21178615_T_C","genotypeAnnotationText":"Patients with the rs4149056 CC genotype may have increased concentrations of pitavastatin when treated with pitavastatin as compared to patients with TT genotype. Other genetic and clinical factors may also influence the metabolism of pitavastatin. This annotation only covers the pharmacokinetic relationship between rs4149056 and pitavastatin and does not include evidence about clinical outcomes.","datasourceId":"pharmgkb","datasourceVersion":"2024-07-05","datatypeId":"clinical_annotation","drugs":[{"drugFromSource":"pitavastatin"}],"evidenceLevel":"1A","genotype":"CC","literature":["23556337","17460607"],"pgxCategory":"metabolism/pk","studyId":"1451678210","targetFromSourceId":"ENSG00000134538","variantFunctionalConsequenceId":"SO_0001583","variantRsId":"rs4149056","phenotypeText":"increased concentrations of pitavastatin"} +{"genotypeId":"8_18400860_G_A,A","variantId":"8_18400860_G_A","genotypeAnnotationText":"Patients with the AA genotype may have decreased but not absent risk of toxicity with docetaxel and thalidomide as compared to patients with the AG or GG genotypes. Other genetic and clinical factors may also influence treatment response.","datasourceId":"pharmgkb","datasourceVersion":"2024-07-05","datatypeId":"clinical_annotation","drugs":[{"drugFromSource":"thalidomide"}],"evidenceLevel":"3","genotype":"AA","literature":["20038957"],"pgxCategory":"toxicity","studyId":"655386176","targetFromSourceId":"ENSG00000156006","variantFunctionalConsequenceId":"SO_0001583","variantRsId":"rs1799931","phenotypeText":"decreased risk of toxicity"} +{"genotypeId":"13_46895805_G_A,A","variantId":"13_46895805_G_A","genotypeAnnotationText":"Patients with the rs6313 AA genotype and major depressive disorder may be more likely to develop sexual dysfunction and less likely to develop heart palpitations and when treated with citalopram as compared to patients with the AG or GG genotype. The current evidence base suggests that there is no association between the genotype and gastrointestinal toxicity. Other genetic and clinical factors may also influence likelihood of developing sexual dysfunction when treated with citalopram.","datasourceId":"pharmgkb","datasourceVersion":"2024-07-05","datatypeId":"clinical_annotation","drugs":[{"drugFromSource":"citalopram"}],"evidenceLevel":"3","genotype":"AA","literature":["31792367","23158458","23158458","30221791"],"pgxCategory":"toxicity","studyId":"1451407329","targetFromSourceId":"ENSG00000102468","variantFunctionalConsequenceId":"SO_0001819","variantRsId":"rs6313","phenotypeText":"less likely to develop heart palpitations"} +{"genotypeId":"2_233772999_G_C,C","variantId":"2_233772999_G_C","genotypeAnnotationText":"Patients with the CC genotype and HIV may have a decreased risk of nephrolithiasis when treated with atazanavir and ritonavir as compared to patients with the CG and GG genotypes. Other genetic and clinical factors may also affect risk of nephrolithiasis in patients with HIV who are taking atazanavir and ritonavir.","datasourceId":"pharmgkb","datasourceVersion":"2024-07-05","datatypeId":"clinical_annotation","drugs":[{"drugFromSource":"ritonavir"}],"evidenceLevel":"3","genotype":"CC","literature":["25151207"],"pgxCategory":"toxicity","studyId":"1185000369","targetFromSourceId":"ENSG00000244474","variantFunctionalConsequenceId":"SO_0001624","variantRsId":"rs8330","phenotypeText":"decreased risk of nephrolithiasis"} +{"genotypeId":"1_161215085_A_A,G","variantId":"1_161215085_A_G","genotypeAnnotationText":"Patients with the AG genotype and asthma may have a decreased risk for aspirin sensitivity but patients with chronic urticaria may have an increased risk for aspirin sensitivity as compared to patients with the AA genotype. Other genetic and clinical factors may also influence a patient's risk for aspirin sensitivity.","datasourceId":"pharmgkb","datasourceVersion":"2024-07-05","datatypeId":"clinical_annotation","drugs":[{"drugFromSource":"aspirin"}],"evidenceLevel":"3","genotype":"AG","literature":["18534082","18595682"],"pgxCategory":"toxicity","studyId":"1043858680","targetFromSourceId":"ENSG00000158869","variantFunctionalConsequenceId":"SO_0001631","variantRsId":"rs11587213","phenotypeText":"decreased risk for aspirin sensitivity"} diff --git a/tests/gentropy/data_samples/variant_sources/uniprot-test-sort.jsonl b/tests/gentropy/data_samples/variant_sources/uniprot-test-sort.jsonl new file mode 100644 index 000000000..c408b4fe4 --- /dev/null +++ b/tests/gentropy/data_samples/variant_sources/uniprot-test-sort.jsonl @@ -0,0 +1,9 @@ +{"confidence":"high","datasourceId":"uniprot_variants","datatypeId":"genetic_association","diseaseFromSource":"Pontocerebellar hypoplasia, hypotonia, and respiratory insufficiency syndrome, neonatal lethal","diseaseFromSourceId":"OMIM:618810","diseaseFromSourceMappedId":"MONDO_0032931","literature":"['31727539']","targetFromSourceId":"Q9NVI7","targetModulation":"up_or_down","variantRsId":"rs1570345942","variantFunctionalConsequenceId":"SO_0001583","variantId":"1_1525242_T_G"} +{"confidence":"high","datasourceId":"uniprot_variants","datatypeId":"genetic_association","diseaseFromSource":"Charcot-Marie-Tooth disease, demyelinating, 1B","diseaseFromSourceId":"OMIM:118200","diseaseFromSourceMappedId":"MONDO_0007307","literature":"['8797476', '7688964', '10737979', '11437164', '12221176', '14711881']","targetFromSourceId":"P25189","targetModulation":"up_or_down","variantRsId":"rs121913589","variantFunctionalConsequenceId":"SO_0001583","variantId":"1_161306863_C_T"} +{"confidence":"high","datasourceId":"uniprot_variants","datatypeId":"genetic_association","diseaseFromSource":"Achromatopsia 2","diseaseFromSourceId":"OMIM:216900","diseaseFromSourceMappedId":null,"literature":"['9662398', '11536077', '18521937']","targetFromSourceId":"Q16281","targetModulation":"up_or_down","variantRsId":"rs104893614","variantFunctionalConsequenceId":"SO_0001583","variantId":"2_98396018_G_A"} +{"confidence":"high","datasourceId":"uniprot_variants","datatypeId":"genetic_association","diseaseFromSource":"Brugada syndrome 1","diseaseFromSourceId":"OMIM:601144","diseaseFromSourceMappedId":"MONDO_0011001","literature":"['20129283']","targetFromSourceId":"Q14524","targetModulation":"up_or_down","variantRsId":"rs199473172","variantFunctionalConsequenceId":"SO_0001583","variantId":"3_38585800_C_T"} +{"confidence":"high","datasourceId":"uniprot_variants","datatypeId":"genetic_association","diseaseFromSource":"Ataxia telangiectasia","diseaseFromSourceId":"OMIM:208900","diseaseFromSourceMappedId":"Orphanet_100","literature":"['10817650', '10873394', '9288106', '9443866']","targetFromSourceId":"Q13315","targetModulation":"up_or_down","variantRsId":"rs587779872","variantFunctionalConsequenceId":"SO_0001583","variantId":"11_108345818_C_G"} +{"confidence":"high","datasourceId":"uniprot_variants","datatypeId":"genetic_association","diseaseFromSource":"Autoimmune polyendocrine syndrome 1, with or without reversible metaphyseal dysplasia","diseaseFromSourceId":"OMIM:240300","diseaseFromSourceMappedId":"Orphanet_3453","literature":"['11524733', '11836330', '15712268', '14974083', '11524731']","targetFromSourceId":"O43918","targetModulation":"up_or_down","variantRsId":"rs179363880","variantFunctionalConsequenceId":"SO_0001583","variantId":"21_44286656_T_A"} +{"confidence":"high","datasourceId":"uniprot_variants","datatypeId":"genetic_association","diseaseFromSource":"Lowe oculocerebrorenal syndrome","diseaseFromSourceId":"OMIM:309000","diseaseFromSourceMappedId":"MONDO_0010645","literature":"['10923037']","targetFromSourceId":"Q01968","targetModulation":"up_or_down","variantRsId":"rs137853854","variantFunctionalConsequenceId":"SO_0001583","variantId":"X_129562612_G_A"} +{"confidence":"high","datasourceId":"uniprot_variants","datatypeId":"genetic_association","diseaseFromSource":"46,XY sex reversal 1","diseaseFromSourceId":"OMIM:400044","diseaseFromSourceMappedId":"MONDO_0020712","literature":"['2247149', '1570829']","targetFromSourceId":"Q05066","targetModulation":"up_or_down","variantRsId":"rs104894957","variantFunctionalConsequenceId":"SO_0001583","variantId":"Y_2787426_C_G"} +{"confidence":"medium","datasourceId":"uniprot_variants","datatypeId":"genetic_association","diseaseFromSource":"Colorectal cancer","diseaseFromSourceId":"OMIM:114500","diseaseFromSourceMappedId":"MONDO_0005575","literature":"['16407113', '19218458']","targetFromSourceId":"P00395","targetModulation":"up_or_down","variantRsId":"rs281865417","variantFunctionalConsequenceId":"SO_0001583","variantId":"MT_6277_G_A"} diff --git a/tests/gentropy/data_samples/variant_sources/uniprot-test.jsonl b/tests/gentropy/data_samples/variant_sources/uniprot-test.jsonl new file mode 100644 index 000000000..f3a637b1b --- /dev/null +++ b/tests/gentropy/data_samples/variant_sources/uniprot-test.jsonl @@ -0,0 +1,50 @@ +{"confidence":"high","datasourceId":"uniprot_variants","datatypeId":"genetic_association","diseaseFromSource":"Brugada syndrome 1","diseaseFromSourceId":"OMIM:601144","diseaseFromSourceMappedId":"MONDO_0011001","literature":"['20129283']","targetFromSourceId":"Q14524","targetModulation":"up_or_down","variantRsId":"rs199473172","variantFunctionalConsequenceId":"SO_0001583","variantId":"3_38585800_C_T"} +{"confidence":"high","datasourceId":"uniprot_variants","datatypeId":"genetic_association","diseaseFromSource":"Lowe oculocerebrorenal syndrome","diseaseFromSourceId":"OMIM:309000","diseaseFromSourceMappedId":"MONDO_0010645","literature":"['10923037']","targetFromSourceId":"Q01968","targetModulation":"up_or_down","variantRsId":"rs137853854","variantFunctionalConsequenceId":"SO_0001583","variantId":"X_129562612_G_A"} +{"confidence":"high","datasourceId":"uniprot_variants","datatypeId":"genetic_association","diseaseFromSource":"Pontocerebellar hypoplasia, hypotonia, and respiratory insufficiency syndrome, neonatal lethal","diseaseFromSourceId":"OMIM:618810","diseaseFromSourceMappedId":"MONDO_0032931","literature":"['31727539']","targetFromSourceId":"Q9NVI7","targetModulation":"up_or_down","variantRsId":"rs1570345942","variantFunctionalConsequenceId":"SO_0001583","variantId":"1_1525242_T_G"} +{"confidence":"medium","datasourceId":"uniprot_variants","datatypeId":"genetic_association","diseaseFromSource":"Colorectal cancer","diseaseFromSourceId":"OMIM:114500","diseaseFromSourceMappedId":"MONDO_0005575","literature":"['16407113', '19218458']","targetFromSourceId":"P00395","targetModulation":"up_or_down","variantRsId":"rs281865417","variantFunctionalConsequenceId":"SO_0001583","variantId":"MT_6277_G_A"} +{"confidence":"high","datasourceId":"uniprot_variants","datatypeId":"genetic_association","diseaseFromSource":"Ataxia telangiectasia","diseaseFromSourceId":"OMIM:208900","diseaseFromSourceMappedId":"Orphanet_100","literature":"['10817650', '10873394', '9288106', '9443866']","targetFromSourceId":"Q13315","targetModulation":"up_or_down","variantRsId":"rs587779872","variantFunctionalConsequenceId":"SO_0001583","variantId":"11_108345818_C_G"} +{"confidence":"high","datasourceId":"uniprot_variants","datatypeId":"genetic_association","diseaseFromSource":"Long QT syndrome 3","diseaseFromSourceId":"OMIM:603830","diseaseFromSourceMappedId":"MONDO_0011377","literature":"['10911008']","targetFromSourceId":"Q14524","targetModulation":"up_or_down","variantRsId":"rs137854605","variantFunctionalConsequenceId":"SO_0001583","variantId":"3_38581337_GA_AT"} +{"confidence":"high","datasourceId":"uniprot_variants","datatypeId":"genetic_association","diseaseFromSource":"Alzheimer disease 3","diseaseFromSourceId":"OMIM:607822","diseaseFromSourceMappedId":"MONDO_0011913","literature":"['11524469', '9384602', '12552037']","targetFromSourceId":"P49768","targetModulation":"up_or_down","variantRsId":"rs63750450","variantFunctionalConsequenceId":"SO_0001583","variantId":"14_73173571_A_G"} +{"confidence":"high","datasourceId":"uniprot_variants","datatypeId":"genetic_association","diseaseFromSource":"Telangiectasia, hereditary hemorrhagic, 2","diseaseFromSourceId":"OMIM:600376","diseaseFromSourceMappedId":null,"literature":"['8640225']","targetFromSourceId":"P37023","targetModulation":"up_or_down","variantRsId":"rs28936399","variantFunctionalConsequenceId":"SO_0001583","variantId":"12_51916114_T_G"} +{"confidence":"high","datasourceId":"uniprot_variants","datatypeId":"genetic_association","diseaseFromSource":"Cystathionine beta-synthase deficiency","diseaseFromSourceId":"OMIM:236200","diseaseFromSourceMappedId":"Orphanet_394","literature":"['16205833']","targetFromSourceId":"P35520","targetModulation":"up_or_down","variantRsId":"rs141502207","variantFunctionalConsequenceId":"SO_0001583","variantId":"21_43063045_C_G"} +{"confidence":"high","datasourceId":"uniprot_variants","datatypeId":"genetic_association","diseaseFromSource":"Autoimmune polyendocrine syndrome 1, with or without reversible metaphyseal dysplasia","diseaseFromSourceId":"OMIM:240300","diseaseFromSourceMappedId":"Orphanet_3453","literature":"['11524733', '11836330', '15712268', '14974083', '11524731']","targetFromSourceId":"O43918","targetModulation":"up_or_down","variantRsId":"rs179363880","variantFunctionalConsequenceId":"SO_0001583","variantId":"21_44286656_T_A"} +{"confidence":"high","datasourceId":"uniprot_variants","datatypeId":"genetic_association","diseaseFromSource":"Retinitis pigmentosa 1","diseaseFromSourceId":"OMIM:180100","diseaseFromSourceMappedId":null,"literature":"['15933747']","targetFromSourceId":"P56715","targetModulation":"up_or_down","variantRsId":"rs200135800","variantFunctionalConsequenceId":"SO_0001583","variantId":"8_54626833_A_G"} +{"confidence":"high","datasourceId":"uniprot_variants","datatypeId":"genetic_association","diseaseFromSource":"Meier-Gorlin syndrome 4","diseaseFromSourceId":"OMIM:613804","diseaseFromSourceMappedId":"Orphanet_2554","literature":"['21358632']","targetFromSourceId":"Q9H211","targetModulation":"up_or_down","variantRsId":"rs200672589","variantFunctionalConsequenceId":"SO_0001583","variantId":"16_88807362_C_T"} +{"confidence":"high","datasourceId":"uniprot_variants","datatypeId":"genetic_association","diseaseFromSource":"Breast cancer","diseaseFromSourceId":"OMIM:114480","diseaseFromSourceMappedId":"EFO_0003869","literature":"['15026808', '15635067']","targetFromSourceId":"P51587","targetModulation":"up_or_down","variantRsId":"rs28897754","variantFunctionalConsequenceId":"SO_0001583","variantId":"13_32379412_G_C"} +{"confidence":"high","datasourceId":"uniprot_variants","datatypeId":"genetic_association","diseaseFromSource":"Ceroid lipofuscinosis, neuronal, 6","diseaseFromSourceId":"OMIM:601780","diseaseFromSourceMappedId":"Orphanet_228363","literature":"['21990111']","targetFromSourceId":"Q9NWW5","targetModulation":"up_or_down","variantRsId":"rs150363441","variantFunctionalConsequenceId":"SO_0001583","variantId":"15_68208301_C_A"} +{"confidence":"high","datasourceId":"uniprot_variants","datatypeId":"genetic_association","diseaseFromSource":"46,XY sex reversal 1","diseaseFromSourceId":"OMIM:400044","diseaseFromSourceMappedId":"MONDO_0020712","literature":"['2247149', '1570829']","targetFromSourceId":"Q05066","targetModulation":"up_or_down","variantRsId":"rs104894957","variantFunctionalConsequenceId":"SO_0001583","variantId":"Y_2787426_C_G"} +{"confidence":"high","datasourceId":"uniprot_variants","datatypeId":"genetic_association","diseaseFromSource":"Houge-Janssens syndrome 3","diseaseFromSourceId":"OMIM:618354","diseaseFromSourceMappedId":"MONDO_0032697","literature":"['30595372']","targetFromSourceId":"P67775","targetModulation":"up_or_down","variantRsId":"rs1580636665","variantFunctionalConsequenceId":"SO_0001583","variantId":"5_134200405_T_A"} +{"confidence":"high","datasourceId":"uniprot_variants","datatypeId":"genetic_association","diseaseFromSource":"Lymphatic malformation 9","diseaseFromSourceId":"OMIM:619319","diseaseFromSourceMappedId":null,"literature":"['31215153']","targetFromSourceId":"Q9NYQ6","targetModulation":"up_or_down","variantRsId":"rs369237672","variantFunctionalConsequenceId":"SO_0001583","variantId":"22_46397727_G_A"} +{"confidence":"high","datasourceId":"uniprot_variants","datatypeId":"genetic_association","diseaseFromSource":"Tyrosinemia 1","diseaseFromSourceId":"OMIM:276700","diseaseFromSourceMappedId":"Orphanet_882","literature":"['7757089']","targetFromSourceId":"P16930","targetModulation":"up_or_down","variantRsId":"rs121965077","variantFunctionalConsequenceId":"SO_0001583","variantId":"15_80181120_A_G"} +{"confidence":"high","datasourceId":"uniprot_variants","datatypeId":"genetic_association","diseaseFromSource":"Miyoshi muscular dystrophy 1","diseaseFromSourceId":"OMIM:254130","diseaseFromSourceMappedId":"MONDO_0024545","literature":"['16010686', '18853459']","targetFromSourceId":"O75923","targetModulation":"up_or_down","variantRsId":"rs1258728780","variantFunctionalConsequenceId":"SO_0001583","variantId":"2_71517029_G_A"} +{"confidence":"high","datasourceId":"uniprot_variants","datatypeId":"genetic_association","diseaseFromSource":"Adenine phosphoribosyltransferase deficiency","diseaseFromSourceId":"OMIM:614723","diseaseFromSourceMappedId":"MONDO_0013869","literature":"['1746557']","targetFromSourceId":"P07741","targetModulation":"up_or_down","variantRsId":"rs104894506","variantFunctionalConsequenceId":"SO_0001583","variantId":"16_88810550_T_A"} +{"confidence":"high","datasourceId":"uniprot_variants","datatypeId":"genetic_association","diseaseFromSource":"Developmental and epileptic encephalopathy 7","diseaseFromSourceId":"OMIM:613720","diseaseFromSourceMappedId":null,"literature":"['25818041']","targetFromSourceId":"O43526","targetModulation":"up_or_down","variantRsId":"rs796052665","variantFunctionalConsequenceId":"SO_0001059","variantId":"20_63413478_GC_TT"} +{"confidence":"high","datasourceId":"uniprot_variants","datatypeId":"genetic_association","diseaseFromSource":"Hirschsprung disease 1","diseaseFromSourceId":"OMIM:142623","diseaseFromSourceMappedId":null,"literature":"['8114939', '10618407']","targetFromSourceId":"P07949","targetModulation":"up_or_down","variantRsId":"rs76764689","variantFunctionalConsequenceId":"SO_0001583","variantId":"10_43100480_C_G"} +{"confidence":"high","datasourceId":"uniprot_variants","datatypeId":"genetic_association","diseaseFromSource":"Hirschsprung disease 1","diseaseFromSourceId":"OMIM:142623","diseaseFromSourceMappedId":null,"literature":"['22174939']","targetFromSourceId":"P07949","targetModulation":"up_or_down","variantRsId":"rs746970700","variantFunctionalConsequenceId":"SO_0001583","variantId":"10_43109201_G_A"} +{"confidence":"high","datasourceId":"uniprot_variants","datatypeId":"genetic_association","diseaseFromSource":"Macular dystrophy, vitelliform, 2","diseaseFromSourceId":"OMIM:153700","diseaseFromSourceMappedId":"MONDO_0007931","literature":"['12324875']","targetFromSourceId":"O76090","targetModulation":"up_or_down","variantRsId":"rs281865262","variantFunctionalConsequenceId":"SO_0001583","variantId":"11_61959534_G_A"} +{"confidence":"high","datasourceId":"uniprot_variants","datatypeId":"genetic_association","diseaseFromSource":"Hyperornithinemia-hyperammonemia-homocitrullinuria syndrome","diseaseFromSourceId":"OMIM:238970","diseaseFromSourceMappedId":"MONDO_0009393","literature":"['19242930']","targetFromSourceId":"Q9Y619","targetModulation":"up_or_down","variantRsId":"rs121908533","variantFunctionalConsequenceId":"SO_0001583","variantId":"13_40799111_T_G"} +{"confidence":"high","datasourceId":"uniprot_variants","datatypeId":"genetic_association","diseaseFromSource":"Bosma arhinia microphthalmia syndrome","diseaseFromSourceId":"OMIM:603457","diseaseFromSourceMappedId":"Orphanet_2250","literature":"['28067909']","targetFromSourceId":"A6NHR9","targetModulation":"up_or_down","variantRsId":"rs1135402741","variantFunctionalConsequenceId":"SO_0001583","variantId":"18_2688480_C_G"} +{"confidence":"high","datasourceId":"uniprot_variants","datatypeId":"genetic_association","diseaseFromSource":"Left ventricular non-compaction 1","diseaseFromSourceId":"OMIM:604169","diseaseFromSourceMappedId":null,"literature":"['11238270']","targetFromSourceId":"Q9Y4J8","targetModulation":"up_or_down","variantRsId":"rs104894654","variantFunctionalConsequenceId":"SO_0001583","variantId":"18_34794250_C_T"} +{"confidence":"high","datasourceId":"uniprot_variants","datatypeId":"genetic_association","diseaseFromSource":"Mismatch repair cancer syndrome 4","diseaseFromSourceId":"OMIM:619101","diseaseFromSourceMappedId":null,"literature":"['18602922', '24027009', '27435373']","targetFromSourceId":"P54278","targetModulation":"up_or_down","variantRsId":"rs587779342","variantFunctionalConsequenceId":"SO_0001583","variantId":"7_5999199_T_G"} +{"confidence":"high","datasourceId":"uniprot_variants","datatypeId":"genetic_association","diseaseFromSource":"Frontotemporal dementia and\/or amyotrophic lateral sclerosis 2","diseaseFromSourceId":"OMIM:615911","diseaseFromSourceMappedId":null,"literature":"['24934289']","targetFromSourceId":"Q8WYQ3","targetModulation":"up_or_down","variantRsId":"rs587777574","variantFunctionalConsequenceId":"SO_0001583","variantId":"22_23767459_G_A"} +{"confidence":"high","datasourceId":"uniprot_variants","datatypeId":"genetic_association","diseaseFromSource":"Congenital bilateral absence of the vas deferens","diseaseFromSourceId":"OMIM:277180","diseaseFromSourceMappedId":"MONDO_0010178","literature":"['17329263']","targetFromSourceId":"P13569","targetModulation":"up_or_down","variantRsId":"rs115545701","variantFunctionalConsequenceId":"SO_0001583","variantId":"7_117509089_C_T"} +{"confidence":"high","datasourceId":"uniprot_variants","datatypeId":"genetic_association","diseaseFromSource":"Deafness, autosomal dominant, 6","diseaseFromSourceId":"OMIM:600965","diseaseFromSourceMappedId":null,"literature":"['11709537']","targetFromSourceId":"O76024","targetModulation":"up_or_down","variantRsId":"rs104893883","variantFunctionalConsequenceId":"SO_0001583","variantId":"4_6302281_T_C"} +{"confidence":"high","datasourceId":"uniprot_variants","datatypeId":"genetic_association","diseaseFromSource":"Osteoporosis","diseaseFromSourceId":"OMIM:166710","diseaseFromSourceMappedId":"EFO_0003882","literature":"['23499309']","targetFromSourceId":"P04628","targetModulation":"up_or_down","variantRsId":"rs387907359","variantFunctionalConsequenceId":"SO_0001583","variantId":"12_48981230_C_T"} +{"confidence":"high","datasourceId":"uniprot_variants","datatypeId":"genetic_association","diseaseFromSource":"MASA syndrome","diseaseFromSourceId":"OMIM:303350","diseaseFromSourceMappedId":"MONDO_0010559","literature":"['7920660', '8556302', '7920659', '22973895', '24155914']","targetFromSourceId":"P32004","targetModulation":"up_or_down","variantRsId":"rs28933683","variantFunctionalConsequenceId":"SO_0001583","variantId":"X_153870854_G_A"} +{"confidence":"high","datasourceId":"uniprot_variants","datatypeId":"genetic_association","diseaseFromSource":"Hypercholesterolemia, familial, 1","diseaseFromSourceId":"OMIM:143890","diseaseFromSourceMappedId":"MONDO_0007750","literature":"['24529145']","targetFromSourceId":"P01130","targetModulation":"up_or_down","variantRsId":"rs121908043","variantFunctionalConsequenceId":"SO_0001583","variantId":"19_11113307_C_T"} +{"confidence":"high","datasourceId":"uniprot_variants","datatypeId":"genetic_association","diseaseFromSource":"Developmental and epileptic encephalopathy 14","diseaseFromSourceId":"OMIM:614959","diseaseFromSourceMappedId":"MONDO_0013989","literature":"['26993267', '24029078']","targetFromSourceId":"Q5JUK3","targetModulation":"up_or_down","variantRsId":"rs587777264","variantFunctionalConsequenceId":"SO_0001583","variantId":"9_135759686_G_A"} +{"confidence":"high","datasourceId":"uniprot_variants","datatypeId":"genetic_association","diseaseFromSource":"Adrenal hyperplasia 3","diseaseFromSourceId":"OMIM:201910","diseaseFromSourceMappedId":"MONDO_0008728","literature":"['10364682']","targetFromSourceId":"P08686","targetModulation":"up_or_down","variantRsId":"rs72552751","variantFunctionalConsequenceId":"SO_0001583","variantId":"6_32039444_G_C"} +{"confidence":"high","datasourceId":"uniprot_variants","datatypeId":"genetic_association","diseaseFromSource":"46,XY sex reversal 1","diseaseFromSourceId":"OMIM:400044","diseaseFromSourceMappedId":"MONDO_0020712","literature":"['12107262']","targetFromSourceId":"Q05066","targetModulation":"up_or_down","variantRsId":"rs104894973","variantFunctionalConsequenceId":"SO_0001583","variantId":"Y_2787224_T_C"} +{"confidence":"high","datasourceId":"uniprot_variants","datatypeId":"genetic_association","diseaseFromSource":"Galactosemia 1","diseaseFromSourceId":"OMIM:230400","diseaseFromSourceMappedId":"MONDO_0009258","literature":"['10408771']","targetFromSourceId":"P07902","targetModulation":"up_or_down","variantRsId":"rs111033741","variantFunctionalConsequenceId":"SO_0001583","variantId":"9_34648419_T_C"} +{"confidence":"high","datasourceId":"uniprot_variants","datatypeId":"genetic_association","diseaseFromSource":"Hypercholesterolemia, familial, 1","diseaseFromSourceId":"OMIM:143890","diseaseFromSourceMappedId":"EFO_0004911","literature":"['9104431']","targetFromSourceId":"P01130","targetModulation":"up_or_down","variantRsId":"rs121908033","variantFunctionalConsequenceId":"SO_0001583","variantId":"19_11105429_G_T"} +{"confidence":"high","datasourceId":"uniprot_variants","datatypeId":"genetic_association","diseaseFromSource":"Spastic paraplegia 79B, autosomal recessive","diseaseFromSourceId":"OMIM:615491","diseaseFromSourceMappedId":"Orphanet_352654","literature":"['28007905']","targetFromSourceId":"P09936","targetModulation":"up_or_down","variantRsId":"rs1057519600","variantFunctionalConsequenceId":"SO_0001583","variantId":"4_41268048_C_A"} +{"confidence":"high","datasourceId":"uniprot_variants","datatypeId":"genetic_association","diseaseFromSource":"Breast cancer","diseaseFromSourceId":"OMIM:114480","diseaseFromSourceMappedId":"EFO_0003869","literature":"['17924331', '21473589', '23867111', '14746861', '25472942']","targetFromSourceId":"P38398","targetModulation":"up_or_down","variantRsId":"rs55770810","variantFunctionalConsequenceId":"SO_0001583","variantId":"17_43063931_G_A"} +{"confidence":"high","datasourceId":"uniprot_variants","datatypeId":"genetic_association","diseaseFromSource":"Achromatopsia 2","diseaseFromSourceId":"OMIM:216900","diseaseFromSourceMappedId":null,"literature":"['9662398', '11536077', '18521937']","targetFromSourceId":"Q16281","targetModulation":"up_or_down","variantRsId":"rs104893614","variantFunctionalConsequenceId":"SO_0001583","variantId":"2_98396018_G_A"} +{"confidence":"high","datasourceId":"uniprot_variants","datatypeId":"genetic_association","diseaseFromSource":"Aicardi-Goutieres syndrome 5","diseaseFromSourceId":"OMIM:612952","diseaseFromSourceMappedId":"Orphanet_51","literature":"['24183309', '28229507', '19525956']","targetFromSourceId":"Q9Y3Z3","targetModulation":"up_or_down","variantRsId":"rs515726140","variantFunctionalConsequenceId":"SO_0001583","variantId":"20_36912462_T_C"} +{"confidence":"high","datasourceId":"uniprot_variants","datatypeId":"genetic_association","diseaseFromSource":"Rhizomelic chondrodysplasia punctata 1","diseaseFromSourceId":"OMIM:215100","diseaseFromSourceMappedId":"MONDO_0008972","literature":"['9090381']","targetFromSourceId":"O00628","targetModulation":"up_or_down","variantRsId":"rs121909151","variantFunctionalConsequenceId":"SO_0001583","variantId":"6_136869909_C_T"} +{"confidence":"high","datasourceId":"uniprot_variants","datatypeId":"genetic_association","diseaseFromSource":"Lysinuric protein intolerance","diseaseFromSourceId":"OMIM:222700","diseaseFromSourceMappedId":"MONDO_0009109","literature":"['17764084', '10631139', '15776427']","targetFromSourceId":"Q9UM01","targetModulation":"up_or_down","variantRsId":"rs386833799","variantFunctionalConsequenceId":"SO_0001583","variantId":"14_22774441_G_T"} +{"confidence":"high","datasourceId":"uniprot_variants","datatypeId":"genetic_association","diseaseFromSource":"Neurofibromatosis 1","diseaseFromSourceId":"OMIM:162200","diseaseFromSourceMappedId":"MONDO_0018975","literature":"['9003501', '15060124']","targetFromSourceId":"P21359","targetModulation":"up_or_down","variantRsId":"rs199474743","variantFunctionalConsequenceId":"SO_0001583","variantId":"17_31260403_A_T"} +{"confidence":"high","datasourceId":"uniprot_variants","datatypeId":"genetic_association","diseaseFromSource":"Charcot-Marie-Tooth disease, demyelinating, 1B","diseaseFromSourceId":"OMIM:118200","diseaseFromSourceMappedId":"MONDO_0007307","literature":"['8797476', '7688964', '10737979', '11437164', '12221176', '14711881']","targetFromSourceId":"P25189","targetModulation":"up_or_down","variantRsId":"rs121913589","variantFunctionalConsequenceId":"SO_0001583","variantId":"1_161306863_C_T"} +{"confidence":"high","datasourceId":"uniprot_variants","datatypeId":"genetic_association","diseaseFromSource":"Atrial septal defect 7, with or without atrioventricular conduction defects","diseaseFromSourceId":"OMIM:108900","diseaseFromSourceMappedId":"MONDO_0007173","literature":"['15810002', '14607454']","targetFromSourceId":"P52952","targetModulation":"up_or_down","variantRsId":"rs387906774","variantFunctionalConsequenceId":"SO_0001583","variantId":"5_173233164_G_C"} +{"confidence":"high","datasourceId":"uniprot_variants","datatypeId":"genetic_association","diseaseFromSource":"Mitochondrial infantile bilateral striatal necrosis","diseaseFromSourceId":"OMIM:500003","diseaseFromSourceMappedId":null,"literature":"['7668837', '9270604', '9501263']","targetFromSourceId":"P00846","targetModulation":"up_or_down","variantRsId":"rs199476135","variantFunctionalConsequenceId":"SO_0001583","variantId":"MT_9176_T_C"} +{"confidence":"high","datasourceId":"uniprot_variants","datatypeId":"genetic_association","diseaseFromSource":"Charcot-Marie-Tooth disease, axonal, 2K","diseaseFromSourceId":"OMIM:607831","diseaseFromSourceMappedId":"MONDO_0011916","literature":"['22206013']","targetFromSourceId":"Q8TB36","targetModulation":"up_or_down","variantRsId":"rs375431837","variantFunctionalConsequenceId":"SO_0001583","variantId":"8_74364135_G_A"} diff --git a/tests/gentropy/step/test_convert_to_vcf_step.py b/tests/gentropy/step/test_convert_to_vcf_step.py new file mode 100644 index 000000000..945f0fce6 --- /dev/null +++ b/tests/gentropy/step/test_convert_to_vcf_step.py @@ -0,0 +1,154 @@ +"""Test convert to vcf step.""" + +from __future__ import annotations + +from pathlib import Path +from typing import TYPE_CHECKING + +import pandas as pd +import pytest + +from gentropy.common.session import Session +from gentropy.variant_index import ConvertToVcfStep + +if TYPE_CHECKING: + from typing import Any, Literal + + +@pytest.mark.step_test +class TestConvertToVcfStep: + """Test ConvertToVcfStep. + + Test if the step correctly read multiple variant sources and extracts + non duplicated variants and collects to sorted vcf partitions. + """ + + @pytest.mark.parametrize( + ["sources", "partition_size", "expected_partition_number"], + [ + pytest.param( + [ + { + "path": "tests/gentropy/data_samples/variant_sources/uniprot-test.jsonl", + "format": "json", + "n_variants": 50, # 2 variants per chromosome + }, + { + "path": "tests/gentropy/data_samples/variant_sources/eva-test.jsonl", + "format": "json", + "n_variants": 50, # 2 variants per chromosome + }, + { + "path": "tests/gentropy/data_samples/variant_sources/pharmacogenomics-test.jsonl", + "format": "json", + "n_variants": 44, # missing Y and MT, input contains two duplicated variants 22_19963748_G_A and 12_21178615_T_C and + }, + { + "path": "tests/gentropy/data_samples/variant_sources/credible-sets", + "format": "parquet", + "n_variants": 42, # after loci explosion + }, + ], + 10, + 19, # 186 variants / 10 size ~ 19 partitions + id="Multiple OT datasets", + ), + pytest.param( + [ + { + "path": "tests/gentropy/data_samples/variant_sources/credible-sets-extended", + "format": "parquet", + "n_variants": 1187, # after deduplication of locus object + } + ], + 2000, + 1, # 1199 variants / 2000 size ~ 1 partition + id="More variants than spark default partition size", + ), + ], + ) + def test_step( + self, + session: Session, + tmp_path: Path, + sources: list[dict[Literal["path", "format", "n_variants"], Any]], + partition_size: int, + expected_partition_number: int, + ) -> None: + """Test step. + + Expect that step outputs asserted number of partitions, where each partition + contains expected number of variants. + """ + source_paths = [s["path"] for s in sources] + source_formats = [s["format"] for s in sources] + output_path = str(tmp_path / "variants") + ConvertToVcfStep( + session, source_paths, source_formats, output_path, partition_size + ) + + variants_df = session.spark.read.csv(output_path, sep="\t", header=True) + # 40 variants (10 variants from each source) + expected_variant_count = sum(c["n_variants"] for c in sources) + assert ( + variants_df.count() == expected_variant_count + ), "Found incorrect number of variants" + partitions = [ + str(p) for p in Path(output_path).iterdir() if str(p).endswith("csv") + ] + assert ( + len(partitions) == expected_partition_number + ), "Found incorrect number of partitions" + + def test_sorting( + self, + session: Session, + tmp_path: Path, + ) -> None: + """Test sorting in partitions. + + Test if variants within single partition are sorted correctly. + The partition should be naturally sorted by #CHROM and POS fields. + """ + source_path = ( + "tests/gentropy/data_samples/variant_sources/uniprot-test-sort.jsonl" + ) + output_path = str(tmp_path / "variants") + ConvertToVcfStep(session, [source_path], ["json"], output_path, 10) + + partitions = [ + str(p) for p in Path(output_path).iterdir() if str(p).endswith("csv") + ] + assert len(partitions) == 1, "Must be one partition to test variant sorting" + df = pd.read_csv( + partitions[0], + usecols=[0, 1], # just read #CHROM and POS + sep="\t", + ) + assert df.equals( + # values comes from input file tests/gentropy/data_samples/variant_sources/uniprot-test-sorting.jsonl + # NOTE: Natural ordering in CHROM (str) and POS (int) + pd.DataFrame( + [ + ("1", 1525242), + ("1", 161306863), + ("11", 108345818), + ("2", 98396018), + ("21", 44286656), + ("3", 38585800), + ("MT", 6277), + ("X", 129562612), + ("Y", 2787426), + ], + columns=["#CHROM", "POS"], + ) + ), "Variant sorting does not match expectations." + + def test_raises_assertion_imbalanced_arg_ratios(self, session: Session) -> None: + """Test imbalanced argument ratio exception. + + Test if passing uneven number of sources to paths, not 1:1 ratio should result in assertion + """ + with pytest.raises(AssertionError) as e: + ConvertToVcfStep(session, ["dummy_path"], ["json", "json"], "output", 10) + assert e.value[0] == "Must provide format for each source path." From e0304fc49f6c5e25dfbf76ed02b8a04b1048022a Mon Sep 17 00:00:00 2001 From: Daniel Suveges Date: Mon, 4 Nov 2024 15:14:33 +0000 Subject: [PATCH 150/188] feat: deconvolute studies upon ingestion of GWAS Catalog datasets (#887) * feat: adding logic to deconvolute studies with the same id * fix: import type * fix: import again * fix: flagging condition * feat: adding flag to gwas catalog studies to indicate no summary statistics * feat: adding flags for gwas catalog hop hit ingestion * feat: remove not curated flag if no sumstats available * fix: removing test for duplicated study locus * fix: changing flag name to clarify meaning * fix: flagging condition --- src/gentropy/dataset/study_index.py | 157 ++++++++++++++++++ src/gentropy/dataset/study_locus.py | 92 +++++----- .../datasource/gwas_catalog/study_index.py | 16 ++ src/gentropy/gwas_catalog_top_hits.py | 9 +- src/gentropy/study_locus_validation.py | 6 +- src/gentropy/study_validation.py | 4 +- tests/gentropy/dataset/test_study_locus.py | 37 +---- 7 files changed, 237 insertions(+), 84 deletions(-) diff --git a/src/gentropy/dataset/study_index.py b/src/gentropy/dataset/study_index.py index 92bdc61a4..da310f6f1 100644 --- a/src/gentropy/dataset/study_index.py +++ b/src/gentropy/dataset/study_index.py @@ -10,6 +10,8 @@ from typing import TYPE_CHECKING from pyspark.sql import functions as f +from pyspark.sql.types import ArrayType, StringType, StructType +from pyspark.sql.window import Window from gentropy.assets import data from gentropy.common.schemas import parse_spark_schema @@ -590,3 +592,158 @@ def annotate_sumstats_qc( _df=df, _schema=StudyIndex.get_schema(), ) + + def deconvolute_studies(self: StudyIndex) -> StudyIndex: + """Deconvolute the study index dataset. + + When ingesting the study index dataset, the same studyId might be ingested from more than one source. + In such cases, the data needs to be merged and the quality control flags need to be combined. + + Returns: + StudyIndex: Deconvoluted study index dataset. + """ + # Windowing by study ID assume random order, but this is OK, because we are not selecting rows by a specific order. + study_id_window = Window.partitionBy("studyId").orderBy(f.rand()) + + # For certain aggregation, the full window is needed to be considered: + full_study_id_window = study_id_window.orderBy("studyId").rangeBetween( + Window.unboundedPreceding, Window.unboundedFollowing + ) + + # Temporary columns to drop at the end: + columns_to_drop = ["keepTopHit", "mostGranular", "rank"] + + return StudyIndex( + _df=( + self.df + # Initialising quality controls column, if not present: + .withColumn( + "qualityControls", + f.when( + f.col("qualityControls").isNull(), + f.array().cast(ArrayType(StringType())), + ).otherwise(f.col("qualityControls")), + ) + # Keeping top hit studies unless the same study is available from a summmary statistics source: + # This value will be set for all rows for the same `studyId`: + .withColumn( + "keepTopHit", + f.when( + f.array_contains( + f.collect_set(f.col("hasSumstats")).over( + full_study_id_window + ), + True, + ), + f.lit(False), + ).otherwise(True), + ) + # For studies without summary statistics, we remove the "Not curated by Open Targets" flag: + .withColumn( + "qualityControls", + f.when( + ~f.col("hasSumstats"), + f.array_remove( + f.col("qualityControls"), + StudyQualityCheck.NO_OT_CURATION.value, + ), + ).otherwise(f.col("qualityControls")), + ) + # If top hits are not kept, we remove the "sumstats not available" flag from all QC lists: + .withColumn( + "qualityControls", + f.when( + ~f.col("keepTopHit"), + f.array_remove( + f.col("qualityControls"), + StudyQualityCheck.SUMSTATS_NOT_AVAILABLE.value, + ), + ).otherwise(f.col("qualityControls")), + ) + # Then propagate quality checks for all sources of the same study: + .withColumn( + "qualityControls", + f.array_distinct( + f.flatten( + f.collect_set("qualityControls").over(full_study_id_window) + ) + ), + ) + # Propagating sumstatQCValues -> map, cannot be flatten: + .withColumn( + "sumstatQCValues", + f.first("sumstatQCValues", ignorenulls=True).over( + full_study_id_window + ), + ) + # Propagating analysisFlags: + .withColumn( + "analysisFlags", + f.flatten( + f.collect_list("analysisFlags").over(full_study_id_window) + ), + ) + # Propagating hasSumstatsFlag - if no flag, leave null: + .withColumn( + "hasSumstats", + f.when( + # There's a true: + f.array_contains( + f.collect_set("hasSumstats").over(full_study_id_window), + True, + ), + f.lit(True), + ).when( + # There's a false: + f.array_contains( + f.collect_set("hasSumstats").over(full_study_id_window), + False, + ), + f.lit(False), + ), + ) + # Propagating disease: when different sets of diseases available for the same study, + # we pick the shortest list, becasuse we assume, that is the most accurate disease assignment: + .withColumn( + "mostGranular", + f.size(f.col("traitFromSourceMappedIds")) + == f.min(f.size(f.col("traitFromSourceMappedIds"))).over( + full_study_id_window + ), + ) + # Remove less granular disease mappings: + .withColumn( + "traitFromSourceMappedIds", + f.when(f.col("mostGranular"), f.col("traitFromSourceMappedIds")), + ) + # Propagate mapped disease: + .withColumn( + "traitFromSourceMappedIds", + f.last(f.col("traitFromSourceMappedIds"), True).over( + full_study_id_window + ), + ) + # Repeating these steps for the `traitFromSource` column: + .withColumn( + "traitFromSource", + f.when(f.col("mostGranular"), f.col("traitFromSource")), + ) + # Propagate disease: + .withColumn( + "traitFromSource", + f.last(f.col("traitFromSource"), True).over(full_study_id_window), + ) + # Distinct study types are joined together into a string. So, if there's ambiguite, the study will be flagged when the study type is validated: + .withColumn( + "studyType", + f.concat_ws( + ",", f.collect_set("studyType").over(full_study_id_window) + ), + ) + # At this point, all studies in one window is expected to be identical. Let's just pick one: + .withColumn("rank", f.row_number().over(study_id_window)) + .filter(f.col("rank") == 1) + .drop(*columns_to_drop) + ), + _schema=StudyIndex.get_schema(), + ) diff --git a/src/gentropy/dataset/study_locus.py b/src/gentropy/dataset/study_locus.py index e685d828f..468ab0efc 100644 --- a/src/gentropy/dataset/study_locus.py +++ b/src/gentropy/dataset/study_locus.py @@ -21,6 +21,7 @@ from gentropy.common.utils import get_logsum from gentropy.config import WindowBasedClumpingStepConfig from gentropy.dataset.dataset import Dataset +from gentropy.dataset.study_index import StudyQualityCheck from gentropy.dataset.study_locus_overlap import StudyLocusOverlap from gentropy.dataset.variant_index import VariantIndex from gentropy.method.clump import LDclumping @@ -74,7 +75,7 @@ class StudyLocusQualityCheck(Enum): WINDOW_CLUMPED (str): Explained by a more significant variant in the same window NO_POPULATION (str): Study does not have population annotation to resolve LD NOT_QUALIFYING_LD_BLOCK (str): LD block does not contain variants at the required R^2 threshold - FAILED_STUDY (str): Flagging study loci if the study has failed QC + FLAGGED_STUDY (str): Study has quality control flag(s) MISSING_STUDY (str): Flagging study loci if the study is not found in the study index as a reference DUPLICATED_STUDYLOCUS_ID (str): Study-locus identifier is not unique INVALID_VARIANT_IDENTIFIER (str): Flagging study loci where identifier of any tagging variant was not found in the variant index @@ -85,6 +86,7 @@ class StudyLocusQualityCheck(Enum): ABNORMAL_PIPS (str): Flagging study loci with a sum of PIPs that are not in [0.99,1] OUT_OF_SAMPLE_LD (str): Study locus finemapped without in-sample LD reference INVALID_CHROMOSOME (str): Chromosome not in 1:22, X, Y, XY or MT + TOP_HIT_AND_SUMMARY_STATS (str): Curated top hit is flagged because summary statistics are available for study """ SUBSIGNIFICANT_FLAG = "Subsignificant p-value" @@ -101,7 +103,7 @@ class StudyLocusQualityCheck(Enum): NOT_QUALIFYING_LD_BLOCK = ( "LD block does not contain variants at the required R^2 threshold" ) - FAILED_STUDY = "Study has failed quality controls" + FLAGGED_STUDY = "Study has quality control flag(s)" MISSING_STUDY = "Study not found in the study index" DUPLICATED_STUDYLOCUS_ID = "Non-unique study locus identifier" INVALID_VARIANT_IDENTIFIER = ( @@ -114,8 +116,13 @@ class StudyLocusQualityCheck(Enum): TOP_HIT = "Study locus from curated top hit" EXPLAINED_BY_SUSIE = "Study locus in region explained by a SuSiE credible set" OUT_OF_SAMPLE_LD = "Study locus finemapped without in-sample LD reference" - ABNORMAL_PIPS = "Study locus with a sum of PIPs that not in the expected range [0.99,1]" + ABNORMAL_PIPS = ( + "Study locus with a sum of PIPs that not in the expected range [0.99,1]" + ) INVALID_CHROMOSOME = "Chromosome not in 1:22, X, Y, XY or MT" + TOP_HIT_AND_SUMMARY_STATS = ( + "Curated top hit is flagged because summary statistics are available for study" + ) class CredibleInterval(Enum): @@ -143,7 +150,8 @@ def validate_study(self: StudyLocus, study_index: StudyIndex) -> StudyLocus: """Flagging study loci if the corresponding study has issues. There are two different potential flags: - - failed study: flagging locus if the corresponding study has failed a quality check. + - flagged study: flagging locus if the study has quality control flags. + - study with summary statistics for top hit: flagging locus if the study has available summary statistics. - missing study: flagging locus if the study was not found in the reference study index. Args: @@ -159,6 +167,7 @@ def validate_study(self: StudyLocus, study_index: StudyIndex) -> StudyLocus: else f.lit(None).cast(StringType()) ) + # The study Id of the study index needs to be kept, because we would not know which study was in the index after the left join: study_flags = study_index.df.select( f.col("studyId").alias("study_studyId"), qc_select_expression.alias("study_qualityControls"), @@ -169,13 +178,30 @@ def validate_study(self: StudyLocus, study_index: StudyIndex) -> StudyLocus: self.df.join( study_flags, f.col("studyId") == f.col("study_studyId"), "left" ) - # Flagging loci with failed studies: + # Flagging loci with flagged studies - without propagating the actual flags: .withColumn( "qualityControls", StudyLocus.update_quality_flag( f.col("qualityControls"), f.size(f.col("study_qualityControls")) > 0, - StudyLocusQualityCheck.FAILED_STUDY, + StudyLocusQualityCheck.FLAGGED_STUDY, + ), + ) + # Flagging top-hits, where the study has available summary statistics: + .withColumn( + "qualityControls", + StudyLocus.update_quality_flag( + f.col("qualityControls"), + # Condition is true, if the study has summary statistics available and the locus is a top hit: + f.array_contains( + f.col("qualityControls"), + StudyLocusQualityCheck.TOP_HIT.value, + ) + & ~f.array_contains( + f.col("study_qualityControls"), + StudyQualityCheck.SUMSTATS_NOT_AVAILABLE.value, + ), + StudyLocusQualityCheck.TOP_HIT_AND_SUMMARY_STATS, ), ) # Flagging loci where no studies were found: @@ -396,7 +422,7 @@ def _qc_subsignificant_associations( def qc_abnormal_pips( self: StudyLocus, sum_pips_lower_threshold: float = 0.99, - sum_pips_upper_threshold: float = 1.0001, # Set slightly above 1 to account for floating point errors + sum_pips_upper_threshold: float = 1.0001, # Set slightly above 1 to account for floating point errors ) -> StudyLocus: """Filter study-locus by sum of posterior inclusion probabilities to ensure that the sum of PIPs is within a given range. @@ -414,32 +440,36 @@ def qc_abnormal_pips( else f.lit(None).cast(ArrayType(StringType())) ) - flag = (self.df.withColumn( + flag = self.df.withColumn( "sumPosteriorProbability", f.aggregate( f.col("locus"), f.lit(0.0), - lambda acc, x: acc + x["posteriorProbability"] - )).withColumn( - "pipOutOfRange", - f.when( - (f.col("sumPosteriorProbability") < sum_pips_lower_threshold) | - (f.col("sumPosteriorProbability") > sum_pips_upper_threshold), - True - ).otherwise(False))) + lambda acc, x: acc + x["posteriorProbability"], + ), + ).withColumn( + "pipOutOfRange", + f.when( + (f.col("sumPosteriorProbability") < sum_pips_lower_threshold) + | (f.col("sumPosteriorProbability") > sum_pips_upper_threshold), + True, + ).otherwise(False), + ) return StudyLocus( - _df=(flag + _df=( + flag # Flagging loci with failed studies: .withColumn( "qualityControls", self.update_quality_flag( qc_select_expression, f.col("pipOutOfRange"), - StudyLocusQualityCheck.ABNORMAL_PIPS + StudyLocusQualityCheck.ABNORMAL_PIPS, ), - ).drop("sumPosteriorProbability", "pipOutOfRange")), - _schema=self.get_schema() + ).drop("sumPosteriorProbability", "pipOutOfRange") + ), + _schema=self.get_schema(), ) @staticmethod @@ -641,28 +671,6 @@ def get_QC_mappings(cls: type[StudyLocus]) -> dict[str, str]: """ return {member.name: member.value for member in StudyLocusQualityCheck} - def filter_by_study_type(self: StudyLocus, study_type: str) -> StudyLocus: - """Creates a new StudyLocus dataset filtered by study type. - - Args: - study_type (str): Study type to filter for. Can be one of `gwas`, `eqtl`, `pqtl`, `eqtl`. - - Returns: - StudyLocus: Filtered study-locus dataset. - - Raises: - ValueError: If study type is not supported. - """ - if study_type not in ["gwas", "eqtl", "pqtl", "sqtl"]: - raise ValueError( - f"Study type {study_type} not supported. Supported types are: gwas, eqtl, pqtl, sqtl." - ) - new_df = self.df.filter(f.col("studyType") == study_type).drop("studyType") - return StudyLocus( - _df=new_df, - _schema=self._schema, - ) - def filter_credible_set( self: StudyLocus, credible_interval: CredibleInterval, diff --git a/src/gentropy/datasource/gwas_catalog/study_index.py b/src/gentropy/datasource/gwas_catalog/study_index.py index 421f53d0f..c01d6d263 100644 --- a/src/gentropy/datasource/gwas_catalog/study_index.py +++ b/src/gentropy/datasource/gwas_catalog/study_index.py @@ -647,6 +647,22 @@ def apply_inclusion_list( _schema=StudyIndexGWASCatalog.get_schema(), ) + def add_no_sumstats_flag(self: StudyIndexGWASCatalog) -> StudyIndexGWASCatalog: + """Add a flag to the study index if no summary statistics are available. + + Returns: + StudyIndexGWASCatalog: Updated study index. + """ + self.df = self.df.withColumn( + "qualityControls", + StudyIndex.update_quality_flag( + f.col("qualityControls"), + ~f.col("hasSumstats"), + StudyQualityCheck.SUMSTATS_NOT_AVAILABLE, + ), + ) + return self + @staticmethod def _parse_gwas_catalog_study_id(sumstats_path_column: str) -> Column: """Extract GWAS Catalog study accession from the summary statistics path. diff --git a/src/gentropy/gwas_catalog_top_hits.py b/src/gentropy/gwas_catalog_top_hits.py index 95722c768..2295900e8 100644 --- a/src/gentropy/gwas_catalog_top_hits.py +++ b/src/gentropy/gwas_catalog_top_hits.py @@ -60,7 +60,14 @@ def __init__( ), ) # Load - study_index.df.write.mode(session.write_mode).parquet(catalog_studies_out) + ( + study_index + # Flag all studies without sumstats + .add_no_sumstats_flag() + # Save dataset: + .df.write.mode(session.write_mode) + .parquet(catalog_studies_out) + ) ( study_locus.window_based_clumping(distance) diff --git a/src/gentropy/study_locus_validation.py b/src/gentropy/study_locus_validation.py index 1c8ae161c..1d1d128b6 100644 --- a/src/gentropy/study_locus_validation.py +++ b/src/gentropy/study_locus_validation.py @@ -46,13 +46,13 @@ def __init__( .qc_redundant_top_hits_from_PICS() # Flagging top hits from studies with PICS summary statistics .qc_explained_by_SuSiE() # Flagging credible sets in regions explained by SuSiE # Flagging credible sets with PIP > 1 or PIP < 0.99 - .qc_abnormal_pips(sum_pips_lower_threshold=0.99,sum_pips_upper_threshold=1.0001) + .qc_abnormal_pips( + sum_pips_lower_threshold=0.99, sum_pips_upper_threshold=1.0001 + ) # Annotates credible intervals and filter to only keep 99% credible sets .filter_credible_set(credible_interval=CredibleInterval.IS99) # Annotate credible set confidence: .assign_confidence() - # Flagging credible sets that are duplicated: - .validate_unique_study_locus_id() ).persist() # we will need this for 2 types of outputs study_locus_with_qc.valid_rows(invalid_qc_reasons, invalid=True).df.write.mode( diff --git a/src/gentropy/study_validation.py b/src/gentropy/study_validation.py index a9bebe25e..08f601f1e 100644 --- a/src/gentropy/study_validation.py +++ b/src/gentropy/study_validation.py @@ -62,8 +62,8 @@ def __init__( # Running validation: study_index_with_qc = ( - study_index.validate_unique_study_id() # Flagging duplicated study ids - .validate_study_type() # Flagging non-supported study types. + study_index.deconvolute_studies() # Deconvolute studies where the same study is ingested from multiple sources + .validate_study_type() # Flagging non-supported study types .validate_target(target_index) # Flagging QTL studies with invalid targets .validate_disease(disease_index) # Flagging invalid EFOs .validate_biosample( diff --git a/tests/gentropy/dataset/test_study_locus.py b/tests/gentropy/dataset/test_study_locus.py index 7f15a11a6..1d34479e1 100644 --- a/tests/gentropy/dataset/test_study_locus.py +++ b/tests/gentropy/dataset/test_study_locus.py @@ -151,41 +151,6 @@ def test_find_overlaps(mock_study_locus: StudyLocus) -> None: assert isinstance(mock_study_locus.find_overlaps(), StudyLocusOverlap) -@pytest.mark.parametrize( - "study_type, expected_sl_count", [("gwas", 1), ("eqtl", 1), ("pqtl", 0)] -) -def test_filter_by_study_type( - spark: SparkSession, study_type: str, expected_sl_count: int -) -> None: - """Test filter by study type.""" - # Input data - sl = StudyLocus( - _df=spark.createDataFrame( - [ - { - # from gwas - "studyLocusId": "1", - "variantId": "lead1", - "studyId": "study1", - "studyType": "gwas", - }, - { - # from eqtl - "studyLocusId": "2", - "variantId": "lead2", - "studyId": "study2", - "studyType": "eqtl", - }, - ], - StudyLocus.get_schema(), - ), - _schema=StudyLocus.get_schema(), - ) - - observed = sl.filter_by_study_type(study_type) - assert observed.df.count() == expected_sl_count - - def test_annotate_locus_statistics( mock_study_locus: StudyLocus, mock_summary_statistics: SummaryStatistics ) -> None: @@ -797,7 +762,7 @@ def test_study_validation_correctness(self: TestStudyLocusValidation) -> None: self.study_locus.validate_study(self.study_index) .df.filter( f.array_contains( - f.col("qualityControls"), StudyLocusQualityCheck.FAILED_STUDY.value + f.col("qualityControls"), StudyLocusQualityCheck.FLAGGED_STUDY.value ) ) .count() From 3639b23829eb1d167d28726d6262df2ddebc18e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Irene=20L=C3=B3pez=20Santiago?= <45119610+ireneisdoomed@users.noreply.github.com> Date: Mon, 4 Nov 2024 16:12:19 +0000 Subject: [PATCH 151/188] fix(`credibleSetConfidence`): inner join between study locus and variant index to avoid null genes (#890) --- src/gentropy/dataset/l2g_features/other.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gentropy/dataset/l2g_features/other.py b/src/gentropy/dataset/l2g_features/other.py index 4c28c2a0c..2fc32592b 100644 --- a/src/gentropy/dataset/l2g_features/other.py +++ b/src/gentropy/dataset/l2g_features/other.py @@ -291,10 +291,10 @@ def compute( ), ), on="variantId", - how="left", + how="inner", ) # Annotate credible set confidence - .join(full_credible_set, ["variantId", "studyId"], "left") + .join(full_credible_set, ["variantId", "studyId"]) .select("studyLocusId", "geneId", cls.feature_name) ), id_vars=("studyLocusId", "geneId"), From 04b1e222c51bc24387116f2b7535e40931a06458 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Irene=20L=C3=B3pez=20Santiago?= <45119610+ireneisdoomed@users.noreply.github.com> Date: Tue, 5 Nov 2024 11:24:12 +0000 Subject: [PATCH 152/188] feat(feature_matrix): impute values for gene attribute cols (#895) * feat(feature_matrix): impute values for gene attribute cols + semantic test * fix: change window * chore: fill na in the feature matrix generation step --- src/gentropy/dataset/l2g_feature_matrix.py | 22 ++++++- src/gentropy/dataset/l2g_gold_standard.py | 2 +- src/gentropy/dataset/study_locus.py | 2 +- src/gentropy/l2g.py | 46 ++++++++------- .../dataset/test_l2g_feature_matrix.py | 57 +++++++++++++++++++ 5 files changed, 102 insertions(+), 27 deletions(-) diff --git a/src/gentropy/dataset/l2g_feature_matrix.py b/src/gentropy/dataset/l2g_feature_matrix.py index bb4942312..9caa4b58a 100644 --- a/src/gentropy/dataset/l2g_feature_matrix.py +++ b/src/gentropy/dataset/l2g_feature_matrix.py @@ -5,6 +5,8 @@ from functools import reduce from typing import TYPE_CHECKING, Type +import pyspark.sql.functions as f +from pyspark.sql import Window from typing_extensions import Self from gentropy.common.spark_helpers import convert_from_long_to_wide @@ -128,18 +130,32 @@ def calculate_feature_missingness_rate( } def fill_na( - self: L2GFeatureMatrix, value: float = 0.0, subset: list[str] | None = None + self: L2GFeatureMatrix, na_value: float = 0.0, subset: list[str] | None = None ) -> L2GFeatureMatrix: """Fill missing values in a column with a given value. + For features that correspond to gene attributes, missing values are imputed using the mean of the column. + Args: - value (float): Value to replace missing values with. Defaults to 0.0. + na_value (float): Value to replace missing values with. Defaults to 0.0. subset (list[str] | None): Subset of columns to consider. Defaults to None. Returns: L2GFeatureMatrix: L2G feature matrix dataset """ - self._df = self._df.fillna(value, subset=subset) + cols_to_impute = ["proteinGeneCount500kb", "geneCount500kb", "isProteinCoding"] + for col in cols_to_impute: + if col not in self._df.columns: + continue + else: + self._df = self._df.withColumn( + col, + f.when( + f.col(col).isNull(), + f.mean(f.col(col)).over(Window.partitionBy("studyLocusId")), + ).otherwise(f.col(col)), + ) + self._df = self._df.fillna(na_value, subset=subset) return self def select_features( diff --git a/src/gentropy/dataset/l2g_gold_standard.py b/src/gentropy/dataset/l2g_gold_standard.py index f1df3a700..ec99f7141 100644 --- a/src/gentropy/dataset/l2g_gold_standard.py +++ b/src/gentropy/dataset/l2g_gold_standard.py @@ -135,7 +135,7 @@ def build_feature_matrix( .drop("studyId", "variantId") .distinct(), with_gold_standard=True, - ) + ).fill_na() def filter_unique_associations( self: L2GGoldStandard, diff --git a/src/gentropy/dataset/study_locus.py b/src/gentropy/dataset/study_locus.py index 468ab0efc..908c093b6 100644 --- a/src/gentropy/dataset/study_locus.py +++ b/src/gentropy/dataset/study_locus.py @@ -806,7 +806,7 @@ def build_feature_matrix( self, features_list, features_input_loader, - ) + ).fill_na() def annotate_credible_sets(self: StudyLocus) -> StudyLocus: """Annotate study-locus dataset with credible set flags. diff --git a/src/gentropy/l2g.py b/src/gentropy/l2g.py index 1004fa0fb..79be2385a 100644 --- a/src/gentropy/l2g.py +++ b/src/gentropy/l2g.py @@ -274,7 +274,6 @@ def _annotate_gold_standards_w_feature_matrix(self) -> L2GFeatureMatrix: gold_standards.build_feature_matrix( self.feature_matrix, self.credible_set ) - .fill_na() .select_features(self.features_list) .persist() ) @@ -322,6 +321,7 @@ def __init__( .json(evidence_output_path) ) + class LocusToGeneAssociationsStep: """Locus to gene associations step.""" @@ -343,39 +343,41 @@ def __init__( indirect_associations_output_path (str): Path to the indirect associations output dataset """ # Read in the disease index - disease_index = ( - session.spark.read.parquet(disease_index_path) - .select( - f.col("id").alias("diseaseId"), - f.explode("ancestors").alias("ancestorDiseaseId") - ) + disease_index = session.spark.read.parquet(disease_index_path).select( + f.col("id").alias("diseaseId"), + f.explode("ancestors").alias("ancestorDiseaseId"), ) # Read in the L2G evidence - disease_target_evidence = ( - session.spark.read.json(evidence_input_path) - .select( - f.col("targetFromSourceId").alias("targetId"), - f.col("diseaseFromSourceMappedId").alias("diseaseId"), - f.col("resourceScore") - ) + disease_target_evidence = session.spark.read.json(evidence_input_path).select( + f.col("targetFromSourceId").alias("targetId"), + f.col("diseaseFromSourceMappedId").alias("diseaseId"), + f.col("resourceScore"), ) # Generate direct assocations and save file ( - disease_target_evidence - .groupBy("targetId", "diseaseId") + disease_target_evidence.groupBy("targetId", "diseaseId") .agg(f.collect_set("resourceScore").alias("scores")) - .select("targetId", "diseaseId", calculate_harmonic_sum(f.col("scores")).alias("harmonicSum")) - .write.mode(session.write_mode).parquet(direct_associations_output_path) + .select( + "targetId", + "diseaseId", + calculate_harmonic_sum(f.col("scores")).alias("harmonicSum"), + ) + .write.mode(session.write_mode) + .parquet(direct_associations_output_path) ) # Generate indirect assocations and save file ( - disease_target_evidence - .join(disease_index, on="diseaseId", how="inner") + disease_target_evidence.join(disease_index, on="diseaseId", how="inner") .groupBy("targetId", "ancestorDiseaseId") .agg(f.collect_set("resourceScore").alias("scores")) - .select("targetId", "ancestorDiseaseId", calculate_harmonic_sum(f.col("scores")).alias("harmonicSum")) - .write.mode(session.write_mode).parquet(indirect_associations_output_path) + .select( + "targetId", + "ancestorDiseaseId", + calculate_harmonic_sum(f.col("scores")).alias("harmonicSum"), + ) + .write.mode(session.write_mode) + .parquet(indirect_associations_output_path) ) diff --git a/tests/gentropy/dataset/test_l2g_feature_matrix.py b/tests/gentropy/dataset/test_l2g_feature_matrix.py index 76661e170..f821daaac 100644 --- a/tests/gentropy/dataset/test_l2g_feature_matrix.py +++ b/tests/gentropy/dataset/test_l2g_feature_matrix.py @@ -4,6 +4,7 @@ from typing import TYPE_CHECKING +import pyspark.sql.functions as f import pytest from pyspark.sql.types import ( ArrayType, @@ -184,3 +185,59 @@ def _setup(self: TestFromFeaturesList, spark: SparkSession) -> None: ), _schema=GeneIndex.get_schema(), ) + + +def test_fill_na(spark: SparkSession) -> None: + """Tests L2GFeatureMatrix.fill_na, particularly the imputation logic.""" + sample_fm = L2GFeatureMatrix( + _df=spark.createDataFrame( + [ + { + "studyLocusId": "1", + "geneId": "gene1", + "proteinGeneCount500kb": 3.0, + "geneCount500kb": 8.0, + "isProteinCoding": 1.0, + "anotherFeature": None, + }, + { + "studyLocusId": "1", + "geneId": "gene2", + "proteinGeneCount500kb": 4.0, + "geneCount500kb": 10.0, + "isProteinCoding": 1.0, + "anotherFeature": None, + }, + { + "studyLocusId": "1", + "geneId": "gene3", + "proteinGeneCount500kb": None, + "geneCount500kb": None, + "isProteinCoding": None, + "anotherFeature": None, + }, + ], + schema="studyLocusId STRING, geneId STRING, proteinGeneCount500kb DOUBLE, geneCount500kb DOUBLE, isProteinCoding DOUBLE, anotherFeature DOUBLE", + ), + ) + observed_df = sample_fm.fill_na()._df.filter(f.col("geneId") == "gene3") + expected_df_missing_row = spark.createDataFrame( + [ + { + "studyLocusId": "1", + "geneId": "gene3", + "proteinGeneCount500kb": 3.5, + "geneCount500kb": 9.0, + "isProteinCoding": 1.0, + "anotherFeature": 0.0, + }, + ], + ).select( + "studyLocusId", + "geneId", + "proteinGeneCount500kb", + "geneCount500kb", + "isProteinCoding", + "anotherFeature", + ) + assert observed_df.collect() == expected_df_missing_row.collect() From 94abc792f0b515d605d8b4d8b9908c5a8c2b6789 Mon Sep 17 00:00:00 2001 From: Daniel Suveges Date: Tue, 5 Nov 2024 13:23:25 +0000 Subject: [PATCH 153/188] feat: adding l2g features to prediction table (#899) * feat: adding l2g features to prediction table * fix: renaming method for better name * fix: remove show statement * fix: dropping locusToGeneFeatures if already exist * feat: dropping features with null values from the map --- .../assets/schemas/l2g_predictions.json | 11 ++++ src/gentropy/dataset/l2g_prediction.py | 51 +++++++++++++++++++ src/gentropy/l2g.py | 6 +-- 3 files changed, 65 insertions(+), 3 deletions(-) diff --git a/src/gentropy/assets/schemas/l2g_predictions.json b/src/gentropy/assets/schemas/l2g_predictions.json index 238ff4087..57247a49a 100644 --- a/src/gentropy/assets/schemas/l2g_predictions.json +++ b/src/gentropy/assets/schemas/l2g_predictions.json @@ -18,6 +18,17 @@ "type": "double", "nullable": false, "metadata": {} + }, + { + "metadata": {}, + "name": "locusToGeneFeatures", + "nullable": true, + "type": { + "keyType": "string", + "type": "map", + "valueContainsNull": true, + "valueType": "float" + } } ] } diff --git a/src/gentropy/dataset/l2g_prediction.py b/src/gentropy/dataset/l2g_prediction.py index 169f5a846..64ce964c7 100644 --- a/src/gentropy/dataset/l2g_prediction.py +++ b/src/gentropy/dataset/l2g_prediction.py @@ -126,3 +126,54 @@ def to_disease_target_evidence( "studyLocusId", ) ) + + def add_locus_to_gene_features( + self: L2GPrediction, feature_matrix: L2GFeatureMatrix + ) -> L2GPrediction: + """Add features to the L2G predictions. + + Args: + feature_matrix (L2GFeatureMatrix): Feature matrix dataset + + Returns: + L2GPrediction: L2G predictions with additional features + """ + # Testing if `locusToGeneFeatures` column already exists: + if "locusToGeneFeatures" in self.df.columns: + self.df = self.df.drop("locusToGeneFeatures") + + # Columns identifying a studyLocus/gene pair + prediction_id_columns = ["studyLocusId", "geneId"] + + # L2G matrix columns to build the map: + columns_to_map = [ + column + for column in feature_matrix._df.columns + if column not in prediction_id_columns + ] + + # Aggregating all features into a single map column: + aggregated_features = ( + feature_matrix._df.withColumn( + "locusToGeneFeatures", + f.create_map( + *sum( + [ + (f.lit(colname), f.col(colname)) + for colname in columns_to_map + ], + (), + ) + ), + ) + # from the freshly created map, we filter out the null values + .withColumn( + "locusToGeneFeatures", + f.expr("map_filter(locusToGeneFeatures, (k, v) -> v is not null)"), + ) + .drop(*columns_to_map) + ) + return L2GPrediction( + _df=self.df.join(aggregated_features, on=prediction_id_columns, how="left"), + _schema=self.get_schema(), + ) diff --git a/src/gentropy/l2g.py b/src/gentropy/l2g.py index 79be2385a..cc1b5a5d1 100644 --- a/src/gentropy/l2g.py +++ b/src/gentropy/l2g.py @@ -190,9 +190,9 @@ def run_predict(self) -> None: hf_token=access_gcp_secret("hfhub-key", "open-targets-genetics-dev"), download_from_hub=self.download_from_hub, ) - predictions.df.write.mode(self.session.write_mode).parquet( - self.predictions_path - ) + predictions.add_locus_to_gene_features(self.feature_matrix).df.write.mode( + self.session.write_mode + ).parquet(self.predictions_path) self.session.logger.info("L2G predictions saved successfully.") def run_train(self) -> None: From 4d8e7c42e8e94473495d12d50efb7d7942afbe73 Mon Sep 17 00:00:00 2001 From: Szymon Szyszkowski <69353402+project-defiant@users.noreply.github.com> Date: Tue, 5 Nov 2024 13:39:24 +0000 Subject: [PATCH 154/188] fix: ensure the #CHROM is not quoted (#896) Co-authored-by: Szymon Szyszkowski Co-authored-by: Daniel Suveges --- src/gentropy/variant_index.py | 20 +++++++-- .../gentropy/step/test_convert_to_vcf_step.py | 41 ++++++++++--------- 2 files changed, 38 insertions(+), 23 deletions(-) diff --git a/src/gentropy/variant_index.py b/src/gentropy/variant_index.py index 4843553e8..9eac684b2 100644 --- a/src/gentropy/variant_index.py +++ b/src/gentropy/variant_index.py @@ -64,7 +64,13 @@ def __init__( class ConvertToVcfStep: - """Convert dataset with variant annotation to VCF step.""" + """Convert dataset with variant annotation to VCF step. + + This step converts in-house data source formats to VCF like format. + + NOTE! Due to the csv DataSourceWriter limitations we can not save the column name + `#CHROM` as in vcf file. The column is replaced with `CHROM`. + """ def __init__( self, @@ -112,8 +118,14 @@ def __init__( .sortWithinPartitions(f.col("#CHROM").asc(), f.col("POS").asc()) # Due to the large number of partitions ensure we do not lose the partitions before saving them .persist() + # FIXME the #CHROM column is saved as "#CHROM" by pyspark which fails under VEP, + # The native solution would be to implement the datasource with proper writer + # see https://docs.databricks.com/en/pyspark/datasources.html. + # Proposed solution will require adding # at the start of the first line of + # vcf before processing it in orchestration. + .withColumnRenamed("#CHROM", "CHROM") ) # Write - partitioned_variants.write.mode(session.write_mode).csv( - output_path, sep="\t", header=True - ) + partitioned_variants.write.mode(session.write_mode).option("sep", "\t").option( + "quote", "" + ).option("quoteAll", False).option("header", True).csv(output_path) diff --git a/tests/gentropy/step/test_convert_to_vcf_step.py b/tests/gentropy/step/test_convert_to_vcf_step.py index 945f0fce6..cc4ec800d 100644 --- a/tests/gentropy/step/test_convert_to_vcf_step.py +++ b/tests/gentropy/step/test_convert_to_vcf_step.py @@ -115,7 +115,6 @@ def test_sorting( ) output_path = str(tmp_path / "variants") ConvertToVcfStep(session, [source_path], ["json"], output_path, 10) - partitions = [ str(p) for p in Path(output_path).iterdir() if str(p).endswith("csv") ] @@ -125,24 +124,28 @@ def test_sorting( usecols=[0, 1], # just read #CHROM and POS sep="\t", ) - assert df.equals( - # values comes from input file tests/gentropy/data_samples/variant_sources/uniprot-test-sorting.jsonl - # NOTE: Natural ordering in CHROM (str) and POS (int) - pd.DataFrame( - [ - ("1", 1525242), - ("1", 161306863), - ("11", 108345818), - ("2", 98396018), - ("21", 44286656), - ("3", 38585800), - ("MT", 6277), - ("X", 129562612), - ("Y", 2787426), - ], - columns=["#CHROM", "POS"], - ) - ), "Variant sorting does not match expectations." + # values comes from input file tests/gentropy/data_samples/variant_sources/uniprot-test-sorting.jsonl + # NOTE: Natural ordering in CHROM (str) and POS (int) + with open(partitions[0]) as fp: + assert fp.readline().startswith("CHROM\tPOS") + + expected_df = pd.DataFrame( + [ + ("1", 1525242), + ("1", 161306863), + ("11", 108345818), + ("2", 98396018), + ("21", 44286656), + ("3", 38585800), + ("MT", 6277), + ("X", 129562612), + ("Y", 2787426), + ], + columns=["CHROM", "POS"], + ) + + assert list(df.columns) == list(expected_df.columns) + assert df.equals(expected_df), "Variant sorting does not match expectations." def test_raises_assertion_imbalanced_arg_ratios(self, session: Session) -> None: """Test imbalanced argument ratio exception. From 2af1074def5d6e02838c2188179270ec72b2cee2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Irene=20L=C3=B3pez=20Santiago?= <45119610+ireneisdoomed@users.noreply.github.com> Date: Tue, 5 Nov 2024 14:18:02 +0000 Subject: [PATCH 155/188] feat(feature_matrix): extract features for gwas associations only (#901) --- src/gentropy/l2g.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/gentropy/l2g.py b/src/gentropy/l2g.py index cc1b5a5d1..b585166c1 100644 --- a/src/gentropy/l2g.py +++ b/src/gentropy/l2g.py @@ -84,7 +84,9 @@ def __init__( gene_index=gene_index, ) - fm = credible_set.build_feature_matrix(features_list, features_input_loader) + fm = credible_set.filter(f.col("studyType") == "gwas").build_feature_matrix( + features_list, features_input_loader + ) fm._df.write.mode(session.write_mode).parquet(feature_matrix_path) From 6ec0d45baf48eeefa04c79632645c893f128b150 Mon Sep 17 00:00:00 2001 From: Yakov Date: Tue, 5 Nov 2024 15:30:56 +0000 Subject: [PATCH 156/188] fix: do not impute `isProteinCoding` (#902) * fix: fix col names for imputation * fix: fix v1 * fix: test --- src/gentropy/dataset/l2g_feature_matrix.py | 5 ++++- tests/gentropy/dataset/test_l2g_feature_matrix.py | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/gentropy/dataset/l2g_feature_matrix.py b/src/gentropy/dataset/l2g_feature_matrix.py index 9caa4b58a..f59e1e725 100644 --- a/src/gentropy/dataset/l2g_feature_matrix.py +++ b/src/gentropy/dataset/l2g_feature_matrix.py @@ -143,7 +143,10 @@ def fill_na( Returns: L2GFeatureMatrix: L2G feature matrix dataset """ - cols_to_impute = ["proteinGeneCount500kb", "geneCount500kb", "isProteinCoding"] + cols_to_impute = [ + "proteinGeneCount500kb", + "geneCount500kb", + ] for col in cols_to_impute: if col not in self._df.columns: continue diff --git a/tests/gentropy/dataset/test_l2g_feature_matrix.py b/tests/gentropy/dataset/test_l2g_feature_matrix.py index f821daaac..4fe338254 100644 --- a/tests/gentropy/dataset/test_l2g_feature_matrix.py +++ b/tests/gentropy/dataset/test_l2g_feature_matrix.py @@ -228,7 +228,7 @@ def test_fill_na(spark: SparkSession) -> None: "geneId": "gene3", "proteinGeneCount500kb": 3.5, "geneCount500kb": 9.0, - "isProteinCoding": 1.0, + "isProteinCoding": 0.0, "anotherFeature": 0.0, }, ], From c305dbef6ccd9adc5f17ae723b4f6ffb10c8f6e3 Mon Sep 17 00:00:00 2001 From: Tobi Alegbe Date: Wed, 6 Nov 2024 11:34:00 +0000 Subject: [PATCH 157/188] fix: reclassify eqtl catalogue sc datasets (#894) * fix: tweak sc vs bulk eqtl catalogue logic * fix: update tests * fix: correct coloc calling of method * fix: address PR comments * fix: change string to col * fix: change eqtl catalogue path to specific commit * chore: fix method description --- src/gentropy/dataset/colocalisation.py | 4 +- .../datasource/eqtl_catalogue/finemapping.py | 4 +- .../datasource/eqtl_catalogue/study_index.py | 40 ++++++++----------- 3 files changed, 19 insertions(+), 29 deletions(-) diff --git a/src/gentropy/dataset/colocalisation.py b/src/gentropy/dataset/colocalisation.py index db0040652..e384dd796 100644 --- a/src/gentropy/dataset/colocalisation.py +++ b/src/gentropy/dataset/colocalisation.py @@ -61,11 +61,11 @@ def extract_maximum_coloc_probability_per_region_and_gene( from gentropy.colocalisation import ColocalisationStep valid_qtls = list( - set(EqtlCatalogueStudyIndex.method_to_study_type_mapping.values()) + set(EqtlCatalogueStudyIndex.method_to_qtl_type_mapping.values()) ) + [ f"sc{qtl}" for qtl in set( - EqtlCatalogueStudyIndex.method_to_study_type_mapping.values() + EqtlCatalogueStudyIndex.method_to_qtl_type_mapping.values() ) ] diff --git a/src/gentropy/datasource/eqtl_catalogue/finemapping.py b/src/gentropy/datasource/eqtl_catalogue/finemapping.py index ea46359df..ea4264fdd 100644 --- a/src/gentropy/datasource/eqtl_catalogue/finemapping.py +++ b/src/gentropy/datasource/eqtl_catalogue/finemapping.py @@ -179,9 +179,7 @@ def parse_susie_results( f.col("molecular_trait_id"), ).alias("studyId"), f.col("tissue_id").alias("biosampleFromSourceId"), - EqtlCatalogueStudyIndex._identify_study_type( - f.col("quant_method"), f.col("tissue_id") - ).alias("studyType"), + EqtlCatalogueStudyIndex._identify_study_type().alias("studyType"), f.col("study_label").alias("projectId"), f.concat_ws( "/", diff --git a/src/gentropy/datasource/eqtl_catalogue/study_index.py b/src/gentropy/datasource/eqtl_catalogue/study_index.py index d284eb781..b1bcfb17d 100644 --- a/src/gentropy/datasource/eqtl_catalogue/study_index.py +++ b/src/gentropy/datasource/eqtl_catalogue/study_index.py @@ -42,10 +42,11 @@ class EqtlCatalogueStudyIndex: StructField("sample_size", IntegerType(), True), StructField("quant_method", StringType(), True), StructField("pmid", StringType(), True), + StructField("study_type", StringType(), True), ] ) - raw_studies_metadata_path = "https://raw.githubusercontent.com/eQTL-Catalogue/eQTL-Catalogue-resources/092e01a9601feb404f1c88f86311b43b907a88f6/data_tables/dataset_metadata_upcoming.tsv" - method_to_study_type_mapping = { + raw_studies_metadata_path = "https://raw.githubusercontent.com/eQTL-Catalogue/eQTL-Catalogue-resources/fe3c4b4ed911b3a184271a6aadcd8c8769a66aba/data_tables/dataset_metadata.tsv" + method_to_qtl_type_mapping = { "ge": "eqtl", "exon": "eqtl", "tx": "eqtl", @@ -58,38 +59,29 @@ class EqtlCatalogueStudyIndex: @classmethod def _identify_study_type( cls: type[EqtlCatalogueStudyIndex], - quantification_method_col: Column, - biosample_col: Column, ) -> Column: - """Identify the study type based on the method to quantify the trait and the biosample where the trait was measured. - - The quantification method identifies the type of molecular QTLs that were found. - The biosample identifies the biosample where the trait was measured, distinguishing between bulk and single cell. - - Args: - quantification_method_col (Column): column with the label of the method to quantify the trait. Available methods are [here](https://www.ebi.ac.uk/eqtl/Methods/) - biosample_col (Column): column with the label of the biosample where the trait was measured. + """Identify the qtl type based on the quantification method and eqtl catalogue study type. Returns: Column: The study type. Examples: - >>> df = spark.createDataFrame([("ge", "CL_1"), ("leafcutter", "UBERON_2"), ("tx", "EFO_3")], ["quant_method", "tissue_id"]) - >>> df.withColumn("study_type", EqtlCatalogueStudyIndex._identify_study_type(f.col("quant_method"), f.col("tissue_id"))).show() - +------------+---------+----------+ - |quant_method|tissue_id|study_type| - +------------+---------+----------+ - | ge| CL_1| sceqtl| - | leafcutter| UBERON_2| sqtl| - | tx| EFO_3| eqtl| - +------------+---------+----------+ + >>> df = spark.createDataFrame([("ge", "bulk"), ("leafcutter", "bulk"), ("tx", "single-cell")], ["quant_method", "study_type"]) + >>> df.withColumn("studyType", EqtlCatalogueStudyIndex._identify_study_type()).show() + +------------+-----------+---------+ + |quant_method| study_type|studyType| + +------------+-----------+---------+ + | ge| bulk| eqtl| + | leafcutter| bulk| sqtl| + | tx|single-cell| sceqtl| + +------------+-----------+---------+ """ qtl_type_mapping = f.create_map( - *[f.lit(x) for x in chain(*cls.method_to_study_type_mapping.items())] - )[quantification_method_col] + *[f.lit(x) for x in chain(*cls.method_to_qtl_type_mapping.items())] + )[f.col("quant_method")] return f.when( - biosample_col.startswith("CL"), f.concat(f.lit("sc"), qtl_type_mapping) + f.col("study_type") == "single-cell", f.concat(f.lit("sc"), qtl_type_mapping) ).otherwise(qtl_type_mapping) @classmethod From ebde0da0f247db43f0bd1d3c9de0e590a618229c Mon Sep 17 00:00:00 2001 From: David Ochoa Date: Wed, 6 Nov 2024 17:14:36 +0000 Subject: [PATCH 158/188] feat: improve partitioning of credible sets (#900) --- src/gentropy/study_locus_validation.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/gentropy/study_locus_validation.py b/src/gentropy/study_locus_validation.py index 1d1d128b6..d5dd900de 100644 --- a/src/gentropy/study_locus_validation.py +++ b/src/gentropy/study_locus_validation.py @@ -55,10 +55,14 @@ def __init__( .assign_confidence() ).persist() # we will need this for 2 types of outputs - study_locus_with_qc.valid_rows(invalid_qc_reasons, invalid=True).df.write.mode( - session.write_mode - ).parquet(invalid_study_locus_path) + # Valid study locus partitioned to simplify the finding of overlaps + study_locus_with_qc.valid_rows( + invalid_qc_reasons, invalid=True + ).df.repartitionByRange("chromosome", "position").sortWithinPartitions( + "chromosome", "position" + ).write.mode(session.write_mode).parquet(invalid_study_locus_path) + # Infalid study locus study_locus_with_qc.valid_rows(invalid_qc_reasons).df.write.mode( session.write_mode ).parquet(valid_study_locus_path) From 0d3c01bcb0456c72d76d41f5108d498c0c29c6d2 Mon Sep 17 00:00:00 2001 From: Daniel-Considine <113430683+Daniel-Considine@users.noreply.github.com> Date: Thu, 7 Nov 2024 13:15:57 +0000 Subject: [PATCH 159/188] fix: using the 99% PIP cs column, (#904) * feat: changing to 99 credible sets * fix: change summary schema * fix: adding purity metrics * fix: updating test data samples * fix: updating test data samples * Update finemapping.py --- .../datasource/finngen/finemapping.py | 20 ++++++++++----- .../finngen_credset_summary_sample.tsv | 24 +++++++++--------- .../finngen_credset_summary_sample.tsv.bgz | Bin 1338 -> 1350 bytes 3 files changed, 26 insertions(+), 18 deletions(-) diff --git a/src/gentropy/datasource/finngen/finemapping.py b/src/gentropy/datasource/finngen/finemapping.py index 36ab97e80..723d918bf 100644 --- a/src/gentropy/datasource/finngen/finemapping.py +++ b/src/gentropy/datasource/finngen/finemapping.py @@ -105,8 +105,10 @@ class FinnGenFinemapping: [ StructField("trait", StringType(), True), StructField("region", StringType(), True), - StructField("cs", StringType(), True), + StructField("cs_number", StringType(), True), StructField("cs_log10bf", DoubleType(), True), + StructField("cs_avg_r2", DoubleType(), True), + StructField("cs_min_r2", DoubleType(), True), ] ) @@ -182,8 +184,10 @@ class FinnGenFinemapping: summary_hail_schema: hl.tstruct = hl.tstruct( trait=hl.tstr, region=hl.tstr, - cs=hl.tstr, + cs_number=hl.tstr, cs_log10bf=hl.tfloat64, + cs_avg_r2=hl.tfloat64, + cs_min_r2=hl.tfloat64, ) @staticmethod @@ -241,7 +245,7 @@ def from_finngen_susie_finemapping( The finngen_susie_finemapping_cs_summary_files are files that Contains credible set summaries from SuSiE fine-mapping for all genome-wide significant regions with following schema: - trait: phenotype - region: region for which the fine-mapping was run. - - cs: running number for independent credible sets in a region + - cs_number: running number for independent credible sets in a region, assigned to 99% PIP - cs_log10bf: Log10 bayes factor of comparing the solution of this model (cs independent credible sets) to cs -1 credible sets - cs_avg_r2: Average correlation R2 between variants in the credible set - cs_min_r2: minimum r2 between variants in the credible set @@ -294,7 +298,7 @@ def from_finngen_susie_finemapping( # Drop rows which don't have proper position. snps_df.filter(f.col("position").cast(t.IntegerType()).isNotNull()) # Drop non credible set SNPs: - .filter(f.col("cs").cast(t.IntegerType()) > 0) + .filter(f.col("cs_99").cast(t.IntegerType()) > 0) .select( # Add study idenfitier. f.concat_ws("_", f.lit(finngen_release_prefix), f.col("trait")) @@ -303,7 +307,7 @@ def from_finngen_susie_finemapping( f.col("region"), # Add variant information. f.regexp_replace(f.col("v"), ":", "_").alias("variantId"), - f.col("cs").cast("integer").alias("credibleSetIndex"), + f.col("cs_99").cast("integer").alias("credibleSetIndex"), f.regexp_replace(f.col("chromosome"), "^chr", "") .cast(t.StringType()) .alias("chromosome"), @@ -433,8 +437,10 @@ def from_finngen_susie_finemapping( cs_summary_df.select( f.col("region"), f.col("trait"), - f.col("cs").cast("integer").alias("credibleSetIndex"), + f.col("cs_number").cast("integer").alias("credibleSetIndex"), f.col("cs_log10bf").cast("double").alias("credibleSetlog10BF"), + f.col("cs_avg_r2").cast("double").alias("purityMeanR2"), + f.col("cs_min_r2").cast("double").alias("purityMinR2"), ) .filter( (f.col("credibleSetlog10BF") > credset_lbf_threshold) @@ -471,6 +477,8 @@ def from_finngen_susie_finemapping( "credibleSetIndex", "finemappingMethod", "credibleSetlog10BF", + "purityMeanR2", + "purityMinR2", ) processed_finngen_finemapping_df = ( diff --git a/tests/gentropy/data_samples/finngen_credset_summary_sample.tsv b/tests/gentropy/data_samples/finngen_credset_summary_sample.tsv index 6ba610807..ca973d8fc 100644 --- a/tests/gentropy/data_samples/finngen_credset_summary_sample.tsv +++ b/tests/gentropy/data_samples/finngen_credset_summary_sample.tsv @@ -1,12 +1,12 @@ -trait region cs cs_log10bf cs_avg_r2 cs_min_r2 low_purity cs_size good_cs cs_id v rsid p beta sd prob cs_specific_prob most_severe gene_most_severe -H7_HORDEOLUM chr1:156514826-159514826 1 1.46467818637 1.0 1.0 False 1 True chr1:156514826-159514826_1 1:158014826:C:T chr1_158014826_C_T 2.54378e-08 1.88207 0.446902952132688 0.971307293706789 0.971297199099758 intron_variant KIRREL1 -G6_MIGRAINE_NO_AURA chr6:11403725-14403725 1 1.36783669104 0.760565917219 0.140997997009 True 19 False chr6:11403725-14403725_1 6:12903725:A:G chr6_12903725_A_G 3.61468e-08 -0.0981548 0.0320646607273439 0.90799209537494 0.907981878613055 intron_variant PHACTR1 -G6_MIGRAINE_NO_AURA chr12:55647065-58647065 1 1.66017507931 0.804011708889 0.804011708889 False 2 True chr12:55647065-58647065_1 12:57147065:C:G chr12_57147065_C_G 2.29261e-08 0.105129 0.0353895280800414 0.898218191602507 0.898218191602507 intron_variant LRP1 -G6_MIGRAINE_NO_AURA chr12:2906208-5906208 1 1.87518878137 0.762329739726 0.382297363204 False 11 True chr12:2906208-5906208_1 12:4406208:T:C chr12_4406208_T_C 3.52631e-08 -0.097881 0.0413367587403912 0.244577820826502 0.244317125809489 downstream_gene_variant AC008012.1 -G6_MIGRAINE_NO_AURA chr6:95113283-98113283 1 3.00789560938 0.917456939478 0.788796212164 False 43 True chr6:95113283-98113283_1 6:96613283:C:T chr6_96613283_C_T 5.56352e-09 0.110915 0.0357600937089016 0.122046568781673 0.122046568781673 intron_variant FHL5 -K11_APHTA_RECUR chr2:203986459-206986459 1 1.53062868484 1.0 1.0 False 1 True chr2:203986459-206986459_1 2:205486459:A:G chr2_205486459_A_G 2.5015e-08 0.225777 0.0591109424642432 0.956659971956856 0.956659971956856 intron_variant PARD3B -DM_NEPHROPATHY_EXMORE chr2:224821033-227821033 1 5.02824362893 0.984196974601 0.661904280625 False 50 True chr2:224821033-227821033_1 2:226321033:T:C chr2_226321033_T_C 2.42008e-10 -0.144142 0.0211352709908576 0.0225587152970605 0.0225587152970605 intergenic_variant -DM_NEPHROPATHY_EXMORE chr11:660994-3660994 1 2.7116635835 0.870906412027 0.809751619044 False 3 True chr11:660994-3660994_1 11:2160994:A:T chr11_2160994_A_T 3.15043e-09 0.168647 0.08489428697954 0.47925285536432 0.479123015291369 splice_region_variant INS-IGF2 -DM_NEPHROPATHY_EXMORE chr12:2775678-5775678 1 2.25532985077 1.0 1.0 False 1 True chr12:2775678-5775678_1 12:4275678:T:G chr12_4275678_T_G 3.72503e-09 -0.433585 0.0763706359152554 0.996634114263842 0.996632992137397 intron_variant CCND2 -AB1_EBV chr6:1412516-4412516 1 4.4609149402 0.678175582701 0.468032488641 False 4 True chr6:1412516-4412516_1 6:2912516:CCA:C chr6_2912516_CCA_C 4.90908e-11 0.196413 0.0943211787286286 0.367291808726716 0.367106415849495 upstream_gene_variant AL133351.2 -AB1_EBV chr20:16016584-19016584 1 1.27192551601 1.0 1.0 False 1 True chr20:16016584-19016584_1 20:17516584:C:T chr20_17516584_C_T 3.72152e-08 2.00466 0.504004034147034 0.963905759488349 0.963892713745976 intron_variant BFSP1 +trait region cs cs_log10bf cs_avg_r2 cs_min_r2 low_purity cs_size good_cs cs_id v rsid p beta sd prob cs_specific_prob most_severe gene_most_severe cs_number +H7_HORDEOLUM chr1:156514826-159514826 1 1.46467818637 1.0 1.0 False 1 True chr1:156514826-159514826_1 1:158014826:C:T chr1_158014826_C_T 2.54378e-08 1.88207 0.446902952132688 0.971307293706789 0.971297199099758 intron_variant KIRREL1 1 +G6_MIGRAINE_NO_AURA chr6:11403725-14403725 1 1.36783669104 0.760565917219 0.140997997009 True 19 False chr6:11403725-14403725_1 6:12903725:A:G chr6_12903725_A_G 3.61468e-08 -0.0981548 0.0320646607273439 0.90799209537494 0.907981878613055 intron_variant PHACTR1 1 +G6_MIGRAINE_NO_AURA chr12:55647065-58647065 1 1.66017507931 0.804011708889 0.804011708889 False 2 True chr12:55647065-58647065_1 12:57147065:C:G chr12_57147065_C_G 2.29261e-08 0.105129 0.0353895280800414 0.898218191602507 0.898218191602507 intron_variant LRP1 1 +G6_MIGRAINE_NO_AURA chr12:2906208-5906208 1 1.87518878137 0.762329739726 0.382297363204 False 11 True chr12:2906208-5906208_1 12:4406208:T:C chr12_4406208_T_C 3.52631e-08 -0.097881 0.0413367587403912 0.244577820826502 0.244317125809489 downstream_gene_variant AC008012.1 1 +G6_MIGRAINE_NO_AURA chr6:95113283-98113283 1 3.00789560938 0.917456939478 0.788796212164 False 43 True chr6:95113283-98113283_1 6:96613283:C:T chr6_96613283_C_T 5.56352e-09 0.110915 0.0357600937089016 0.122046568781673 0.122046568781673 intron_variant FHL5 1 +K11_APHTA_RECUR chr2:203986459-206986459 1 1.53062868484 1.0 1.0 False 1 True chr2:203986459-206986459_1 2:205486459:A:G chr2_205486459_A_G 2.5015e-08 0.225777 0.0591109424642432 0.956659971956856 0.956659971956856 intron_variant PARD3B 1 +DM_NEPHROPATHY_EXMORE chr2:224821033-227821033 1 5.02824362893 0.984196974601 0.661904280625 False 50 True chr2:224821033-227821033_1 2:226321033:T:C chr2_226321033_T_C 2.42008e-10 -0.144142 0.0211352709908576 0.0225587152970605 0.0225587152970605 intergenic_variant 1 +DM_NEPHROPATHY_EXMORE chr11:660994-3660994 1 2.7116635835 0.870906412027 0.809751619044 False 3 True chr11:660994-3660994_1 11:2160994:A:T chr11_2160994_A_T 3.15043e-09 0.168647 0.08489428697954 0.47925285536432 0.479123015291369 splice_region_variant INS-IGF2 1 +DM_NEPHROPATHY_EXMORE chr12:2775678-5775678 1 2.25532985077 1.0 1.0 False 1 True chr12:2775678-5775678_1 12:4275678:T:G chr12_4275678_T_G 3.72503e-09 -0.433585 0.0763706359152554 0.996634114263842 0.996632992137397 intron_variant CCND2 1 +AB1_EBV chr6:1412516-4412516 1 4.4609149402 0.678175582701 0.468032488641 False 4 True chr6:1412516-4412516_1 6:2912516:CCA:C chr6_2912516_CCA_C 4.90908e-11 0.196413 0.0943211787286286 0.367291808726716 0.367106415849495 upstream_gene_variant AL133351.2 1 +AB1_EBV chr20:16016584-19016584 1 1.27192551601 1.0 1.0 False 1 True chr20:16016584-19016584_1 20:17516584:C:T chr20_17516584_C_T 3.72152e-08 2.00466 0.504004034147034 0.963905759488349 0.963892713745976 intron_variant BFSP1 1 diff --git a/tests/gentropy/data_samples/finngen_credset_summary_sample.tsv.bgz b/tests/gentropy/data_samples/finngen_credset_summary_sample.tsv.bgz index 148f0f22fa564b24d7c9319c85a5fa24e6cd27f1..68e6965506938a056fb620caae22fc610628d285 100644 GIT binary patch delta 1338 zcmV-A1;zTh3dRb5ABzYC000000RIL6LPG)oDFuC2O>Y}F5Ir;hMT?o?eC|zA9NVa4 z8>&*YC&IBeu7E@`Bqc%n>kD!vCsh<5gq?X>k~@!Y9=Y4xEq7@%JTBL(biYma+wy7s zi16WK4e!1_mJQYD^KwC0xh`=^52<-bFET(2L0$~bcQkiMqPcKMK=(uZMp zm$nb-X|w*&-hCSGmmin+r2(JU+g;fXUx&?*9*5OXegy8fW%cFrhhg*T!pg-?Wi?0FYzaGPzqfavwnM_S*nAm&Il5q~xI@eOS-)tn zmS?EU$|6yJC!EcP33$TJoxl=w%o;!;gqhSmK^KM@j3OJTd5j2!VFW~&cv`M@oAs)E zz1uABR=f1u<$Qj2g$ZAsYk7BhKA&D*pOx#IGJQXv)-TZ>ks%w&1bGZv!CB3-Y9Mfe z&J;u?&{1BkJFj6EHvr!1JXM~as8)Be1Fy;lxMnU?dEJ4M!!g9&sHj>5HQ z$OOu&U}Twds~RkVAS4?H?*T_QSIi)COvCNPbhenkKm$@QqHLft5g&ubgDRj2SY%Al zIWQm^xHt0umyY$*cR8GxvZ{f4F>F~s8;L+F2dK=-d7_Sj6dM!JAqY}k4YFhpAqNLw ztYv$DIH6;p0!h=%F>*x2)%^Bl7AQaod?Mqsao{HCZjQOGU`m<7au{iXE<4psGXWo3 z0)HgoXvUEO=9ct}ezs>|kCa83rQ8W=#_v)v_ewu7=By@e3^|Yzbi^!XPT-^hdnBVF zi9@hQdRTv3ZFigD?sI8YaG+v318_jq;~hjT~$> zHFpaoB-8^VoSzvvF=gwHP;JSWzKs5vpK&}4~0jp@; zFtvOFInu=2iz`X^>NmtPy}ejW%lvHieqO(UdV(CTEHNR_F=~>K3`(xf&cF1-lcNiN zriu%<>|g~{o}uOi)Cr*M8-Pg6s`5ah7S6=V#JO&Eh^j<2Kv5SxfgC%*bp9s4PWbB0 zyK;SYdojPcoh~l^DrbMbyP2QuKbzPIA?FE^jZwlR9gq`eC6CH#IAdrSD^zW&VgQqa zlI*Dv_>qgBCmp#U%`H3h0+nZ|H3M~jOaMMi5Nb0ZGjc5*2r&y8M1YHFgGj^;g~C8V zPC?7nZrD5ytL6POCoi#q*sDSWPxAOon5Z*E)hwRt5^fNnj0Dsi2*Ly#8wdG+SN~7b zRXf0*uqFL;e>`H@BV}3^DR(Hq`JjERW?D;g_F!@i3#o3%79`{%Sx0rS1yY88T0CZr zw0-)tydTPV9eFPQ^7{A5<@sBBkp}9?Ow@cLNG<6X&xgPs zDT{U*8VQUwPoU$R#oKsBDgXcg delta 1326 zcmV+}1=0G(3c3n^ABzYC000000RIL6LPG)o9R+<>O>f&s3_VZ&iv^OyPu*NMO@d96 zz;ze9r$L&iSp%&d*lvs6U%!}290uw&m0M z0pY{P8s2_=C>yHL=jEzKpVr^XrN&`Nxx4W_(z7CrqJq)X%`~aMsTRFd;zdpUbeE&Ax{jw4|T*XYIanK+3e7rQ9ihvW^T)po4G}t}R0*P*w#a%bZ)! zU=ai%**JI)IJ&uF29f6^+?-Emi}{NrAoU{31}YQrF=#BP0-AtD#sr-M1EPU@BmSp! z?4G_$;Yi7<1nR}GW&LcV0jV6IGAn0^Ito&3JV1vaNcCxuC3^@tH~?d9+QSJQ0~JV` zUY;X=&uF-u-~5gP3Qz){$arlGxCy$OW3Kg0DN|SuBTdj{rZT?Xb}$p^-q)x?b<2U3ELn8nNqoK#?sWHcmk2=++#>u;;= zZZq6|E^YJ=L`-J@4oKZ^<{|_!ljlkJ7$i)8xdSi{QHb285sgJ72U|_e-9iZo^}q+` zCq9mpY;zH+Ejd_&mIKn9K|0YaG)$n49zvjudN2j3M&JRc^*g@cY3m#ovFjZW*Wd{qO@&q-1 z51>u}WiNdqF{`QriP|<3D--9s(IKi5)%HYP^a%3Y0jBfU`PIqmx8>^e=6rsAGhLkj zT~7acdp$qhzcjHELe3K+8>56tIv^*`N*KGt1a%~)c2r&y8M1YHFgGj^;g~C8VjzP=SZrD5wtL5E+ zk(a4J>{TIxCwaUkOw<{oY8KD6z8eH6BLOwrfiS^F#XH^pkwxpl#&qFMG zq)f{qnIGiK*~@%$E=aIkDr!zLm9t+I-b;U zarJI;arTCOLjv_=CTc#B@!D7*kxbzN_M5MOUzYBDk6O|%o_v3gltnxKj0DDxC(v=u z;%zHU>sg;AP)J(S5vrLHnKXM-MMEfpFjsSaF8NTBAUtu|Y_2>SGW+XwK@OVv_ zxMPJt4sKRjKXy#S$(qnv9Wt?hyD}cE?FVOjR<8LPMT`5{Y&vRO%N{DT*|f|OcLC8f zUY~%WjCI5yI1{3|kyo>+2aOs9I=GP Date: Thu, 7 Nov 2024 14:21:27 +0000 Subject: [PATCH 160/188] chore: add `hf_model_commit_message` to `LocusToGeneStep` (#905) --- src/gentropy/config.py | 3 +++ src/gentropy/l2g.py | 7 +++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/gentropy/config.py b/src/gentropy/config.py index 82ead9ed0..b931bb686 100644 --- a/src/gentropy/config.py +++ b/src/gentropy/config.py @@ -274,6 +274,7 @@ class LocusToGeneConfig(StepConfig): ) wandb_run_name: str | None = None hf_hub_repo_id: str | None = "opentargets/locus_to_gene" + hf_model_commit_message: str | None = "chore: update model" download_from_hub: bool = True _target_: str = "gentropy.l2g.LocusToGeneStep" @@ -633,6 +634,7 @@ class LocusToGeneEvidenceStepConfig(StepConfig): locus_to_gene_threshold: float = 0.05 _target_: str = "gentropy.l2g.LocusToGeneEvidenceStep" + @dataclass class LocusToGeneAssociationsStepConfig(StepConfig): """Configuration of the locus to gene association step.""" @@ -643,6 +645,7 @@ class LocusToGeneAssociationsStepConfig(StepConfig): indirect_associations_output_path: str = MISSING _target_: str = "gentropy.l2g.LocusToGeneAssociationsStep" + @dataclass class StudyLocusValidationStepConfig(StepConfig): """Configuration of the study index validation step. diff --git a/src/gentropy/l2g.py b/src/gentropy/l2g.py index b585166c1..30d2a9837 100644 --- a/src/gentropy/l2g.py +++ b/src/gentropy/l2g.py @@ -110,6 +110,7 @@ def __init__( gene_interactions_path: str | None = None, predictions_path: str | None = None, hf_hub_repo_id: str | None, + hf_model_commit_message: str | None = "chore: update model", ) -> None: """Initialise the step and run the logic based on mode. @@ -128,6 +129,7 @@ def __init__( gene_interactions_path (str | None): Path to the gene interactions dataset predictions_path (str | None): Path to the L2G predictions output dataset hf_hub_repo_id (str | None): Hugging Face Hub repository ID. If provided, the model will be uploaded to Hugging Face. + hf_model_commit_message (str | None): Commit message when we upload the model to the Hugging Face Hub Raises: ValueError: If run_mode is not 'train' or 'predict' @@ -146,6 +148,7 @@ def __init__( self.wandb_run_name = wandb_run_name self.hf_hub_repo_id = hf_hub_repo_id self.download_from_hub = download_from_hub + self.hf_model_commit_message = hf_model_commit_message # Load common inputs self.credible_set = StudyLocus.from_parquet( @@ -219,7 +222,7 @@ def run_train(self) -> None: ).train(self.wandb_run_name) if trained_model.training_data and trained_model.model and self.model_path: trained_model.save(self.model_path) - if self.hf_hub_repo_id: + if self.hf_hub_repo_id and self.hf_model_commit_message: hf_hub_token = access_gcp_secret( "hfhub-key", "open-targets-genetics-dev" ) @@ -231,7 +234,7 @@ def run_train(self) -> None: "goldStandardSet", "geneId" ).toPandas(), repo_id=self.hf_hub_repo_id, - commit_message="chore: update model", + commit_message=self.hf_model_commit_message, ) def _annotate_gold_standards_w_feature_matrix(self) -> L2GFeatureMatrix: From b5b71f0a288163845e26d9ba9c085120c3a9b6ca Mon Sep 17 00:00:00 2001 From: David Ochoa Date: Fri, 8 Nov 2024 12:41:54 +0000 Subject: [PATCH 161/188] refactor: finemapping method enum (#897) Co-authored-by: Yakov --- docs/python_api/datasets/study_locus.md | 4 ++ src/gentropy/colocalisation.py | 6 ++- src/gentropy/dataset/study_locus.py | 53 ++++++++++++++++--- .../datasource/eqtl_catalogue/finemapping.py | 4 +- .../datasource/finngen/finemapping.py | 4 +- src/gentropy/method/pics.py | 12 +++-- src/gentropy/susie_finemapper.py | 8 ++- 7 files changed, 72 insertions(+), 19 deletions(-) diff --git a/docs/python_api/datasets/study_locus.md b/docs/python_api/datasets/study_locus.md index 6896db167..700e39944 100644 --- a/docs/python_api/datasets/study_locus.md +++ b/docs/python_api/datasets/study_locus.md @@ -6,6 +6,10 @@ title: Study Locus --- +::: gentropy.dataset.study_locus.FinemappingMethod + +--- + ::: gentropy.dataset.study_locus.StudyLocusQualityCheck --- diff --git a/src/gentropy/colocalisation.py b/src/gentropy/colocalisation.py index a45a9a6a1..9682a8ed9 100644 --- a/src/gentropy/colocalisation.py +++ b/src/gentropy/colocalisation.py @@ -8,7 +8,7 @@ from pyspark.sql.functions import col from gentropy.common.session import Session -from gentropy.dataset.study_locus import StudyLocus +from gentropy.dataset.study_locus import FinemappingMethod, StudyLocus from gentropy.method.colocalisation import Coloc, ColocalisationMethodInterface @@ -56,7 +56,9 @@ def __init__( ) if colocalisation_method == Coloc.METHOD_NAME.lower(): credible_set = credible_set.filter( - col("finemappingMethod").isin("SuSie", "SuSiE-inf") + col("finemappingMethod").isin( + FinemappingMethod.SUSIE.value, FinemappingMethod.SUSIE_INF.value + ) ) # Transform diff --git a/src/gentropy/dataset/study_locus.py b/src/gentropy/dataset/study_locus.py index 908c093b6..1a2aa3697 100644 --- a/src/gentropy/dataset/study_locus.py +++ b/src/gentropy/dataset/study_locus.py @@ -139,6 +139,20 @@ class CredibleInterval(Enum): IS99 = "is99CredibleSet" +class FinemappingMethod(Enum): + """Finemapping method enum. + + Attributes: + PICS (str): PICS + SUSIE (str): SuSiE method + SUSIE_INF (str): SuSiE-inf method implemented in `gentropy` + """ + + PICS = "pics" + SUSIE = "SuSie" + SUSIE_INF = "SuSiE-inf" + + @dataclass class StudyLocus(Dataset): """Study-Locus dataset. @@ -1056,7 +1070,7 @@ def qc_redundant_top_hits_from_PICS(self: StudyLocus) -> StudyLocus: StudyLocus: Updated study locus with redundant top hits flagged. """ studies_with_pics_sumstats = ( - self.df.filter(f.col("finemappingMethod") == "pics") + self.df.filter(f.col("finemappingMethod") == FinemappingMethod.PICS.value) # Returns True if the study contains any PICS associations from summary statistics .withColumn( "hasPicsSumstats", @@ -1095,7 +1109,11 @@ def qc_explained_by_SuSiE(self: StudyLocus) -> StudyLocus: """ # unique study-regions covered by SuSie credible sets susie_study_regions = ( - self.filter(f.col("finemappingMethod") == "SuSiE-inf") + self.filter( + f.col("finemappingMethod").isin( + FinemappingMethod.SUSIE.value, FinemappingMethod.SUSIE_INF.value + ) + ) .df.select( "studyId", "chromosome", @@ -1108,7 +1126,11 @@ def qc_explained_by_SuSiE(self: StudyLocus) -> StudyLocus: # non SuSiE credible sets (studyLocusId) overlapping in any variant with SuSiE locus redundant_study_locus = ( - self.filter(f.col("finemappingMethod") != "SuSiE-inf") + self.filter( + ~f.col("finemappingMethod").isin( + FinemappingMethod.SUSIE.value, FinemappingMethod.SUSIE_INF.value + ) + ) .df.withColumn("l", f.explode("locus")) .select( "studyLocusId", @@ -1141,7 +1163,12 @@ def qc_explained_by_SuSiE(self: StudyLocus) -> StudyLocus: # credible set in SuSiE overlapping region f.col("inSuSiE") # credible set not based on SuSiE - & (f.col("finemappingMethod") != "SuSiE-inf"), + & ( + ~f.col("finemappingMethod").isin( + FinemappingMethod.SUSIE.value, + FinemappingMethod.SUSIE_INF.value, + ) + ), StudyLocusQualityCheck.EXPLAINED_BY_SUSIE, ), ) @@ -1268,7 +1295,12 @@ def assign_confidence(self: StudyLocus) -> StudyLocus: df = self.df.withColumn( "confidence", f.when( - (f.col("finemappingMethod").isin(["SuSiE-inf", "SuSie"])) + ( + f.col("finemappingMethod").isin( + FinemappingMethod.SUSIE.value, + FinemappingMethod.SUSIE_INF.value, + ) + ) & ( ~f.array_contains( f.col("qualityControls"), @@ -1278,7 +1310,12 @@ def assign_confidence(self: StudyLocus) -> StudyLocus: CredibleSetConfidenceClasses.FINEMAPPED_IN_SAMPLE_LD.value, ) .when( - (f.col("finemappingMethod").isin(["SuSiE-inf", "SuSie"])) + ( + f.col("finemappingMethod").isin( + FinemappingMethod.SUSIE.value, + FinemappingMethod.SUSIE_INF.value, + ) + ) & ( f.array_contains( f.col("qualityControls"), @@ -1288,7 +1325,7 @@ def assign_confidence(self: StudyLocus) -> StudyLocus: CredibleSetConfidenceClasses.FINEMAPPED_OUT_OF_SAMPLE_LD.value, ) .when( - (f.col("finemappingMethod") == "pics") + (f.col("finemappingMethod") == FinemappingMethod.PICS.value) & ( ~f.array_contains( f.col("qualityControls"), StudyLocusQualityCheck.TOP_HIT.value @@ -1297,7 +1334,7 @@ def assign_confidence(self: StudyLocus) -> StudyLocus: CredibleSetConfidenceClasses.PICSED_SUMMARY_STATS.value, ) .when( - (f.col("finemappingMethod") == "pics") + (f.col("finemappingMethod") == FinemappingMethod.PICS.value) & ( f.array_contains( f.col("qualityControls"), StudyLocusQualityCheck.TOP_HIT.value diff --git a/src/gentropy/datasource/eqtl_catalogue/finemapping.py b/src/gentropy/datasource/eqtl_catalogue/finemapping.py index ea4264fdd..0db240350 100644 --- a/src/gentropy/datasource/eqtl_catalogue/finemapping.py +++ b/src/gentropy/datasource/eqtl_catalogue/finemapping.py @@ -17,7 +17,7 @@ from gentropy.common.session import Session from gentropy.common.utils import parse_pvalue -from gentropy.dataset.study_locus import StudyLocus +from gentropy.dataset.study_locus import FinemappingMethod, StudyLocus from gentropy.datasource.eqtl_catalogue.study_index import EqtlCatalogueStudyIndex if TYPE_CHECKING: @@ -166,7 +166,7 @@ def parse_susie_results( f.col("se").alias("standardError"), f.col("credibleSetIndex"), f.col("logBF"), - f.lit("SuSie").alias("finemappingMethod"), + f.lit(FinemappingMethod.SUSIE.value).alias("finemappingMethod"), # Study metadata f.col("molecular_trait_id").alias("traitFromSource"), f.col("gene_id").alias("geneId"), diff --git a/src/gentropy/datasource/finngen/finemapping.py b/src/gentropy/datasource/finngen/finemapping.py index 723d918bf..e0f39689d 100644 --- a/src/gentropy/datasource/finngen/finemapping.py +++ b/src/gentropy/datasource/finngen/finemapping.py @@ -13,7 +13,7 @@ from gentropy.common.spark_helpers import get_top_ranked_in_window from gentropy.common.utils import parse_pvalue -from gentropy.dataset.study_locus import StudyLocus +from gentropy.dataset.study_locus import FinemappingMethod, StudyLocus @dataclass @@ -319,7 +319,7 @@ def from_finngen_susie_finemapping( # Add standard error, and allele frequency information. f.col("se").cast("double").alias("standardError"), f.col("maf").cast("float").alias("effectAlleleFrequencyFromSource"), - f.lit("SuSie").cast("string").alias("finemappingMethod"), + f.lit(FinemappingMethod.SUSIE.value).alias("finemappingMethod"), *[ f.col(f"alpha{i}").cast(t.DoubleType()).alias(f"alpha_{i}") for i in range(1, 11) diff --git a/src/gentropy/method/pics.py b/src/gentropy/method/pics.py index 918850527..96d0902c3 100644 --- a/src/gentropy/method/pics.py +++ b/src/gentropy/method/pics.py @@ -8,7 +8,11 @@ import pyspark.sql.types as t from scipy.stats import norm -from gentropy.dataset.study_locus import StudyLocus, StudyLocusQualityCheck +from gentropy.dataset.study_locus import ( + FinemappingMethod, + StudyLocus, + StudyLocusQualityCheck, +) if TYPE_CHECKING: from pyspark.sql import Row @@ -213,9 +217,11 @@ def finemap( """ # Finemapping method is an optional column: finemapping_method_expression = ( - f.lit("pics") + f.lit(FinemappingMethod.PICS.value) if "finemappingMethod" not in associations.df.columns - else f.coalesce(f.col("finemappingMethod"), f.lit("pics")) + else f.coalesce( + f.col("finemappingMethod"), f.lit(FinemappingMethod.PICS.value) + ) ) # Flagging expression for loci that do not qualify for PICS: diff --git a/src/gentropy/susie_finemapper.py b/src/gentropy/susie_finemapper.py index 03a8730ef..94ad918a5 100644 --- a/src/gentropy/susie_finemapper.py +++ b/src/gentropy/susie_finemapper.py @@ -26,7 +26,11 @@ order_array_of_structs_by_field, ) from gentropy.dataset.study_index import StudyIndex -from gentropy.dataset.study_locus import StudyLocus, StudyLocusQualityCheck +from gentropy.dataset.study_locus import ( + FinemappingMethod, + StudyLocus, + StudyLocusQualityCheck, +) from gentropy.method.carma import CARMA from gentropy.method.ld import LDAnnotator from gentropy.method.ld_matrix_interface import LDMatrixInterface @@ -290,7 +294,7 @@ def susie_inf_to_studylocus( # noqa: C901 "region": f.lit(region), "credibleSetIndex": f.lit(counter), "credibleSetlog10BF": f.lit(cs_lbf_value * 0.4342944819), - "finemappingMethod": f.lit("SuSiE-inf"), + "finemappingMethod": f.lit(FinemappingMethod.SUSIE_INF.value), } ) .withColumn( From 0e7e815b5f7c8b1b63a711f819ce8c345858600c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Irene=20L=C3=B3pez=20Santiago?= <45119610+ireneisdoomed@users.noreply.github.com> Date: Mon, 11 Nov 2024 09:41:58 +0000 Subject: [PATCH 162/188] chore(l2g): parametrise score threshold when writing predictions (#907) --- src/gentropy/config.py | 1 + src/gentropy/l2g.py | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/gentropy/config.py b/src/gentropy/config.py index b931bb686..6befe472e 100644 --- a/src/gentropy/config.py +++ b/src/gentropy/config.py @@ -221,6 +221,7 @@ class LocusToGeneConfig(StepConfig): credible_set_path: str = MISSING feature_matrix_path: str = MISSING predictions_path: str | None = None + l2g_threshold: float | None = 0.05 variant_index_path: str | None = None model_path: str | None = None gold_standard_curation_path: str | None = None diff --git a/src/gentropy/l2g.py b/src/gentropy/l2g.py index 30d2a9837..07cd14336 100644 --- a/src/gentropy/l2g.py +++ b/src/gentropy/l2g.py @@ -109,6 +109,7 @@ def __init__( variant_index_path: str | None = None, gene_interactions_path: str | None = None, predictions_path: str | None = None, + l2g_threshold: float | None, hf_hub_repo_id: str | None, hf_model_commit_message: str | None = "chore: update model", ) -> None: @@ -128,6 +129,7 @@ def __init__( variant_index_path (str | None): Path to the variant index gene_interactions_path (str | None): Path to the gene interactions dataset predictions_path (str | None): Path to the L2G predictions output dataset + l2g_threshold (float | None): An optional threshold for the L2G score to filter predictions. A threshold of 0.05 is recommended. hf_hub_repo_id (str | None): Hugging Face Hub repository ID. If provided, the model will be uploaded to Hugging Face. hf_model_commit_message (str | None): Commit message when we upload the model to the Hugging Face Hub @@ -149,6 +151,7 @@ def __init__( self.hf_hub_repo_id = hf_hub_repo_id self.download_from_hub = download_from_hub self.hf_model_commit_message = hf_model_commit_message + self.l2g_threshold = l2g_threshold or 0.0 # Load common inputs self.credible_set = StudyLocus.from_parquet( @@ -195,7 +198,9 @@ def run_predict(self) -> None: hf_token=access_gcp_secret("hfhub-key", "open-targets-genetics-dev"), download_from_hub=self.download_from_hub, ) - predictions.add_locus_to_gene_features(self.feature_matrix).df.write.mode( + predictions.filter( + f.col("score") >= self.l2g_threshold + ).add_locus_to_gene_features(self.feature_matrix).df.write.mode( self.session.write_mode ).parquet(self.predictions_path) self.session.logger.info("L2G predictions saved successfully.") From bb609cb20671c868500a10ca3f71856bbc679a8a Mon Sep 17 00:00:00 2001 From: Daniel Suveges Date: Mon, 11 Nov 2024 16:21:13 +0000 Subject: [PATCH 163/188] chore: validate chromosome (#906) --- src/gentropy/study_locus_validation.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gentropy/study_locus_validation.py b/src/gentropy/study_locus_validation.py index d5dd900de..4c0c8c4c5 100644 --- a/src/gentropy/study_locus_validation.py +++ b/src/gentropy/study_locus_validation.py @@ -41,6 +41,7 @@ def __init__( StudyLocus.from_parquet(session, list(study_locus_path)) # Add flag for MHC region .qc_MHC_region() + .validate_chromosome_label() # Flagging credible sets with unsupported chromosomes .validate_study(study_index) # Flagging studies not in study index .annotate_study_type(study_index) # Add study type to study locus .qc_redundant_top_hits_from_PICS() # Flagging top hits from studies with PICS summary statistics From 10b4be0308698fedeb38da597f272526db81622f Mon Sep 17 00:00:00 2001 From: Szymon Szyszkowski <69353402+project-defiant@users.noreply.github.com> Date: Mon, 11 Nov 2024 20:01:32 +0000 Subject: [PATCH 164/188] feat: extract pos and chromosome from variantid (#909) Co-authored-by: Szymon Szyszkowski --- src/gentropy/common/utils.py | 56 ++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/src/gentropy/common/utils.py b/src/gentropy/common/utils.py index ca6e8e7f2..91b002fe2 100644 --- a/src/gentropy/common/utils.py +++ b/src/gentropy/common/utils.py @@ -315,3 +315,59 @@ def copy_to_gcs(source_path: str, destination_blob: str) -> None: bucket = client.bucket(bucket_name=urlparse(destination_blob).hostname) blob = bucket.blob(blob_name=urlparse(destination_blob).path.lstrip("/")) blob.upload_from_filename(source_path) + + +def extract_chromosome(variant_id: Column) -> Column: + """Extract chromosome from variant ID. + + This function extracts the chromosome from a variant ID. The variantId is expected to be in the format `chromosome_position_ref_alt`. + The function does not convert the GENCODE to Ensembl chromosome notation. + See https://genome.ucsc.edu/FAQ/FAQgenes.html#:~:text=maps%20only%20once.-,The%20differences,-Some%20of%20our + + Args: + variant_id (Column): Variant ID + + Returns: + Column: Chromosome + + Examples: + >>> d = [("chr1_12345_A_T",),("15_KI270850v1_alt_48777_C_T",),] + >>> df = spark.createDataFrame(d).toDF("variantId") + >>> df.withColumn("chromosome", extract_chromosome(f.col("variantId"))).show(truncate=False) + +---------------------------+-----------------+ + |variantId |chromosome | + +---------------------------+-----------------+ + |chr1_12345_A_T |chr1 | + |15_KI270850v1_alt_48777_C_T|15_KI270850v1_alt| + +---------------------------+-----------------+ + + + """ + return f.regexp_extract(variant_id, r"^(.*)_\d+_.*$", 1) + + +def extract_position(variant_id: Column) -> Column: + """Extract position from variant ID. + + This function extracts the position from a variant ID. The variantId is expected to be in the format `chromosome_position_ref_alt`. + + Args: + variant_id (Column): Variant ID + + Returns: + Column: Position + + Examples: + >>> d = [("chr1_12345_A_T",),("15_KI270850v1_alt_48777_C_T",),] + >>> df = spark.createDataFrame(d).toDF("variantId") + >>> df.withColumn("position", extract_position(f.col("variantId"))).show(truncate=False) + +---------------------------+--------+ + |variantId |position| + +---------------------------+--------+ + |chr1_12345_A_T |12345 | + |15_KI270850v1_alt_48777_C_T|48777 | + +---------------------------+--------+ + + + """ + return f.regexp_extract(variant_id, r"^.*_(\d+)_.*$", 1) From e5b3c9ed1bba769ea61c89a6175eb2d45ceee4f1 Mon Sep 17 00:00:00 2001 From: Vivien Ho <56025826+vivienho@users.noreply.github.com> Date: Tue, 12 Nov 2024 15:12:37 +0000 Subject: [PATCH 165/188] feat: changes to PICS credible sets (OUT_OF_SAMPLE_LD QC flag and capital PICS) (#910) * feat: add OUT_OF_SAMPLE_LD QC flag to PICS credible sets * feat: change pics finemapping method to PICS * test: change pics to PICS in test data * fix: flag studies without sumstats without relying on hasSumstats column * fix: flag studies without sumstats without using update_quality_flag function --- src/gentropy/dataset/study_locus.py | 2 +- .../datasource/gwas_catalog/study_index.py | 6 +-- src/gentropy/method/pics.py | 9 ++++ tests/gentropy/dataset/test_study_locus.py | 42 +++++++++---------- 4 files changed, 32 insertions(+), 27 deletions(-) diff --git a/src/gentropy/dataset/study_locus.py b/src/gentropy/dataset/study_locus.py index 1a2aa3697..e6fd06c12 100644 --- a/src/gentropy/dataset/study_locus.py +++ b/src/gentropy/dataset/study_locus.py @@ -148,7 +148,7 @@ class FinemappingMethod(Enum): SUSIE_INF (str): SuSiE-inf method implemented in `gentropy` """ - PICS = "pics" + PICS = "PICS" SUSIE = "SuSie" SUSIE_INF = "SuSiE-inf" diff --git a/src/gentropy/datasource/gwas_catalog/study_index.py b/src/gentropy/datasource/gwas_catalog/study_index.py index c01d6d263..8630d31f6 100644 --- a/src/gentropy/datasource/gwas_catalog/study_index.py +++ b/src/gentropy/datasource/gwas_catalog/study_index.py @@ -655,11 +655,7 @@ def add_no_sumstats_flag(self: StudyIndexGWASCatalog) -> StudyIndexGWASCatalog: """ self.df = self.df.withColumn( "qualityControls", - StudyIndex.update_quality_flag( - f.col("qualityControls"), - ~f.col("hasSumstats"), - StudyQualityCheck.SUMSTATS_NOT_AVAILABLE, - ), + f.array(f.lit(StudyQualityCheck.SUMSTATS_NOT_AVAILABLE.value)) ) return self diff --git a/src/gentropy/method/pics.py b/src/gentropy/method/pics.py index 96d0902c3..60e28b9a1 100644 --- a/src/gentropy/method/pics.py +++ b/src/gentropy/method/pics.py @@ -280,6 +280,15 @@ def finemap( StudyLocusQualityCheck.NOT_QUALIFYING_LD_BLOCK, ), ) + # Flagging all PICS loci with OUT_OF_SAMPLE_LD flag: + .withColumn( + "qualityControls", + StudyLocus.update_quality_flag( + f.col("qualityControls"), + f.lit(True), + StudyLocusQualityCheck.OUT_OF_SAMPLE_LD, + ), + ) .withColumn( "finemappingMethod", finemapping_method_expression, diff --git a/tests/gentropy/dataset/test_study_locus.py b/tests/gentropy/dataset/test_study_locus.py index 1d34479e1..19b833124 100644 --- a/tests/gentropy/dataset/test_study_locus.py +++ b/tests/gentropy/dataset/test_study_locus.py @@ -629,7 +629,7 @@ class TestStudyLocusValidation: STUDY_LOCUS_DATA = [ # Won't be flagged: - ("1", "v1", "s1", 1.0, -8, [], "pics"), + ("1", "v1", "s1", 1.0, -8, [], "PICS"), # Already flagged, needs to be tested if the flag reamins unique: ( "2", @@ -638,7 +638,7 @@ class TestStudyLocusValidation: 5.0, -4, [StudyLocusQualityCheck.SUBSIGNIFICANT_FLAG.value], - "pics", + "PICS", ), # To be flagged: ("3", "v3", "s3", 1.0, -4, [], "SuSiE-inf"), @@ -869,18 +869,18 @@ class TestStudyLocusRedundancyFlagging: """Collection of tests related to flagging redundant credible sets.""" STUDY_LOCUS_DATA = [ - ("1", "v1", "s1", "pics", []), - ("2", "v2", "s1", "pics", [StudyLocusQualityCheck.TOP_HIT.value]), - ("3", "v3", "s1", "pics", []), - ("3", "v3", "s1", "pics", []), - ("1", "v1", "s1", "pics", [StudyLocusQualityCheck.TOP_HIT.value]), - ("1", "v1", "s2", "pics", [StudyLocusQualityCheck.TOP_HIT.value]), - ("1", "v1", "s2", "pics", [StudyLocusQualityCheck.TOP_HIT.value]), + ("1", "v1", "s1", "PICS", []), + ("2", "v2", "s1", "PICS", [StudyLocusQualityCheck.TOP_HIT.value]), + ("3", "v3", "s1", "PICS", []), + ("3", "v3", "s1", "PICS", []), + ("1", "v1", "s1", "PICS", [StudyLocusQualityCheck.TOP_HIT.value]), + ("1", "v1", "s2", "PICS", [StudyLocusQualityCheck.TOP_HIT.value]), + ("1", "v1", "s2", "PICS", [StudyLocusQualityCheck.TOP_HIT.value]), ("1", "v1", "s3", "SuSie", []), - ("1", "v1", "s3", "pics", [StudyLocusQualityCheck.TOP_HIT.value]), - ("1", "v1", "s4", "pics", []), + ("1", "v1", "s3", "PICS", [StudyLocusQualityCheck.TOP_HIT.value]), + ("1", "v1", "s4", "PICS", []), ("1", "v1", "s4", "SuSie", []), - ("1", "v1", "s4", "pics", [StudyLocusQualityCheck.TOP_HIT.value]), + ("1", "v1", "s4", "PICS", [StudyLocusQualityCheck.TOP_HIT.value]), ] STUDY_LOCUS_SCHEMA = t.StructType( @@ -946,7 +946,7 @@ class TestStudyLocusSuSiERedundancyFlagging: "v1", "s1", "X", - "pics", + "PICS", 1, 3, [ @@ -962,7 +962,7 @@ class TestStudyLocusSuSiERedundancyFlagging: "v2", "s1", "X", - "pics", + "PICS", 4, 5, [ @@ -977,7 +977,7 @@ class TestStudyLocusSuSiERedundancyFlagging: "v3", "s1", "X", - "pics", + "PICS", 6, 7, [ @@ -1004,7 +1004,7 @@ class TestStudyLocusSuSiERedundancyFlagging: "v5", "s1", "X", - "pics", + "PICS", 5, 5, [ @@ -1018,7 +1018,7 @@ class TestStudyLocusSuSiERedundancyFlagging: "v6", "s2", "X", - "pics", + "PICS", 3, 5, [ @@ -1141,11 +1141,11 @@ class TestStudyLocusDuplicationFlagging: STUDY_LOCUS_DATA = [ # Non-duplicated: - ("1", "v1", "s1", "pics"), + ("1", "v1", "s1", "PICS"), # Triplicate: - ("3", "v3", "s1", "pics"), - ("3", "v3", "s1", "pics"), - ("3", "v3", "s1", "pics"), + ("3", "v3", "s1", "PICS"), + ("3", "v3", "s1", "PICS"), + ("3", "v3", "s1", "PICS"), ] STUDY_LOCUS_SCHEMA = t.StructType( From 253fe31dd1b1d5861c70f864bd4d9ae6813dad98 Mon Sep 17 00:00:00 2001 From: Szymon Szyszkowski <69353402+project-defiant@users.noreply.github.com> Date: Thu, 14 Nov 2024 16:12:28 +0100 Subject: [PATCH 166/188] feat(gold_standard): arbitrary gold standards (#912) * feat(gold_standard): filter by protein coding genes * feat: arbitrary gold standards * feat: read model from gcs * feat: read model from gcs * feat: get untrusted types from blob * revert: changes to gene_index * fix: correct list of missing and unexpected fields * chore: addressing comments * fix: selective check on the schema issues --------- Co-authored-by: Szymon Szyszkowski --- src/gentropy/l2g.py | 227 ++++++++++++++++++----------- src/gentropy/method/l2g/model.py | 23 ++- src/gentropy/method/l2g/trainer.py | 10 +- 3 files changed, 165 insertions(+), 95 deletions(-) diff --git a/src/gentropy/l2g.py b/src/gentropy/l2g.py index 07cd14336..dc95bb670 100644 --- a/src/gentropy/l2g.py +++ b/src/gentropy/l2g.py @@ -2,12 +2,14 @@ from __future__ import annotations +import logging from typing import Any import pyspark.sql.functions as f from sklearn.ensemble import GradientBoostingClassifier from wandb import login as wandb_login +from gentropy.common.schemas import compare_struct_schemas from gentropy.common.session import Session from gentropy.common.spark_helpers import calculate_harmonic_sum from gentropy.common.utils import access_gcp_secret @@ -152,6 +154,9 @@ def __init__( self.download_from_hub = download_from_hub self.hf_model_commit_message = hf_model_commit_message self.l2g_threshold = l2g_threshold or 0.0 + self.gold_standard_curation_path = gold_standard_curation_path + self.gene_interactions_path = gene_interactions_path + self.variant_index_path = variant_index_path # Load common inputs self.credible_set = StudyLocus.from_parquet( @@ -160,27 +165,105 @@ def __init__( self.feature_matrix = L2GFeatureMatrix( _df=session.load_data(feature_matrix_path), features_list=self.features_list ) - self.variant_index = ( - VariantIndex.from_parquet(session, variant_index_path) - if variant_index_path - else None - ) if run_mode == "predict": self.run_predict() elif run_mode == "train": - self.gs_curation = ( - self.session.spark.read.json(gold_standard_curation_path) - if gold_standard_curation_path - else None - ) - self.interactions = ( - self.session.spark.read.parquet(gene_interactions_path) - if gene_interactions_path - else None - ) + self.gold_standard = self.prepare_gold_standard() self.run_train() + def prepare_gold_standard(self) -> L2GGoldStandard: + """Prepare the gold standard for training. + + Returns: + L2GGoldStandard: training dataset. + + Raises: + ValueError: When gold standard path, is not provided, or when + parsing OTG gold standard but missing interactions and variant index paths. + TypeError: When gold standard is not OTG gold standard nor L2GGoldStandard. + + """ + if self.gold_standard_curation_path is None: + raise ValueError("Gold Standard is required for model training.") + # Read the gold standard either from json or parquet, default to parquet if can not infer the format from extension. + ext = self.gold_standard_curation_path.split(".")[-1] + ext = "parquet" if ext not in ["parquet", "json"] else ext + gold_standard = self.session.load_data(self.gold_standard_curation_path, ext) + schema_issues = compare_struct_schemas( + gold_standard.schema, L2GGoldStandard.get_schema() + ) + # Parse the gold standard depending on the input schema + match schema_issues: + case {**extra} if not extra: + # Schema is the same as L2GGoldStandard - load the GS + # NOTE: match to empty dict will be non-selective + # see https://stackoverflow.com/questions/75389166/how-to-match-an-empty-dictionary + logging.info("Successfully parsed gold standard.") + return L2GGoldStandard( + _df=gold_standard, + _schema=L2GGoldStandard.get_schema(), + ) + case { + "missing_mandatory_columns": [ + "studyLocusId", + "variantId", + "studyId", + "geneId", + "goldStandardSet", + ], + "unexpected_columns": [ + "association_info", + "gold_standard_info", + "metadata", + "sentinel_variant", + "trait_info", + ], + }: + # There are schema mismatches, this would mean that we have + logging.info("Detected OTG Gold Standard. Attempting to parse it.") + otg_curation = gold_standard + if self.gene_interactions_path is None: + raise ValueError("Interactions are required for parsing curation.") + if self.variant_index_path is None: + raise ValueError("Variant Index are required for parsing curation.") + + interactions = self.session.load_data( + self.gene_interactions_path, "parquet" + ) + variant_index = VariantIndex.from_parquet( + self.session, self.variant_index_path + ) + study_locus_overlap = StudyLocus( + _df=self.credible_set.df.join( + otg_curation.select( + f.concat_ws( + "_", + f.col("sentinel_variant.locus_GRCh38.chromosome"), + f.col("sentinel_variant.locus_GRCh38.position"), + f.col("sentinel_variant.alleles.reference"), + f.col("sentinel_variant.alleles.alternative"), + ).alias("variantId"), + f.col("association_info.otg_id").alias("studyId"), + ), + on=[ + "studyId", + "variantId", + ], + how="inner", + ), + _schema=StudyLocus.get_schema(), + ).find_overlaps() + + return L2GGoldStandard.from_otg_curation( + gold_standard_curation=otg_curation, + variant_index=variant_index, + study_locus_overlap=study_locus_overlap, + interactions=interactions, + ) + case _: + raise TypeError("Incorrect gold standard dataset provided.") + def run_predict(self) -> None: """Run the prediction step. @@ -207,87 +290,55 @@ def run_predict(self) -> None: def run_train(self) -> None: """Run the training step.""" - if ( - self.gs_curation - and self.interactions - and self.wandb_run_name - and self.model_path - ): - wandb_key = access_gcp_secret("wandb-key", "open-targets-genetics-dev") - - # Instantiate classifier and train model - l2g_model = LocusToGeneModel( - model=GradientBoostingClassifier(random_state=42), - hyperparameters=self.hyperparameters, - ) - wandb_login(key=wandb_key) - trained_model = LocusToGeneTrainer( - model=l2g_model, - feature_matrix=self._annotate_gold_standards_w_feature_matrix(), - ).train(self.wandb_run_name) - if trained_model.training_data and trained_model.model and self.model_path: - trained_model.save(self.model_path) - if self.hf_hub_repo_id and self.hf_model_commit_message: - hf_hub_token = access_gcp_secret( - "hfhub-key", "open-targets-genetics-dev" - ) - trained_model.export_to_hugging_face_hub( - # we upload the model in the filesystem - self.model_path.split("/")[-1], - hf_hub_token, - data=trained_model.training_data._df.drop( - "goldStandardSet", "geneId" - ).toPandas(), - repo_id=self.hf_hub_repo_id, - commit_message=self.hf_model_commit_message, - ) + # Initialize access to weights and biases + wandb_key = access_gcp_secret("wandb-key", "open-targets-genetics-dev") + wandb_login(key=wandb_key) + + # Instantiate classifier and train model + l2g_model = LocusToGeneModel( + model=GradientBoostingClassifier(random_state=42), + hyperparameters=self.hyperparameters, + ) + + # Calculate the gold standard features + feature_matrix = self._annotate_gold_standards_w_feature_matrix() + + # Run the training + trained_model = LocusToGeneTrainer( + model=l2g_model, feature_matrix=feature_matrix + ).train(self.wandb_run_name) + + # Export the model + if trained_model.training_data and trained_model.model and self.model_path: + trained_model.save(self.model_path) + if self.hf_hub_repo_id and self.hf_model_commit_message: + hf_hub_token = access_gcp_secret( + "hfhub-key", "open-targets-genetics-dev" + ) + trained_model.export_to_hugging_face_hub( + # we upload the model in the filesystem + self.model_path.split("/")[-1], + hf_hub_token, + data=trained_model.training_data._df.drop( + "goldStandardSet", "geneId" + ).toPandas(), + repo_id=self.hf_hub_repo_id, + commit_message=self.hf_model_commit_message, + ) def _annotate_gold_standards_w_feature_matrix(self) -> L2GFeatureMatrix: """Generate the feature matrix of annotated gold standards. Returns: L2GFeatureMatrix: Feature matrix with gold standards annotated with features. - - Raises: - ValueError: Not all training dependencies are defined """ - if self.gs_curation and self.interactions and self.variant_index: - study_locus_overlap = StudyLocus( - _df=self.credible_set.df.join( - self.gs_curation.select( - f.concat_ws( - "_", - f.col("sentinel_variant.locus_GRCh38.chromosome"), - f.col("sentinel_variant.locus_GRCh38.position"), - f.col("sentinel_variant.alleles.reference"), - f.col("sentinel_variant.alleles.alternative"), - ).alias("variantId"), - f.col("association_info.otg_id").alias("studyId"), - ), - on=[ - "studyId", - "variantId", - ], - how="inner", - ), - _schema=StudyLocus.get_schema(), - ).find_overlaps() - - gold_standards = L2GGoldStandard.from_otg_curation( - gold_standard_curation=self.gs_curation, - variant_index=self.variant_index, - study_locus_overlap=study_locus_overlap, - interactions=self.interactions, + return ( + self.gold_standard.build_feature_matrix( + self.feature_matrix, self.credible_set ) - - return ( - gold_standards.build_feature_matrix( - self.feature_matrix, self.credible_set - ) - .select_features(self.features_list) - .persist() - ) - raise ValueError("Dependencies for train mode not set.") + .select_features(self.features_list) + .persist() + ) class LocusToGeneEvidenceStep: diff --git a/src/gentropy/method/l2g/model.py b/src/gentropy/method/l2g/model.py index e35e255a2..336efeb7f 100644 --- a/src/gentropy/method/l2g/model.py +++ b/src/gentropy/method/l2g/model.py @@ -42,13 +42,11 @@ def __post_init__(self: LocusToGeneModel) -> None: self.model.set_params(**self.hyperparameters_dict) @classmethod - def load_from_disk( - cls: Type[LocusToGeneModel], path: str | Path - ) -> LocusToGeneModel: + def load_from_disk(cls: Type[LocusToGeneModel], path: str) -> LocusToGeneModel: """Load a fitted model from disk. Args: - path (str | Path): Path to the model + path (str): Path to the model Returns: LocusToGeneModel: L2G model loaded from disk @@ -56,7 +54,20 @@ def load_from_disk( Raises: ValueError: If the model has not been fitted yet """ - loaded_model = sio.load(path, trusted=sio.get_untrusted_types(file=path)) + if path.startswith("gs://"): + path = path.removeprefix("gs://") + bucket_name = path.split("/")[0] + blob_name = "/".join(path.split("/")[1:]) + from google.cloud import storage + + client = storage.Client() + bucket = storage.Bucket(client=client, name=bucket_name) + blob = storage.Blob(name=blob_name, bucket=bucket) + data = blob.download_as_string(client=client) + loaded_model = sio.loads(data, trusted=sio.get_untrusted_types(data=data)) + else: + loaded_model = sio.load(path, trusted=sio.get_untrusted_types(file=path)) + if not loaded_model._is_fitted(): raise ValueError("Model has not been fitted yet.") return cls(model=loaded_model) @@ -80,7 +91,7 @@ def load_from_hub( """ local_path = Path(model_id) hub_utils.download(repo_id=model_id, dst=local_path, token=hf_token) - return cls.load_from_disk(Path(local_path) / model_name) + return cls.load_from_disk(str(Path(local_path) / model_name)) @property def hyperparameters_dict(self) -> dict[str, Any]: diff --git a/src/gentropy/method/l2g/trainer.py b/src/gentropy/method/l2g/trainer.py index fe56b3f42..ab2a3fa7e 100644 --- a/src/gentropy/method/l2g/trainer.py +++ b/src/gentropy/method/l2g/trainer.py @@ -97,6 +97,7 @@ def _get_shap_explanation( Raises: ValueError: Train data not set, cannot get SHAP values. + Exception: (ExplanationError) When the additivity check fails. """ if self.x_train is not None and self.x_test is not None: training_data = pd.concat([self.x_train, self.x_test], ignore_index=True) @@ -105,7 +106,14 @@ def _get_shap_explanation( data=training_data, feature_perturbation="interventional", ) - return explainer(training_data) + try: + return explainer(training_data) + except Exception as e: + if "Additivity check failed in TreeExplainer" in repr(e): + return explainer(training_data, check_additivity=False) + else: + raise + raise ValueError("Train data not set.") def log_plot_image_to_wandb( From c46480b1e0d16e1287aaaebafeb07539bdc444dc Mon Sep 17 00:00:00 2001 From: Szymon Szyszkowski <69353402+project-defiant@users.noreply.github.com> Date: Fri, 15 Nov 2024 14:41:46 +0100 Subject: [PATCH 167/188] feat: gzip evicence output to match existing format (#915) * feat: gzip evicence output to match existing format * docs: added info about compression to docstring --------- Co-authored-by: Szymon Szyszkowski --- src/gentropy/l2g.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/gentropy/l2g.py b/src/gentropy/l2g.py index dc95bb670..0dbcd226e 100644 --- a/src/gentropy/l2g.py +++ b/src/gentropy/l2g.py @@ -360,7 +360,7 @@ def __init__( locus_to_gene_predictions_path (str): Path to the L2G predictions dataset credible_set_path (str): Path to the credible set dataset study_index_path (str): Path to the study index dataset - evidence_output_path (str): Path to the L2G evidence output dataset + evidence_output_path (str): Path to the L2G evidence output dataset. The output format is ndjson gzipped. locus_to_gene_threshold (float, optional): Threshold to consider a gene as a target. Defaults to 0.05. """ # Reading the predictions @@ -379,6 +379,7 @@ def __init__( credible_sets, study_index, locus_to_gene_threshold ) .write.mode(session.write_mode) + .option("compression", "gzip") .json(evidence_output_path) ) From 40ca21565fe9dd1441f2f3529de3a202c98d1e0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Irene=20L=C3=B3pez=20Santiago?= <45119610+ireneisdoomed@users.noreply.github.com> Date: Fri, 15 Nov 2024 14:27:48 +0000 Subject: [PATCH 168/188] feat: redefine neighbourhood features to represent similarity with best metric + other fixes (#913) * feat: mean to max * fix: remove protein coding * fix: adding protein coding * feat(l2g): neighbourhood features are a division between local and regional * feat(l2g): regional max for distance features only consider protein coding genes * fix(coloc_features): regional max for coloc features only consider protein coding genes * fix(vep_features): regional max for vep features only consider protein coding genes * feat(l2g): train and predict based on protein coding genes only * feat: set nbh feature to 1 if features are 0 in the region * feat: set nbh feature to 1 if features are 0 in the region * Revert "feat: set nbh feature to 1 if features are 0 in the region" This reverts commit da145ab6465892fcdb79eded7816964765fbe271. * fix: return nbh features only for protein coding genes + optimisation * test: change expected results based on changes * test: change expected results based on changes * fix: test --------- Co-authored-by: Yakov Tsepilov --- src/gentropy/config.py | 2 +- .../dataset/l2g_features/colocalisation.py | 29 +++--- src/gentropy/dataset/l2g_features/distance.py | 41 +++++--- src/gentropy/dataset/l2g_features/vep.py | 36 ++++--- src/gentropy/dataset/l2g_gold_standard.py | 1 + src/gentropy/dataset/l2g_prediction.py | 1 + src/gentropy/l2g.py | 2 +- tests/gentropy/dataset/test_l2g_feature.py | 99 ++++++++----------- .../open_targets/test_l2g_gold_standard.py | 5 +- 9 files changed, 117 insertions(+), 99 deletions(-) diff --git a/src/gentropy/config.py b/src/gentropy/config.py index 6befe472e..4e8cb99e3 100644 --- a/src/gentropy/config.py +++ b/src/gentropy/config.py @@ -263,7 +263,7 @@ class LocusToGeneConfig(StepConfig): "geneCount500kb", "proteinGeneCount500kb", "credibleSetConfidence", - "isProteinCoding", + # "isProteinCoding", ] ) hyperparameters: dict[str, Any] = field( diff --git a/src/gentropy/dataset/l2g_features/colocalisation.py b/src/gentropy/dataset/l2g_features/colocalisation.py index fdbf3ed18..68509ca79 100644 --- a/src/gentropy/dataset/l2g_features/colocalisation.py +++ b/src/gentropy/dataset/l2g_features/colocalisation.py @@ -5,6 +5,7 @@ from typing import TYPE_CHECKING, Any import pyspark.sql.functions as f +from pyspark.sql import Window from gentropy.common.spark_helpers import convert_from_wide_to_long from gentropy.dataset.colocalisation import Colocalisation @@ -168,23 +169,27 @@ def common_neighbourhood_colocalisation_feature_logic( study_locus, ) ) - # Compute average score in the vicinity (feature will be the same for any gene associated with a studyLocus) - # (non protein coding genes in the vicinity are excluded see #3552) - regional_mean_per_study_locus = ( + return ( extended_local_max.join( - gene_index.df.select("geneId", "biotype"), "geneId", "left" + # Compute average score in the vicinity (feature will be the same for any gene associated with a studyLocus) + # (non protein coding genes in the vicinity are excluded see #3552) + gene_index.df.filter(f.col("biotype") == "protein_coding").select("geneId"), + "geneId", + "inner", + ) + .withColumn( + "regional_max", + f.max(local_feature_name).over(Window.partitionBy("studyLocusId")), ) - .filter(f.col("biotype") == "protein_coding") - .groupBy("studyLocusId") - .agg(f.mean(local_feature_name).alias("regional_mean")) - ) - return ( - local_max.join(regional_mean_per_study_locus, "studyLocusId", "left") .withColumn( feature_name, - f.col(local_feature_name) - f.coalesce(f.col("regional_mean"), f.lit(0.0)), + f.when( + (f.col("regional_max").isNotNull()) & (f.col("regional_max") != 0.0), + f.col(local_feature_name) + / f.coalesce(f.col("regional_max"), f.lit(0.0)), + ).otherwise(f.lit(0.0)), ) - .drop("regional_mean", local_feature_name) + .drop("regional_max", local_feature_name) ) diff --git a/src/gentropy/dataset/l2g_features/distance.py b/src/gentropy/dataset/l2g_features/distance.py index 08ffc7c5e..40ad568ac 100644 --- a/src/gentropy/dataset/l2g_features/distance.py +++ b/src/gentropy/dataset/l2g_features/distance.py @@ -8,6 +8,7 @@ from pyspark.sql import Window from gentropy.common.spark_helpers import convert_from_wide_to_long +from gentropy.dataset.gene_index import GeneIndex from gentropy.dataset.l2g_features.l2g_feature import L2GFeature from gentropy.dataset.l2g_gold_standard import L2GGoldStandard from gentropy.dataset.study_locus import StudyLocus @@ -55,7 +56,7 @@ def common_distance_feature_logic( agg_expr = f.sum(f.col("distance_score")) elif "Sentinel" in feature_name: df = study_loci_to_annotate.df.select("studyLocusId", "variantId") - # For minimum distances we calculate the unweighted distance between the sentinel (lead) and the gene. This + # For minimum distances we calculate the unweighted distance between the sentinel (lead) and the gene. distance_score_expr = f.lit(genomic_window) - f.col(distance_type) + f.lit(1) agg_expr = f.first(f.col("distance_score")) return ( @@ -84,15 +85,17 @@ def common_neighbourhood_distance_feature_logic( variant_index: VariantIndex, feature_name: str, distance_type: str, + gene_index: GeneIndex, genomic_window: int = 500_000, ) -> DataFrame: - """Calculate the distance feature that correlates any variant in a credible set with any gene nearby the locus. The distance is weighted by the posterior probability of the variant to factor in its contribution to the trait. + """Calculate the distance feature that correlates any variant in a credible set with any protein coding gene nearby the locus. The distance is weighted by the posterior probability of the variant to factor in its contribution to the trait. Args: study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation variant_index (VariantIndex): The dataset containing distance to gene information feature_name (str): The name of the feature distance_type (str): The type of distance to gene + gene_index (GeneIndex): The dataset containing gene information genomic_window (int): The maximum window size to consider Returns: @@ -109,16 +112,30 @@ def common_neighbourhood_distance_feature_logic( ) return ( # Then compute mean distance in the vicinity (feature will be the same for any gene associated with a studyLocus) - local_metric.withColumn( - "regional_metric", - f.mean(f.col(local_feature_name)).over(Window.partitionBy("studyLocusId")), + local_metric.join( + gene_index.df.filter(f.col("biotype") == "protein_coding").select("geneId"), + "geneId", + "inner", + ) + .withColumn( + "regional_max", + f.max(local_feature_name).over(Window.partitionBy("studyLocusId")), + ) + .withColumn( + feature_name, + f.when( + (f.col("regional_max").isNotNull()) & (f.col("regional_max") != 0.0), + f.col(local_feature_name) + / f.coalesce(f.col("regional_max"), f.lit(0.0)), + ).otherwise(f.lit(0.0)), ) .withColumn( feature_name, - (f.col(local_feature_name) - f.col("regional_metric")) - / f.log10(f.lit(genomic_window + 1)), + f.when(f.col(feature_name) < 0, f.lit(0.0)) + .when(f.col(feature_name) > 1, f.lit(1.0)) + .otherwise(f.col(feature_name)), ) - .drop("regional_metric", local_feature_name) + .drop("regional_max", local_feature_name) ) @@ -168,7 +185,7 @@ def compute( class DistanceTssMeanNeighbourhoodFeature(L2GFeature): """Minimum mean distance to TSS for all genes in the vicinity of a studyLocus.""" - feature_dependency_type = VariantIndex + feature_dependency_type = [VariantIndex, GeneIndex] feature_name = "distanceTssMeanNeighbourhood" @classmethod @@ -244,7 +261,7 @@ def compute( class DistanceSentinelTssNeighbourhoodFeature(L2GFeature): """Distance between the sentinel variant and a gene TSS as a relation of the distnace with all the genes in the vicinity of a studyLocus. This is not weighted by the causal probability.""" - feature_dependency_type = VariantIndex + feature_dependency_type = [VariantIndex, GeneIndex] feature_name = "distanceSentinelTssNeighbourhood" @classmethod @@ -325,7 +342,7 @@ def compute( class DistanceFootprintMeanNeighbourhoodFeature(L2GFeature): """Minimum mean distance to footprint for all genes in the vicinity of a studyLocus.""" - feature_dependency_type = VariantIndex + feature_dependency_type = [VariantIndex, GeneIndex] feature_name = "distanceFootprintMeanNeighbourhood" @classmethod @@ -401,7 +418,7 @@ def compute( class DistanceSentinelFootprintNeighbourhoodFeature(L2GFeature): """Distance between the sentinel variant and a gene footprint as a relation of the distnace with all the genes in the vicinity of a studyLocus. This is not weighted by the causal probability.""" - feature_dependency_type = VariantIndex + feature_dependency_type = [VariantIndex, GeneIndex] feature_name = "distanceSentinelFootprintNeighbourhood" @classmethod diff --git a/src/gentropy/dataset/l2g_features/vep.py b/src/gentropy/dataset/l2g_features/vep.py index 91b03d57b..4f8dd6779 100644 --- a/src/gentropy/dataset/l2g_features/vep.py +++ b/src/gentropy/dataset/l2g_features/vep.py @@ -5,6 +5,7 @@ from typing import TYPE_CHECKING, Any import pyspark.sql.functions as f +from pyspark.sql import Window from gentropy.common.spark_helpers import convert_from_wide_to_long from gentropy.dataset.gene_index import GeneIndex @@ -79,7 +80,7 @@ def common_neighbourhood_vep_feature_logic( gene_index: GeneIndex, feature_name: str, ) -> DataFrame: - """Extracts variant severity score computed from VEP for any gene, based on what is the mean score for protein coding genes that are nearby the locus. + """Extracts variant severity score computed from VEP for any gene, based on what is the max score for protein coding genes that are nearby the locus. Args: study_loci_to_annotate (StudyLocus | L2GGoldStandard): The dataset containing study loci that will be used for annotation @@ -95,26 +96,29 @@ def common_neighbourhood_vep_feature_logic( study_loci_to_annotate, feature_name=local_feature_name, variant_index=variant_index, - ).join( - # Bring gene classification - gene_index.df.select("geneId", "biotype"), - "geneId", - "inner", - ) - # Compute average score in the vicinity (feature will be the same for any gene associated with a studyLocus) - # (non protein coding genes in the vicinity are excluded see #3552) - regional_mean_per_study_locus = ( - local_metric.filter(f.col("biotype") == "protein_coding") - .groupBy("studyLocusId") - .agg(f.mean(local_feature_name).alias("regional_mean")) ) return ( - local_metric.join(regional_mean_per_study_locus, "studyLocusId", "left") + local_metric + # Compute average score in the vicinity (feature will be the same for any gene associated with a studyLocus) + # (non protein coding genes in the vicinity are excluded see #3552) + .join( + gene_index.df.filter(f.col("biotype") == "protein_coding").select("geneId"), + "geneId", + "inner", + ) + .withColumn( + "regional_max", + f.max(local_feature_name).over(Window.partitionBy("studyLocusId")), + ) .withColumn( feature_name, - f.col(local_feature_name) - f.coalesce(f.col("regional_mean"), f.lit(0.0)), + f.when( + (f.col("regional_max").isNotNull()) & (f.col("regional_max") != 0.0), + f.col(local_feature_name) + / f.coalesce(f.col("regional_max"), f.lit(0.0)), + ).otherwise(f.lit(0.0)), ) - .drop("regional_mean", local_feature_name, "biotype") + .drop("regional_max", local_feature_name) ) diff --git a/src/gentropy/dataset/l2g_gold_standard.py b/src/gentropy/dataset/l2g_gold_standard.py index ec99f7141..4acf96cd2 100644 --- a/src/gentropy/dataset/l2g_gold_standard.py +++ b/src/gentropy/dataset/l2g_gold_standard.py @@ -132,6 +132,7 @@ def build_feature_matrix( on=["studyId", "variantId", "geneId"], how="inner", ) + .filter(f.col("isProteinCoding") == 1) .drop("studyId", "variantId") .distinct(), with_gold_standard=True, diff --git a/src/gentropy/dataset/l2g_prediction.py b/src/gentropy/dataset/l2g_prediction.py index 64ce964c7..2bc286a40 100644 --- a/src/gentropy/dataset/l2g_prediction.py +++ b/src/gentropy/dataset/l2g_prediction.py @@ -78,6 +78,7 @@ def from_credible_set( credible_set.df.filter(f.col("studyType") == "gwas") .select("studyLocusId") .join(feature_matrix._df, "studyLocusId") + .filter(f.col("isProteinCoding") == 1) ) ) .fill_na() diff --git a/src/gentropy/l2g.py b/src/gentropy/l2g.py index 0dbcd226e..548368967 100644 --- a/src/gentropy/l2g.py +++ b/src/gentropy/l2g.py @@ -163,7 +163,7 @@ def __init__( session, credible_set_path, recursiveFileLookup=True ) self.feature_matrix = L2GFeatureMatrix( - _df=session.load_data(feature_matrix_path), features_list=self.features_list + _df=session.load_data(feature_matrix_path), ) if run_mode == "predict": diff --git a/tests/gentropy/dataset/test_l2g_feature.py b/tests/gentropy/dataset/test_l2g_feature.py index 0637b4a86..feb8e449a 100644 --- a/tests/gentropy/dataset/test_l2g_feature.py +++ b/tests/gentropy/dataset/test_l2g_feature.py @@ -346,21 +346,21 @@ def test_common_neighbourhood_colocalisation_feature_logic( gene_index=sample_gene_index, variant_index=sample_variant_index, ).withColumn(feature_name, f.round(f.col(feature_name), 3)) - # expected average is (0.81 + 0)/2 = 0.405 + # expected max is 0.81 expected_df = spark.createDataFrame( [ { "studyLocusId": "1", "geneId": "gene1", - "eQtlColocH4MaximumNeighbourhood": 0.405, # 0.81 - 0.405 + "eQtlColocH4MaximumNeighbourhood": 1.0, # 0.81 / 0.81 }, { "studyLocusId": "1", - "geneId": "gene2", - "eQtlColocH4MaximumNeighbourhood": 0.495, # 0.9 - 0.405 + "geneId": "gene3", + "eQtlColocH4MaximumNeighbourhood": 0.0, # 0.0 (no coloc with gene3) /0.81 }, ], - ).select("studyLocusId", "geneId", "eQtlColocH4MaximumNeighbourhood") + ).select("geneId", "studyLocusId", "eQtlColocH4MaximumNeighbourhood") assert ( observed_df.collect() == expected_df.collect() ), "The expected and observed dataframes do not match." @@ -561,6 +561,7 @@ def test_common_neighbourhood_distance_feature_logic( common_neighbourhood_distance_feature_logic( self.sample_study_locus, variant_index=self.sample_variant_index, + gene_index=self.sample_gene_index, feature_name=feature_name, distance_type=self.distance_type, genomic_window=10, @@ -568,9 +569,12 @@ def test_common_neighbourhood_distance_feature_logic( .withColumn(feature_name, f.round(f.col(feature_name), 2)) .orderBy(f.col(feature_name).asc()) ) - expected_df = spark.createDataFrame( - (["1", "gene1", -0.44], ["1", "gene2", 0.44]), - ["studyLocusId", "geneId", feature_name], + expected_df = spark.createDataFrame( # regional max is 0.91 from gene2 + ( + ["gene1", "1", 0.0], # (10-10)/0.91 + ["gene2", "1", 1.0], + ), # 0.91/0.91 + ["geneId", "studyLocusId", feature_name], ).orderBy(feature_name) assert ( observed_df.collect() == expected_df.collect() @@ -649,6 +653,32 @@ def _setup( ), _schema=VariantIndex.get_schema(), ) + self.sample_gene_index = GeneIndex( + _df=spark.createDataFrame( + [ + { + "geneId": "gene1", + "chromosome": "1", + "tss": 950000, + "biotype": "protein_coding", + }, + { + "geneId": "gene2", + "chromosome": "1", + "tss": 1050000, + "biotype": "protein_coding", + }, + { + "geneId": "gene3", + "chromosome": "1", + "tss": 1010000, + "biotype": "non_coding", + }, + ], + GeneIndex.get_schema(), + ), + _schema=GeneIndex.get_schema(), + ) class TestCommonVepFeatureLogic: @@ -727,55 +757,13 @@ def test_common_vep_feature_logic( observed_df.collect() == expected_df.collect() ), f"Expected and observed dataframes are not equal for feature {feature_name}." - def test_common_neighbourhood_vep_feature_logic_no_protein_coding( - self: TestCommonVepFeatureLogic, - spark: SparkSession, - sample_gene_index: GeneIndex, - sample_variant_index: VariantIndex, - ) -> None: - """Test the logic of the function that extracts the maximum severity score for a gene given the average of the maximum scores for all protein coding genes in the vicinity. - - Because the genes in the vicinity are all non coding, the neighbourhood features should equal the local ones. - """ - feature_name = "vepMaximumNeighbourhood" - non_protein_coding_gene_index = GeneIndex( - _df=sample_gene_index.df.filter(f.col("geneId") != "gene3"), - _schema=GeneIndex.get_schema(), - ) - observed_df = ( - common_neighbourhood_vep_feature_logic( - self.sample_study_locus, - variant_index=sample_variant_index, - gene_index=non_protein_coding_gene_index, - feature_name=feature_name, - ) - .withColumn(feature_name, f.round(f.col(feature_name), 2)) - .orderBy(f.col(feature_name).asc()) - .select("studyLocusId", "geneId", feature_name) - ) - expected_df = ( - spark.createDataFrame( - # regional mean is 0.66 - ( - ["1", "gene1", 0.0], - ["1", "gene2", 0.34], - ), # (0.66-0.66) and (1.0-0.66) - ["studyLocusId", "geneId", feature_name], - ) - .orderBy(feature_name) - .select("studyLocusId", "geneId", feature_name) - ) - assert ( - observed_df.collect() == expected_df.collect() - ), "Output doesn't meet the expectation." - def test_common_neighbourhood_vep_feature_logic( self: TestCommonVepFeatureLogic, spark: SparkSession, sample_gene_index: GeneIndex, sample_variant_index: VariantIndex, ) -> None: - """Test the logic of the function that extracts the maximum severity score for a gene given the average of the maximum scores for all protein coding genes in the vicinity.""" + """Test the logic of the function that extracts the maximum severity score for a gene given the maximum of the maximum scores for all protein coding genes in the vicinity.""" feature_name = "vepMaximumNeighbourhood" observed_df = ( common_neighbourhood_vep_feature_logic( @@ -789,12 +777,11 @@ def test_common_neighbourhood_vep_feature_logic( ) expected_df = ( spark.createDataFrame( - # regional mean is 0.66/2 = 0.33 + # regional max is 0.66 ( - ["1", "gene3", -0.33], - ["1", "gene1", 0.33], - ["1", "gene2", 0.67], - ), # (0 - 0.33) and (0.66-0.33) and (1.0 -0.33) + ["1", "gene1", 1.0], # 0.66/0.66 + ["1", "gene3", 0.0], # 0/0.66 + ), ["studyLocusId", "geneId", feature_name], ) .orderBy(feature_name) diff --git a/tests/gentropy/datasource/open_targets/test_l2g_gold_standard.py b/tests/gentropy/datasource/open_targets/test_l2g_gold_standard.py index e6afc942f..79f9d925a 100644 --- a/tests/gentropy/datasource/open_targets/test_l2g_gold_standard.py +++ b/tests/gentropy/datasource/open_targets/test_l2g_gold_standard.py @@ -29,6 +29,7 @@ from pyspark.sql.session import SparkSession from gentropy.dataset.colocalisation import Colocalisation + from gentropy.dataset.gene_index import GeneIndex from gentropy.dataset.study_locus import StudyLocus @@ -161,13 +162,15 @@ def test_build_feature_matrix( mock_study_locus: StudyLocus, mock_colocalisation: Colocalisation, mock_study_index: StudyIndex, + mock_gene_index: GeneIndex, ) -> None: """Test building feature matrix with the eQtlColocH4Maximum feature.""" - features_list = ["eQtlColocH4Maximum"] + features_list = ["eQtlColocH4Maximum", "isProteinCoding"] loader = L2GFeatureInputLoader( colocalisation=mock_colocalisation, study_index=mock_study_index, study_locus=mock_study_locus, + gene_index=mock_gene_index, ) fm = mock_study_locus.build_feature_matrix(features_list, loader) assert isinstance( From 8f8c711a54d3332f925394f455b69334f359e90a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Nov 2024 11:34:25 +0000 Subject: [PATCH 169/188] chore(deps): bump codecov/codecov-action from 4 to 5 (#916) Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 4 to 5. - [Release notes](https://github.com/codecov/codecov-action/releases) - [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/codecov/codecov-action/compare/v4...v5) --- updated-dependencies: - dependency-name: codecov/codecov-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/pr.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index f27ae499e..d32a3b28e 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -46,7 +46,7 @@ jobs: - name: Run tests run: poetry run pytest - name: Upload coverage to Codecov - uses: codecov/codecov-action@v4 + uses: codecov/codecov-action@v5 with: token: ${{ secrets.CODECOV_TOKEN }} files: ./coverage.xml From cff83ce059286d48fa27fe9f90740b9a672dd037 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Nov 2024 11:49:34 +0000 Subject: [PATCH 170/188] build(deps-dev): bump pytest-cov from 5.0.0 to 6.0.0 (#893) Bumps [pytest-cov](https://github.com/pytest-dev/pytest-cov) from 5.0.0 to 6.0.0. - [Changelog](https://github.com/pytest-dev/pytest-cov/blob/master/CHANGELOG.rst) - [Commits](https://github.com/pytest-dev/pytest-cov/compare/v5.0.0...v6.0.0) --- updated-dependencies: - dependency-name: pytest-cov dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- poetry.lock | 14 +++++++------- pyproject.toml | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/poetry.lock b/poetry.lock index edba6ef99..aea09f8c9 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. [[package]] name = "aiodns" @@ -4414,17 +4414,17 @@ dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments [[package]] name = "pytest-cov" -version = "5.0.0" +version = "6.0.0" description = "Pytest plugin for measuring coverage." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "pytest-cov-5.0.0.tar.gz", hash = "sha256:5837b58e9f6ebd335b0f8060eecce69b662415b16dc503883a02f45dfeb14857"}, - {file = "pytest_cov-5.0.0-py3-none-any.whl", hash = "sha256:4f0764a1219df53214206bf1feea4633c3b558a2925c8b59f144f682861ce652"}, + {file = "pytest-cov-6.0.0.tar.gz", hash = "sha256:fde0b595ca248bb8e2d76f020b465f3b107c9632e6a1d1705f17834c89dcadc0"}, + {file = "pytest_cov-6.0.0-py3-none-any.whl", hash = "sha256:eee6f1b9e61008bd34975a4d5bab25801eb31898b032dd55addc93e96fcaaa35"}, ] [package.dependencies] -coverage = {version = ">=5.2.1", extras = ["toml"]} +coverage = {version = ">=7.5", extras = ["toml"]} pytest = ">=4.6" [package.extras] @@ -5959,4 +5959,4 @@ propcache = ">=0.2.0" [metadata] lock-version = "2.0" python-versions = "^3.10, <3.11" -content-hash = "c22ab3de1b76f7549448f4204d52fe0a2d9e68cbbd4d4e873fad667a075dffe3" +content-hash = "af70455b40ec31084130c90b9dc468a5c1198f80e6ae30d10bfb1b17d1706537" diff --git a/pyproject.toml b/pyproject.toml index 54b5a20ca..fd69201cb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -61,7 +61,7 @@ pymdown-extensions = "^10.7" [tool.poetry.group.tests.dependencies] -pytest-cov = ">=4.1,<6.0" +pytest-cov = ">=4.1,<7.0" pytest-sugar = ">=0.9.5,<1.1.0" dbldatagen = ">=0.3.1,<0.5.0" pyparsing = "^3.1.1" From 4104ce3efc54e0db2f622940fc43ff46c3e26bdf Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 18 Nov 2024 12:31:52 +0000 Subject: [PATCH 171/188] chore: pre-commit autoupdate (#898) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.7.1 → v0.7.3](https://github.com/astral-sh/ruff-pre-commit/compare/v0.7.1...v0.7.3) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e62a9d790..2c9da9926 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -6,7 +6,7 @@ ci: skip: [poetry-lock] repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.7.1 + rev: v0.7.3 hooks: - id: ruff args: From 9f9cfd6479b2bbef71ac596457cf27e3804ea2a5 Mon Sep 17 00:00:00 2001 From: Daniel Suveges Date: Tue, 19 Nov 2024 11:18:08 +0000 Subject: [PATCH 172/188] feat(variant index): variant description to summarise variant consequences in transcripts (#914) * feat: extending the VEP schema * feat(vep parser): adding logic to build variant description based on VEP annotation * fix: remove commented lines * fix: improving consequence to so term mapping * fix: nullified variant descriptions * fix: assessment_flag_column_name type fix * chore: pre-commit auto fixes [...] * feat: adding formatting to distances in description * fix: formatting * fix: variant index schema * fix: conftest for variant index * feat(variant index): normalising assessments of in-silico predictors * feat: adding VEP predictor * fix: variant test config * fix: variant test config * fix: schema type * fix: dropping failing test * fix: variant annotatin * fix: gnomad variant index repartition --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .../assets/schemas/variant_index.json | 24 + .../assets/schemas/vep_json_output.json | 12 + src/gentropy/common/spark_helpers.py | 7 +- src/gentropy/config.py | 6 + src/gentropy/dataset/variant_index.py | 266 +++++++++++ src/gentropy/datasource/ensembl/vep_parser.py | 445 +++++++++++++++--- src/gentropy/datasource/gnomad/variants.py | 13 +- src/gentropy/gnomad_ingestion.py | 4 +- tests/gentropy/conftest.py | 7 +- .../datasource/ensembl/test_vep_variants.py | 28 -- 10 files changed, 708 insertions(+), 104 deletions(-) diff --git a/src/gentropy/assets/schemas/variant_index.json b/src/gentropy/assets/schemas/variant_index.json index 6d5e211ac..1f1ef787c 100644 --- a/src/gentropy/assets/schemas/variant_index.json +++ b/src/gentropy/assets/schemas/variant_index.json @@ -67,6 +67,12 @@ "name": "targetId", "nullable": true, "type": "string" + }, + { + "metadata": {}, + "name": "normalisedScore", + "nullable": true, + "type": "double" } ], "type": "struct" @@ -192,6 +198,18 @@ "nullable": true, "type": "integer" }, + { + "metadata": {}, + "name": "approvedSymbol", + "nullable": true, + "type": "string" + }, + { + "metadata": {}, + "name": "biotype", + "nullable": true, + "type": "string" + }, { "metadata": {}, "name": "transcriptId", @@ -271,6 +289,12 @@ }, "type": "array" } + }, + { + "metadata": {}, + "name": "variantDescription", + "nullable": true, + "type": "string" } ], "type": "struct" diff --git a/src/gentropy/assets/schemas/vep_json_output.json b/src/gentropy/assets/schemas/vep_json_output.json index 43c3f4ad7..674788407 100644 --- a/src/gentropy/assets/schemas/vep_json_output.json +++ b/src/gentropy/assets/schemas/vep_json_output.json @@ -340,6 +340,18 @@ "nullable": true, "type": "string" }, + { + "metadata": {}, + "name": "gene_symbol", + "nullable": true, + "type": "string" + }, + { + "metadata": {}, + "name": "biotype", + "nullable": true, + "type": "string" + }, { "metadata": {}, "name": "appris", diff --git a/src/gentropy/common/spark_helpers.py b/src/gentropy/common/spark_helpers.py index a1bf9670a..64a8bceb7 100644 --- a/src/gentropy/common/spark_helpers.py +++ b/src/gentropy/common/spark_helpers.py @@ -848,6 +848,7 @@ def get_struct_field_schema(schema: t.StructType, name: str) -> t.DataType: raise ValueError("Provided name %s is not present in the schema.", name) return matching_fields[0].dataType + def calculate_harmonic_sum(input_array: Column) -> Column: """Calculate the harmonic sum of an array. @@ -876,9 +877,11 @@ def calculate_harmonic_sum(input_array: Column) -> Column: return f.aggregate( f.arrays_zip( f.sort_array(input_array, False).alias("score"), - f.sequence(f.lit(1), f.size(input_array)).alias("pos") + f.sequence(f.lit(1), f.size(input_array)).alias("pos"), ), f.lit(0.0), lambda acc, x: acc - + x["score"]/f.pow(x["pos"], 2)/f.lit(sum(1 / ((i + 1)**2) for i in range(1000))) + + x["score"] + / f.pow(x["pos"], 2) + / f.lit(sum(1 / ((i + 1) ** 2) for i in range(1000))), ) diff --git a/src/gentropy/config.py b/src/gentropy/config.py index 4e8cb99e3..a84dbd89e 100644 --- a/src/gentropy/config.py +++ b/src/gentropy/config.py @@ -476,6 +476,11 @@ class _ConsequenceToPathogenicityScoreMap(TypedDict): "label": "splice_polypyrimidine_tract_variant", "score": 0.33, }, + { + "id": "SO_0001626", + "label": "incomplete_terminal_codon_variant", + "score": 0.33, + }, {"id": "SO_0001819", "label": "synonymous_variant", "score": 0.33}, { "id": "SO_0002170", @@ -499,6 +504,7 @@ class _ConsequenceToPathogenicityScoreMap(TypedDict): "score": 0.0, }, {"id": "SO_0001620", "label": "mature_miRNA_variant", "score": 0.0}, + {"id": "SO_0001060", "label": "intergenic_variant", "score": 0.0}, ] _target_: str = "gentropy.variant_index.VariantIndexStep" diff --git a/src/gentropy/dataset/variant_index.py b/src/gentropy/dataset/variant_index.py index 9e8740aa6..4092ca961 100644 --- a/src/gentropy/dataset/variant_index.py +++ b/src/gentropy/dataset/variant_index.py @@ -298,3 +298,269 @@ def get_loftee(self: VariantIndex) -> DataFrame: "isHighQualityPlof", ) ) + + +class InSilicoPredictorNormaliser: + """Class to normalise in silico predictor assessments. + + Essentially based on the raw scores, it normalises the scores to a range between -1 and 1, and appends the normalised + value to the in silico predictor struct. + + The higher negative values indicate increasingly confident prediction to be a benign variant, + while the higher positive values indicate increasingly deleterious predicted effect. + + The point of these operations to make the scores comparable across different in silico predictors. + """ + + @classmethod + def normalise_in_silico_predictors( + cls: type[InSilicoPredictorNormaliser], + in_silico_predictors: Column, + ) -> Column: + """Normalise in silico predictors. Appends a normalised score to the in silico predictor struct. + + Args: + in_silico_predictors (Column): Column containing in silico predictors (list of structs). + + Returns: + Column: Normalised in silico predictors. + """ + return f.transform( + in_silico_predictors, + lambda predictor: f.struct( + # Extracing all existing columns: + predictor.method.alias("method"), + predictor.assessment.alias("assessment"), + predictor.score.alias("score"), + predictor.assessmentFlag.alias("assessmentFlag"), + predictor.targetId.alias("targetId"), + # Normalising the score + cls.resolve_predictor_methods( + predictor.score, predictor.method, predictor.assessment + ).alias("normalisedScore"), + ), + ) + + @classmethod + def resolve_predictor_methods( + cls: type[InSilicoPredictorNormaliser], + score: Column, + method: Column, + assessment: Column, + ) -> Column: + """It takes a score, a method, and an assessment, and returns a normalized score for the in silico predictor. + + Args: + score (Column): The raw score from the in silico predictor. + method (Column): The method used to generate the score. + assessment (Column): The assessment of the score. + + Returns: + Column: Normalised score for the in silico predictor. + """ + return ( + f.when(method == "LOFTEE", cls._normalise_loftee(assessment)) + .when(method == "SIFT", cls._normalise_sift(score, assessment)) + .when(method == "PolyPhen", cls._normalise_polyphen(assessment, score)) + .when(method == "AlphaMissense", cls._normalise_alpha_missense(score)) + .when(method == "CADD", cls._normalise_cadd(score)) + .when(method == "Pangolin", cls._normalise_pangolin(score)) + # The following predictors are not normalised: + .when(method == "SpliceAI", score) + .when(method == "VEP", score) + ) + + @staticmethod + def _rescaleColumnValue( + column: Column, + min_value: float, + max_value: float, + minimum: float = 0.0, + maximum: float = 1.0, + ) -> Column: + """Rescale a column to a new range. Similar to MinMaxScaler in pyspark ML. + + Args: + column (Column): Column to rescale. + min_value (float): Minimum value of the column. + max_value (float): Maximum value of the column. + minimum (float, optional): Minimum value of the new range. Defaults to 0.0. + maximum (float, optional): Maximum value of the new range. Defaults to 1.0. + + Returns: + Column: Rescaled column. + """ + return (column - min_value) / (max_value - min_value) * ( + maximum - minimum + ) + minimum + + @classmethod + def _normalise_cadd( + cls: type[InSilicoPredictorNormaliser], + score: Column, + ) -> Column: + """Normalise CADD scores. + + Logic: CADD scores are divided into four ranges and scaled accordingly: + - 0-10 -> -1-0 (likely benign ~2M) + - 10-20 -> 0-0.5 (potentially deleterious ~300k) + - 20-30 -> 0.5-0.75 (likely deleterious ~350k) + - 30-81 -> 0.75-1 (highly likely deleterious ~86k) + + Args: + score (Column): CADD score. + + Returns: + Column: Normalised CADD score. + """ + return ( + f.when(score <= 10, cls._rescaleColumnValue(score, 0, 10, -1.0, 0.0)) + .when(score <= 20, cls._rescaleColumnValue(score, 10, 20, 0.0, 0.5)) + .when(score <= 30, cls._rescaleColumnValue(score, 20, 30, 0.5, 0.75)) + .when(score > 30, cls._rescaleColumnValue(score, 30, 81, 0.75, 1)) + ) + + @classmethod + def _normalise_loftee( + cls: type[InSilicoPredictorNormaliser], + assessment: Column, + ) -> Column: + """Normalise LOFTEE scores. + + Logic: LOFTEE scores are divided into two categories: + - HC (high confidence): 1.0 (~120k) + - LC (low confidence): 0.85 (~18k) + The normalised score is calculated based on the category the score falls into. + + Args: + assessment (Column): LOFTEE assessment. + + Returns: + Column: Normalised LOFTEE score. + """ + return f.when(assessment == "HC", f.lit(1)).when( + assessment == "LC", f.lit(0.85) + ) + + @classmethod + def _normalise_sift( + cls: type[InSilicoPredictorNormaliser], + score: Column, + assessment: Column, + ) -> Column: + """Normalise SIFT scores. + + Logic: SIFT scores are divided into four categories: + - deleterious and score >= 0.95: 0.75-1 + - deleterious_low_confidence and score >= 0.95: 0.5-0.75 + - tolerated_low_confidence and score <= 0.95: 0.25-0.5 + - tolerated and score <= 0.95: 0-0.25 + + Args: + score (Column): SIFT score. + assessment (Column): SIFT assessment. + + Returns: + Column: Normalised SIFT score. + """ + return ( + f.when( + (1 - f.round(score.cast(t.DoubleType()), 2) >= 0.95) + & (assessment == "deleterious"), + cls._rescaleColumnValue(1 - score, 0.95, 1, 0.5, 1), + ) + .when( + (1 - f.round(score.cast(t.DoubleType()), 2) >= 0.95) + & (assessment == "deleterious_low_confidence"), + cls._rescaleColumnValue(1 - score, 0.95, 1, 0, 0.5), + ) + .when( + (1 - f.round(score.cast(t.DoubleType()), 2) <= 0.95) + & (assessment == "tolerated_low_confidence"), + cls._rescaleColumnValue(1 - score, 0, 0.95, -0.5, 0.0), + ) + .when( + (1 - f.round(score.cast(t.DoubleType()), 2) <= 0.95) + & (assessment == "tolerated"), + cls._rescaleColumnValue(1 - score, 0, 0.95, -1, -0.5), + ) + ) + + @classmethod + def _normalise_polyphen( + cls: type[InSilicoPredictorNormaliser], + assessment: Column, + score: Column, + ) -> Column: + """Normalise PolyPhen scores. + + Logic: PolyPhen scores are divided into three categories: + - benign: 0-0.446: -1--0.25 + - possibly_damaging: 0.446-0.908: -0.25-0.25 + - probably_damaging: 0.908-1: 0.25-1 + - if assessment is unknown: None + + Args: + assessment (Column): PolyPhen assessment. + score (Column): PolyPhen score. + + Returns: + Column: Normalised PolyPhen score. + """ + return ( + f.when(assessment == "unknown", f.lit(None).cast(t.DoubleType())) + .when(score <= 0.446, cls._rescaleColumnValue(score, 0, 0.446, -1.0, -0.25)) + .when( + score <= 0.908, + cls._rescaleColumnValue(score, 0.446, 0.908, -0.25, 0.25), + ) + .when(score > 0.908, cls._rescaleColumnValue(score, 0.908, 1.0, 0.25, 1.0)) + ) + + @classmethod + def _normalise_alpha_missense( + cls: type[InSilicoPredictorNormaliser], + score: Column, + ) -> Column: + """Normalise AlphaMissense scores. + + Logic: AlphaMissense scores are divided into three categories: + - 0-0.06: -1.0--0.25 + - 0.06-0.77: -0.25-0.25 + - 0.77-1: 0.25-1 + + Args: + score (Column): AlphaMissense score. + + Returns: + Column: Normalised AlphaMissense score. + """ + return ( + f.when(score < 0.06, cls._rescaleColumnValue(score, 0, 0.06, -1.0, -0.25)) + .when(score < 0.77, cls._rescaleColumnValue(score, 0.06, 0.77, -0.25, 0.25)) + .when(score >= 0.77, cls._rescaleColumnValue(score, 0.77, 1, 0.25, 1)) + ) + + @classmethod + def _normalise_pangolin( + cls: type[InSilicoPredictorNormaliser], + score: Column, + ) -> Column: + """Normalise Pangolin scores. + + Logic: Pangolin scores are divided into two categories: + - 0-0.14: 0-0.25 + - 0.14-1: 0.75-1 + + Args: + score (Column): Pangolin score. + + Returns: + Column: Normalised Pangolin score. + """ + return f.when( + f.abs(score) > 0.14, cls._rescaleColumnValue(f.abs(score), 0.14, 1, 0.5, 1) + ).when( + f.abs(score) <= 0.14, + cls._rescaleColumnValue(f.abs(score), 0, 0.14, 0.0, 0.5), + ) diff --git a/src/gentropy/datasource/ensembl/vep_parser.py b/src/gentropy/datasource/ensembl/vep_parser.py index 01c820513..9494bf6f3 100644 --- a/src/gentropy/datasource/ensembl/vep_parser.py +++ b/src/gentropy/datasource/ensembl/vep_parser.py @@ -16,7 +16,7 @@ order_array_of_structs_by_field, order_array_of_structs_by_two_fields, ) -from gentropy.dataset.variant_index import VariantIndex +from gentropy.dataset.variant_index import InSilicoPredictorNormaliser, VariantIndex if TYPE_CHECKING: from pyspark.sql import Column, DataFrame @@ -41,6 +41,18 @@ class VariantEffectPredictorParser: # Schema for the allele frequency column: ALLELE_FREQUENCY_SCHEMA = VariantIndex.get_schema()["alleleFrequencies"].dataType + # Consequence to sequence ontology map: + SEQUENCE_ONTOLOGY_MAP = { + item["label"]: item["id"] + for item in VariantIndexConfig.consequence_to_pathogenicity_score + } + + # Sequence ontology to score map: + LABEL_TO_SCORE_MAP = { + item["label"]: item["score"] + for item in VariantIndexConfig.consequence_to_pathogenicity_score + } + @staticmethod def get_schema() -> t.StructType: """Return the schema of the VEP output. @@ -328,8 +340,19 @@ def _get_most_severe_transcript( lambda transcript: transcript.getItem(score_field_name).isNotNull(), )[0] + @classmethod @enforce_schema(IN_SILICO_PREDICTOR_SCHEMA) + def _get_vep_prediction(cls, most_severe_consequence: Column) -> Column: + return f.struct( + f.lit("VEP").alias("method"), + most_severe_consequence.alias("assessment"), + map_column_by_dictionary( + most_severe_consequence, cls.LABEL_TO_SCORE_MAP + ).alias("score"), + ) + @staticmethod + @enforce_schema(IN_SILICO_PREDICTOR_SCHEMA) def _get_max_alpha_missense(transcripts: Column) -> Column: """Return the most severe alpha missense prediction from all transcripts. @@ -354,37 +377,42 @@ def _get_max_alpha_missense(transcripts: Column) -> Column: ... .select(VariantEffectPredictorParser._get_max_alpha_missense(f.col('transcripts')).alias('am')) ... .show(truncate=False) ... ) - +----------------------------------------------------+ - |am | - +----------------------------------------------------+ - |{max alpha missense, assessment 1, 0.4, null, gene1}| - |{max alpha missense, null, null, null, gene1} | - +----------------------------------------------------+ + +-----------------------------------------------------+ + |am | + +-----------------------------------------------------+ + |{AlphaMissense, assessment 1, 0.4, null, gene1, null}| + |{AlphaMissense, null, null, null, gene1, null} | + +-----------------------------------------------------+ """ - return f.transform( - # Extract transcripts with alpha missense values: - f.filter( - transcripts, - lambda transcript: transcript.getItem("alphamissense").isNotNull(), - ), - # Extract alpha missense values: - lambda transcript: f.struct( - transcript.getItem("alphamissense") - .getItem("am_pathogenicity") - .cast(t.FloatType()) - .alias("score"), - transcript.getItem("alphamissense") - .getItem("am_class") - .alias("assessment"), - f.lit("max alpha missense").alias("method"), - transcript.getItem("gene_id").alias("targetId"), - ), + # Extracting transcript with alpha missense values: + transcript = f.filter( + transcripts, + lambda transcript: transcript.getItem("alphamissense").isNotNull(), )[0] + return f.when( + transcript.isNotNull(), + f.struct( + # Adding method: + f.lit("AlphaMissense").alias("method"), + # Extracting assessment: + transcript.alphamissense.am_class.alias("assessment"), + # Extracting score: + transcript.alphamissense.am_pathogenicity.cast(t.FloatType()).alias( + "score" + ), + # Adding assessment flag: + f.lit(None).cast(t.StringType()).alias("assessmentFlag"), + # Extracting target id: + transcript.gene_id.alias("targetId"), + ), + ) + + @classmethod @enforce_schema(IN_SILICO_PREDICTOR_SCHEMA) - @staticmethod def _vep_in_silico_prediction_extractor( + cls: type[VariantEffectPredictorParser], transcript_column_name: str, method_name: str, score_column_name: str | None = None, @@ -403,7 +431,7 @@ def _vep_in_silico_prediction_extractor( Returns: Column: In silico predictor. """ - # Get highest score: + # Get transcript with the highest score: most_severe_transcript: Column = ( # Getting the most severe transcript: VariantEffectPredictorParser._get_most_severe_transcript( @@ -419,31 +447,44 @@ def _vep_in_silico_prediction_extractor( ) ) + # Get assessment: + assessment = ( + f.lit(None).cast(t.StringType()).alias("assessment") + if assessment_column_name is None + else most_severe_transcript.getField(assessment_column_name).alias( + "assessment" + ) + ) + + # Get score: + score = ( + f.lit(None).cast(t.FloatType()).alias("score") + if score_column_name is None + else most_severe_transcript.getField(score_column_name) + .cast(t.FloatType()) + .alias("score") + ) + + # Get assessment flag: + assessment_flag = ( + f.lit(None).cast(t.StringType()).alias("assessmentFlag") + if assessment_flag_column_name is None + else most_severe_transcript.getField(assessment_flag_column_name) + .cast(t.StringType()) + .alias("assessmentFlag") + ) + + # Extract gene id: + gene_id = most_severe_transcript.getItem("gene_id").alias("targetId") + return f.when( most_severe_transcript.isNotNull(), f.struct( - # Adding method name: - f.lit(method_name).cast(t.StringType()).alias("method"), - # Adding assessment: - f.lit(None).cast(t.StringType()).alias("assessment") - if assessment_column_name is None - else most_severe_transcript.getField(assessment_column_name).alias( - "assessment" - ), - # Adding score: - f.lit(None).cast(t.FloatType()).alias("score") - if score_column_name is None - else most_severe_transcript.getField(score_column_name) - .cast(t.FloatType()) - .alias("score"), - # Adding assessment flag: - f.lit(None).cast(t.StringType()).alias("assessmentFlag") - if assessment_flag_column_name is None - else most_severe_transcript.getField(assessment_flag_column_name) - .cast(t.FloatType()) - .alias("assessmentFlag"), - # Adding target id if present: - most_severe_transcript.getItem("gene_id").alias("targetId"), + f.lit(method_name).alias("method"), + assessment, + score, + assessment_flag, + gene_id, ), ) @@ -569,16 +610,6 @@ def process_vep_output( Returns: DataFrame: processed data in the right shape. """ - # Consequence to sequence ontology map: - sequence_ontology_map = { - item["label"]: item["id"] - for item in VariantIndexConfig.consequence_to_pathogenicity_score - } - # Sequence ontology to score map: - label_to_score_map = { - item["label"]: item["score"] - for item in VariantIndexConfig.consequence_to_pathogenicity_score - } # Processing VEP output: return ( vep_output @@ -612,26 +643,26 @@ def process_vep_output( # Extract CADD scores: cls._vep_in_silico_prediction_extractor( transcript_column_name="transcript_consequences", - method_name="phred scaled CADD", + method_name="CADD", score_column_name="cadd_phred", ), # Extract polyphen scores: cls._vep_in_silico_prediction_extractor( transcript_column_name="transcript_consequences", - method_name="polyphen", + method_name="PolyPhen", score_column_name="polyphen_score", assessment_column_name="polyphen_prediction", ), # Extract sift scores: cls._vep_in_silico_prediction_extractor( transcript_column_name="transcript_consequences", - method_name="sift", + method_name="SIFT", score_column_name="sift_score", assessment_column_name="sift_prediction", ), # Extract loftee scores: cls._vep_in_silico_prediction_extractor( - method_name="loftee", + method_name="LOFTEE", transcript_column_name="transcript_consequences", score_column_name="lof", assessment_column_name="lof", @@ -641,6 +672,8 @@ def process_vep_output( cls._get_max_alpha_missense( f.col("transcript_consequences") ), + # Extract VEP prediction: + cls._get_vep_prediction(f.col("most_severe_consequence")), ), lambda predictor: predictor.isNotNull(), ), @@ -650,16 +683,20 @@ def process_vep_output( f.array( cls._vep_in_silico_prediction_extractor( transcript_column_name="intergenic_consequences", - method_name="phred scaled CADD", + method_name="CADD", score_column_name="cadd_phred", ), + # Extract VEP prediction: + cls._get_vep_prediction(f.col("most_severe_consequence")), ) ) .alias("inSilicoPredictors"), # Convert consequence to SO: map_column_by_dictionary( - f.col("most_severe_consequence"), sequence_ontology_map + f.col("most_severe_consequence"), cls.SEQUENCE_ONTOLOGY_MAP ).alias("mostSevereConsequenceId"), + # Propagate most severe consequence: + "most_severe_consequence", # Extract HGVS identifier: f.when( f.size("transcript_consequences") > 0, @@ -681,7 +718,7 @@ def process_vep_output( f.transform( transcript.consequence_terms, lambda y: map_column_by_dictionary( - y, sequence_ontology_map + y, cls.SEQUENCE_ONTOLOGY_MAP ), ).alias("variantFunctionalConsequenceIds"), # Convert consequence terms to consequence score: @@ -689,7 +726,7 @@ def process_vep_output( f.transform( transcript.consequence_terms, lambda term: map_column_by_dictionary( - term, label_to_score_map + term, cls.LABEL_TO_SCORE_MAP ), ) ) @@ -732,6 +769,8 @@ def process_vep_output( "polyphenPrediction" ), transcript.transcript_id.alias("transcriptId"), + transcript.biotype.alias("biotype"), + transcript.gene_symbol.alias("approvedSymbol"), ), ), ).alias("transcriptConsequences"), @@ -806,8 +845,278 @@ def process_vep_output( hash_threshold, ), ) + # Generating a temporary column with only protein coding transcripts: + .withColumn( + "proteinCodingTranscripts", + f.filter( + f.col("transcriptConsequences"), + lambda x: x.getItem("biotype") == "protein_coding", + ), + ) + # Generate variant descrioption: + .withColumn( + "variantDescription", + cls._compose_variant_description( + # Passing the most severe consequence: + f.col("most_severe_consequence"), + # The first transcript: + f.filter( + f.col("transcriptConsequences"), + lambda vep: vep.transcriptIndex == 1, + ).getItem(0), + # The first protein coding transcript: + order_array_of_structs_by_field( + "proteinCodingTranscripts", "transcriptIndex" + )[f.size("proteinCodingTranscripts") - 1], + ), + ) + # Normalising in silico predictor assessments: + .withColumn( + "inSilicoPredictors", + InSilicoPredictorNormaliser.normalise_in_silico_predictors( + f.col("inSilicoPredictors") + ), + ) # Dropping intermediate xref columns: - .drop(*["ensembl_xrefs", "omim_xrefs", "clinvar_xrefs", "protvar_xrefs"]) + .drop( + *[ + "ensembl_xrefs", + "omim_xrefs", + "clinvar_xrefs", + "protvar_xrefs", + "most_severe_consequence", + "proteinCodingTranscripts", + ] + ) # Drooping rows with null position: .filter(f.col("position").isNotNull()) ) + + @classmethod + def _compose_variant_description( + cls: type[VariantEffectPredictorParser], + most_severe_consequence: Column, + first_transcript: Column, + first_protein_coding: Column, + ) -> Column: + """Compose variant description based on the most severe consequence. + + Args: + most_severe_consequence (Column): Most severe consequence + first_transcript (Column): First transcript + first_protein_coding (Column): First protein coding transcript + + Returns: + Column: Variant description + """ + return ( + # When there's no transcript whatsoever: + f.when( + first_transcript.isNull(), + f.lit("Intergenic variant no gene in window"), + ) + # When the biotype of the first gene is protein coding: + .when( + first_transcript.getItem("biotype") == "protein_coding", + cls._process_protein_coding_transcript( + first_transcript, most_severe_consequence + ), + ) + # When the first gene is not protein coding, we also pass the first protein coding gene: + .otherwise( + cls._process_non_protein_coding_transcript( + most_severe_consequence, first_transcript, first_protein_coding + ) + ) + ) + + @staticmethod + def _process_consequence_term(consequence_term: Column) -> Column: + """Cleaning up consequence term: capitalizing and replacing underscores. + + Args: + consequence_term (Column): Consequence term. + + Returns: + Column: Cleaned up consequence term. + """ + last = f.when(consequence_term.contains("variant"), f.lit("")).otherwise( + " variant" + ) + return f.concat(f.regexp_replace(f.initcap(consequence_term), "_", " "), last) + + @staticmethod + def _process_overlap(transcript: Column) -> Column: + """Process overlap with gene: if the variant overlaps with the gene, return the gene name or distance. + + Args: + transcript (Column): Transcript. + + Returns: + Column: string column with overlap description. + """ + gene_label = f.when( + transcript.getField("approvedSymbol").isNotNull(), + transcript.getField("approvedSymbol"), + ).otherwise(transcript.getField("targetId")) + + return f.when( + transcript.getField("distanceFromFootprint") == 0, + # "overlapping with CCDC8" + f.concat(f.lit(" overlapping with "), gene_label), + ).otherwise( + # " 123 basepair away from CCDC8" + f.concat( + f.lit(" "), + f.format_number(transcript.getField("distanceFromFootprint"), 0), + f.lit(" basepair away from "), + gene_label, + ) + ) + + @staticmethod + def _process_aa_change(transcript: Column) -> Column: + """Extract amino acid change information from transcript when available. + + Args: + transcript (Column): Transcript. + + Returns: + Column: Amino acid change information. + """ + return f.when( + transcript.getField("aminoAcidChange").isNotNull(), + f.concat( + f.lit(", causing amio-acid change: "), + transcript.getField("aminoAcidChange"), + f.lit(" with "), + f.lower(transcript.getField("impact")), + f.lit(" impact."), + ), + ).otherwise(f.lit(".")) + + @staticmethod + def _process_lof(transcript: Column) -> Column: + """Process loss of function annotation from LOFTEE prediction. + + Args: + transcript (Column): Transcript. + + Returns: + Column: Loss of function annotation. + """ + return f.when( + transcript.getField("lofteePrediction").isNotNull() + & (transcript.getField("lofteePrediction") == "HC"), + f.lit(" A high-confidence loss-of-function variant by loftee."), + ).otherwise(f.lit("")) + + @classmethod + def _process_protein_coding_transcript( + cls: type[VariantEffectPredictorParser], + transcript: Column, + most_severe_consequence: Column, + ) -> Column: + """Extract information from the first, protein coding transcript. + + Args: + transcript (Column): Transcript. + most_severe_consequence (Column): Most severe consequence. + + Returns: + Column: Variant description. + """ + # Process consequence term: + consequence_text = cls._process_consequence_term(most_severe_consequence) + + # Does it overlap with the gene: + overlap = cls._process_overlap(transcript) + + # Does it cause amino acid change: + amino_acid_change = cls._process_aa_change(transcript) + + # Processing lof annotation: + lof_assessment = cls._process_lof(transcript) + + # Concat all together: + return f.concat(consequence_text, overlap, amino_acid_change, lof_assessment) + + @staticmethod + def _adding_biotype(transcript: Column) -> Column: + """Adding biotype information to the variant description. + + Args: + transcript (Column): Transcript. + + Returns: + Column: Biotype information. + """ + biotype = f.when( + transcript.getField("biotype").contains("gene"), + f.regexp_replace(transcript.getField("biotype"), "_", " "), + ).otherwise( + f.concat( + f.regexp_replace(transcript.getField("biotype"), "_", " "), + f.lit(" gene."), + ) + ) + + return f.concat(f.lit(", a "), biotype) + + @staticmethod + def _parse_protein_coding_transcript(transcript: Column) -> Column: + """Parse the closest, not first protein coding transcript: extract gene symbol and distance. + + Args: + transcript (Column): Transcript. + + Returns: + Column: Protein coding transcript information. + """ + gene_label = f.when( + transcript.getField("approvedSymbol").isNotNull(), + transcript.getField("approvedSymbol"), + ).otherwise(transcript.getField("targetId")) + + return f.when( + transcript.isNotNull(), + f.concat( + f.lit(" The closest protein-coding gene is "), + gene_label, + f.lit(" ("), + f.format_number(transcript.getField("distanceFromFootprint"), 0), + f.lit(" basepair away)."), + ), + ).otherwise(f.lit("")) + + @classmethod + def _process_non_protein_coding_transcript( + cls: type[VariantEffectPredictorParser], + most_severe_consequence: Column, + first_transcript: Column, + first_protein_coding: Column, + ) -> Column: + """Extract information from the first, non-protein coding transcript. + + Args: + most_severe_consequence (Column): Most severe consequence. + first_transcript (Column): First transcript. + first_protein_coding (Column): First protein coding transcript. + + Returns: + Column: Variant description. + """ + # Process consequence term: + consequence_text = cls._process_consequence_term(most_severe_consequence) + + # Does it overlap with the gene: + overlap = cls._process_overlap(first_transcript) + + # Adding biotype: + biotype = cls._adding_biotype(first_transcript) + + # Adding protein coding gene: + protein_transcript = cls._parse_protein_coding_transcript(first_protein_coding) + + # Concat all together: + return f.concat(consequence_text, overlap, biotype, protein_transcript) diff --git a/src/gentropy/datasource/gnomad/variants.py b/src/gentropy/datasource/gnomad/variants.py index 0575261c2..7540c374f 100644 --- a/src/gentropy/datasource/gnomad/variants.py +++ b/src/gentropy/datasource/gnomad/variants.py @@ -10,7 +10,7 @@ from gentropy.common.types import VariantPopulation from gentropy.config import GnomadVariantConfig, VariantIndexConfig -from gentropy.dataset.variant_index import VariantIndex +from gentropy.dataset.variant_index import InSilicoPredictorNormaliser, VariantIndex if TYPE_CHECKING: pass @@ -91,7 +91,7 @@ def as_variant_index(self: GnomADVariants) -> VariantIndex: inSilicoPredictors=hl.array( [ hl.struct( - method=hl.str("spliceai"), + method=hl.str("SpliceAI"), assessment=hl.missing(hl.tstr), score=hl.expr.functions.float32( ht.in_silico_predictors.spliceai_ds_max @@ -100,7 +100,7 @@ def as_variant_index(self: GnomADVariants) -> VariantIndex: targetId=hl.missing(hl.tstr), ), hl.struct( - method=hl.str("pangolin"), + method=hl.str("Pangolin"), assessment=hl.missing(hl.tstr), score=hl.expr.functions.float32( ht.in_silico_predictors.pangolin_largest_ds @@ -149,6 +149,13 @@ def as_variant_index(self: GnomADVariants) -> VariantIndex: "mostSevereConsequenceId": f.lit(None).cast(t.StringType()), } ) + # Normalising in silico predictor assessments: + .withColumn( + "inSilicoPredictors", + InSilicoPredictorNormaliser.normalise_in_silico_predictors( + f.col("inSilicoPredictors") + ), + ) ), _schema=VariantIndex.get_schema(), ) diff --git a/src/gentropy/gnomad_ingestion.py b/src/gentropy/gnomad_ingestion.py index 8d2cd92f9..9b4de8a0c 100644 --- a/src/gentropy/gnomad_ingestion.py +++ b/src/gentropy/gnomad_ingestion.py @@ -114,6 +114,8 @@ def __init__( # Convert data to variant index: .as_variant_index() # Write file: - .df.write.mode(session.write_mode) + .df.repartitionByRange("chromosome", "position") + .sortWithinPartitions("chromosome", "position") + .write.mode(session.write_mode) .parquet(variant_annotation_path) ) diff --git a/tests/gentropy/conftest.py b/tests/gentropy/conftest.py index 10298205d..f19c28623 100644 --- a/tests/gentropy/conftest.py +++ b/tests/gentropy/conftest.py @@ -275,7 +275,8 @@ def mock_variant_index(spark: SparkSession) -> VariantIndex: "assessment", cast(rand() as string), "score", rand(), "assessmentFlag", cast(rand() as string), - "targetId", cast(rand() as string) + "targetId", cast(rand() as string), + "normalizedScore", cast(rand() as float) ) ) """, @@ -308,7 +309,9 @@ def mock_variant_index(spark: SparkSession) -> VariantIndex: "polyphenPrediction", rand(), "consequenceScore", cast(rand() as float), "transcriptIndex", cast(rand() as integer), - "transcriptId", cast(rand() as string) + "transcriptId", cast(rand() as string), + "biotype", cast(rand() as string), + "approvedSymbol", cast(rand() as string) ) ) """, diff --git a/tests/gentropy/datasource/ensembl/test_vep_variants.py b/tests/gentropy/datasource/ensembl/test_vep_variants.py index 556a22411..f0127b9b2 100644 --- a/tests/gentropy/datasource/ensembl/test_vep_variants.py +++ b/tests/gentropy/datasource/ensembl/test_vep_variants.py @@ -7,7 +7,6 @@ import pytest from pyspark.sql import DataFrame from pyspark.sql import functions as f -from pyspark.sql import types as t from gentropy.dataset.variant_index import VariantIndex from gentropy.datasource.ensembl.vep_parser import VariantEffectPredictorParser @@ -108,33 +107,6 @@ def _setup(self: TestVEPParser, spark: SparkSession) -> None: self.raw_vep_output, 200 ) - def test_extract_variant_index_from_vep( - self: TestVEPParser, spark: SparkSession - ) -> None: - """Test if the variant index can be extracted from the VEP output.""" - variant_index = VariantEffectPredictorParser.extract_variant_index_from_vep( - spark, self.SAMPLE_VEP_DATA_PATH, hash_threshold=100 - ) - - assert isinstance( - variant_index, VariantIndex - ), "VariantIndex object not created." - in_silico_schema = t.ArrayType( - t.StructType( - [ - t.StructField("method", t.StringType(), True), - t.StructField("assessment", t.StringType(), True), - t.StructField("score", t.FloatType(), True), - t.StructField("assessmentFlag", t.StringType(), True), - t.StructField("targetId", t.StringType(), True), - ] - ) - ) - assert ( - variant_index.df.select("inSilicoPredictors").schema.fields[0].dataType - == in_silico_schema - ), "In silico schema is not correct." - def test_process(self: TestVEPParser) -> None: """Test process method.""" df = VariantEffectPredictorParser.process_vep_output(self.raw_vep_output) From a858662c41824c54954491d20bdbd0f20bfee283 Mon Sep 17 00:00:00 2001 From: Yakov Date: Wed, 20 Nov 2024 10:16:08 +0000 Subject: [PATCH 173/188] fix: r2 for lead variant is always 1 (#919) * fix: r2 for lead varaint is always 1 * fix: removing not needed quality flag * test: removing unused condition * fix: type: ignore --------- Co-authored-by: DSuveges --- src/gentropy/dataset/study_locus.py | 4 -- src/gentropy/method/ld.py | 57 ++++++++++++++++------------- src/gentropy/method/pics.py | 14 ------- tests/gentropy/method/test_pics.py | 19 ++-------- 4 files changed, 34 insertions(+), 60 deletions(-) diff --git a/src/gentropy/dataset/study_locus.py b/src/gentropy/dataset/study_locus.py index e6fd06c12..10dc9c10d 100644 --- a/src/gentropy/dataset/study_locus.py +++ b/src/gentropy/dataset/study_locus.py @@ -74,7 +74,6 @@ class StudyLocusQualityCheck(Enum): LD_CLUMPED (str): Explained by a more significant variant in high LD WINDOW_CLUMPED (str): Explained by a more significant variant in the same window NO_POPULATION (str): Study does not have population annotation to resolve LD - NOT_QUALIFYING_LD_BLOCK (str): LD block does not contain variants at the required R^2 threshold FLAGGED_STUDY (str): Study has quality control flag(s) MISSING_STUDY (str): Flagging study loci if the study is not found in the study index as a reference DUPLICATED_STUDYLOCUS_ID (str): Study-locus identifier is not unique @@ -100,9 +99,6 @@ class StudyLocusQualityCheck(Enum): LD_CLUMPED = "Explained by a more significant variant in high LD" WINDOW_CLUMPED = "Explained by a more significant variant in the same window" NO_POPULATION = "Study does not have population annotation to resolve LD" - NOT_QUALIFYING_LD_BLOCK = ( - "LD block does not contain variants at the required R^2 threshold" - ) FLAGGED_STUDY = "Study has quality control flag(s)" MISSING_STUDY = "Study not found in the study index" DUPLICATED_STUDYLOCUS_ID = "Non-unique study locus identifier" diff --git a/src/gentropy/method/ld.py b/src/gentropy/method/ld.py index 64d47451d..4fe27e2ee 100644 --- a/src/gentropy/method/ld.py +++ b/src/gentropy/method/ld.py @@ -35,19 +35,13 @@ def _get_major_population(ordered_populations: Column) -> Column: major_population_size = ordered_populations["relativeSampleSize"][0] major_populations = f.filter( ordered_populations, - lambda x: x["relativeSampleSize"] == major_population_size + lambda x: x["relativeSampleSize"] == major_population_size, ) # Check if nfe (Non-Finnish European) is one of the major populations - has_nfe = f.filter( - major_populations, - lambda x: x["ldPopulation"] == "nfe" - ) + has_nfe = f.filter(major_populations, lambda x: x["ldPopulation"] == "nfe") return f.when( - (f.size(major_populations) > 1) & (f.size(has_nfe) == 1), - f.lit("nfe") - ).otherwise( - ordered_populations["ldPopulation"][0] - ) + (f.size(major_populations) > 1) & (f.size(has_nfe) == 1), f.lit("nfe") + ).otherwise(ordered_populations["ldPopulation"][0]) @staticmethod def _calculate_r2_major(ld_set: Column, major_population: Column) -> Column: @@ -65,19 +59,18 @@ def _calculate_r2_major(ld_set: Column, major_population: Column) -> Column: lambda x: f.struct( x["tagVariantId"].alias("tagVariantId"), f.filter( - x["rValues"], - lambda y: y["population"] == major_population - ).alias("rValues") - ) + x["rValues"], lambda y: y["population"] == major_population + ).alias("rValues"), + ), ) return f.transform( ld_set_with_major_pop, lambda x: f.struct( x["tagVariantId"].alias("tagVariantId"), - f.coalesce( - f.pow(x["rValues"]["r"][0], 2), f.lit(0.0) - ).alias("r2Overall") - ) + f.coalesce(f.pow(x["rValues"]["r"][0], 2), f.lit(0.0)).alias( + "r2Overall" + ), + ), ) @staticmethod @@ -160,8 +153,8 @@ def ld_annotate( studies.df.select( "studyId", order_array_of_structs_by_field( - "ldPopulationStructure", "relativeSampleSize" - ).alias("ldPopulationStructure") + "ldPopulationStructure", "relativeSampleSize" + ).alias("ldPopulationStructure"), ), on="studyId", how="left", @@ -177,10 +170,8 @@ def ld_annotate( "majorPopulation", f.when( f.col("ldPopulationStructure").isNotNull(), - cls._get_major_population( - f.col("ldPopulationStructure") - ) - ) + cls._get_major_population(f.col("ldPopulationStructure")), + ), ) # Calculate R2 using R of the major population .withColumn( @@ -189,8 +180,8 @@ def ld_annotate( f.col("ldPopulationStructure").isNotNull(), cls._calculate_r2_major( f.col("ldSet"), f.col("majorPopulation") - ) - ) + ), + ), ) .drop("ldPopulationStructure", "majorPopulation") # Filter the LD set by the R2 threshold and set to null if no LD information passes the threshold @@ -209,6 +200,20 @@ def ld_annotate( "ldSet", cls._rescue_lead_variant(f.col("ldSet"), f.col("variantId")), ) + # Ensure that the lead varaitn is always with r2==1 + .withColumn( + "ldSet", + f.expr( + """ + transform(ldSet, x -> + IF(x.tagVariantId == variantId, + named_struct('tagVariantId', x.tagVariantId, 'r2Overall', 1.0), + x + ) + ) + """ + ), + ) ), _schema=StudyLocus.get_schema(), )._qc_no_population() diff --git a/src/gentropy/method/pics.py b/src/gentropy/method/pics.py index 60e28b9a1..dd767204e 100644 --- a/src/gentropy/method/pics.py +++ b/src/gentropy/method/pics.py @@ -224,11 +224,6 @@ def finemap( ) ) - # Flagging expression for loci that do not qualify for PICS: - non_picsable_expr = ( - f.size(f.filter(f.col("ldSet"), lambda x: x.r2Overall >= 0.5)) == 0 - ) - # Registering the UDF to be used in the pipeline: finemap_udf = f.udf( lambda ld_set, neglog_p: cls._finemap(ld_set, neglog_p, k), @@ -271,15 +266,6 @@ def finemap( ), ), ) - # Flagging loci that do not qualify for PICS: - .withColumn( - "qualityControls", - StudyLocus.update_quality_flag( - f.col("qualityControls"), - non_picsable_expr, - StudyLocusQualityCheck.NOT_QUALIFYING_LD_BLOCK, - ), - ) # Flagging all PICS loci with OUT_OF_SAMPLE_LD flag: .withColumn( "qualityControls", diff --git a/tests/gentropy/method/test_pics.py b/tests/gentropy/method/test_pics.py index d5a8eb5d0..9c1fc80b3 100644 --- a/tests/gentropy/method/test_pics.py +++ b/tests/gentropy/method/test_pics.py @@ -38,21 +38,6 @@ def test_finemap_null_ld_set( observed_df = PICS.finemap(mock_study_locus).df.limit(1) assert observed_df.collect()[0]["locus"] is None - def test_finemap_quality_control( - self: TestFinemap, mock_study_locus: StudyLocus - ) -> None: - """Test that we add a `empty locus` flag when any variant in the locus meets PICS criteria.""" - mock_study_locus.df = mock_study_locus.df.withColumn( - # Association with an empty ldSet - "ldSet", - f.when(f.col("ldSet").isNull(), f.array()).otherwise(f.col("ldSet")), - ).filter(f.size("ldSet") == 0) - observed_df = PICS.finemap(mock_study_locus).df.limit(1) - qc_flag = "LD block does not contain variants at the required R^2 threshold" - assert ( - qc_flag in observed_df.collect()[0]["qualityControls"] - ), "Empty locus QC flag is missing." - def test__finemap_udf() -> None: """Test the _finemap UDF with a simple case.""" @@ -75,7 +60,9 @@ def test__finemap_udf() -> None: "posteriorProbability": 0.9288304011311763, }, ] - for idx, tag in enumerate(result): # type: ignore + + assert result is not None, "The result of _finemap should not be None" + for idx, tag in enumerate(result): # assert both dictionaries have the same content regardless of its order assert tag == expected[idx] From b6303d571d19cb6262386c5d02adfdfefb7184be Mon Sep 17 00:00:00 2001 From: Daniel-Considine <113430683+Daniel-Considine@users.noreply.github.com> Date: Thu, 21 Nov 2024 13:15:22 +0000 Subject: [PATCH 174/188] feat: reverting to using finngen 95% credible sets (#922) * feat: reverting to 95% finngen credible sets * fix: updating tests and column names --- .../datasource/finngen/finemapping.py | 12 +++++----- .../finngen_credset_summary_sample.tsv | 24 +++++++++---------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/gentropy/datasource/finngen/finemapping.py b/src/gentropy/datasource/finngen/finemapping.py index e0f39689d..e4c1f776f 100644 --- a/src/gentropy/datasource/finngen/finemapping.py +++ b/src/gentropy/datasource/finngen/finemapping.py @@ -105,7 +105,7 @@ class FinnGenFinemapping: [ StructField("trait", StringType(), True), StructField("region", StringType(), True), - StructField("cs_number", StringType(), True), + StructField("cs", StringType(), True), StructField("cs_log10bf", DoubleType(), True), StructField("cs_avg_r2", DoubleType(), True), StructField("cs_min_r2", DoubleType(), True), @@ -184,7 +184,7 @@ class FinnGenFinemapping: summary_hail_schema: hl.tstruct = hl.tstruct( trait=hl.tstr, region=hl.tstr, - cs_number=hl.tstr, + cs=hl.tstr, cs_log10bf=hl.tfloat64, cs_avg_r2=hl.tfloat64, cs_min_r2=hl.tfloat64, @@ -245,7 +245,7 @@ def from_finngen_susie_finemapping( The finngen_susie_finemapping_cs_summary_files are files that Contains credible set summaries from SuSiE fine-mapping for all genome-wide significant regions with following schema: - trait: phenotype - region: region for which the fine-mapping was run. - - cs_number: running number for independent credible sets in a region, assigned to 99% PIP + - cs: running number for independent credible sets in a region, assigned to 95% PIP - cs_log10bf: Log10 bayes factor of comparing the solution of this model (cs independent credible sets) to cs -1 credible sets - cs_avg_r2: Average correlation R2 between variants in the credible set - cs_min_r2: minimum r2 between variants in the credible set @@ -298,7 +298,7 @@ def from_finngen_susie_finemapping( # Drop rows which don't have proper position. snps_df.filter(f.col("position").cast(t.IntegerType()).isNotNull()) # Drop non credible set SNPs: - .filter(f.col("cs_99").cast(t.IntegerType()) > 0) + .filter(f.col("cs").cast(t.IntegerType()) > 0) .select( # Add study idenfitier. f.concat_ws("_", f.lit(finngen_release_prefix), f.col("trait")) @@ -307,7 +307,7 @@ def from_finngen_susie_finemapping( f.col("region"), # Add variant information. f.regexp_replace(f.col("v"), ":", "_").alias("variantId"), - f.col("cs_99").cast("integer").alias("credibleSetIndex"), + f.col("cs").cast("integer").alias("credibleSetIndex"), f.regexp_replace(f.col("chromosome"), "^chr", "") .cast(t.StringType()) .alias("chromosome"), @@ -437,7 +437,7 @@ def from_finngen_susie_finemapping( cs_summary_df.select( f.col("region"), f.col("trait"), - f.col("cs_number").cast("integer").alias("credibleSetIndex"), + f.col("cs").cast("integer").alias("credibleSetIndex"), f.col("cs_log10bf").cast("double").alias("credibleSetlog10BF"), f.col("cs_avg_r2").cast("double").alias("purityMeanR2"), f.col("cs_min_r2").cast("double").alias("purityMinR2"), diff --git a/tests/gentropy/data_samples/finngen_credset_summary_sample.tsv b/tests/gentropy/data_samples/finngen_credset_summary_sample.tsv index ca973d8fc..6ba610807 100644 --- a/tests/gentropy/data_samples/finngen_credset_summary_sample.tsv +++ b/tests/gentropy/data_samples/finngen_credset_summary_sample.tsv @@ -1,12 +1,12 @@ -trait region cs cs_log10bf cs_avg_r2 cs_min_r2 low_purity cs_size good_cs cs_id v rsid p beta sd prob cs_specific_prob most_severe gene_most_severe cs_number -H7_HORDEOLUM chr1:156514826-159514826 1 1.46467818637 1.0 1.0 False 1 True chr1:156514826-159514826_1 1:158014826:C:T chr1_158014826_C_T 2.54378e-08 1.88207 0.446902952132688 0.971307293706789 0.971297199099758 intron_variant KIRREL1 1 -G6_MIGRAINE_NO_AURA chr6:11403725-14403725 1 1.36783669104 0.760565917219 0.140997997009 True 19 False chr6:11403725-14403725_1 6:12903725:A:G chr6_12903725_A_G 3.61468e-08 -0.0981548 0.0320646607273439 0.90799209537494 0.907981878613055 intron_variant PHACTR1 1 -G6_MIGRAINE_NO_AURA chr12:55647065-58647065 1 1.66017507931 0.804011708889 0.804011708889 False 2 True chr12:55647065-58647065_1 12:57147065:C:G chr12_57147065_C_G 2.29261e-08 0.105129 0.0353895280800414 0.898218191602507 0.898218191602507 intron_variant LRP1 1 -G6_MIGRAINE_NO_AURA chr12:2906208-5906208 1 1.87518878137 0.762329739726 0.382297363204 False 11 True chr12:2906208-5906208_1 12:4406208:T:C chr12_4406208_T_C 3.52631e-08 -0.097881 0.0413367587403912 0.244577820826502 0.244317125809489 downstream_gene_variant AC008012.1 1 -G6_MIGRAINE_NO_AURA chr6:95113283-98113283 1 3.00789560938 0.917456939478 0.788796212164 False 43 True chr6:95113283-98113283_1 6:96613283:C:T chr6_96613283_C_T 5.56352e-09 0.110915 0.0357600937089016 0.122046568781673 0.122046568781673 intron_variant FHL5 1 -K11_APHTA_RECUR chr2:203986459-206986459 1 1.53062868484 1.0 1.0 False 1 True chr2:203986459-206986459_1 2:205486459:A:G chr2_205486459_A_G 2.5015e-08 0.225777 0.0591109424642432 0.956659971956856 0.956659971956856 intron_variant PARD3B 1 -DM_NEPHROPATHY_EXMORE chr2:224821033-227821033 1 5.02824362893 0.984196974601 0.661904280625 False 50 True chr2:224821033-227821033_1 2:226321033:T:C chr2_226321033_T_C 2.42008e-10 -0.144142 0.0211352709908576 0.0225587152970605 0.0225587152970605 intergenic_variant 1 -DM_NEPHROPATHY_EXMORE chr11:660994-3660994 1 2.7116635835 0.870906412027 0.809751619044 False 3 True chr11:660994-3660994_1 11:2160994:A:T chr11_2160994_A_T 3.15043e-09 0.168647 0.08489428697954 0.47925285536432 0.479123015291369 splice_region_variant INS-IGF2 1 -DM_NEPHROPATHY_EXMORE chr12:2775678-5775678 1 2.25532985077 1.0 1.0 False 1 True chr12:2775678-5775678_1 12:4275678:T:G chr12_4275678_T_G 3.72503e-09 -0.433585 0.0763706359152554 0.996634114263842 0.996632992137397 intron_variant CCND2 1 -AB1_EBV chr6:1412516-4412516 1 4.4609149402 0.678175582701 0.468032488641 False 4 True chr6:1412516-4412516_1 6:2912516:CCA:C chr6_2912516_CCA_C 4.90908e-11 0.196413 0.0943211787286286 0.367291808726716 0.367106415849495 upstream_gene_variant AL133351.2 1 -AB1_EBV chr20:16016584-19016584 1 1.27192551601 1.0 1.0 False 1 True chr20:16016584-19016584_1 20:17516584:C:T chr20_17516584_C_T 3.72152e-08 2.00466 0.504004034147034 0.963905759488349 0.963892713745976 intron_variant BFSP1 1 +trait region cs cs_log10bf cs_avg_r2 cs_min_r2 low_purity cs_size good_cs cs_id v rsid p beta sd prob cs_specific_prob most_severe gene_most_severe +H7_HORDEOLUM chr1:156514826-159514826 1 1.46467818637 1.0 1.0 False 1 True chr1:156514826-159514826_1 1:158014826:C:T chr1_158014826_C_T 2.54378e-08 1.88207 0.446902952132688 0.971307293706789 0.971297199099758 intron_variant KIRREL1 +G6_MIGRAINE_NO_AURA chr6:11403725-14403725 1 1.36783669104 0.760565917219 0.140997997009 True 19 False chr6:11403725-14403725_1 6:12903725:A:G chr6_12903725_A_G 3.61468e-08 -0.0981548 0.0320646607273439 0.90799209537494 0.907981878613055 intron_variant PHACTR1 +G6_MIGRAINE_NO_AURA chr12:55647065-58647065 1 1.66017507931 0.804011708889 0.804011708889 False 2 True chr12:55647065-58647065_1 12:57147065:C:G chr12_57147065_C_G 2.29261e-08 0.105129 0.0353895280800414 0.898218191602507 0.898218191602507 intron_variant LRP1 +G6_MIGRAINE_NO_AURA chr12:2906208-5906208 1 1.87518878137 0.762329739726 0.382297363204 False 11 True chr12:2906208-5906208_1 12:4406208:T:C chr12_4406208_T_C 3.52631e-08 -0.097881 0.0413367587403912 0.244577820826502 0.244317125809489 downstream_gene_variant AC008012.1 +G6_MIGRAINE_NO_AURA chr6:95113283-98113283 1 3.00789560938 0.917456939478 0.788796212164 False 43 True chr6:95113283-98113283_1 6:96613283:C:T chr6_96613283_C_T 5.56352e-09 0.110915 0.0357600937089016 0.122046568781673 0.122046568781673 intron_variant FHL5 +K11_APHTA_RECUR chr2:203986459-206986459 1 1.53062868484 1.0 1.0 False 1 True chr2:203986459-206986459_1 2:205486459:A:G chr2_205486459_A_G 2.5015e-08 0.225777 0.0591109424642432 0.956659971956856 0.956659971956856 intron_variant PARD3B +DM_NEPHROPATHY_EXMORE chr2:224821033-227821033 1 5.02824362893 0.984196974601 0.661904280625 False 50 True chr2:224821033-227821033_1 2:226321033:T:C chr2_226321033_T_C 2.42008e-10 -0.144142 0.0211352709908576 0.0225587152970605 0.0225587152970605 intergenic_variant +DM_NEPHROPATHY_EXMORE chr11:660994-3660994 1 2.7116635835 0.870906412027 0.809751619044 False 3 True chr11:660994-3660994_1 11:2160994:A:T chr11_2160994_A_T 3.15043e-09 0.168647 0.08489428697954 0.47925285536432 0.479123015291369 splice_region_variant INS-IGF2 +DM_NEPHROPATHY_EXMORE chr12:2775678-5775678 1 2.25532985077 1.0 1.0 False 1 True chr12:2775678-5775678_1 12:4275678:T:G chr12_4275678_T_G 3.72503e-09 -0.433585 0.0763706359152554 0.996634114263842 0.996632992137397 intron_variant CCND2 +AB1_EBV chr6:1412516-4412516 1 4.4609149402 0.678175582701 0.468032488641 False 4 True chr6:1412516-4412516_1 6:2912516:CCA:C chr6_2912516_CCA_C 4.90908e-11 0.196413 0.0943211787286286 0.367291808726716 0.367106415849495 upstream_gene_variant AL133351.2 +AB1_EBV chr20:16016584-19016584 1 1.27192551601 1.0 1.0 False 1 True chr20:16016584-19016584_1 20:17516584:C:T chr20_17516584_C_T 3.72152e-08 2.00466 0.504004034147034 0.963905759488349 0.963892713745976 intron_variant BFSP1 From 05e47a384b03bdcb7dd3999b6645775db99da9eb Mon Sep 17 00:00:00 2001 From: Daniel-Considine <113430683+Daniel-Considine@users.noreply.github.com> Date: Thu, 21 Nov 2024 13:29:49 +0000 Subject: [PATCH 175/188] feat: changing studylocus validation to 95 percent credible sets (#921) * feat: changing studylocus validation to 95 percent credible sets * fix: updating comment in code to reflect 95% credset * fix: removing credset number of partitions * fix: flag name --------- Co-authored-by: Yakov Tsepilov --- src/gentropy/dataset/study_locus.py | 2 +- src/gentropy/study_locus_validation.py | 22 +++++++++++----------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/gentropy/dataset/study_locus.py b/src/gentropy/dataset/study_locus.py index 10dc9c10d..5abb30c8e 100644 --- a/src/gentropy/dataset/study_locus.py +++ b/src/gentropy/dataset/study_locus.py @@ -113,7 +113,7 @@ class StudyLocusQualityCheck(Enum): EXPLAINED_BY_SUSIE = "Study locus in region explained by a SuSiE credible set" OUT_OF_SAMPLE_LD = "Study locus finemapped without in-sample LD reference" ABNORMAL_PIPS = ( - "Study locus with a sum of PIPs that not in the expected range [0.99,1]" + "Study locus with a sum of PIPs that not in the expected range [0.95,1]" ) INVALID_CHROMOSOME = "Chromosome not in 1:22, X, Y, XY or MT" TOP_HIT_AND_SUMMARY_STATS = ( diff --git a/src/gentropy/study_locus_validation.py b/src/gentropy/study_locus_validation.py index 4c0c8c4c5..cf36a4389 100644 --- a/src/gentropy/study_locus_validation.py +++ b/src/gentropy/study_locus_validation.py @@ -46,24 +46,24 @@ def __init__( .annotate_study_type(study_index) # Add study type to study locus .qc_redundant_top_hits_from_PICS() # Flagging top hits from studies with PICS summary statistics .qc_explained_by_SuSiE() # Flagging credible sets in regions explained by SuSiE - # Flagging credible sets with PIP > 1 or PIP < 0.99 + # Annotates credible intervals and filter to only keep 95% credible sets + .filter_credible_set(credible_interval=CredibleInterval.IS95) + # Flagging credible sets with PIP > 1 or PIP < 0.95 .qc_abnormal_pips( - sum_pips_lower_threshold=0.99, sum_pips_upper_threshold=1.0001 + sum_pips_lower_threshold=0.95, sum_pips_upper_threshold=1.0001 ) - # Annotates credible intervals and filter to only keep 99% credible sets - .filter_credible_set(credible_interval=CredibleInterval.IS99) # Annotate credible set confidence: .assign_confidence() ).persist() # we will need this for 2 types of outputs # Valid study locus partitioned to simplify the finding of overlaps - study_locus_with_qc.valid_rows( - invalid_qc_reasons, invalid=True - ).df.repartitionByRange("chromosome", "position").sortWithinPartitions( + study_locus_with_qc.valid_rows(invalid_qc_reasons).df.repartitionByRange( "chromosome", "position" - ).write.mode(session.write_mode).parquet(invalid_study_locus_path) - - # Infalid study locus - study_locus_with_qc.valid_rows(invalid_qc_reasons).df.write.mode( + ).sortWithinPartitions("chromosome", "position").write.mode( session.write_mode ).parquet(valid_study_locus_path) + + # Invalid study locus + study_locus_with_qc.valid_rows(invalid_qc_reasons, invalid=True).df.write.mode( + session.write_mode + ).parquet(invalid_study_locus_path) From 8a83ec692b5426870941c12fb3c20bca7c9fc499 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 22 Nov 2024 10:40:15 +0000 Subject: [PATCH 176/188] chore: pre-commit autoupdate (#918) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.7.3 → v0.7.4](https://github.com/astral-sh/ruff-pre-commit/compare/v0.7.3...v0.7.4) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 2c9da9926..5bf5e6239 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -6,7 +6,7 @@ ci: skip: [poetry-lock] repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.7.3 + rev: v0.7.4 hooks: - id: ruff args: From 008aa3898cfbb75281b5a88be35abef216aa2a9f Mon Sep 17 00:00:00 2001 From: Daniel Suveges Date: Tue, 26 Nov 2024 14:08:36 +0000 Subject: [PATCH 177/188] chore(gnomad): updating GnomAD version to 4.1 from 4.0 + using joint frequencies (#929) * fix: gnomad 4.1 frequencies * fix: removing in-silico extraction in gnomad * fix: removing in silico predictor ingestion from gnomad pre-process --- src/gentropy/config.py | 4 ++- src/gentropy/datasource/gnomad/variants.py | 41 +++------------------- src/gentropy/gnomad_ingestion.py | 2 ++ 3 files changed, 9 insertions(+), 38 deletions(-) diff --git a/src/gentropy/config.py b/src/gentropy/config.py index a84dbd89e..b32647acf 100644 --- a/src/gentropy/config.py +++ b/src/gentropy/config.py @@ -387,7 +387,9 @@ class GnomadVariantConfig(StepConfig): } ) variant_annotation_path: str = MISSING - gnomad_genomes_path: str = "gs://gcp-public-data--gnomad/release/4.0/ht/genomes/gnomad.genomes.v4.0.sites.ht/" + gnomad_genomes_path: str = ( + "gs://gcp-public-data--gnomad/release/4.1/ht/joint/gnomad.joint.v4.1.sites.ht/" + ) gnomad_variant_populations: list[str] = field( default_factory=lambda: [ "afr", # African-American diff --git a/src/gentropy/datasource/gnomad/variants.py b/src/gentropy/datasource/gnomad/variants.py index 7540c374f..0731181b7 100644 --- a/src/gentropy/datasource/gnomad/variants.py +++ b/src/gentropy/datasource/gnomad/variants.py @@ -10,7 +10,7 @@ from gentropy.common.types import VariantPopulation from gentropy.config import GnomadVariantConfig, VariantIndexConfig -from gentropy.dataset.variant_index import InSilicoPredictorNormaliser, VariantIndex +from gentropy.dataset.variant_index import VariantIndex if TYPE_CHECKING: pass @@ -84,32 +84,11 @@ def as_variant_index(self: GnomADVariants) -> VariantIndex: ).map( lambda p: hl.struct( populationName=p, - alleleFrequency=ht.freq[ht.globals.freq_index_dict[p]].AF, + alleleFrequency=ht.joint.freq[ + ht.joint_globals.freq_index_dict[p] + ].AF, ) ), - # Extract in silico predictors: - inSilicoPredictors=hl.array( - [ - hl.struct( - method=hl.str("SpliceAI"), - assessment=hl.missing(hl.tstr), - score=hl.expr.functions.float32( - ht.in_silico_predictors.spliceai_ds_max - ), - assessmentFlag=hl.missing(hl.tstr), - targetId=hl.missing(hl.tstr), - ), - hl.struct( - method=hl.str("Pangolin"), - assessment=hl.missing(hl.tstr), - score=hl.expr.functions.float32( - ht.in_silico_predictors.pangolin_largest_ds - ), - assessmentFlag=hl.missing(hl.tstr), - targetId=hl.missing(hl.tstr), - ), - ] - ), # Extract cross references to GnomAD: dbXrefs=hl.array( [ @@ -133,11 +112,6 @@ def as_variant_index(self: GnomADVariants) -> VariantIndex: .to_spark(flatten=False) .withColumns( { - # Once The parsing is done, we have to drop objects with no score from inSilicoPredictors: - "inSilicoPredictors": f.filter( - f.col("inSilicoPredictors"), - lambda predictor: predictor["score"].isNotNull(), - ), # Generate a variantId that is hashed for long variant ids: "variantId": VariantIndex.hash_long_variant_ids( f.col("variantId"), @@ -149,13 +123,6 @@ def as_variant_index(self: GnomADVariants) -> VariantIndex: "mostSevereConsequenceId": f.lit(None).cast(t.StringType()), } ) - # Normalising in silico predictor assessments: - .withColumn( - "inSilicoPredictors", - InSilicoPredictorNormaliser.normalise_in_silico_predictors( - f.col("inSilicoPredictors") - ), - ) ), _schema=VariantIndex.get_schema(), ) diff --git a/src/gentropy/gnomad_ingestion.py b/src/gentropy/gnomad_ingestion.py index 9b4de8a0c..d930b54c6 100644 --- a/src/gentropy/gnomad_ingestion.py +++ b/src/gentropy/gnomad_ingestion.py @@ -105,6 +105,8 @@ def __init__( gnomad_genomes_path, variant_annotation_path ) + session.logger.info("Gnomad variant annotation path:") + session.logger.info(variant_annotation_path) # Parse variant info from source. ( GnomADVariants( From 4837a4b4add387ac9e1edb3fba7fbbbea712bc80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Irene=20L=C3=B3pez=20Santiago?= <45119610+ireneisdoomed@users.noreply.github.com> Date: Wed, 27 Nov 2024 10:07:42 +0000 Subject: [PATCH 178/188] feat(gold_standard): add traitFromSourceMappedId to schema (#924) * feat(gold_standard): add traitFromSourceMappedId to schema * chore: adapt tests * feat(feature_matrix): consider `traitFromSourceMappedId` a static column * feat(feature_matrix): consider `traitFromSourceMappedId` an optional column --- src/gentropy/assets/schemas/l2g_gold_standard.json | 6 ++++++ src/gentropy/dataset/l2g_feature_matrix.py | 2 ++ tests/gentropy/dataset/test_l2g_feature_matrix.py | 2 +- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/gentropy/assets/schemas/l2g_gold_standard.json b/src/gentropy/assets/schemas/l2g_gold_standard.json index 6af921d61..6ba715963 100644 --- a/src/gentropy/assets/schemas/l2g_gold_standard.json +++ b/src/gentropy/assets/schemas/l2g_gold_standard.json @@ -25,6 +25,12 @@ "nullable": false, "metadata": {} }, + { + "name": "traitFromSourceMappedId", + "type": "string", + "nullable": true, + "metadata": {} + }, { "name": "goldStandardSet", "type": "string", diff --git a/src/gentropy/dataset/l2g_feature_matrix.py b/src/gentropy/dataset/l2g_feature_matrix.py index f59e1e725..8c3d97e88 100644 --- a/src/gentropy/dataset/l2g_feature_matrix.py +++ b/src/gentropy/dataset/l2g_feature_matrix.py @@ -39,6 +39,8 @@ def __init__( self.fixed_cols = ["studyLocusId", "geneId"] if self.with_gold_standard: self.fixed_cols.append("goldStandardSet") + if "traitFromSourceMappedId" in _df.columns: + self.fixed_cols.append("traitFromSourceMappedId") self.features_list = features_list or [ col for col in _df.columns if col not in self.fixed_cols diff --git a/tests/gentropy/dataset/test_l2g_feature_matrix.py b/tests/gentropy/dataset/test_l2g_feature_matrix.py index 4fe338254..6677d123e 100644 --- a/tests/gentropy/dataset/test_l2g_feature_matrix.py +++ b/tests/gentropy/dataset/test_l2g_feature_matrix.py @@ -87,7 +87,7 @@ def _setup(self: TestFromFeaturesList, spark: SparkSession) -> None: """Setup fixture.""" self.sample_gold_standard = L2GGoldStandard( _df=spark.createDataFrame( - [(1, "var1", "gwas1", "g1", "positive", ["a_source"])], + [(1, "var1", "gwas1", "g1", "efo1", "positive", ["a_source"])], L2GGoldStandard.get_schema(), ), _schema=L2GGoldStandard.get_schema(), From 7b3bfade5cf39b890346327a6e4c0f8e94990184 Mon Sep 17 00:00:00 2001 From: Szymon Szyszkowski <69353402+project-defiant@users.noreply.github.com> Date: Wed, 27 Nov 2024 14:31:49 +0100 Subject: [PATCH 179/188] feat: coalescing the datasets (#932) Co-authored-by: Szymon Szyszkowski --- src/gentropy/biosample_index.py | 13 ++++++++++--- src/gentropy/colocalisation.py | 6 +++--- src/gentropy/common/session.py | 3 +++ src/gentropy/config.py | 1 + src/gentropy/gene_index.py | 5 ++++- src/gentropy/study_locus_validation.py | 8 ++++---- src/gentropy/study_validation.py | 12 ++++++------ src/gentropy/variant_index.py | 4 +++- 8 files changed, 34 insertions(+), 18 deletions(-) diff --git a/src/gentropy/biosample_index.py b/src/gentropy/biosample_index.py index e0b5e9b10..a6e8b5223 100644 --- a/src/gentropy/biosample_index.py +++ b/src/gentropy/biosample_index.py @@ -1,4 +1,5 @@ """Step to generate biosample index dataset.""" + from __future__ import annotations from gentropy.common.session import Session @@ -28,10 +29,16 @@ def __init__( efo_input_path (str): Input efo dataset path. biosample_index_path (str): Output gene index dataset path. """ - cell_ontology_index = extract_ontology_from_json(cell_ontology_input_path, session.spark) + cell_ontology_index = extract_ontology_from_json( + cell_ontology_input_path, session.spark + ) uberon_index = extract_ontology_from_json(uberon_input_path, session.spark) - efo_index = extract_ontology_from_json(efo_input_path, session.spark).retain_rows_with_ancestor_id(["CL_0000000"]) + efo_index = extract_ontology_from_json( + efo_input_path, session.spark + ).retain_rows_with_ancestor_id(["CL_0000000"]) biosample_index = cell_ontology_index.merge_indices([uberon_index, efo_index]) - biosample_index.df.write.mode(session.write_mode).parquet(biosample_index_path) + biosample_index.df.coalesce(session.output_partitions).write.mode( + session.write_mode + ).parquet(biosample_index_path) diff --git a/src/gentropy/colocalisation.py b/src/gentropy/colocalisation.py index 9682a8ed9..6a4568397 100644 --- a/src/gentropy/colocalisation.py +++ b/src/gentropy/colocalisation.py @@ -70,9 +70,9 @@ def __init__( coloc = partial(coloc, **colocalisation_method_params) colocalisation_results = coloc(overlaps) # Load - colocalisation_results.df.write.mode(session.write_mode).parquet( - f"{coloc_path}/{colocalisation_method.lower()}" - ) + colocalisation_results.df.coalesce(session.output_partitions).write.mode( + session.write_mode + ).parquet(f"{coloc_path}/{colocalisation_method.lower()}") @classmethod def _get_colocalisation_class( diff --git a/src/gentropy/common/session.py b/src/gentropy/common/session.py index 297903629..3a8ad4af7 100644 --- a/src/gentropy/common/session.py +++ b/src/gentropy/common/session.py @@ -24,6 +24,7 @@ def __init__( # noqa: D107 hail_home: str | None = None, start_hail: bool = False, extended_spark_conf: dict[str, str] | None = None, + output_partitions: int = 200, ) -> None: """Initialises spark session and logger. @@ -34,6 +35,7 @@ def __init__( # noqa: D107 hail_home (str | None): Path to Hail installation. Defaults to None. start_hail (bool): Whether to start Hail. Defaults to False. extended_spark_conf (dict[str, str] | None): Extended Spark configuration. Defaults to None. + output_partitions (int): Number of partitions for output datasets. Defaults to 200. """ merged_conf = self._create_merged_config( start_hail, hail_home, extended_spark_conf @@ -53,6 +55,7 @@ def __init__( # noqa: D107 self.start_hail = start_hail if start_hail: hl.init(sc=self.spark.sparkContext, log="/dev/null") + self.output_partitions = output_partitions def _default_config(self: Session) -> SparkConf: """Default spark configuration. diff --git a/src/gentropy/config.py b/src/gentropy/config.py index b32647acf..65fdb5897 100644 --- a/src/gentropy/config.py +++ b/src/gentropy/config.py @@ -18,6 +18,7 @@ class SessionConfig: spark_uri: str = "local[*]" hail_home: str = os.path.dirname(hail_location) extended_spark_conf: dict[str, str] | None = field(default_factory=dict[str, str]) + output_partitions: int = 200 _target_: str = "gentropy.common.session.Session" diff --git a/src/gentropy/gene_index.py b/src/gentropy/gene_index.py index ad8e95083..0a317d077 100644 --- a/src/gentropy/gene_index.py +++ b/src/gentropy/gene_index.py @@ -1,4 +1,5 @@ """Step to generate gene index dataset.""" + from __future__ import annotations from gentropy.common.session import Session @@ -28,4 +29,6 @@ def __init__( # Transform gene_index = OpenTargetsTarget.as_gene_index(platform_target) # Load - gene_index.df.write.mode(session.write_mode).parquet(gene_index_path) + gene_index.df.coalesce(session.output_partitions).write.mode( + session.write_mode + ).parquet(gene_index_path) diff --git a/src/gentropy/study_locus_validation.py b/src/gentropy/study_locus_validation.py index cf36a4389..ce2201f80 100644 --- a/src/gentropy/study_locus_validation.py +++ b/src/gentropy/study_locus_validation.py @@ -58,12 +58,12 @@ def __init__( # Valid study locus partitioned to simplify the finding of overlaps study_locus_with_qc.valid_rows(invalid_qc_reasons).df.repartitionByRange( - "chromosome", "position" + session.output_partitions, "chromosome", "position" ).sortWithinPartitions("chromosome", "position").write.mode( session.write_mode ).parquet(valid_study_locus_path) # Invalid study locus - study_locus_with_qc.valid_rows(invalid_qc_reasons, invalid=True).df.write.mode( - session.write_mode - ).parquet(invalid_study_locus_path) + study_locus_with_qc.valid_rows(invalid_qc_reasons, invalid=True).df.coalesce( + session.output_partitions + ).write.mode(session.write_mode).parquet(invalid_study_locus_path) diff --git a/src/gentropy/study_validation.py b/src/gentropy/study_validation.py index 08f601f1e..3d2fdd060 100644 --- a/src/gentropy/study_validation.py +++ b/src/gentropy/study_validation.py @@ -71,10 +71,10 @@ def __init__( ) # Flagging QTL studies with invalid biosamples ).persist() # we will need this for 2 types of outputs - study_index_with_qc.valid_rows(invalid_qc_reasons, invalid=True).df.write.mode( - session.write_mode - ).parquet(invalid_study_index_path) + study_index_with_qc.valid_rows(invalid_qc_reasons, invalid=True).df.coalesce( + session.output_partitions + ).write.mode(session.write_mode).parquet(invalid_study_index_path) - study_index_with_qc.valid_rows(invalid_qc_reasons).df.write.mode( - session.write_mode - ).parquet(valid_study_index_path) + study_index_with_qc.valid_rows(invalid_qc_reasons).df.coalesce( + session.output_partitions + ).write.mode(session.write_mode).parquet(valid_study_index_path) diff --git a/src/gentropy/variant_index.py b/src/gentropy/variant_index.py index 9eac684b2..ae7efa5c4 100644 --- a/src/gentropy/variant_index.py +++ b/src/gentropy/variant_index.py @@ -56,7 +56,9 @@ def __init__( variant_index = variant_index.add_annotation(annotations) ( - variant_index.df.repartitionByRange("chromosome", "position") + variant_index.df.repartitionByRange( + session.output_partitions, "chromosome", "position" + ) .sortWithinPartitions("chromosome", "position") .write.mode(session.write_mode) .parquet(variant_index_path) From d2c741713a2dc66049be41033eb2ab9f87670901 Mon Sep 17 00:00:00 2001 From: Daniel Suveges Date: Wed, 27 Nov 2024 15:29:05 +0000 Subject: [PATCH 180/188] chore(vep): Ensembl version update (#931) * chore: vep version bump * fix: bump version to most recent --------- Co-authored-by: Szymon Szyszkowski <69353402+project-defiant@users.noreply.github.com> --- src/vep/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vep/Dockerfile b/src/vep/Dockerfile index ade55e3da..6b2fef42d 100644 --- a/src/vep/Dockerfile +++ b/src/vep/Dockerfile @@ -1,4 +1,4 @@ -FROM ensemblorg/ensembl-vep:release_111.0 +FROM ensemblorg/ensembl-vep:release_113.3 USER root From 9a9fb7b91f8fae56e7fdc54cfb313f70c6cd8261 Mon Sep 17 00:00:00 2001 From: Szymon Szyszkowski <69353402+project-defiant@users.noreply.github.com> Date: Wed, 27 Nov 2024 16:40:25 +0100 Subject: [PATCH 181/188] feat: coalesce l2g fm and predictions (#934) Co-authored-by: Szymon Szyszkowski --- src/gentropy/l2g.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/gentropy/l2g.py b/src/gentropy/l2g.py index 548368967..16922ef78 100644 --- a/src/gentropy/l2g.py +++ b/src/gentropy/l2g.py @@ -89,7 +89,9 @@ def __init__( fm = credible_set.filter(f.col("studyType") == "gwas").build_feature_matrix( features_list, features_input_loader ) - fm._df.write.mode(session.write_mode).parquet(feature_matrix_path) + fm._df.coalesce(session.output_partitions).write.mode( + session.write_mode + ).parquet(feature_matrix_path) class LocusToGeneStep: @@ -283,9 +285,9 @@ def run_predict(self) -> None: ) predictions.filter( f.col("score") >= self.l2g_threshold - ).add_locus_to_gene_features(self.feature_matrix).df.write.mode( - self.session.write_mode - ).parquet(self.predictions_path) + ).add_locus_to_gene_features(self.feature_matrix).df.coalesce( + self.session.output_partitions + ).write.mode(self.session.write_mode).parquet(self.predictions_path) self.session.logger.info("L2G predictions saved successfully.") def run_train(self) -> None: @@ -378,6 +380,7 @@ def __init__( locus_to_gene_prediction.to_disease_target_evidence( credible_sets, study_index, locus_to_gene_threshold ) + .coalesce(session.output_partitions) .write.mode(session.write_mode) .option("compression", "gzip") .json(evidence_output_path) From 8595e5b1deecb80719fed6ff8053c55a4d9eb15e Mon Sep 17 00:00:00 2001 From: Szymon Szyszkowski <69353402+project-defiant@users.noreply.github.com> Date: Wed, 27 Nov 2024 16:54:29 +0100 Subject: [PATCH 182/188] feat: allow building package from tag (#930) * feat: allow building package from tag * fix: indent --------- Co-authored-by: Szymon Szyszkowski --- Makefile | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 1d79d35fd..377661299 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,15 @@ PROJECT_ID ?= open-targets-genetics-dev REGION ?= europe-west1 APP_NAME ?= $$(cat pyproject.toml | grep -m 1 "name" | cut -d" " -f3 | sed 's/"//g') -REF ?= $$(git rev-parse --abbrev-ref HEAD) PACKAGE_VERSION ?= $$(poetry version --short) +# NOTE: git rev-parse will always return the HEAD if it sits in the tag, +# this way we can distinguish the tag vs branch name +ifeq ($(shell git rev-parse --abbrev-ref HEAD)),HEAD) + REF := $(shell git rev-parse --abbrev-ref HEAD) +else + REF := $(shell git describe --exact-match --tags) +endif + CLEAN_PACKAGE_VERSION := $(shell echo "$(PACKAGE_VERSION)" | tr -cd '[:alnum:]') BUCKET_NAME=gs://genetics_etl_python_playground/initialisation/${APP_NAME}/${REF} From 19219dd116493050648a80f00140c0e1fab76989 Mon Sep 17 00:00:00 2001 From: Daniel Suveges Date: Wed, 27 Nov 2024 16:50:08 +0000 Subject: [PATCH 183/188] feat: adding GERP conservation score to variant annotation (#933) * feat: adding GERP conservation score to variant annotation * fix: typo --------- Co-authored-by: Szymon Szyszkowski <69353402+project-defiant@users.noreply.github.com> --- .../assets/schemas/vep_json_output.json | 12 +++++++ src/gentropy/dataset/variant_index.py | 33 +++++++++++++++++++ src/gentropy/datasource/ensembl/vep_parser.py | 12 +++++++ 3 files changed, 57 insertions(+) diff --git a/src/gentropy/assets/schemas/vep_json_output.json b/src/gentropy/assets/schemas/vep_json_output.json index 674788407..14aae6b84 100644 --- a/src/gentropy/assets/schemas/vep_json_output.json +++ b/src/gentropy/assets/schemas/vep_json_output.json @@ -20,6 +20,12 @@ "containsNull": true, "elementType": { "fields": [ + { + "metadata": {}, + "name": "conservation", + "nullable": true, + "type": "double" + }, { "metadata": {}, "name": "hgvsg", @@ -294,6 +300,12 @@ "containsNull": true, "elementType": { "fields": [ + { + "metadata": {}, + "name": "conservation", + "nullable": true, + "type": "double" + }, { "metadata": {}, "name": "alphamissense", diff --git a/src/gentropy/dataset/variant_index.py b/src/gentropy/dataset/variant_index.py index 4092ca961..649b9f3ff 100644 --- a/src/gentropy/dataset/variant_index.py +++ b/src/gentropy/dataset/variant_index.py @@ -368,6 +368,7 @@ def resolve_predictor_methods( # The following predictors are not normalised: .when(method == "SpliceAI", score) .when(method == "VEP", score) + .when(method == "GERP", cls._normalise_gerp(score)) ) @staticmethod @@ -420,6 +421,38 @@ def _normalise_cadd( .when(score > 30, cls._rescaleColumnValue(score, 30, 81, 0.75, 1)) ) + @classmethod + def _normalise_gerp( + cls: type[InSilicoPredictorNormaliser], + score: Column, + ) -> Column: + """Normalise GERP scores. + + # Score interpretation from here: + # https://pmc.ncbi.nlm.nih.gov/articles/PMC7286533/ + # https://genome.ucsc.edu/cgi-bin/hgTrackUi?db=hg19&g=allHg19RS_BW + + Logic: GERP scores are divided into three categories: + - >6 : 1.0 - GERP scores are not bounded, so any value above 6 is considered as 1.0 + - 2-6: 0.5-1 - Highly conserved regions are scaled between 0.5 and 1 + - 0-2: 0-0.5 - Moderately conserved regions are scaled between 0 and 0.5 + - -3-0: -1-0.0 - Negative conservation indicates benign sequence alteration, so scaled between -1 and 0 + - < -3: -1.0 - As the score goes below -3, it is considered as -1.0 + + Args: + score (Column): GERP score. + + Returns: + Column: Normalised GERP score. + """ + return ( + f.when(score > 6, f.lit(1.0)) + .when(score >= 2, cls._rescaleColumnValue(score, 2, 6, 0.5, 1)) + .when(score >= 0, cls._rescaleColumnValue(score, 0, 2, 0, 0.5)) + .when(score >= -3, cls._rescaleColumnValue(score, -3, 0, -1, 0)) + .when(score < -3, f.lit(-1.0)) + ) + @classmethod def _normalise_loftee( cls: type[InSilicoPredictorNormaliser], diff --git a/src/gentropy/datasource/ensembl/vep_parser.py b/src/gentropy/datasource/ensembl/vep_parser.py index 9494bf6f3..b0a2e50a2 100644 --- a/src/gentropy/datasource/ensembl/vep_parser.py +++ b/src/gentropy/datasource/ensembl/vep_parser.py @@ -668,6 +668,12 @@ def process_vep_output( assessment_column_name="lof", assessment_flag_column_name="lof_filter", ), + # Extract GERP conservation score: + cls._vep_in_silico_prediction_extractor( + method_name="GERP", + transcript_column_name="transcript_consequences", + score_column_name="conservation", + ), # Extract max alpha missense: cls._get_max_alpha_missense( f.col("transcript_consequences") @@ -686,6 +692,12 @@ def process_vep_output( method_name="CADD", score_column_name="cadd_phred", ), + # Extract GERP conservation score: + cls._vep_in_silico_prediction_extractor( + method_name="GERP", + transcript_column_name="intergenic_consequences", + score_column_name="conservation", + ), # Extract VEP prediction: cls._get_vep_prediction(f.col("most_severe_consequence")), ) From ff35db4a35c3dbdf5c94505541ba67da68f97a2b Mon Sep 17 00:00:00 2001 From: Szymon Szyszkowski <69353402+project-defiant@users.noreply.github.com> Date: Thu, 28 Nov 2024 12:51:09 +0100 Subject: [PATCH 184/188] fix: swap the ref parse (#935) Co-authored-by: Szymon Szyszkowski --- Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 377661299..4e6a7463f 100644 --- a/Makefile +++ b/Makefile @@ -4,10 +4,10 @@ APP_NAME ?= $$(cat pyproject.toml | grep -m 1 "name" | cut -d" " -f3 | sed 's/" PACKAGE_VERSION ?= $$(poetry version --short) # NOTE: git rev-parse will always return the HEAD if it sits in the tag, # this way we can distinguish the tag vs branch name -ifeq ($(shell git rev-parse --abbrev-ref HEAD)),HEAD) - REF := $(shell git rev-parse --abbrev-ref HEAD) -else +ifeq ($(shell git rev-parse --abbrev-ref HEAD),HEAD) REF := $(shell git describe --exact-match --tags) +else + REF := $(shell git rev-parse --abbrev-ref HEAD) endif CLEAN_PACKAGE_VERSION := $(shell echo "$(PACKAGE_VERSION)" | tr -cd '[:alnum:]') From e49608de994a62a3489feea52e9ee2f459550b6c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 3 Dec 2024 11:42:33 +0000 Subject: [PATCH 185/188] build(deps-dev): bump ipython from 8.29.0 to 8.30.0 (#937) Bumps [ipython](https://github.com/ipython/ipython) from 8.29.0 to 8.30.0. - [Release notes](https://github.com/ipython/ipython/releases) - [Commits](https://github.com/ipython/ipython/compare/8.29.0...8.30.0) --- updated-dependencies: - dependency-name: ipython dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- poetry.lock | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/poetry.lock b/poetry.lock index aea09f8c9..434673775 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2080,13 +2080,13 @@ test = ["flaky", "ipyparallel", "pre-commit", "pytest (>=7.0)", "pytest-asyncio [[package]] name = "ipython" -version = "8.29.0" +version = "8.30.0" description = "IPython: Productive Interactive Computing" optional = false python-versions = ">=3.10" files = [ - {file = "ipython-8.29.0-py3-none-any.whl", hash = "sha256:0188a1bd83267192123ccea7f4a8ed0a78910535dbaa3f37671dca76ebd429c8"}, - {file = "ipython-8.29.0.tar.gz", hash = "sha256:40b60e15b22591450eef73e40a027cf77bd652e757523eebc5bd7c7c498290eb"}, + {file = "ipython-8.30.0-py3-none-any.whl", hash = "sha256:85ec56a7e20f6c38fce7727dcca699ae4ffc85985aa7b23635a8008f918ae321"}, + {file = "ipython-8.30.0.tar.gz", hash = "sha256:cb0a405a306d2995a5cbb9901894d240784a9f341394c6ba3f4fe8c6eb89ff6e"}, ] [package.dependencies] @@ -2096,16 +2096,16 @@ exceptiongroup = {version = "*", markers = "python_version < \"3.11\""} jedi = ">=0.16" matplotlib-inline = "*" pexpect = {version = ">4.3", markers = "sys_platform != \"win32\" and sys_platform != \"emscripten\""} -prompt-toolkit = ">=3.0.41,<3.1.0" +prompt_toolkit = ">=3.0.41,<3.1.0" pygments = ">=2.4.0" -stack-data = "*" +stack_data = "*" traitlets = ">=5.13.0" -typing-extensions = {version = ">=4.6", markers = "python_version < \"3.12\""} +typing_extensions = {version = ">=4.6", markers = "python_version < \"3.12\""} [package.extras] all = ["ipython[black,doc,kernel,matplotlib,nbconvert,nbformat,notebook,parallel,qtconsole]", "ipython[test,test-extra]"] black = ["black"] -doc = ["docrepr", "exceptiongroup", "intersphinx-registry", "ipykernel", "ipython[test]", "matplotlib", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "sphinxcontrib-jquery", "tomli", "typing-extensions"] +doc = ["docrepr", "exceptiongroup", "intersphinx_registry", "ipykernel", "ipython[test]", "matplotlib", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "sphinxcontrib-jquery", "tomli", "typing_extensions"] kernel = ["ipykernel"] matplotlib = ["matplotlib"] nbconvert = ["nbconvert"] From a02f9c118f05adb71e873bf9739ad07914a514e0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 3 Dec 2024 11:50:39 +0000 Subject: [PATCH 186/188] build(deps-dev): bump ruff from 0.7.1 to 0.8.1 (#936) Bumps [ruff](https://github.com/astral-sh/ruff) from 0.7.1 to 0.8.1. - [Release notes](https://github.com/astral-sh/ruff/releases) - [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md) - [Commits](https://github.com/astral-sh/ruff/compare/0.7.1...0.8.1) --- updated-dependencies: - dependency-name: ruff dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- poetry.lock | 40 ++++++++++++++++++++-------------------- pyproject.toml | 2 +- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/poetry.lock b/poetry.lock index 434673775..53d95babf 100644 --- a/poetry.lock +++ b/poetry.lock @@ -4905,29 +4905,29 @@ pyasn1 = ">=0.1.3" [[package]] name = "ruff" -version = "0.7.1" +version = "0.8.1" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.7.1-py3-none-linux_armv6l.whl", hash = "sha256:cb1bc5ed9403daa7da05475d615739cc0212e861b7306f314379d958592aaa89"}, - {file = "ruff-0.7.1-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:27c1c52a8d199a257ff1e5582d078eab7145129aa02721815ca8fa4f9612dc35"}, - {file = "ruff-0.7.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:588a34e1ef2ea55b4ddfec26bbe76bc866e92523d8c6cdec5e8aceefeff02d99"}, - {file = "ruff-0.7.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94fc32f9cdf72dc75c451e5f072758b118ab8100727168a3df58502b43a599ca"}, - {file = "ruff-0.7.1-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:985818742b833bffa543a84d1cc11b5e6871de1b4e0ac3060a59a2bae3969250"}, - {file = "ruff-0.7.1-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:32f1e8a192e261366c702c5fb2ece9f68d26625f198a25c408861c16dc2dea9c"}, - {file = "ruff-0.7.1-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:699085bf05819588551b11751eff33e9ca58b1b86a6843e1b082a7de40da1565"}, - {file = "ruff-0.7.1-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:344cc2b0814047dc8c3a8ff2cd1f3d808bb23c6658db830d25147339d9bf9ea7"}, - {file = "ruff-0.7.1-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4316bbf69d5a859cc937890c7ac7a6551252b6a01b1d2c97e8fc96e45a7c8b4a"}, - {file = "ruff-0.7.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:79d3af9dca4c56043e738a4d6dd1e9444b6d6c10598ac52d146e331eb155a8ad"}, - {file = "ruff-0.7.1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:c5c121b46abde94a505175524e51891f829414e093cd8326d6e741ecfc0a9112"}, - {file = "ruff-0.7.1-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:8422104078324ea250886954e48f1373a8fe7de59283d747c3a7eca050b4e378"}, - {file = "ruff-0.7.1-py3-none-musllinux_1_2_i686.whl", hash = "sha256:56aad830af8a9db644e80098fe4984a948e2b6fc2e73891538f43bbe478461b8"}, - {file = "ruff-0.7.1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:658304f02f68d3a83c998ad8bf91f9b4f53e93e5412b8f2388359d55869727fd"}, - {file = "ruff-0.7.1-py3-none-win32.whl", hash = "sha256:b517a2011333eb7ce2d402652ecaa0ac1a30c114fbbd55c6b8ee466a7f600ee9"}, - {file = "ruff-0.7.1-py3-none-win_amd64.whl", hash = "sha256:f38c41fcde1728736b4eb2b18850f6d1e3eedd9678c914dede554a70d5241307"}, - {file = "ruff-0.7.1-py3-none-win_arm64.whl", hash = "sha256:19aa200ec824c0f36d0c9114c8ec0087082021732979a359d6f3c390a6ff2a37"}, - {file = "ruff-0.7.1.tar.gz", hash = "sha256:9d8a41d4aa2dad1575adb98a82870cf5db5f76b2938cf2206c22c940034a36f4"}, + {file = "ruff-0.8.1-py3-none-linux_armv6l.whl", hash = "sha256:fae0805bd514066f20309f6742f6ee7904a773eb9e6c17c45d6b1600ca65c9b5"}, + {file = "ruff-0.8.1-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b8a4f7385c2285c30f34b200ca5511fcc865f17578383db154e098150ce0a087"}, + {file = "ruff-0.8.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:cd054486da0c53e41e0086e1730eb77d1f698154f910e0cd9e0d64274979a209"}, + {file = "ruff-0.8.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2029b8c22da147c50ae577e621a5bfbc5d1fed75d86af53643d7a7aee1d23871"}, + {file = "ruff-0.8.1-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2666520828dee7dfc7e47ee4ea0d928f40de72056d929a7c5292d95071d881d1"}, + {file = "ruff-0.8.1-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:333c57013ef8c97a53892aa56042831c372e0bb1785ab7026187b7abd0135ad5"}, + {file = "ruff-0.8.1-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:288326162804f34088ac007139488dcb43de590a5ccfec3166396530b58fb89d"}, + {file = "ruff-0.8.1-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b12c39b9448632284561cbf4191aa1b005882acbc81900ffa9f9f471c8ff7e26"}, + {file = "ruff-0.8.1-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:364e6674450cbac8e998f7b30639040c99d81dfb5bbc6dfad69bc7a8f916b3d1"}, + {file = "ruff-0.8.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b22346f845fec132aa39cd29acb94451d030c10874408dbf776af3aaeb53284c"}, + {file = "ruff-0.8.1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:b2f2f7a7e7648a2bfe6ead4e0a16745db956da0e3a231ad443d2a66a105c04fa"}, + {file = "ruff-0.8.1-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:adf314fc458374c25c5c4a4a9270c3e8a6a807b1bec018cfa2813d6546215540"}, + {file = "ruff-0.8.1-py3-none-musllinux_1_2_i686.whl", hash = "sha256:a885d68342a231b5ba4d30b8c6e1b1ee3a65cf37e3d29b3c74069cdf1ee1e3c9"}, + {file = "ruff-0.8.1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:d2c16e3508c8cc73e96aa5127d0df8913d2290098f776416a4b157657bee44c5"}, + {file = "ruff-0.8.1-py3-none-win32.whl", hash = "sha256:93335cd7c0eaedb44882d75a7acb7df4b77cd7cd0d2255c93b28791716e81790"}, + {file = "ruff-0.8.1-py3-none-win_amd64.whl", hash = "sha256:2954cdbe8dfd8ab359d4a30cd971b589d335a44d444b6ca2cb3d1da21b75e4b6"}, + {file = "ruff-0.8.1-py3-none-win_arm64.whl", hash = "sha256:55873cc1a473e5ac129d15eccb3c008c096b94809d693fc7053f588b67822737"}, + {file = "ruff-0.8.1.tar.gz", hash = "sha256:3583db9a6450364ed5ca3f3b4225958b24f78178908d5c4bc0f46251ccca898f"}, ] [[package]] @@ -5959,4 +5959,4 @@ propcache = ">=0.2.0" [metadata] lock-version = "2.0" python-versions = "^3.10, <3.11" -content-hash = "af70455b40ec31084130c90b9dc468a5c1198f80e6ae30d10bfb1b17d1706537" +content-hash = "b47b8a546db802a97c4656174b4417d844f3af383cf6617b7743c43f7e2a5381" diff --git a/pyproject.toml b/pyproject.toml index fd69201cb..ebdacef7d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -44,7 +44,7 @@ pep8-naming = "^0.14.1" interrogate = "^1.7.0" isort = "^5.13.2" darglint = "^1.8.1" -ruff = "^0.7.0" +ruff = "^0.8.1" [tool.poetry.group.docs.dependencies] mkdocs = "^1.5.3" From 43f047a9c1a34942a69b5230e98e4e85c87bcc24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Irene=20L=C3=B3pez=20Santiago?= <45119610+ireneisdoomed@users.noreply.github.com> Date: Thu, 5 Dec 2024 15:35:54 +0000 Subject: [PATCH 187/188] fix(l2g_predictions): annotate based on list of features + filter out missing annotation (#925) * fix(prediction): do not annotate all features from matrix * fix(prediction): filter out features with 0 * chore: pre-commit auto fixes [...] --- src/gentropy/dataset/l2g_prediction.py | 29 ++++++++------------------ src/gentropy/l2g.py | 10 +++++---- 2 files changed, 15 insertions(+), 24 deletions(-) diff --git a/src/gentropy/dataset/l2g_prediction.py b/src/gentropy/dataset/l2g_prediction.py index 2bc286a40..915b2b7dc 100644 --- a/src/gentropy/dataset/l2g_prediction.py +++ b/src/gentropy/dataset/l2g_prediction.py @@ -129,12 +129,13 @@ def to_disease_target_evidence( ) def add_locus_to_gene_features( - self: L2GPrediction, feature_matrix: L2GFeatureMatrix + self: L2GPrediction, feature_matrix: L2GFeatureMatrix, features_list: list[str] ) -> L2GPrediction: - """Add features to the L2G predictions. + """Add features used to extract the L2G predictions. Args: feature_matrix (L2GFeatureMatrix): Feature matrix dataset + features_list (list[str]): List of features used in the model Returns: L2GPrediction: L2G predictions with additional features @@ -143,38 +144,26 @@ def add_locus_to_gene_features( if "locusToGeneFeatures" in self.df.columns: self.df = self.df.drop("locusToGeneFeatures") - # Columns identifying a studyLocus/gene pair - prediction_id_columns = ["studyLocusId", "geneId"] - - # L2G matrix columns to build the map: - columns_to_map = [ - column - for column in feature_matrix._df.columns - if column not in prediction_id_columns - ] - # Aggregating all features into a single map column: aggregated_features = ( feature_matrix._df.withColumn( "locusToGeneFeatures", f.create_map( *sum( - [ - (f.lit(colname), f.col(colname)) - for colname in columns_to_map - ], + ((f.lit(feature), f.col(feature)) for feature in features_list), (), ) ), ) - # from the freshly created map, we filter out the null values .withColumn( "locusToGeneFeatures", - f.expr("map_filter(locusToGeneFeatures, (k, v) -> v is not null)"), + f.expr("map_filter(locusToGeneFeatures, (k, v) -> v != 0)"), ) - .drop(*columns_to_map) + .drop(*features_list) ) return L2GPrediction( - _df=self.df.join(aggregated_features, on=prediction_id_columns, how="left"), + _df=self.df.join( + aggregated_features, on=["studyLocusId", "geneId"], how="left" + ), _schema=self.get_schema(), ) diff --git a/src/gentropy/l2g.py b/src/gentropy/l2g.py index 16922ef78..ff0d47f58 100644 --- a/src/gentropy/l2g.py +++ b/src/gentropy/l2g.py @@ -7,7 +7,7 @@ import pyspark.sql.functions as f from sklearn.ensemble import GradientBoostingClassifier -from wandb import login as wandb_login +from wandb.sdk.wandb_login import login as wandb_login from gentropy.common.schemas import compare_struct_schemas from gentropy.common.session import Session @@ -285,9 +285,11 @@ def run_predict(self) -> None: ) predictions.filter( f.col("score") >= self.l2g_threshold - ).add_locus_to_gene_features(self.feature_matrix).df.coalesce( - self.session.output_partitions - ).write.mode(self.session.write_mode).parquet(self.predictions_path) + ).add_locus_to_gene_features( + self.feature_matrix, self.features_list + ).df.coalesce(self.session.output_partitions).write.mode( + self.session.write_mode + ).parquet(self.predictions_path) self.session.logger.info("L2G predictions saved successfully.") def run_train(self) -> None: From 79f6fcc383bcc0f165f9c51e4a32675bf6f2f8c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Irene=20L=C3=B3pez=20Santiago?= <45119610+ireneisdoomed@users.noreply.github.com> Date: Mon, 9 Dec 2024 16:34:54 +0000 Subject: [PATCH 188/188] feat(l2g)!: implement new training strategy splitting between EFO/gene pairs and with cross validation (#938) * feat(gold_standard): add traitFromSourceMappedId to schema * chore: adapt tests * feat(feature_matrix): consider `traitFromSourceMappedId` a static column * feat(feature_matrix): consider `traitFromSourceMappedId` an optional column * feat: update l2g config with best hyperparams * feat(trainer): new train runs when cross_validate=False * chore(model): add default hyperparams based on best params * chore: debug sweep, one single run * feat(trainer): new train runs when cross_validate=True * feat(cross_validate): sweep runs are now together * chore: pre-commit auto fixes [...] * chore: improve error message --- src/gentropy/config.py | 10 +- src/gentropy/l2g.py | 15 +- src/gentropy/method/l2g/model.py | 15 +- src/gentropy/method/l2g/trainer.py | 398 ++++++++++++++++++++--------- 4 files changed, 309 insertions(+), 129 deletions(-) diff --git a/src/gentropy/config.py b/src/gentropy/config.py index 65fdb5897..9c454d41b 100644 --- a/src/gentropy/config.py +++ b/src/gentropy/config.py @@ -264,20 +264,24 @@ class LocusToGeneConfig(StepConfig): "geneCount500kb", "proteinGeneCount500kb", "credibleSetConfidence", - # "isProteinCoding", ] ) hyperparameters: dict[str, Any] = field( default_factory=lambda: { "n_estimators": 100, - "max_depth": 5, - "loss": "log_loss", + "max_depth": 10, + "ccp_alpha": 0, + "learning_rate": 0.1, + "min_samples_leaf": 5, + "min_samples_split": 5, + "subsample": 1, } ) wandb_run_name: str | None = None hf_hub_repo_id: str | None = "opentargets/locus_to_gene" hf_model_commit_message: str | None = "chore: update model" download_from_hub: bool = True + cross_validate: bool = True _target_: str = "gentropy.l2g.LocusToGeneStep" diff --git a/src/gentropy/l2g.py b/src/gentropy/l2g.py index ff0d47f58..3b73a377d 100644 --- a/src/gentropy/l2g.py +++ b/src/gentropy/l2g.py @@ -100,11 +100,12 @@ class LocusToGeneStep: def __init__( self, session: Session, - hyperparameters: dict[str, Any], *, run_mode: str, features_list: list[str], + hyperparameters: dict[str, Any], download_from_hub: bool, + cross_validate: bool, wandb_run_name: str, credible_set_path: str, feature_matrix_path: str, @@ -113,18 +114,19 @@ def __init__( variant_index_path: str | None = None, gene_interactions_path: str | None = None, predictions_path: str | None = None, - l2g_threshold: float | None, - hf_hub_repo_id: str | None, + l2g_threshold: float | None = None, + hf_hub_repo_id: str | None = None, hf_model_commit_message: str | None = "chore: update model", ) -> None: """Initialise the step and run the logic based on mode. Args: session (Session): Session object that contains the Spark session - hyperparameters (dict[str, Any]): Hyperparameters for the model run_mode (str): Run mode, either 'train' or 'predict' features_list (list[str]): List of features to use for the model + hyperparameters (dict[str, Any]): Hyperparameters for the model download_from_hub (bool): Whether to download the model from Hugging Face Hub + cross_validate (bool): Whether to run cross validation (5-fold by default) to train the model. wandb_run_name (str): Name of the run to track model training in Weights and Biases credible_set_path (str): Path to the credible set dataset necessary to build the feature matrix feature_matrix_path (str): Path to the L2G feature matrix input dataset @@ -152,6 +154,7 @@ def __init__( self.features_list = list(features_list) self.hyperparameters = dict(hyperparameters) self.wandb_run_name = wandb_run_name + self.cross_validate = cross_validate self.hf_hub_repo_id = hf_hub_repo_id self.download_from_hub = download_from_hub self.hf_model_commit_message = hf_model_commit_message @@ -300,7 +303,7 @@ def run_train(self) -> None: # Instantiate classifier and train model l2g_model = LocusToGeneModel( - model=GradientBoostingClassifier(random_state=42), + model=GradientBoostingClassifier(random_state=42, loss="log_loss"), hyperparameters=self.hyperparameters, ) @@ -310,7 +313,7 @@ def run_train(self) -> None: # Run the training trained_model = LocusToGeneTrainer( model=l2g_model, feature_matrix=feature_matrix - ).train(self.wandb_run_name) + ).train(self.wandb_run_name, cross_validate=self.cross_validate) # Export the model if trained_model.training_data and trained_model.model and self.model_path: diff --git a/src/gentropy/method/l2g/model.py b/src/gentropy/method/l2g/model.py index 336efeb7f..1f18f227f 100644 --- a/src/gentropy/method/l2g/model.py +++ b/src/gentropy/method/l2g/model.py @@ -27,7 +27,17 @@ class LocusToGeneModel: """Wrapper for the Locus to Gene classifier.""" model: Any = GradientBoostingClassifier(random_state=42) - hyperparameters: dict[str, Any] | None = None + hyperparameters: dict[str, Any] = field( + default_factory=lambda: { + "n_estimators": 100, + "max_depth": 10, + "ccp_alpha": 0, + "learning_rate": 0.1, + "min_samples_leaf": 5, + "min_samples_split": 5, + "subsample": 1, + } + ) training_data: L2GFeatureMatrix | None = None label_encoder: dict[str, int] = field( default_factory=lambda: { @@ -38,8 +48,7 @@ class LocusToGeneModel: def __post_init__(self: LocusToGeneModel) -> None: """Post-initialisation to fit the estimator with the provided params.""" - if self.hyperparameters: - self.model.set_params(**self.hyperparameters_dict) + self.model.set_params(**self.hyperparameters_dict) @classmethod def load_from_disk(cls: Type[LocusToGeneModel], path: str) -> LocusToGeneModel: diff --git a/src/gentropy/method/l2g/trainer.py b/src/gentropy/method/l2g/trainer.py index ab2a3fa7e..a43d6609d 100644 --- a/src/gentropy/method/l2g/trainer.py +++ b/src/gentropy/method/l2g/trainer.py @@ -4,23 +4,26 @@ import os from dataclasses import dataclass -from functools import partial from typing import TYPE_CHECKING, Any import matplotlib.pyplot as plt +import numpy as np import pandas as pd import shap +from sklearn.base import clone from sklearn.metrics import ( accuracy_score, + average_precision_score, f1_score, precision_score, recall_score, roc_auc_score, ) -from sklearn.model_selection import train_test_split +from sklearn.model_selection import GroupKFold, GroupShuffleSplit from wandb.data_types import Image, Table from wandb.errors.term import termlog as wandb_termlog from wandb.sdk.wandb_init import init as wandb_init +from wandb.sdk.wandb_setup import _setup from wandb.sdk.wandb_sweep import sweep as wandb_sweep from wandb.sklearn import plot_classifier from wandb.wandb_agent import agent as wandb_agent @@ -34,6 +37,21 @@ from wandb.sdk.wandb_run import Run +def reset_wandb_env() -> None: + """Reset Wandb environment variables except for project, entity and API key. + + This is necessary to log multiple runs in the same sweep without overwriting. More context here: https://github.com/wandb/wandb/issues/5119 + """ + exclude = { + "WANDB_PROJECT", + "WANDB_ENTITY", + "WANDB_API_KEY", + } + for key in list(os.environ.keys()): + if key.startswith("WANDB_") and key not in exclude: + del os.environ[key] + + @dataclass class LocusToGeneTrainer: """Modelling of what is the most likely causal gene associated with a given locus.""" @@ -44,10 +62,11 @@ class LocusToGeneTrainer: # Initialise vars features_list: list[str] | None = None label_col: str = "goldStandardSet" - x_train: pd.DataFrame | None = None - y_train: pd.Series | None = None - x_test: pd.DataFrame | None = None - y_test: pd.Series | None = None + x_train: np.ndarray | None = None + y_train: np.ndarray | None = None + x_test: np.ndarray | None = None + y_test: np.ndarray | None = None + groups_train: np.ndarray | None = None run: Run | None = None wandb_l2g_project_name: str = "gentropy-locus-to-gene" @@ -72,9 +91,9 @@ def fit( """ if self.x_train is not None and self.y_train is not None: assert ( - not self.x_train.empty and not self.y_train.empty + self.x_train.size != 0 and self.y_train.size != 0 ), "Train data not set, nothing to fit." - fitted_model = self.model.model.fit(X=self.x_train.values, y=self.y_train) + fitted_model = self.model.model.fit(X=self.x_train, y=self.y_train) self.model = LocusToGeneModel( model=fitted_model, hyperparameters=fitted_model.get_params(), @@ -100,7 +119,10 @@ def _get_shap_explanation( Exception: (ExplanationError) When the additivity check fails. """ if self.x_train is not None and self.x_test is not None: - training_data = pd.concat([self.x_train, self.x_test], ignore_index=True) + training_data = pd.DataFrame( + np.vstack((self.x_train, self.x_test)), + columns=self.features_list, + ) explainer = shap.TreeExplainer( model.model, data=training_data, @@ -152,151 +174,293 @@ def log_to_wandb( wandb_run_name (str): Name of the W&B run Raises: - ValueError: If dependencies are not available. + RuntimeError: If dependencies are not available. """ if ( - self.x_train is not None - and self.x_test is not None - and self.y_train is not None - and self.y_test is not None - and self.features_list is not None + self.x_train is None + or self.x_test is None + or self.y_train is None + or self.y_test is None + or self.features_list is None ): - assert ( - not self.x_train.empty and not self.y_train.empty - ), "Train data not set, nothing to evaluate." - fitted_classifier = self.model.model - y_predicted = fitted_classifier.predict(self.x_test.values) - y_probas = fitted_classifier.predict_proba(self.x_test.values) - self.run = wandb_init( - project=self.wandb_l2g_project_name, - name=wandb_run_name, - config=fitted_classifier.get_params(), - ) - # Track classification plots - plot_classifier( - self.model.model, - self.x_train.values, - self.x_test.values, - self.y_train, - self.y_test, - y_predicted, - y_probas, - labels=list(self.model.label_encoder.values()), - model_name="L2G-classifier", - feature_names=self.features_list, - is_binary=True, - ) - # Track evaluation metrics - self.run.log( - { - "areaUnderROC": roc_auc_score( - self.y_test, y_probas[:, 1], average="weighted" - ) - } - ) - self.run.log({"accuracy": accuracy_score(self.y_test, y_predicted)}) - self.run.log( - { - "weightedPrecision": precision_score( - self.y_test, y_predicted, average="weighted" - ) - } - ) - self.run.log( - { - "weightedRecall": recall_score( - self.y_test, y_predicted, average="weighted" - ) - } - ) - self.run.log({"f1": f1_score(self.y_test, y_predicted, average="weighted")}) - # Track gold standards and their features - self.run.log( - {"featureMatrix": Table(dataframe=self.feature_matrix._df.toPandas())} - ) - # Log feature missingness - self.run.log( - { - "missingnessRates": self.feature_matrix.calculate_feature_missingness_rate() - } - ) - # Plot marginal contribution of each feature - explanation = self._get_shap_explanation(self.model) - self.log_plot_image_to_wandb( - "Feature Contribution", - shap.plots.bar( - explanation, max_display=len(self.x_train.columns), show=False - ), - ) + raise RuntimeError("Train data not set, we cannot log to W&B.") + assert ( + self.x_train.size != 0 and self.y_train.size != 0 + ), "Train data not set, nothing to evaluate." + fitted_classifier = self.model.model + y_predicted = fitted_classifier.predict(self.x_test) + y_probas = fitted_classifier.predict_proba(self.x_test) + self.run = wandb_init( + project=self.wandb_l2g_project_name, + name=wandb_run_name, + config=fitted_classifier.get_params(), + ) + # Track classification plots + plot_classifier( + self.model.model, + self.x_train, + self.x_test, + self.y_train, + self.y_test, + y_predicted, + y_probas, + labels=list(self.model.label_encoder.values()), + model_name="L2G-classifier", + feature_names=self.features_list, + is_binary=True, + ) + # Track evaluation metrics + self.run.log( + { + "areaUnderROC": roc_auc_score( + self.y_test, y_probas[:, 1], average="weighted" + ) + } + ) + self.run.log({"accuracy": accuracy_score(self.y_test, y_predicted)}) + self.run.log( + { + "weightedPrecision": precision_score( + self.y_test, y_predicted, average="weighted" + ) + } + ) + self.run.log( + { + "averagePrecision": average_precision_score( + self.y_test, y_predicted, average="weighted" + ) + } + ) + self.run.log( + { + "weightedRecall": recall_score( + self.y_test, y_predicted, average="weighted" + ) + } + ) + self.run.log({"f1": f1_score(self.y_test, y_predicted, average="weighted")}) + # Track gold standards and their features + self.run.log( + {"featureMatrix": Table(dataframe=self.feature_matrix._df.toPandas())} + ) + # Log feature missingness + self.run.log( + { + "missingnessRates": self.feature_matrix.calculate_feature_missingness_rate() + } + ) + # Plot marginal contribution of each feature + explanation = self._get_shap_explanation(self.model) + self.log_plot_image_to_wandb( + "Feature Contribution", + shap.plots.bar( + explanation, max_display=len(self.features_list), show=False + ), + ) + self.log_plot_image_to_wandb( + "Beeswarm Plot", + shap.plots.beeswarm( + explanation, max_display=len(self.features_list), show=False + ), + ) + # Plot correlation between feature values and their importance + for feature in self.features_list: self.log_plot_image_to_wandb( - "Beeswarm Plot", - shap.plots.beeswarm( - explanation, max_display=len(self.x_train.columns), show=False + f"Effect of {feature} on the predictions", + shap.plots.scatter( + explanation[:, feature], + show=False, ), ) - # Plot correlation between feature values and their importance - for feature in self.features_list: - self.log_plot_image_to_wandb( - f"Effect of {feature} on the predictions", - shap.plots.scatter( - explanation[:, feature], - show=False, - ), - ) - wandb_termlog("Logged Shapley contributions.") - self.run.finish() - else: - raise ValueError("Something went wrong, couldn't log to W&B.") + wandb_termlog("Logged Shapley contributions.") + self.run.finish() def train( self: LocusToGeneTrainer, wandb_run_name: str, + cross_validate: bool = True, + n_splits: int = 5, + hyperparameter_grid: dict[str, Any] | None = None, ) -> LocusToGeneModel: """Train the Locus to Gene model. + If cross_validation is set to True, we implement the following strategy: + 1. Create held-out test set + 2. Perform cross-validation on training set + 3. Train final model on full training set + 4. Evaluate once on test set + Args: wandb_run_name (str): Name of the W&B run. Unless this is provided, the model will not be logged to W&B. + cross_validate (bool): Whether to run cross-validation. Defaults to True. + n_splits(int): Number of folds the data is splitted in. The model is trained and evaluated `k - 1` times. Defaults to 5. + hyperparameter_grid (dict[str, Any] | None): Hyperparameter grid to sweep over. Defaults to None. Returns: LocusToGeneModel: Fitted model """ - data_df = self.feature_matrix._df.drop("geneId", "studyLocusId").toPandas() + data_df = self.feature_matrix._df.toPandas() + # enforce that data_df is a Pandas DataFrame # Encode labels in `goldStandardSet` to a numeric value data_df[self.label_col] = data_df[self.label_col].map(self.model.label_encoder) - # Ensure all columns are numeric and split - data_df = data_df.apply(pd.to_numeric) - X = data_df[self.features_list].copy() - y = data_df[self.label_col].copy() - self.x_train, self.x_test, self.y_train, self.y_test = train_test_split( - X, y, test_size=0.2, random_state=42 - ) + X = data_df[self.features_list].apply(pd.to_numeric).values + y = data_df[self.label_col].apply(pd.to_numeric).values + gene_trait_groups = ( + data_df["traitFromSourceMappedId"].astype(str) + + "_" + + data_df["geneId"].astype(str) + ) # Group identifier has to be a single string + + # Create hold-out test set separating EFO/Gene pairs between train/test + train_test_split = GroupShuffleSplit(n_splits=1, test_size=0.2, random_state=42) + for train_idx, test_idx in train_test_split.split(X, y, gene_trait_groups): + self.x_train, self.x_test = X[train_idx], X[test_idx] + self.y_train, self.y_test = y[train_idx], y[test_idx] + self.groups_train = gene_trait_groups[train_idx] + + # Cross-validation + if cross_validate: + self.cross_validate( + wandb_run_name=f"{wandb_run_name}-cv", + parameter_grid=hyperparameter_grid, + n_splits=n_splits, + ) - # Train - model = self.fit() + # Train final model on full training set + self.fit() - # Evaluate + # Evaluate once on hold out test set self.log_to_wandb( - wandb_run_name=wandb_run_name, + wandb_run_name=f"{wandb_run_name}-holdout", ) - return model + return self.model - def hyperparameter_tuning( - self: LocusToGeneTrainer, wandb_run_name: str, parameter_grid: dict[str, Any] + def cross_validate( + self: LocusToGeneTrainer, + wandb_run_name: str, + parameter_grid: dict[str, Any] | None = None, + n_splits: int = 5, ) -> None: - """Perform hyperparameter tuning on the model with W&B Sweeps. Metrics for every combination of hyperparameters will be logged to W&B for comparison. + """Log results of cross validation and hyperparameter tuning with W&B Sweeps. Metrics for every combination of hyperparameters will be logged to W&B for comparison. Args: wandb_run_name (str): Name of the W&B run - parameter_grid (dict[str, Any]): Dictionary containing the hyperparameters to sweep over. The keys are the hyperparameter names, and the values are dictionaries containing the values to sweep over. + parameter_grid (dict[str, Any] | None): Dictionary containing the hyperparameters to sweep over. The keys are the hyperparameter names, and the values are dictionaries containing the values to sweep over. + n_splits (int): Number of folds the data is splitted in. The model is trained and evaluated `k - 1` times. Defaults to 5. """ + + def cross_validate_single_fold( + fold_index: int, + sweep_id: str, + sweep_run_name: str, + config: dict[str, Any], + ) -> None: + """Run cross-validation for a single fold. + + Args: + fold_index (int): Index of the fold to run + sweep_id (str): ID of the sweep + sweep_run_name (str): Name of the sweep run + config (dict[str, Any]): Configuration from the sweep + + Raises: + ValueError: If training data is not set + """ + reset_wandb_env() + train_idx, val_idx = cv_splits[fold_index] + + if ( + self.x_train is None + or self.y_train is None + or self.groups_train is None + ): + raise ValueError("Training data not set") + + # Initialize a new run for this fold + os.environ["WANDB_SWEEP_ID"] = sweep_id + run = wandb_init( + project=self.wandb_l2g_project_name, + name=sweep_run_name, + config=config, + group=sweep_run_name, + job_type="fold", + reinit=True, + ) + + x_fold_train, x_fold_val = ( + self.x_train[train_idx], + self.x_train[val_idx], + ) + y_fold_train, y_fold_val = ( + self.y_train[train_idx], + self.y_train[val_idx], + ) + + fold_model = clone(self.model.model) + fold_model.set_params(**config) + fold_model.fit(x_fold_train, y_fold_train) + y_pred_proba = fold_model.predict_proba(x_fold_val)[:, 1] + y_pred = (y_pred_proba >= 0.5).astype(int) + + # Log metrics + metrics = { + "weightedPrecision": precision_score(y_fold_val, y_pred), + "averagePrecision": average_precision_score(y_fold_val, y_pred_proba), + "areaUnderROC": roc_auc_score(y_fold_val, y_pred_proba), + "accuracy": accuracy_score(y_fold_val, y_pred), + "weightedRecall": recall_score(y_fold_val, y_pred, average="weighted"), + "f1": f1_score(y_fold_val, y_pred, average="weighted"), + } + + run.log(metrics) + wandb_termlog(f"Logged metrics for fold {fold_index + 1}.") + run.finish() + + # If no grid is provided, use default ones set in the model + parameter_grid = parameter_grid or { + param: {"values": [value]} + for param, value in self.model.hyperparameters.items() + } sweep_config = { "method": "grid", - "metric": {"name": "roc", "goal": "maximize"}, + "name": wandb_run_name, # Add name to sweep config + "metric": {"name": "areaUnderROC", "goal": "maximize"}, "parameters": parameter_grid, } sweep_id = wandb_sweep(sweep_config, project=self.wandb_l2g_project_name) - wandb_agent(sweep_id, partial(self.train, wandb_run_name=wandb_run_name)) + gkf = GroupKFold(n_splits=n_splits) + cv_splits = list(gkf.split(self.x_train, self.y_train, self.groups_train)) + + def run_all_folds() -> None: + """Run cross-validation for all folds within a sweep.""" + # Initialize the sweep run and get metadata + sweep_run = wandb_init(name=wandb_run_name) + sweep_id = sweep_run.sweep_id or "unknown" + sweep_url = sweep_run.get_sweep_url() + project_url = sweep_run.get_project_url() + sweep_group_url = f"{project_url}/groups/{sweep_id}" + sweep_run.notes = sweep_group_url + sweep_run.save() + config = dict(sweep_run.config) + + # Reset wandb setup to ensure clean state + _setup(_reset=True) + + # Run all folds + for fold_index in range(len(cv_splits)): + cross_validate_single_fold( + fold_index=fold_index, + sweep_id=sweep_id, + sweep_run_name=f"{wandb_run_name}-fold{fold_index+1}", + config=config, + ) + + wandb_termlog(f"Sweep URL: {sweep_url}") + wandb_termlog(f"Sweep Group URL: {sweep_group_url}") + + wandb_agent(sweep_id, run_all_folds)