diff --git a/CHANGELOG.md b/CHANGELOG.md index 38dd3094..3ba8af51 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,7 +41,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * The term `edges` in `metrics` and `adata` is now replaced with `molecules`. * Renaming of variables in per-stage JSON reports. * Changed name of TCRb to TCRVb5 antibody in human-immunology-panel file and bumped to version 0.5.0. -* Renaming of component metrics in adata and +* Renaming of component metrics in adata +* Use MPX graph compatible permutation strategy when calculating Moran's I. ### Fixed diff --git a/poetry.lock b/poetry.lock index ae5985a9..515b1719 100644 --- a/poetry.lock +++ b/poetry.lock @@ -103,25 +103,6 @@ files = [ [package.dependencies] typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.11\""} -[[package]] -name = "attrs" -version = "23.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"}, -] - -[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]"] - [[package]] name = "autograd" version = "1.6.2" @@ -418,40 +399,6 @@ files = [ [package.dependencies] colorama = {version = "*", markers = "platform_system == \"Windows\""} -[[package]] -name = "click-plugins" -version = "1.1.1" -description = "An extension module for click to enable registering CLI commands via setuptools entry-points." -optional = false -python-versions = "*" -files = [ - {file = "click-plugins-1.1.1.tar.gz", hash = "sha256:46ab999744a9d831159c3411bb0c79346d94a444df9a3a3742e9ed63645f264b"}, - {file = "click_plugins-1.1.1-py2.py3-none-any.whl", hash = "sha256:5d262006d3222f5057fd81e1623d4443e41dcda5dc815c06b442aa3c02889fc8"}, -] - -[package.dependencies] -click = ">=4.0" - -[package.extras] -dev = ["coveralls", "pytest (>=3.6)", "pytest-cov", "wheel"] - -[[package]] -name = "cligj" -version = "0.7.2" -description = "Click params for commmand line interfaces to GeoJSON" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, <4" -files = [ - {file = "cligj-0.7.2-py3-none-any.whl", hash = "sha256:c1ca117dbce1fe20a5809dc96f01e1c2840f6dcc939b3ddbb1111bf330ba82df"}, - {file = "cligj-0.7.2.tar.gz", hash = "sha256:a4bc13d623356b373c2c27c53dbd9c68cae5d526270bfa71f6c6fa69669c6b27"}, -] - -[package.dependencies] -click = ">=4.0" - -[package.extras] -test = ["pytest-cov"] - [[package]] name = "colorama" version = "0.4.6" @@ -810,29 +757,6 @@ files = [ {file = "docutils-0.20.1.tar.gz", hash = "sha256:f08a4e276c3a1583a86dce3e34aba3fe04d02bba2dd51ed16106244e8a923e3b"}, ] -[[package]] -name = "esda" -version = "2.5.1" -description = "Exploratory Spatial Data Analysis in PySAL" -optional = false -python-versions = ">=3.8" -files = [ - {file = "esda-2.5.1-py3-none-any.whl", hash = "sha256:6fdbce49e8ef39feeca7ab0f92cd1d8f1ddda527425c42e61d0e8199b70bc8e8"}, - {file = "esda-2.5.1.tar.gz", hash = "sha256:b1f0ac023b3a55dbdbad34a98eae6af2c7d2b3cc7a14ea884dfef51819c04c28"}, -] - -[package.dependencies] -libpysal = "*" -pandas = ">1.4" -scikit-learn = ">=1.0" -scipy = ">=1.9" - -[package.extras] -dev = ["pre-commit"] -docs = ["nbsphinx", "numpydoc", "pandoc", "sphinx", "sphinx-bootstrap-theme", "sphinxcontrib-bibtex"] -notebooks = ["folium", "matplotlib", "matplotlib-scalebar", "seaborn", "watermark"] -tests = ["codecov", "coverage", "geopandas", "pytest", "pytest-cov", "pytest-xdist"] - [[package]] name = "exceptiongroup" version = "1.2.0" @@ -920,54 +844,6 @@ docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1 testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)"] typing = ["typing-extensions (>=4.8)"] -[[package]] -name = "fiona" -version = "1.9.5" -description = "Fiona reads and writes spatial data files" -optional = false -python-versions = ">=3.7" -files = [ - {file = "fiona-1.9.5-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:5f40a40529ecfca5294260316cf987a0420c77a2f0cf0849f529d1afbccd093e"}, - {file = "fiona-1.9.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:374efe749143ecb5cfdd79b585d83917d2bf8ecfbfc6953c819586b336ce9c63"}, - {file = "fiona-1.9.5-cp310-cp310-manylinux2014_x86_64.whl", hash = "sha256:35dae4b0308eb44617cdc4461ceb91f891d944fdebbcba5479efe524ec5db8de"}, - {file = "fiona-1.9.5-cp310-cp310-win_amd64.whl", hash = "sha256:5b4c6a3df53bee8f85bb46685562b21b43346be1fe96419f18f70fa1ab8c561c"}, - {file = "fiona-1.9.5-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:6ad04c1877b9fd742871b11965606c6a52f40706f56a48d66a87cc3073943828"}, - {file = "fiona-1.9.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9fb9a24a8046c724787719e20557141b33049466145fc3e665764ac7caf5748c"}, - {file = "fiona-1.9.5-cp311-cp311-manylinux2014_x86_64.whl", hash = "sha256:d722d7f01a66f4ab6cd08d156df3fdb92f0669cf5f8708ddcb209352f416f241"}, - {file = "fiona-1.9.5-cp311-cp311-win_amd64.whl", hash = "sha256:7ede8ddc798f3d447536080c6db9a5fb73733ad8bdb190cb65eed4e289dd4c50"}, - {file = "fiona-1.9.5-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:8b098054a27c12afac4f819f98cb4d4bf2db9853f70b0c588d7d97d26e128c39"}, - {file = "fiona-1.9.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6d9f29e9bcbb33232ff7fa98b4a3c2234db910c1dc6c4147fc36c0b8b930f2e0"}, - {file = "fiona-1.9.5-cp312-cp312-manylinux2014_x86_64.whl", hash = "sha256:f1af08da4ecea5036cb81c9131946be4404245d1b434b5b24fd3871a1d4030d9"}, - {file = "fiona-1.9.5-cp312-cp312-win_amd64.whl", hash = "sha256:c521e1135c78dec0d7774303e5a1b4c62e0efb0e602bb8f167550ef95e0a2691"}, - {file = "fiona-1.9.5-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:fce4b1dd98810cabccdaa1828430c7402d283295c2ae31bea4f34188ea9e88d7"}, - {file = "fiona-1.9.5-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:3ea04ec2d8c57b5f81a31200fb352cb3242aa106fc3e328963f30ffbdf0ff7c8"}, - {file = "fiona-1.9.5-cp37-cp37m-win_amd64.whl", hash = "sha256:4877cc745d9e82b12b3eafce3719db75759c27bd8a695521202135b36b58c2e7"}, - {file = "fiona-1.9.5-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:ac2c250f509ec19fad7959d75b531984776517ef3c1222d1cc5b4f962825880b"}, - {file = "fiona-1.9.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4df21906235928faad856c288cfea0298e9647f09c9a69a230535cbc8eadfa21"}, - {file = "fiona-1.9.5-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:81d502369493687746cb8d3cd77e5ada4447fb71d513721c9a1826e4fb32b23a"}, - {file = "fiona-1.9.5-cp38-cp38-win_amd64.whl", hash = "sha256:ce3b29230ef70947ead4e701f3f82be81082b7f37fd4899009b1445cc8fc276a"}, - {file = "fiona-1.9.5-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:8b53ce8de773fcd5e2e102e833c8c58479edd8796a522f3d83ef9e08b62bfeea"}, - {file = "fiona-1.9.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:bd2355e859a1cd24a3e485c6dc5003129f27a2051629def70036535ffa7e16a4"}, - {file = "fiona-1.9.5-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:9a2da52f865db1aff0eaf41cdd4c87a7c079b3996514e8e7a1ca38457309e825"}, - {file = "fiona-1.9.5-cp39-cp39-win_amd64.whl", hash = "sha256:cfef6db5b779d463298b1113b50daa6c5b55f26f834dc9e37752116fa17277c1"}, - {file = "fiona-1.9.5.tar.gz", hash = "sha256:99e2604332caa7692855c2ae6ed91e1fffdf9b59449aa8032dd18e070e59a2f7"}, -] - -[package.dependencies] -attrs = ">=19.2.0" -certifi = "*" -click = ">=8.0,<9.0" -click-plugins = ">=1.0" -cligj = ">=0.5" -setuptools = "*" -six = "*" - -[package.extras] -all = ["Fiona[calc,s3,test]"] -calc = ["shapely"] -s3 = ["boto3 (>=1.3.1)"] -test = ["Fiona[s3]", "pytest (>=7)", "pytest-cov", "pytz"] - [[package]] name = "fonttools" version = "4.49.0" @@ -1137,24 +1013,6 @@ docs = ["POT", "Pyro4", "Pyro4 (>=4.27)", "annoy", "matplotlib", "memory-profile test = ["POT", "mock", "pytest", "pytest-cov", "testfixtures", "visdom (>=0.1.8,!=0.1.8.7)"] test-win = ["POT", "mock", "pytest", "pytest-cov", "testfixtures"] -[[package]] -name = "geopandas" -version = "0.14.3" -description = "Geographic pandas extensions" -optional = false -python-versions = ">=3.9" -files = [ - {file = "geopandas-0.14.3-py3-none-any.whl", hash = "sha256:41b31ad39e21bc9e8c4254f78f8dc4ce3d33d144e22e630a00bb336c83160204"}, - {file = "geopandas-0.14.3.tar.gz", hash = "sha256:748af035d4a068a4ae00cab384acb61d387685c833b0022e0729aa45216b23ac"}, -] - -[package.dependencies] -fiona = ">=1.8.21" -packaging = "*" -pandas = ">=1.4.0" -pyproj = ">=3.3.0" -shapely = ">=1.8.0" - [[package]] name = "graspologic" version = "3.3.0" @@ -1623,34 +1481,6 @@ files = [ {file = "kiwisolver-1.4.5.tar.gz", hash = "sha256:e57e563a57fb22a142da34f38acc2fc1a5c864bc29ca1517a88abc963e60d6ec"}, ] -[[package]] -name = "libpysal" -version = "4.9.2" -description = "Core components of PySAL - A library of spatial analysis functions" -optional = false -python-versions = ">=3.10" -files = [ - {file = "libpysal-4.9.2-py3-none-any.whl", hash = "sha256:92533534761e230d54c7ac561056a311a10a85f82be656baeb13cd73c0d50c25"}, - {file = "libpysal-4.9.2.tar.gz", hash = "sha256:621f9fbbd1394193adfc590f1096ab959cee83bade388987c075e44326b5a3f1"}, -] - -[package.dependencies] -beautifulsoup4 = ">=4.10" -geopandas = ">=0.10.0" -numpy = ">=1.22" -packaging = ">=22" -pandas = ">=1.4" -platformdirs = ">=2.0.2" -requests = ">=2.27" -scipy = ">=1.8" -shapely = ">=2.0.1" - -[package.extras] -dev = ["black", "pre-commit", "watermark"] -docs = ["mkdocs-jupyter", "myst-parser", "nbsphinx", "numpydoc", "pandoc", "sphinx", "sphinx-bootstrap-theme", "sphinxcontrib-bibtex"] -plus = ["joblib (>=1.2)", "networkx (>=2.7)", "numba (>=0.55)", "pyarrow (>=7.0)", "scikit-learn (>=1.1)", "sqlalchemy (>=2.0)", "xarray (>=2022.3)", "zstd"] -tests = ["codecov", "geodatasets (>=2023.3.0)", "matplotlib (>=3.6)", "pytest", "pytest-cov", "pytest-mpl", "pytest-xdist"] - [[package]] name = "llvmlite" version = "0.42.0" @@ -2905,45 +2735,6 @@ files = [ [package.extras] diagrams = ["jinja2", "railroad-diagrams"] -[[package]] -name = "pyproj" -version = "3.6.1" -description = "Python interface to PROJ (cartographic projections and coordinate transformations library)" -optional = false -python-versions = ">=3.9" -files = [ - {file = "pyproj-3.6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ab7aa4d9ff3c3acf60d4b285ccec134167a948df02347585fdd934ebad8811b4"}, - {file = "pyproj-3.6.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4bc0472302919e59114aa140fd7213c2370d848a7249d09704f10f5b062031fe"}, - {file = "pyproj-3.6.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5279586013b8d6582e22b6f9e30c49796966770389a9d5b85e25a4223286cd3f"}, - {file = "pyproj-3.6.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80fafd1f3eb421694857f254a9bdbacd1eb22fc6c24ca74b136679f376f97d35"}, - {file = "pyproj-3.6.1-cp310-cp310-win32.whl", hash = "sha256:c41e80ddee130450dcb8829af7118f1ab69eaf8169c4bf0ee8d52b72f098dc2f"}, - {file = "pyproj-3.6.1-cp310-cp310-win_amd64.whl", hash = "sha256:db3aedd458e7f7f21d8176f0a1d924f1ae06d725228302b872885a1c34f3119e"}, - {file = "pyproj-3.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ebfbdbd0936e178091309f6cd4fcb4decd9eab12aa513cdd9add89efa3ec2882"}, - {file = "pyproj-3.6.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:447db19c7efad70ff161e5e46a54ab9cc2399acebb656b6ccf63e4bc4a04b97a"}, - {file = "pyproj-3.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e7e13c40183884ec7f94eb8e0f622f08f1d5716150b8d7a134de48c6110fee85"}, - {file = "pyproj-3.6.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65ad699e0c830e2b8565afe42bd58cc972b47d829b2e0e48ad9638386d994915"}, - {file = "pyproj-3.6.1-cp311-cp311-win32.whl", hash = "sha256:8b8acc31fb8702c54625f4d5a2a6543557bec3c28a0ef638778b7ab1d1772132"}, - {file = "pyproj-3.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:38a3361941eb72b82bd9a18f60c78b0df8408416f9340521df442cebfc4306e2"}, - {file = "pyproj-3.6.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:1e9fbaf920f0f9b4ee62aab832be3ae3968f33f24e2e3f7fbb8c6728ef1d9746"}, - {file = "pyproj-3.6.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6d227a865356f225591b6732430b1d1781e946893789a609bb34f59d09b8b0f8"}, - {file = "pyproj-3.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:83039e5ae04e5afc974f7d25ee0870a80a6bd6b7957c3aca5613ccbe0d3e72bf"}, - {file = "pyproj-3.6.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fffb059ba3bced6f6725961ba758649261d85ed6ce670d3e3b0a26e81cf1aa8d"}, - {file = "pyproj-3.6.1-cp312-cp312-win32.whl", hash = "sha256:2d6ff73cc6dbbce3766b6c0bce70ce070193105d8de17aa2470009463682a8eb"}, - {file = "pyproj-3.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:7a27151ddad8e1439ba70c9b4b2b617b290c39395fa9ddb7411ebb0eb86d6fb0"}, - {file = "pyproj-3.6.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4ba1f9b03d04d8cab24d6375609070580a26ce76eaed54631f03bab00a9c737b"}, - {file = "pyproj-3.6.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:18faa54a3ca475bfe6255156f2f2874e9a1c8917b0004eee9f664b86ccc513d3"}, - {file = "pyproj-3.6.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fd43bd9a9b9239805f406fd82ba6b106bf4838d9ef37c167d3ed70383943ade1"}, - {file = "pyproj-3.6.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50100b2726a3ca946906cbaa789dd0749f213abf0cbb877e6de72ca7aa50e1ae"}, - {file = "pyproj-3.6.1-cp39-cp39-win32.whl", hash = "sha256:9274880263256f6292ff644ca92c46d96aa7e57a75c6df3f11d636ce845a1877"}, - {file = "pyproj-3.6.1-cp39-cp39-win_amd64.whl", hash = "sha256:36b64c2cb6ea1cc091f329c5bd34f9c01bb5da8c8e4492c709bda6a09f96808f"}, - {file = "pyproj-3.6.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:fd93c1a0c6c4aedc77c0fe275a9f2aba4d59b8acf88cebfc19fe3c430cfabf4f"}, - {file = "pyproj-3.6.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6420ea8e7d2a88cb148b124429fba8cd2e0fae700a2d96eab7083c0928a85110"}, - {file = "pyproj-3.6.1.tar.gz", hash = "sha256:44aa7c704c2b7d8fb3d483bbf75af6cb2350d30a63b144279a09b75fead501bf"}, -] - -[package.dependencies] -certifi = "*" - [[package]] name = "pyproject-api" version = "1.6.1" @@ -3392,24 +3183,24 @@ python-versions = ">=3.6" files = [ {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b42169467c42b692c19cf539c38d4602069d8c1505e97b86387fcf7afb766e1d"}, {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-macosx_13_0_arm64.whl", hash = "sha256:07238db9cbdf8fc1e9de2489a4f68474e70dffcb32232db7c08fa61ca0c7c462"}, - {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:d92f81886165cb14d7b067ef37e142256f1c6a90a65cd156b063a43da1708cfd"}, {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:fff3573c2db359f091e1589c3d7c5fc2f86f5bdb6f24252c2d8e539d4e45f412"}, + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-manylinux_2_24_aarch64.whl", hash = "sha256:aa2267c6a303eb483de8d02db2871afb5c5fc15618d894300b88958f729ad74f"}, {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:840f0c7f194986a63d2c2465ca63af8ccbbc90ab1c6001b1978f05119b5e7334"}, {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:024cfe1fc7c7f4e1aff4a81e718109e13409767e4f871443cbff3dba3578203d"}, {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-win32.whl", hash = "sha256:c69212f63169ec1cfc9bb44723bf2917cbbd8f6191a00ef3410f5a7fe300722d"}, {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-win_amd64.whl", hash = "sha256:cabddb8d8ead485e255fe80429f833172b4cadf99274db39abc080e068cbcc31"}, {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:bef08cd86169d9eafb3ccb0a39edb11d8e25f3dae2b28f5c52fd997521133069"}, {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:b16420e621d26fdfa949a8b4b47ade8810c56002f5389970db4ddda51dbff248"}, - {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:b5edda50e5e9e15e54a6a8a0070302b00c518a9d32accc2346ad6c984aacd279"}, {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:25c515e350e5b739842fc3228d662413ef28f295791af5e5110b543cf0b57d9b"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-manylinux_2_24_aarch64.whl", hash = "sha256:1707814f0d9791df063f8c19bb51b0d1278b8e9a2353abbb676c2f685dee6afe"}, {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:46d378daaac94f454b3a0e3d8d78cafd78a026b1d71443f4966c696b48a6d899"}, {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:09b055c05697b38ecacb7ac50bdab2240bfca1a0c4872b0fd309bb07dc9aa3a9"}, {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-win32.whl", hash = "sha256:53a300ed9cea38cf5a2a9b069058137c2ca1ce658a874b79baceb8f892f915a7"}, {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-win_amd64.whl", hash = "sha256:c2a72e9109ea74e511e29032f3b670835f8a59bbdc9ce692c5b4ed91ccf1eedb"}, {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:ebc06178e8821efc9692ea7544aa5644217358490145629914d8020042c24aa1"}, {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-macosx_13_0_arm64.whl", hash = "sha256:edaef1c1200c4b4cb914583150dcaa3bc30e592e907c01117c08b13a07255ec2"}, - {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:7048c338b6c86627afb27faecf418768acb6331fc24cfa56c93e8c9780f815fa"}, {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d176b57452ab5b7028ac47e7b3cf644bcfdc8cacfecf7e71759f7f51a59e5c92"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-manylinux_2_24_aarch64.whl", hash = "sha256:1dc67314e7e1086c9fdf2680b7b6c2be1c0d8e3a8279f2e993ca2a7545fecf62"}, {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:3213ece08ea033eb159ac52ae052a4899b56ecc124bb80020d9bbceeb50258e9"}, {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:aab7fd643f71d7946f2ee58cc88c9b7bfc97debd71dcc93e03e2d174628e7e2d"}, {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-win32.whl", hash = "sha256:5c365d91c88390c8d0a8545df0b5857172824b1c604e867161e6b3d59a827eaa"}, @@ -3417,7 +3208,7 @@ files = [ {file = "ruamel.yaml.clib-0.2.8-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a5aa27bad2bb83670b71683aae140a1f52b0857a2deff56ad3f6c13a017a26ed"}, {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c58ecd827313af6864893e7af0a3bb85fd529f862b6adbefe14643947cfe2942"}, {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-macosx_12_0_arm64.whl", hash = "sha256:f481f16baec5290e45aebdc2a5168ebc6d35189ae6fea7a58787613a25f6e875"}, - {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:3fcc54cb0c8b811ff66082de1680b4b14cf8a81dce0d4fbf665c2265a81e07a1"}, + {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-manylinux_2_24_aarch64.whl", hash = "sha256:77159f5d5b5c14f7c34073862a6b7d34944075d9f93e681638f6d753606c6ce6"}, {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:7f67a1ee819dc4562d444bbafb135832b0b909f81cc90f7aa00260968c9ca1b3"}, {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:4ecbf9c3e19f9562c7fdd462e8d18dd902a47ca046a2e64dba80699f0b6c09b7"}, {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:87ea5ff66d8064301a154b3933ae406b0863402a799b16e4a1d24d9fbbcbe0d3"}, @@ -3425,7 +3216,7 @@ files = [ {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-win_amd64.whl", hash = "sha256:3f215c5daf6a9d7bbed4a0a4f760f3113b10e82ff4c5c44bec20a68c8014f675"}, {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1b617618914cb00bf5c34d4357c37aa15183fa229b24767259657746c9077615"}, {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:a6a9ffd280b71ad062eae53ac1659ad86a17f59a0fdc7699fd9be40525153337"}, - {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:665f58bfd29b167039f714c6998178d27ccd83984084c286110ef26b230f259f"}, + {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-manylinux_2_24_aarch64.whl", hash = "sha256:305889baa4043a09e5b76f8e2a51d4ffba44259f6b4c72dec8ca56207d9c6fe1"}, {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:700e4ebb569e59e16a976857c8798aee258dceac7c7d6b50cab63e080058df91"}, {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:e2b4c44b60eadec492926a7270abb100ef9f72798e18743939bdbf037aab8c28"}, {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e79e5db08739731b0ce4850bed599235d601701d5694c36570a99a0c5ca41a9d"}, @@ -3433,7 +3224,7 @@ files = [ {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-win_amd64.whl", hash = "sha256:56f4252222c067b4ce51ae12cbac231bce32aee1d33fbfc9d17e5b8d6966c312"}, {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:03d1162b6d1df1caa3a4bd27aa51ce17c9afc2046c31b0ad60a0a96ec22f8001"}, {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:bba64af9fa9cebe325a62fa398760f5c7206b215201b0ec825005f1b18b9bccf"}, - {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:9eb5dee2772b0f704ca2e45b1713e4e5198c18f515b52743576d196348f374d3"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-manylinux_2_24_aarch64.whl", hash = "sha256:a1a45e0bb052edf6a1d3a93baef85319733a888363938e1fc9924cb00c8df24c"}, {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:da09ad1c359a728e112d60116f626cc9f29730ff3e0e7db72b9a2dbc2e4beed5"}, {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:184565012b60405d93838167f425713180b949e9d8dd0bbc7b49f074407c5a8b"}, {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a75879bacf2c987c003368cf14bed0ffe99e8e85acfa6c0bfffc21a090f16880"}, @@ -3662,63 +3453,6 @@ docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.2)", "pip (>=19.1)", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff (>=0.2.1)", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.2)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] -[[package]] -name = "shapely" -version = "2.0.3" -description = "Manipulation and analysis of geometric objects" -optional = false -python-versions = ">=3.7" -files = [ - {file = "shapely-2.0.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:af7e9abe180b189431b0f490638281b43b84a33a960620e6b2e8d3e3458b61a1"}, - {file = "shapely-2.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:98040462b36ced9671e266b95c326b97f41290d9d17504a1ee4dc313a7667b9c"}, - {file = "shapely-2.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:71eb736ef2843f23473c6e37f6180f90f0a35d740ab284321548edf4e55d9a52"}, - {file = "shapely-2.0.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:881eb9dbbb4a6419667e91fcb20313bfc1e67f53dbb392c6840ff04793571ed1"}, - {file = "shapely-2.0.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f10d2ccf0554fc0e39fad5886c839e47e207f99fdf09547bc687a2330efda35b"}, - {file = "shapely-2.0.3-cp310-cp310-win32.whl", hash = "sha256:6dfdc077a6fcaf74d3eab23a1ace5abc50c8bce56ac7747d25eab582c5a2990e"}, - {file = "shapely-2.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:64c5013dacd2d81b3bb12672098a0b2795c1bf8190cfc2980e380f5ef9d9e4d9"}, - {file = "shapely-2.0.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:56cee3e4e8159d6f2ce32e421445b8e23154fd02a0ac271d6a6c0b266a8e3cce"}, - {file = "shapely-2.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:619232c8276fded09527d2a9fd91a7885ff95c0ff9ecd5e3cb1e34fbb676e2ae"}, - {file = "shapely-2.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b2a7d256db6f5b4b407dc0c98dd1b2fcf1c9c5814af9416e5498d0a2e4307a4b"}, - {file = "shapely-2.0.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e45f0c8cd4583647db3216d965d49363e6548c300c23fd7e57ce17a03f824034"}, - {file = "shapely-2.0.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13cb37d3826972a82748a450328fe02a931dcaed10e69a4d83cc20ba021bc85f"}, - {file = "shapely-2.0.3-cp311-cp311-win32.whl", hash = "sha256:9302d7011e3e376d25acd30d2d9e70d315d93f03cc748784af19b00988fc30b1"}, - {file = "shapely-2.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:6b464f2666b13902835f201f50e835f2f153f37741db88f68c7f3b932d3505fa"}, - {file = "shapely-2.0.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:e86e7cb8e331a4850e0c2a8b2d66dc08d7a7b301b8d1d34a13060e3a5b4b3b55"}, - {file = "shapely-2.0.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c91981c99ade980fc49e41a544629751a0ccd769f39794ae913e53b07b2f78b9"}, - {file = "shapely-2.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bd45d456983dc60a42c4db437496d3f08a4201fbf662b69779f535eb969660af"}, - {file = "shapely-2.0.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:882fb1ffc7577e88c1194f4f1757e277dc484ba096a3b94844319873d14b0f2d"}, - {file = "shapely-2.0.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b9f2d93bff2ea52fa93245798cddb479766a18510ea9b93a4fb9755c79474889"}, - {file = "shapely-2.0.3-cp312-cp312-win32.whl", hash = "sha256:99abad1fd1303b35d991703432c9481e3242b7b3a393c186cfb02373bf604004"}, - {file = "shapely-2.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:6f555fe3304a1f40398977789bc4fe3c28a11173196df9ece1e15c5bc75a48db"}, - {file = "shapely-2.0.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a983cc418c1fa160b7d797cfef0e0c9f8c6d5871e83eae2c5793fce6a837fad9"}, - {file = "shapely-2.0.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18bddb8c327f392189a8d5d6b9a858945722d0bb95ccbd6a077b8e8fc4c7890d"}, - {file = "shapely-2.0.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:442f4dcf1eb58c5a4e3428d88e988ae153f97ab69a9f24e07bf4af8038536325"}, - {file = "shapely-2.0.3-cp37-cp37m-win32.whl", hash = "sha256:31a40b6e3ab00a4fd3a1d44efb2482278642572b8e0451abdc8e0634b787173e"}, - {file = "shapely-2.0.3-cp37-cp37m-win_amd64.whl", hash = "sha256:59b16976c2473fec85ce65cc9239bef97d4205ab3acead4e6cdcc72aee535679"}, - {file = "shapely-2.0.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:705efbce1950a31a55b1daa9c6ae1c34f1296de71ca8427974ec2f27d57554e3"}, - {file = "shapely-2.0.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:601c5c0058a6192df704cb889439f64994708563f57f99574798721e9777a44b"}, - {file = "shapely-2.0.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f24ecbb90a45c962b3b60d8d9a387272ed50dc010bfe605f1d16dfc94772d8a1"}, - {file = "shapely-2.0.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8c2a2989222c6062f7a0656e16276c01bb308bc7e5d999e54bf4e294ce62e76"}, - {file = "shapely-2.0.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42bceb9bceb3710a774ce04908fda0f28b291323da2688f928b3f213373b5aee"}, - {file = "shapely-2.0.3-cp38-cp38-win32.whl", hash = "sha256:54d925c9a311e4d109ec25f6a54a8bd92cc03481a34ae1a6a92c1fe6729b7e01"}, - {file = "shapely-2.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:300d203b480a4589adefff4c4af0b13919cd6d760ba3cbb1e56275210f96f654"}, - {file = "shapely-2.0.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:083d026e97b6c1f4a9bd2a9171c7692461092ed5375218170d91705550eecfd5"}, - {file = "shapely-2.0.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:27b6e1910094d93e9627f2664121e0e35613262fc037051680a08270f6058daf"}, - {file = "shapely-2.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:71b2de56a9e8c0e5920ae5ddb23b923490557ac50cb0b7fa752761bf4851acde"}, - {file = "shapely-2.0.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d279e56bbb68d218d63f3efc80c819cedcceef0e64efbf058a1df89dc57201b"}, - {file = "shapely-2.0.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88566d01a30f0453f7d038db46bc83ce125e38e47c5f6bfd4c9c287010e9bf74"}, - {file = "shapely-2.0.3-cp39-cp39-win32.whl", hash = "sha256:58afbba12c42c6ed44c4270bc0e22f3dadff5656d711b0ad335c315e02d04707"}, - {file = "shapely-2.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:5026b30433a70911979d390009261b8c4021ff87c7c3cbd825e62bb2ffa181bc"}, - {file = "shapely-2.0.3.tar.gz", hash = "sha256:4d65d0aa7910af71efa72fd6447e02a8e5dd44da81a983de9d736d6e6ccbe674"}, -] - -[package.dependencies] -numpy = ">=1.14,<2" - -[package.extras] -docs = ["matplotlib", "numpydoc (==1.1.*)", "sphinx", "sphinx-book-theme", "sphinx-remove-toctrees"] -test = ["pytest", "pytest-cov"] - [[package]] name = "six" version = "1.16.0" @@ -4563,4 +4297,4 @@ files = [ [metadata] lock-version = "2.0" python-versions = ">=3.10,<3.12" -content-hash = "75ca943bb7fe811d8e0cff717d81c81f34189097ff7dc771562d9420235c7e74" +content-hash = "58a04a367ecd21c757e71bc26fe247571e0314f6419877b9eb3502fe300eb8b5" diff --git a/pyproject.toml b/pyproject.toml index 6aa6caec..704b8115 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,8 +36,6 @@ yappi = "*" pandas = "^2.0.0" numpy = "<1.24.0" annoy = "<=1.17.0" -esda = "*" -libpysal = ">=4.9.2" xopen = "*" anndata = ">=0.8.0" numba = ">=0.56.4" diff --git a/src/pixelator/analysis/__init__.py b/src/pixelator/analysis/__init__.py index bd62f901..ad8fc9a8 100644 --- a/src/pixelator/analysis/__init__.py +++ b/src/pixelator/analysis/__init__.py @@ -104,7 +104,7 @@ def analyse_pixels( edgelist=edgelist, use_full_bipartite=use_full_bipartite, normalization=polarization_normalization, - permutations=polarization_n_permutations, + n_permutations=polarization_n_permutations, ) dataset.polarization = scores @@ -137,7 +137,9 @@ def analyse_pixels( ) } # save dataset - dataset.save(Path(output) / f"{output_prefix}.analysis.dataset.pxl") + dataset.save( + Path(output) / f"{output_prefix}.analysis.dataset.pxl", force_overwrite=True + ) polarization_report = PolarizationReport() colocalization_report = ColocalizationReport() diff --git a/src/pixelator/analysis/colocalization/__init__.py b/src/pixelator/analysis/colocalization/__init__.py index 893b0ec1..5c39127e 100644 --- a/src/pixelator/analysis/colocalization/__init__.py +++ b/src/pixelator/analysis/colocalization/__init__.py @@ -16,7 +16,6 @@ estimate_observation_statistics, permutation_analysis_results, ) -from pixelator.analysis.colocalization.permute import permutations from pixelator.analysis.colocalization.prepare import ( filter_by_region_counts, filter_by_unique_values, @@ -31,6 +30,7 @@ MarkerColocalizationResults, TransformationTypes, ) +from pixelator.analysis.permute import permutations from pixelator.graph.utils import Graph from pixelator.statistics import correct_pvalues, log1p_transformation diff --git a/src/pixelator/analysis/colocalization/estimate.py b/src/pixelator/analysis/colocalization/estimate.py index 38a62e92..3776f512 100644 --- a/src/pixelator/analysis/colocalization/estimate.py +++ b/src/pixelator/analysis/colocalization/estimate.py @@ -12,8 +12,8 @@ from pixelator.analysis.colocalization.types import ( CoLocalizationFunction, - RegionByCountsDataFrame, ) +from pixelator.analysis.types import RegionByCountsDataFrame logger = logging.getLogger(__name__) diff --git a/src/pixelator/analysis/colocalization/prepare.py b/src/pixelator/analysis/colocalization/prepare.py index 4c0e77a7..8936bc35 100644 --- a/src/pixelator/analysis/colocalization/prepare.py +++ b/src/pixelator/analysis/colocalization/prepare.py @@ -7,7 +7,7 @@ import pandas as pd -from pixelator.analysis.colocalization.types import RegionByCountsDataFrame +from pixelator.analysis.types import RegionByCountsDataFrame from pixelator.graph.utils import Graph, create_node_markers_counts diff --git a/src/pixelator/analysis/colocalization/statistics.py b/src/pixelator/analysis/colocalization/statistics.py index 6f92eafa..a7d714e0 100644 --- a/src/pixelator/analysis/colocalization/statistics.py +++ b/src/pixelator/analysis/colocalization/statistics.py @@ -12,8 +12,8 @@ from pixelator.analysis.colocalization.types import ( CoLocalizationFunction, MarkerColocalizationResults, - RegionByCountsDataFrame, ) +from pixelator.analysis.types import RegionByCountsDataFrame def _wide_correlation_matrix_to_long_correlation_results( diff --git a/src/pixelator/analysis/colocalization/types.py b/src/pixelator/analysis/colocalization/types.py index 9bf24237..db64cf7a 100644 --- a/src/pixelator/analysis/colocalization/types.py +++ b/src/pixelator/analysis/colocalization/types.py @@ -8,7 +8,8 @@ import pandas as pd -RegionByCountsDataFrame = pd.DataFrame +from pixelator.analysis.types import RegionByCountsDataFrame + MarkerColocalizationResults = pd.DataFrame TransformationTypes = Literal["raw", "log1p"] diff --git a/src/pixelator/analysis/colocalization/permute.py b/src/pixelator/analysis/permute.py similarity index 98% rename from src/pixelator/analysis/colocalization/permute.py rename to src/pixelator/analysis/permute.py index 770f1a38..5f7d98b0 100644 --- a/src/pixelator/analysis/colocalization/permute.py +++ b/src/pixelator/analysis/permute.py @@ -10,7 +10,7 @@ from numpy.random import Generator as RandomNumberGenerator from numpy.random import default_rng -from pixelator.analysis.colocalization.types import ( +from pixelator.analysis.types import ( RegionByCountsDataFrame, ) diff --git a/src/pixelator/analysis/polarization/__init__.py b/src/pixelator/analysis/polarization/__init__.py index 2c69858e..025f2b58 100644 --- a/src/pixelator/analysis/polarization/__init__.py +++ b/src/pixelator/analysis/polarization/__init__.py @@ -1,93 +1,97 @@ """Copyright © 2023 Pixelgen Technologies AB.""" import logging -import warnings -from concurrent import futures -from typing import get_args +import time +from functools import partial +from typing import Iterable, get_args -import esda.moran import numpy as np import pandas as pd +from scipy.sparse import csr_matrix +from scipy.stats import norm +from pixelator.analysis.permute import permutations from pixelator.analysis.polarization.types import PolarizationNormalizationTypes -from pixelator.graph.utils import Graph, create_node_markers_counts -from pixelator.pixeldataset import ( - MIN_VERTICES_REQUIRED, -) -from pixelator.statistics import ( - clr_transformation, - correct_pvalues, -) +from pixelator.graph.utils import Graph +from pixelator.pixeldataset import MIN_VERTICES_REQUIRED +from pixelator.statistics import clr_transformation, correct_pvalues +from pixelator.utils import get_pool_executor -with warnings.catch_warnings(): - warnings.filterwarnings("ignore", module="libpysal") - from libpysal.weights import WSP +logger = logging.getLogger(__name__) -logger = logging.getLogger(__name__) +def _compute_for_marker( + marker, marker_count_matrix, weight_matrix, normalization_factor +): + try: + x_centered = np.array( + marker_count_matrix[marker] - marker_count_matrix[marker].mean() + ) + x_centered_squared_sum = (x_centered * x_centered).sum() + element_wise_weighted_sum = (x_centered @ weight_matrix @ x_centered).sum() + r = normalization_factor * (element_wise_weighted_sum / x_centered_squared_sum) + return r + except ValueError as e: + logger.warning("Error computing Moran's I for marker %s: %s", marker, e) + return np.nan -def morans_autocorr( - w: np.ndarray, y: np.ndarray, permutations: int -) -> esda.moran.Moran: - """Calculate Moran's I statistics. - - Computes the Moran's I autocorrelation statistics for the given spatial - weights (`w`) and target variable (`y`). The target variable can be the counts - of a specific antibody so the Moran's I value could indicate if the - antibody has a localized spatial pattern. The function returns an object - with the Moran's statistics: I, p_rand and z_rand (as well as p_sim and z_sim - if `permutations` > 0). - :param w: the weights matrix (connectivity matrix) - :param y: the counts vector - :param permutations: the number of permutations for simulated Z-score (z_sim) - estimation (if permutations > 0) - :returns: the Moran's statistics - :rtype: esda.moran.Moran - """ - # Default Moran's transformation is row-standardized "r". - # https://github.com/pysal/esda/blob/main/esda/moran.py - return esda.moran.Moran(y, w, permutations=permutations) +def _compute_morans_i( + marker: str, + marker_count_matrix: pd.DataFrame, + marker_count_matrix_permuted: Iterable[pd.DataFrame], + weight_matrix: csr_matrix, + normalization_factor: float, +): + r = _compute_for_marker( + marker, marker_count_matrix, weight_matrix, normalization_factor + ) + perm_rs = np.fromiter( + ( + _compute_for_marker(marker, perm, weight_matrix, normalization_factor) + for perm in marker_count_matrix_permuted + ), + dtype=np.float64, + ) + perm_rs_mean = np.nanmean(perm_rs) + perm_rs_std_dev = np.nanstd(perm_rs) + perm_rs_z_score = (r - perm_rs_mean) / perm_rs_std_dev + p_value = norm.sf(np.abs(perm_rs_z_score)) + return marker, r, perm_rs_z_score, perm_rs_mean, perm_rs_std_dev, p_value -def polarization_scores_component( +def polarization_scores_component_graph( graph: Graph, component_id: str, normalization: PolarizationNormalizationTypes = "clr", - permutations: int = 0, + n_permutations: int = 50, + random_seed: int | None = None, ) -> pd.DataFrame: - """Calculate Moran's I statistics for a component. + """Calculate Moran's I statistics for a component graph. Computes polarization statistics for all antibodies in the `graph` given as input (a single connected component). The statistics are computed using Moran's I autocorrelation to measure how clustered/localized the spatial - patterns of the antibody is in the graph. Spatial weights (`w`) are derived - directly from the graph. The statistics contain the I value, the p-value, - the adjusted p-value and the z-score under the randomization assumption. + patterns of the antibody is in the graph. + + The statistics contain the I value, as well as a p-value, the adjusted p-value + and the z-score.The later are based on permuting the input graph to estimate a + null-hypothesis for the Moran's I statistic. + The function returns a pd.DataFrame with the following columns: - morans_i, morans_p_value, morans_z, marker, component (morans_p_value_sim - and morans_z_sim if `permutations` > 0) + morans_i, morans_p_value, morans_z, marker, component + :param graph: a graph (it must be a single connected component) :param component_id: the id of the component :param normalization: the normalization method to use (raw or clr) - :param permutations: the number of permutations for simulated Z-score (z_sim) - estimation (if permutations>0) + :param n_permutations: the number of permutations to use to estimate the + null-hypothesis for the Moran's I statistic + :param random_seed: the random seed to use to ensure that the permutations + are reproducible across runs :returns: a pd.DataFrame with the polarization statistics for each antibody :rtype: pd.DataFrame :raises: AssertionError when the input is not valid """ - if len(graph.connected_components()) > 1: - raise AssertionError("The graph given as input is not a single component") - - if normalization not in get_args(PolarizationNormalizationTypes): - raise AssertionError(f"incorrect value for normalization {normalization}") - - logger.debug( - "Computing polarization scores for component %s with %i nodes", - component_id, - graph.vcount(), - ) - if graph.vcount() < MIN_VERTICES_REQUIRED: logger.debug( ( @@ -99,60 +103,113 @@ def polarization_scores_component( ) return pd.DataFrame() - # create antibody node counts - counts_df = create_node_markers_counts(graph=graph, k=0) + def _compute_morans_on_current_graph(): + N = float(graph.vcount()) - # remove markers with zero variance - counts_df = counts_df.loc[ - :, (counts_df != 0).any(axis=0) & (counts_df.nunique() > 1) - ] + W = graph.get_adjacency_sparse() + # Normalize the weights by the degree of the node + W = W / W.sum(axis=0) + X = graph.node_marker_counts - # clr transformation - if normalization == "clr": - counts_df = clr_transformation(df=counts_df, non_negative=True, axis=0) + # remove markers with zero variance + X = X.loc[:, (X != 0).any(axis=0) & (X.nunique() > 1)] - # compute the spatial weights matrix (w) from the graph - w = WSP(graph.get_adjacency_sparse()).to_W(silence_warnings=True) + # Calculate normalization factor + C = N / W.sum() - # compute polarization statistics for each marker using the spatial weights (w) - # and the markers counts distribution (y) (Morans I autocorrelation) - def data(): - for m in counts_df.columns: - yield morans_autocorr(w, counts_df[m], permutations) + X_perm = [ + clr_transformation(x) if normalization == "clr" else x + for x in permutations(X, n=n_permutations, random_seed=random_seed) + ] + + if normalization == "clr": + X = clr_transformation(X, non_negative=True, axis=0) - if permutations > 0: - df = pd.DataFrame( - ((m.I, m.p_rand, m.z_rand, m.p_sim, m.z_sim) for m in data()), + _compute_morans_i_per_marker = partial( + _compute_morans_i, + marker_count_matrix=X, + marker_count_matrix_permuted=X_perm, + weight_matrix=W, + normalization_factor=C, + ) + markers = X.columns + + results = pd.DataFrame( + map(_compute_morans_i_per_marker, markers), columns=[ + "marker", "morans_i", - "morans_p_value", "morans_z", - "morans_p_value_sim", - "morans_z_sim", - ], - ).fillna(0) - else: - df = pd.DataFrame( - ((m.I, m.p_rand, m.z_rand) for m in data()), - columns=[ - "morans_i", + "perm_mean", + "perm_std", "morans_p_value", - "morans_z", ], - ).fillna(0) + ) + return results + + start_time = time.perf_counter() + logger.info("Computing Moran's I for component: %s", component_id) - df["marker"] = counts_df.columns.tolist() - df["component"] = component_id + results = _compute_morans_on_current_graph() + results["component"] = component_id - logger.debug("Polarization scores for components %s computed", component_id) - return df + run_time = time.perf_counter() - start_time + logger.info( + "Finished computing Moran's I for component: %s in %.2fs", + component_id, + run_time, + ) + results = results.drop(columns=["perm_mean", "perm_std"]) + return results + + +def polarization_scores_component_df( + component_id: str, + component_df: pd.DataFrame, + use_full_bipartite: bool, + normalization: PolarizationNormalizationTypes = "clr", + n_permutations: int = 50, + random_seed: int | None = None, +): + """Calculate Moran's I statistics for a component. + + See `polarization_scores_component_graph` for details. + + :param component_id: the id of the component + :param component_df: A data frame with an edgelist for a single connected component + :param use_full_bipartite: use the bipartite graph instead of the projection (UPIA) + :param normalization: the normalization method to use (raw or clr) + :param n_permutations: the number of permutations to use to estimate the + null-hypothesis for the Moran's I statistic + :param random_seed: the random seed to use to ensure that the permutations + are reproducible across runs + :returns: a pd.DataFrame with the polarization statistics for each antibody + :rtype: pd.DataFrame + :raises: AssertionError when the input is not valid + """ + graph = Graph.from_edgelist( + edgelist=component_df, + add_marker_counts=True, + simplify=True, + use_full_bipartite=use_full_bipartite, + ) + + component_result = polarization_scores_component_graph( + graph=graph, + component_id=component_id, + normalization=normalization, + n_permutations=n_permutations, + random_seed=random_seed, + ) + return component_result def polarization_scores( edgelist: pd.DataFrame, use_full_bipartite: bool = False, normalization: PolarizationNormalizationTypes = "clr", - permutations: int = 0, + n_permutations: int = 0, + random_seed: int | None = None, ) -> pd.DataFrame: """Calculate Moran's I statistics for an edgelist. @@ -168,50 +225,52 @@ def polarization_scores( :param edgelist: an edge list (pd.DataFrame) with a component column :param use_full_bipartite: use the bipartite graph instead of the projection (UPIA) :param normalization: the normalization method to use (raw or clr) - :param permutations: the number of permutations for simulated Z-score (z_sim) - estimation (if permutations>0) + :param n_permutations: the number of permutations for simulated Z-score (z_sim) + estimation (if n_permutations>0) + :param random_seed: the random seed to use for reproducibility :returns: a pd.DataFrames with all the polarization scores :rtype: pd.DataFrame :raises: AssertionError when the input is not valid """ + if normalization not in get_args(PolarizationNormalizationTypes): + raise AssertionError(f"incorrect value for normalization {normalization}") + if "component" not in edgelist.columns: raise AssertionError("Edge list is missing the component column") + if n_permutations < 0: + logger.warning( + "Setting `n_permutations < 0` will mean no z-scores and p-values will be calculated." + ) + logger.debug( "Computing polarization for edge list with %i elements", edgelist.shape[0], ) - # we make the computation in parallel (for each component) - with futures.ThreadPoolExecutor() as executor: - tasks = [] - for component_id, component_df in edgelist.groupby("component", observed=True): - # build the graph from the component - graph = Graph.from_edgelist( - edgelist=component_df, - add_marker_counts=True, - simplify=False, + def data(): + with get_pool_executor() as pool: + polarization_function = partial( + polarization_scores_component_df, use_full_bipartite=use_full_bipartite, + normalization=normalization, + n_permutations=n_permutations, + random_seed=random_seed, ) - tasks.append( - executor.submit( - polarization_scores_component, - graph=graph, - component_id=component_id, - normalization=normalization, - permutations=permutations, - ) + yield from pool.starmap( + polarization_function, + ( + (component_id, component_df) + for component_id, component_df in edgelist.groupby( + "component", observed=True + ) + ), + chunksize=10, ) - results = futures.wait(tasks) - data = [] - for result in results.done: - if result.exception() is not None: - raise result.exception() # type: ignore - scores = result.result() - data.append(scores) # create dataframe with all the scores - scores = pd.concat(data, axis=0) + logger.debug("Concatenating the polarization dataframes") + scores = pd.concat(data(), axis=0) if scores.empty: logger.warning("Polarization results were empty") return scores diff --git a/src/pixelator/analysis/types.py b/src/pixelator/analysis/types.py new file mode 100644 index 00000000..8e543475 --- /dev/null +++ b/src/pixelator/analysis/types.py @@ -0,0 +1,8 @@ +"""Module with types related to analysis. + +Copyright © 2024 Pixelgen Technologies AB. +""" + +import pandas as pd + +RegionByCountsDataFrame = pd.DataFrame diff --git a/src/pixelator/annotate/__init__.py b/src/pixelator/annotate/__init__.py index 0a5809ad..5612ccdd 100644 --- a/src/pixelator/annotate/__init__.py +++ b/src/pixelator/annotate/__init__.py @@ -237,7 +237,9 @@ def annotate_components( dataset = PixelDataset.from_data( edgelist=filtered_edgelist, adata=adata, metadata=metadata ) - dataset.save(Path(output) / f"{output_prefix}.annotate.dataset.pxl") + dataset.save( + Path(output) / f"{output_prefix}.annotate.dataset.pxl", force_overwrite=True + ) edgelist_metrics_dict = edgelist_metrics(filtered_edgelist) adata_metrics_dict = anndata_metrics(adata) diff --git a/src/pixelator/cli/analysis.py b/src/pixelator/cli/analysis.py index c4783950..f4388db1 100644 --- a/src/pixelator/cli/analysis.py +++ b/src/pixelator/cli/analysis.py @@ -68,14 +68,13 @@ ) @click.option( "--polarization-n-permutations", - default=0, + default=50, required=False, - type=click.IntRange(min=0), + type=click.IntRange(min=5), show_default=True, help=( "Set the number of permutations use to compute the empirical" - " z-score and p-value for the polarization score. If not set," - " only the analytical z-score estimation will be performed" + " z-score and p-value for the polarization score." ), ) @click.option( diff --git a/src/pixelator/pixeldataset/__init__.py b/src/pixelator/pixeldataset/__init__.py index 519ead49..56db69bf 100644 --- a/src/pixelator/pixeldataset/__init__.py +++ b/src/pixelator/pixeldataset/__init__.py @@ -37,10 +37,6 @@ ) from pixelator.types import PathType -with warnings.catch_warnings(): - warnings.filterwarnings("ignore", module="libpysal") - - logger = logging.getLogger(__name__) SIZE_DEFINITION = "molecules" diff --git a/tests/analysis/colocalization/test_estimate.py b/tests/analysis/colocalization/test_estimate.py index 2e547bc9..506ff609 100644 --- a/tests/analysis/colocalization/test_estimate.py +++ b/tests/analysis/colocalization/test_estimate.py @@ -12,12 +12,12 @@ estimate_observation_statistics, permutation_analysis_results, ) -from pixelator.analysis.colocalization.permute import permutations from pixelator.analysis.colocalization.statistics import ( Jaccard, Pearson, apply_multiple_stats, ) +from pixelator.analysis.permute import permutations def test_estimate_observation_statistics(): diff --git a/tests/analysis/colocalization/test_permute.py b/tests/analysis/colocalization/test_permute.py index 3a3851f4..5426b1c2 100644 --- a/tests/analysis/colocalization/test_permute.py +++ b/tests/analysis/colocalization/test_permute.py @@ -7,7 +7,7 @@ import pandas as pd from numpy.random import default_rng from pandas.testing import assert_series_equal -from pixelator.analysis.colocalization.permute import ( +from pixelator.analysis.permute import ( permutations, permute, ) diff --git a/tests/analysis/polarization/test_polarization.py b/tests/analysis/polarization/test_polarization.py index f45a5ee3..c41ae3cd 100644 --- a/tests/analysis/polarization/test_polarization.py +++ b/tests/analysis/polarization/test_polarization.py @@ -12,7 +12,8 @@ from pandas.testing import assert_frame_equal from pixelator.analysis.polarization import ( polarization_scores, - polarization_scores_component, + polarization_scores_component_df, + polarization_scores_component_graph, ) from tests.graph.networkx.test_tools import create_randomly_connected_bipartite_graph @@ -23,45 +24,68 @@ def test_polarization(enable_backend, full_graph_edgelist: pd.DataFrame): # TODO we should test more scenarios here (sparse and clustered patterns) scores = polarization_scores( - edgelist=full_graph_edgelist, permutations=0, use_full_bipartite=True + edgelist=full_graph_edgelist, + n_permutations=10, + use_full_bipartite=True, + random_seed=1, ) - expected = pd.DataFrame( - data={ - "morans_i": [-0.058418204066991254, -0.05841820406699129], - "morans_p_value": [0.0006289931974147407, 0.0006289931974147351], - "morans_p_adjusted": [0.0006289931974147407, 0.0006289931974147407], - "morans_z": [-3.418794027777849, -3.4187940277778512], - "marker": ["A", "B"], - "component": ["PXLCMP0000000", "PXLCMP0000000"], + expected = pd.DataFrame.from_dict( + { + 0: { + "marker": "A", + "morans_i": -0.058418204066991254, + "morans_z": -7.844216486178604, + "morans_p_value": 2.1783248596911517e-15, + "morans_p_adjusted": 4.356649719382303e-15, + "component": "PXLCMP0000000", + }, + 1: { + "marker": "B", + "morans_i": -0.05841820406699129, + "morans_z": -7.747319374160002, + "morans_p_value": 4.692634773999269e-15, + "morans_p_adjusted": 4.692634773999269e-15, + "component": "PXLCMP0000000", + }, }, - index=pd.Index([0, 1]), + orient="index", ) + # test polarization scores - assert_frame_equal(scores, expected) + assert_frame_equal(scores.sort_index(axis=1), expected.sort_index(axis=1)) @pytest.mark.parametrize("enable_backend", ["networkx"], indirect=True) def test_permuted_polarization(enable_backend, full_graph_edgelist: pd.DataFrame): # TODO we should test more scenarios here (sparse and clustered patterns) - np.random.seed(1) - scores = polarization_scores( - edgelist=full_graph_edgelist, permutations=999, use_full_bipartite=True + edgelist=full_graph_edgelist, + n_permutations=10, + use_full_bipartite=True, + random_seed=1, ) - expected = pd.DataFrame( - data={ - "morans_i": [-0.058418204066991254, -0.05841820406699129], - "morans_p_value": [0.0006289931974147407, 0.0006289931974147351], - "morans_p_adjusted": [0.0006289931974147407, 0.0006289931974147407], - "morans_z": [-3.418794027777849, -3.4187940277778512], - "morans_p_value_sim": {0: 0.02, 1: 0.01}, - "morans_z_sim": {0: -3.2672829000275176, 1: -3.9734152894187327}, - "marker": ["A", "B"], - "component": ["PXLCMP0000000", "PXLCMP0000000"], + expected = pd.DataFrame.from_dict( + { + 0: { + "marker": "A", + "morans_i": -0.058418204066991254, + "morans_z": -7.844216486178604, + "morans_p_value": 2.1783248596911517e-15, + "morans_p_adjusted": 4.356649719382303e-15, + "component": "PXLCMP0000000", + }, + 1: { + "marker": "B", + "morans_i": -0.05841820406699129, + "morans_z": -7.747319374160002, + "morans_p_value": 4.692634773999269e-15, + "morans_p_adjusted": 4.692634773999269e-15, + "component": "PXLCMP0000000", + }, }, - index=pd.Index([0, 1]), + orient="index", ) # test polarization scores assert_frame_equal(scores, expected) @@ -85,18 +109,30 @@ def test_polarization_with_differentially_polarized_markers(): random_vertex = graph.vs.get_vertex(random.randint(0, graph.vcount())) random_vertex["markers"]["C"] = 10 - scores = polarization_scores_component(graph, component_id="PXLCMP0000000") + scores = polarization_scores_component_graph( + graph, component_id="PXLCMP0000000", n_permutations=10, random_seed=1 + ) # We don't expect to get a value for B, since it has only one value in it. # Hence it is filtered out. expected = pd.DataFrame.from_dict( { - "morans_i": {0: 0.37307837882553935, 1: -0.0037658463832960496}, - "morans_p_value": {0: 1.317601591958555e-17, 1: 0.5910333410276116}, - "morans_z": {0: 8.54213868598478, 1: 0.537339187874427}, - "marker": {0: "A", 1: "C"}, - "component": {0: "PXLCMP0000000", 1: "PXLCMP0000000"}, - } + 0: { + "marker": "A", + "morans_i": 0.37307837882553935, + "morans_z": 4.095594525493692, + "morans_p_value": 2.1054318495343033e-05, + "component": "PXLCMP0000000", + }, + 1: { + "marker": "C", + "morans_i": -0.0037658463832960483, + "morans_z": -2.1799059127756326, + "morans_p_value": 0.014632218279985308, + "component": "PXLCMP0000000", + }, + }, + orient="index", ) # test polarization scores assert_frame_equal(scores, expected, check_exact=False, atol=1e-3) @@ -121,22 +157,30 @@ def test_permuted_polarization_with_differentially_polarized_markers(): random_vertex["markers"]["C"] = 10 np.random.seed(1) - scores = polarization_scores_component( - graph, component_id="PXLCMP0000000", permutations=999 + scores = polarization_scores_component_graph( + graph, component_id="PXLCMP0000000", n_permutations=10, random_seed=1 ) # We don't expect to get a value for B, since it has only one value in it. # Hence it is filtered out. expected = pd.DataFrame.from_dict( { - "morans_i": {0: 0.37307837882553935, 1: -0.0037658463832960496}, - "morans_p_value": {0: 1.317601591958555e-17, 1: 0.5910333410276116}, - "morans_z": {0: 8.54213868598478, 1: 0.537339187874427}, - "morans_p_value_sim": {0: 0.001, 1: 0.411}, - "morans_z_sim": {0: 8.91274668296225, 1: 0.5422508893213437}, - "marker": {0: "A", 1: "C"}, - "component": {0: "PXLCMP0000000", 1: "PXLCMP0000000"}, - } + 0: { + "marker": "A", + "morans_i": 0.37307837882553935, + "morans_z": 4.095594525493692, + "morans_p_value": 2.1054318495343033e-05, + "component": "PXLCMP0000000", + }, + 1: { + "marker": "C", + "morans_i": -0.0037658463832960483, + "morans_z": -2.1799059127756326, + "morans_p_value": 0.014632218279985308, + "component": "PXLCMP0000000", + }, + }, + orient="index", ) # test polarization scores assert_frame_equal(scores, expected, check_exact=False, atol=1e-3) diff --git a/tests/integration/test_small_D21.yaml b/tests/integration/test_small_D21.yaml index c5456800..8940ee1c 100644 --- a/tests/integration/test_small_D21.yaml +++ b/tests/integration/test_small_D21.yaml @@ -27,7 +27,7 @@ small-D21: "--compute-colocalization", "--use-full-bipartite", "--polarization-n-permutations", - "0", + "5", "--colocalization-min-region-count", "0", "--colocalization-n-permutations",