py2ls 0.2.5.7__tar.gz → 0.2.5.9__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/PKG-INFO +1 -1
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/ips.py +390 -126
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/pyproject.toml +1 -1
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/README.md +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.DS_Store +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/.DS_Store +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/COMMIT_EDITMSG +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/FETCH_HEAD +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/HEAD +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/config +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/description +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/hooks/applypatch-msg.sample +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/hooks/commit-msg.sample +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/hooks/fsmonitor-watchman.sample +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/hooks/post-update.sample +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/hooks/pre-applypatch.sample +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/hooks/pre-commit.sample +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/hooks/pre-merge-commit.sample +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/hooks/pre-push.sample +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/hooks/pre-rebase.sample +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/hooks/pre-receive.sample +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/hooks/prepare-commit-msg.sample +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/hooks/push-to-checkout.sample +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/hooks/update.sample +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/index +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/info/exclude +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/logs/HEAD +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/logs/refs/heads/main +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/logs/refs/remotes/origin/HEAD +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/logs/refs/remotes/origin/main +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/.DS_Store +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/01/d5bd8065e6860c0bd23ff9fa57161806a099e1 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/09/08da26de58c114225ad81f484b80bf5d351b34 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/0b/409e1bc918277010f5679b402d1d1dda53e15c +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/12/c2808a1b3a4d0892a4154dfba1e2ae3770fa73 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/14/449a0e6ba4ea2f1a73acf63ef91c9c6193f9ed +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/15/a8e468aacfcb440e090020f36d0b985d45da23 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/1a/b4585881a6a42889f01aa0cfe25fd5acfaf46f +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/1c/3f92adda34344bcbbbf9d409c79855ae2aaea8 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/1c/9314c5f69b9390068a2a8616875d974849d71f +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/1d/fe9d9633b24ea560354f4f93d39c6e5f163ea0 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/20/72c28e83f4347959d29f7b3a6c1fc3e4ee6b59 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/24/6b368b986f758630c46dc02b7fa512b53422f7 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/25/b796accd261b9135fd32a2c00785f68edf6c46 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/27/aa6074f652bc6f7078f8647489d9ee8e24f0e2 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/28/c2969d785c1b892c2a96b3f00eba63a59811b3 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/2a/ae95d517d213b660bf4f65a4e0cfae7bb893eb +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/2a/fdf45791a26d42ccead35ace76a8f0b2a56561 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/30/a2f8da47ee947811dc8d993f5a06a45de374f4 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/32/fd627b62fad7cf3b2f9e34ab9777126a0987ad +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/34/9e31b6a3634cea102ce5588b98c11cc1738605 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/34/b6f3a2ee84f39bed4eee57f2c0e0afb994feb1 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/35/1a5f491ab97eee9d1ee699478d75a8bb5d3dc2 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/36/b4a1b7403abc6c360f8fe2cb656ab945254971 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/36/e56a361f526eafa59c5235a5c990bf288b5f9c +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/36/ef43e50009e59db11812c258846d9e38718173 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/39/7ead045fbbcfb17c62019eb18fe21ed05dbee5 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/39/b13be65125556784e44c7a1d9821703c7ab67e +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/3b/507acc7f23391644cc0b824b1e79fd2677a362 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/3b/bd972aa7ad680858f8dfbd0f7fcd97756f0d6f +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/3c/bbe5f4173d165127b9ad96119f1ec24c306ffc +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/3d/9d10d27724657a436c65a6254bfd213d4b3562 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/3f/d6561300938afbb3d11976cf9c8f29549280d9 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/41/dcf4b3bf0460946b2da93776cf9e836d62178f +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/43/dbd49b2ee367c5434dd545e3b5795434f2ef0b +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/45/b1b6178bacbfc997811a998b5cc60c1ea7fac8 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/47/6cbd5a7c5e35cddef2f8a38bdc4896d403b095 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/48/a88fc5806305d0bb0755ee6801161b79696972 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/4f/7afb40dff2153d857fc85748c2eecb85125042 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/50/08ddfcf53c02e82d7eee2e57c38e5672ef89f6 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/53/e0deb1cb4c2c606bced6e7f9a66b0fda60980d +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/56/e4e8b2d5545e0256090f45aa8fc42c5fe067d0 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/57/63d0c52f5c9c69e89d514a1f96034947abe21a +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/57/bd1c0199483ab316235b094543b85edec6c35e +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/58/20a729045d4dc7e37ccaf8aa8eec126850afe2 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/59/380c4c26bdcd4d9b71ae3e2e35f05b3f26c5ab +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/5a/192565abf89c9d765af846ce6d53a92b1ce7ad +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/60/f273eb1c412d916fa3f11318a7da7a9911b52a +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/61/570cec8c061abe74121f27f5face6c69b98f99 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/62/4488173ed2c8936fa5cea3cf5dd3f26a30b86e +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/62/7c81b23b4e56e87b042b650b0103653cc9e34a +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/62/d90ccf8cbefdc2e4fd475e7c6f4f76e9fdf801 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/63/100154b27846e8010e55b6bf4b3d7762c14c5f +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/64/27a4edff08f93d98f511418423f09f2ab90bcd +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/66/6227eeeba24073e63811e89f1449f3d958f183 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/66/c998778721d424bd0aae80602dabbffa93af2e +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/68/6df3072c8b025fb18106ed2df505994ad062a9 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/69/13c452ca319f7cbf6a0836dc10a5bb033c84e4 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/6a/52e747a2b349b128d1490d9e896d2323818eb7 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/6b/7fde264d93a7a0986d394c46c7650d0ce2ab92 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/6c/cebb29b7f3f5b0c889f6dadbf9ff066554587d +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/6d/c2cdf4a84e538e5d4777486aeff87e42f41799 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/6d/ee29dbdcc84edeeacede105110446f3ccac963 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/71/36b2074a2754be8b58127d82250e5b37e3c373 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/72/245a05b0966011cb381e6b32b0465000e969ab +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/72/e4179337639859678ddaecf38b16f33aaec8e1 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/78/063f4c863fc371ec0313303c0a81283b35d9b6 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/78/3d4167bc95c9d2175e0df03ef1c1c880ba75ab +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/79/7ae089b2212a937840e215276005ce76881307 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/7e/5956c806b5edc344d46dab599dec337891ba1f +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/81/8f26b7bf042269729020cf944fc362d66ba27e +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/82/70b319ce4046854fbe7dc41054b6c2d112dab2 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/84/59071b722a255b774a80b27746033f8141ab39 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/85/aee46f478e9afdb84d50a05242c53b04ed2e21 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/86/e288b46f8fe179907e4413f665aeb5053fddb1 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/87/ef1fc3f7f1ddc4d0ab9b3e65381ce9f3388621 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/8b/84f56978e1de8f2ae82abce5f8b3e182d365cd +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/8e/55a7d2b96184030211f20c9b9af201eefcac82 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/91/c69ad88fe0ba94aa7859fb5f7edac5e6f1a3f7 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/94/74152b4b463d70ae5ad07f0c658be3e296026b +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/94/f7dbe88e80c4205a901b71eb8f181974376bba +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/97/1aef09ea939f46b60b9646f8d524c78a9220f4 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/9b/ec5ee2236ee2d5532c36bfd132e23c58fdb69c +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/9d/0df52899fe95279059286d9c0ec42287edc168 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/a1/5389729850729fc7bd78a54f26fce77f30be12 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/a1/906da89d1174f74867800c74c43af36253bd5e +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/a4/63fdd23e5efd713db8a71f316f3a1c7bd60916 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/a5/ec8f74642fbba27f7ea78c53b372ae0c7dedce +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/a7/3e13eafee65c5b8d73ad2d3ea46d0eee82f0d3 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/b0/56be4be89ba6b76949dd641df45bb7036050c8 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/b0/9cd7856d58590578ee1a4f3ad45d1310a97f87 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/b2/18e6a0f0f1c4df8cdefa9852058348abc713b7 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/b3/4f7f271c6d6105e35a6556ffda71d03afe8c96 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/b3/69579064bde9de9a19d114fc33e4e48cc8c0e4 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/b5/61831c7dce8ea51e7ee6b6fa35745f14d8242d +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/b7/2c9e75ab7d0afe594664650aa8f6c772f5ac64 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/bb/81ccc0513f18fc160b54a82861e9a80d23f4f6 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/bb/934eb33bc1a8b85630bf680caffd99560c1b8f +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/bf/67907e337021ebff434e02b19b30a741c144af +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/bf/b54d65922ce1dfda1aaa014913a54e7172d0bc +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/c1/20fc812b9ad311c34a3608512d6a9d976bb48e +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/c1/397c6ed72c4e20ef6b9ab83163e9a6baba5b45 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/c4/cba65f1163661999ee4b8ed23342b63bc1300c +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/c6/7f17e5707313600efcb85e9a3fedea35dba591 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/c6/f32aced880bd165a251cb52b26b0c1107e2141 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/cc/45df1d317a2eb63ff1ff3a5f3b4a9f98fd92b5 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/cd/822b3574a88ebdd1ed82fd6983f37e626d52b4 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/cf/0c0d9c6fb09473aaeb7f7e2edbd770c3f2ef3d +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/d2/992df305f4b56a466a2f221aeb182ddd20f418 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/d6/39e8af592cd75a318d8affddd1bcc70c2095f2 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/d6/9ab1c4aadf279936dd778e8346ba60f74705b6 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/d8/4688b54c0040a30976b3a6540bc47adf7ce680 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/d9/005f2cc7fc4e65f14ed5518276007c08cf2fd0 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/d9/c2403fd166ce791b4e9d0c6792ed8342c71fcd +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/d9/dfa5aee51e92a541b707e8e7baea6f06deff98 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/db/141dbaa93594df2a8156182f361ee4db829359 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/db/3f2cd643292057936230b95cf7ec3046affe11 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/db/ffa8ea7bda721d0cee7b9e4ce5b2ef927733ff +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/dc/c2bdbafb3296e09d9ee4955cfa55d275825f94 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/dc/cdbd4266765d840be2ae35ab1752a0fa312c16 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/dd/87fb5f606fe380d81e6fe3a2c98f9f99e3e09b +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/de/214c626ac2dd2685bfaa0bc0fc20f528d014d7 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/df/e0770424b2a19faf507a501ebfc23be8f54e7b +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/e2/f2f8f4c25e62a297fc55f36acc6b01cfbab76f +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/e3/1356f90ea6dd0577b5e0b40b206319adcbf085 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/e3/5a4dafc50850cacac7bf76c56db2715cbda2c4 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/e4/6c715352db9fe3c887a635f1916df4ca1f4ff9 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/e5/0580a0bd1e1b3d29f834382b80fceb61d5cf0c +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/e9/391ffe371f1cc43b42ef09b705d9c767c2e14f +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/ea/3a18cc75e53792744ef754e05d3f4481768c13 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/ec/40fd8bf8e4c342534a9fc020289e402ba6bc9d +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/ec/d980279432b13f0374b90ca439a6329cdece0f +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/ee/cee64eacaff022dcdc509c0c2b1da492f21060 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/f1/e50757fddc28b445545dc7e2759b54cdd0f42e +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/f4/b64d3107b39e3ad6f540c6607004ea34e6c024 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/f4/ba7f815b886797b73fede071d86e0c134d2bc7 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/f5/61c3c1bf1c9ea9c9d1f556a7be2869f71f3bdf +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/f6/44a8ff56fa035105fc517cbb1ac46c3d8e349a +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/f7/c98ba5c2f903e603b1f5e63d49fbc8a43815cc +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/f9/045a08e96eb76848fc4d68e3e3e687cca39a2d +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/fa/147e6bb78a2e8db241d231295fd7f1ed061af8 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/objects/fc/292e793ecfd42240ac43be407023bd731fa9e7 +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/refs/.DS_Store +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/refs/heads/main +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/refs/remotes/origin/HEAD +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.git/refs/remotes/origin/main +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.gitattributes +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/.gitignore +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/LICENSE +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/README.md +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/__init__.py +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/batman.py +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/bio.py +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/brain_atlas.py +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/chat.py +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/corr.py +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/correlators.py +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/data/.DS_Store +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/data/db2ls_sql_chtsht.json +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/data/docs_links.json +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/data/email/email_html_template.html +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/data/hyper_param_autogluon_zeroshot2024.json +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/data/hyper_param_tabrepo_2024.py +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/data/lang_code_iso639.json +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/data/mygenes_fields_241022.txt +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/data/sns_info.json +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/data/styles/.DS_Store +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/data/styles/example/.DS_Store +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/data/styles/example/style1.pdf +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/data/styles/example/style2.pdf +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/data/styles/example/style3.pdf +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/data/styles/example/style4.pdf +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/data/styles/example/style5.pdf +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/data/styles/example/style6.pdf +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/data/styles/example/style7.pdf +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/data/styles/example/style8.pdf +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/data/styles/example/style9.pdf +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/data/styles/style1.json +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/data/styles/style10.json +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/data/styles/style11.json +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/data/styles/style12.json +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/data/styles/style2.json +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/data/styles/style3.json +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/data/styles/style4.json +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/data/styles/style5.json +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/data/styles/style6.json +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/data/styles/style7.json +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/data/styles/style8.json +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/data/styles/style9.json +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/data/styles/stylelib/.DS_Store +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/data/styles/stylelib/grid.mplstyle +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/data/styles/stylelib/high-contrast.mplstyle +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/data/styles/stylelib/high-vis.mplstyle +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/data/styles/stylelib/ieee.mplstyle +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/data/styles/stylelib/light.mplstyl +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/data/styles/stylelib/muted.mplstyle +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/data/styles/stylelib/nature-reviews-latex.mplstyle +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/data/styles/stylelib/nature-reviews.mplstyle +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/data/styles/stylelib/nature.mplstyle +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/data/styles/stylelib/no-latex.mplstyle +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/data/styles/stylelib/notebook.mplstyle +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/data/styles/stylelib/paper.mplstyle +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/data/styles/stylelib/retro.mplstyle +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/data/styles/stylelib/sans.mplstyle +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/data/styles/stylelib/scatter.mplstyle +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/data/styles/stylelib/science.mplstyle +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/data/styles/stylelib/std-colors.mplstyle +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/data/styles/stylelib/vibrant.mplstyle +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/data/tiles.csv +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/data/usages_pd.json +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/data/usages_sns.json +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/db2ls.py +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/doc.py +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/ec2ls.py +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/export_requirements.py +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/fetch_update.py +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/freqanalysis.py +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/ich2ls.py +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/ml2ls.py +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/mol.py +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/netfinder.py +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/nl2ls.py +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/ocr.py +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/plot.py +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/setuptools-70.1.0-py3-none-any.whl +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/sleep_events_detectors.py +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/stats.py +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/translator.py +0 -0
- {py2ls-0.2.5.7 → py2ls-0.2.5.9}/py2ls/wb_detector.py +0 -0
@@ -3,7 +3,7 @@ import pandas as pd
|
|
3
3
|
import sys
|
4
4
|
import os
|
5
5
|
from IPython.display import display
|
6
|
-
from typing import List, Optional, Union,Any
|
6
|
+
from typing import Dict,List, Optional, Union,Any
|
7
7
|
|
8
8
|
from regex import X
|
9
9
|
|
@@ -5245,63 +5245,169 @@ def split_path(fpath):
|
|
5245
5245
|
dir_ch = "".join(fpath.split(f_slash)[-1:])
|
5246
5246
|
return dir_par, dir_ch
|
5247
5247
|
|
5248
|
+
from pathlib import Path
|
5249
|
+
import matplotlib.pyplot as plt
|
5250
|
+
from PIL import Image
|
5251
|
+
import numpy as np
|
5252
|
+
import cv2
|
5248
5253
|
|
5249
|
-
def figsave(*args, dpi=300):
|
5250
|
-
|
5251
|
-
|
5254
|
+
def figsave(*args, dpi=300, **kwargs):
|
5255
|
+
bbox_inches = kwargs.pop("bbox_inches", "tight")
|
5256
|
+
pad_inches = kwargs.pop("pad_inches", 0)
|
5257
|
+
facecolor = kwargs.pop("facecolor", "white")
|
5258
|
+
edgecolor = kwargs.pop("edgecolor", "auto")
|
5252
5259
|
|
5253
5260
|
dir_save = None
|
5254
5261
|
fname = None
|
5255
5262
|
img = None
|
5256
|
-
|
5263
|
+
|
5257
5264
|
for arg in args:
|
5258
5265
|
if isinstance(arg, str):
|
5259
|
-
|
5260
|
-
|
5266
|
+
path = Path(arg)
|
5267
|
+
if path.suffix: # Has file extension
|
5268
|
+
fname = path.name
|
5269
|
+
dir_save = path.parent
|
5261
5270
|
else:
|
5262
|
-
|
5271
|
+
dir_save = path
|
5263
5272
|
elif isinstance(arg, (Image.Image, np.ndarray)):
|
5264
|
-
img = arg # Store
|
5273
|
+
img = arg # Store PIL image or numpy array
|
5265
5274
|
|
5266
|
-
|
5267
|
-
|
5275
|
+
# Set default save directory
|
5276
|
+
dir_save = Path(dir_save) if dir_save else Path(".")
|
5277
|
+
dir_save.mkdir(parents=True, exist_ok=True)
|
5278
|
+
|
5279
|
+
# Handle filename and extension
|
5280
|
+
if fname is None:
|
5281
|
+
fname = "figure"
|
5282
|
+
fname = dir_save / fname
|
5283
|
+
if fname.suffix == "":
|
5284
|
+
fname = fname.with_suffix(".pdf") # Default format
|
5285
|
+
|
5286
|
+
ftype = fname.suffix.lstrip(".").lower()
|
5287
|
+
|
5288
|
+
# Save figure based on file type
|
5289
|
+
if ftype == "eps":
|
5290
|
+
plt.savefig(fname, format="eps", bbox_inches=bbox_inches)
|
5291
|
+
plt.savefig(fname.with_suffix(".pdf"), format="pdf", dpi=dpi,
|
5292
|
+
pad_inches=pad_inches, bbox_inches=bbox_inches,
|
5293
|
+
facecolor=facecolor, edgecolor=edgecolor)
|
5294
|
+
elif ftype == "pdf":
|
5295
|
+
plt.savefig(fname, format="pdf", dpi=dpi, pad_inches=pad_inches,
|
5296
|
+
bbox_inches=bbox_inches, facecolor=facecolor, edgecolor=edgecolor)
|
5297
|
+
elif ftype in ["jpg", "jpeg", "png", "tiff", "tif"]:
|
5298
|
+
if img is not None: # If an image is provided
|
5299
|
+
if isinstance(img, Image.Image):
|
5300
|
+
img = img.convert("RGB") if img.mode == "RGBA" else img
|
5301
|
+
img.save(fname, format=ftype.upper(), dpi=(dpi, dpi))
|
5302
|
+
elif isinstance(img, np.ndarray):
|
5303
|
+
if img.ndim == 2:
|
5304
|
+
Image.fromarray(img).save(fname, format=ftype.upper(), dpi=(dpi, dpi))
|
5305
|
+
elif img.ndim == 3:
|
5306
|
+
if img.shape[2] == 3:
|
5307
|
+
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
|
5308
|
+
elif img.shape[2] == 4:
|
5309
|
+
img = cv2.cvtColor(img, cv2.COLOR_BGRA2RGBA)
|
5310
|
+
Image.fromarray(img).save(fname, format=ftype.upper(), dpi=(dpi, dpi))
|
5311
|
+
else:
|
5312
|
+
raise ValueError("Unexpected image dimensions.")
|
5313
|
+
else:
|
5314
|
+
plt.savefig(fname, format=ftype, dpi=dpi, pad_inches=pad_inches,
|
5315
|
+
bbox_inches=bbox_inches, facecolor=facecolor, edgecolor=edgecolor)
|
5316
|
+
elif ftype == "ico":
|
5317
|
+
if img is None:
|
5318
|
+
plt.savefig(fname, dpi=dpi, pad_inches=pad_inches,
|
5319
|
+
bbox_inches=bbox_inches, facecolor=facecolor, edgecolor=edgecolor)
|
5320
|
+
img = Image.open(fname)
|
5321
|
+
img = img.convert("RGBA")
|
5322
|
+
icon_sizes = [(32, 32), (64, 64), (128, 128), (256, 256)]
|
5323
|
+
img.save(fname, format="ICO", sizes=icon_sizes)
|
5324
|
+
print(f"Icon saved @: {fname} with sizes: {icon_sizes}")
|
5325
|
+
else:
|
5326
|
+
raise ValueError(f"Unsupported file format: {ftype}")
|
5327
|
+
|
5328
|
+
print(f"\nSaved @ {fname} (dpi={dpi})")
|
5268
5329
|
|
5269
|
-
|
5270
|
-
|
5271
|
-
|
5272
|
-
|
5273
|
-
|
5330
|
+
def figsave(*args, dpi=300, **kwargs):
|
5331
|
+
"""
|
5332
|
+
Save a Matplotlib figure or image file in various formats.
|
5333
|
+
|
5334
|
+
This function automatically determines whether to save a Matplotlib figure
|
5335
|
+
or an image (PIL or NumPy array) and handles different file formats, including:
|
5336
|
+
- PDF, EPS, PNG, JPG, TIFF, ICO, EMF
|
5337
|
+
|
5338
|
+
Parameters:
|
5339
|
+
-----------
|
5340
|
+
*args : str, PIL.Image, np.ndarray
|
5341
|
+
- File path (directory and/or filename) to save the figure.
|
5342
|
+
- If an image is provided (PIL or NumPy), it will be saved accordingly.
|
5343
|
+
|
5344
|
+
dpi : int, optional (default=300)
|
5345
|
+
- Resolution (dots per inch) for saved figures.
|
5346
|
+
|
5347
|
+
**kwargs : dict
|
5348
|
+
- Additional keyword arguments for `matplotlib.pyplot.savefig()`, including:
|
5349
|
+
- bbox_inches (str, default="tight"): Bounding box for figure.
|
5350
|
+
- pad_inches (float, default=0): Padding around figure.
|
5351
|
+
- facecolor (str, default="white"): Background color.
|
5352
|
+
- edgecolor (str, default="auto"): Edge color.
|
5353
|
+
|
5354
|
+
Supported Formats:
|
5355
|
+
------------------
|
5356
|
+
- Vector: `pdf`, `eps`, `emf`
|
5357
|
+
- Raster: `png`, `jpg`, `jpeg`, `tiff`, `tif`, `ico`
|
5358
|
+
|
5359
|
+
Example Usage:
|
5360
|
+
--------------
|
5361
|
+
>>> figsave("output_plot.pdf")
|
5362
|
+
>>> figsave("figs/plot.png", dpi=600)
|
5363
|
+
>>> figsave("./results/figure", format="pdf")
|
5364
|
+
>>> figsave("icons/logo.ico", image) # Save an image file as an icon
|
5365
|
+
|
5366
|
+
Returns:
|
5367
|
+
--------
|
5368
|
+
None
|
5369
|
+
"""
|
5370
|
+
import matplotlib.pyplot as plt
|
5371
|
+
from PIL import Image
|
5372
|
+
from pathlib import Path
|
5373
|
+
|
5374
|
+
bbox_inches=kwargs.pop("bbox_inches","tight")
|
5375
|
+
pad_inches=kwargs.pop("pad_inches",0)
|
5376
|
+
facecolor=kwargs.pop("facecolor",'white')
|
5377
|
+
edgecolor=kwargs.pop("edgecolor",'auto')
|
5378
|
+
|
5379
|
+
dir_save = None
|
5380
|
+
fname = None
|
5381
|
+
img = None
|
5382
|
+
for arg in args:
|
5383
|
+
if isinstance(arg, str):
|
5384
|
+
path = Path(arg)
|
5385
|
+
if path.suffix: # Has file extension
|
5386
|
+
fname = path.name
|
5387
|
+
dir_save = path.parent
|
5388
|
+
else:
|
5389
|
+
dir_save = path
|
5390
|
+
elif isinstance(arg, (Image.Image, np.ndarray)):
|
5391
|
+
img = arg # Store PIL image or numpy array
|
5274
5392
|
|
5393
|
+
dir_save = Path(dir_save) if dir_save else Path(".")
|
5394
|
+
dir_save.mkdir(parents=True, exist_ok=True)
|
5395
|
+
# Handle filename and extension
|
5275
5396
|
if fname is None:
|
5276
|
-
fname =
|
5277
|
-
mkdir(dir_par)
|
5278
|
-
ftype = fname.split(".")[-1]
|
5279
|
-
if len(fname.split(".")) == 1:
|
5280
|
-
ftype = "nofmt"
|
5281
|
-
fname = dir_par + fname + "." + ftype
|
5397
|
+
fname = dir_save
|
5282
5398
|
else:
|
5283
|
-
fname =
|
5399
|
+
fname = dir_save / fname
|
5400
|
+
if fname.suffix == "":
|
5401
|
+
fname = fname.with_suffix(".pdf") # Default format
|
5402
|
+
|
5403
|
+
ftype = fname.suffix.lstrip(".").lower()
|
5284
5404
|
|
5285
5405
|
# Save figure based on file type
|
5286
|
-
if ftype
|
5287
|
-
plt.savefig(fname, format="eps", bbox_inches=
|
5288
|
-
plt.savefig(
|
5289
|
-
|
5290
|
-
|
5291
|
-
bbox_inches="tight",
|
5292
|
-
dpi=dpi,
|
5293
|
-
pad_inches=0,
|
5294
|
-
)
|
5295
|
-
elif ftype.lower() == "nofmt": # default: both "tif" and "pdf"
|
5296
|
-
fname_corr = fname.replace("nofmt", "pdf")
|
5297
|
-
plt.savefig(
|
5298
|
-
fname_corr, format="pdf", bbox_inches="tight", dpi=dpi, pad_inches=0
|
5299
|
-
)
|
5300
|
-
fname = fname.replace("nofmt", "tif")
|
5301
|
-
plt.savefig(fname, format="tiff", dpi=dpi, bbox_inches="tight", pad_inches=0)
|
5302
|
-
print(f"default saving filetype: both 'tif' and 'pdf")
|
5303
|
-
elif ftype.lower() == "pdf":
|
5304
|
-
plt.savefig(fname, format="pdf", bbox_inches="tight", dpi=dpi, pad_inches=0)
|
5406
|
+
if ftype == "eps":
|
5407
|
+
plt.savefig(fname, format="eps", bbox_inches=bbox_inches)
|
5408
|
+
plt.savefig(fname.with_suffix(".pdf"), format="pdf", dpi=dpi,
|
5409
|
+
pad_inches=pad_inches, bbox_inches=bbox_inches,
|
5410
|
+
facecolor=facecolor, edgecolor=edgecolor)
|
5305
5411
|
elif ftype.lower() in ["jpg", "jpeg", "png", "tiff", "tif"]:
|
5306
5412
|
if img is not None: # If a PIL image is provided
|
5307
5413
|
if isinstance(img, Image.Image):
|
@@ -5310,63 +5416,46 @@ def figsave(*args, dpi=300):
|
|
5310
5416
|
img.save(fname, format=ftype.upper(), dpi=(dpi, dpi))
|
5311
5417
|
elif isinstance(img, np.ndarray):
|
5312
5418
|
import cv2
|
5313
|
-
|
5314
|
-
# Check the shape of the image to determine color mode
|
5315
5419
|
if img.ndim == 2:
|
5316
5420
|
# Grayscale image
|
5317
|
-
Image.fromarray(img).save(
|
5318
|
-
fname, format=ftype.upper(), dpi=(dpi, dpi)
|
5319
|
-
)
|
5421
|
+
Image.fromarray(img).save(fname, format=ftype.upper(), dpi=(dpi, dpi))
|
5320
5422
|
elif img.ndim == 3:
|
5321
5423
|
if img.shape[2] == 3:
|
5322
5424
|
# RGB image
|
5323
5425
|
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
|
5324
|
-
Image.fromarray(img).save(
|
5325
|
-
fname, format=ftype.upper(), dpi=(dpi, dpi)
|
5326
|
-
)
|
5426
|
+
Image.fromarray(img).save(fname, format=ftype.upper(), dpi=(dpi, dpi))
|
5327
5427
|
elif img.shape[2] == 4:
|
5328
5428
|
# RGBA image
|
5329
|
-
img = cv2.cvtColor(
|
5330
|
-
|
5331
|
-
) # Convert BGRA to RGBA
|
5332
|
-
Image.fromarray(img).save(
|
5333
|
-
fname, format=ftype.upper(), dpi=(dpi, dpi)
|
5334
|
-
)
|
5429
|
+
img = cv2.cvtColor(img, cv2.COLOR_BGRA2RGBA) # Convert BGRA to RGBA
|
5430
|
+
Image.fromarray(img).save(fname, format=ftype.upper(), dpi=(dpi, dpi))
|
5335
5431
|
else:
|
5336
|
-
raise ValueError(
|
5337
|
-
"Unexpected number of channels in the image array."
|
5338
|
-
)
|
5432
|
+
raise ValueError("Unexpected number of channels in the image array.")
|
5339
5433
|
else:
|
5340
|
-
raise ValueError(
|
5341
|
-
"Image array has an unexpected number of dimensions."
|
5342
|
-
)
|
5434
|
+
raise ValueError("Image array has an unexpected number of dimensions.")
|
5343
5435
|
else:
|
5344
|
-
plt.savefig(
|
5345
|
-
|
5346
|
-
|
5347
|
-
dpi=dpi,
|
5348
|
-
bbox_inches="tight",
|
5349
|
-
transparent=True,
|
5350
|
-
pad_inches=0,
|
5351
|
-
)
|
5352
|
-
elif ftype.lower() == "emf":
|
5353
|
-
plt.savefig(fname, format="emf", dpi=dpi, bbox_inches="tight", pad_inches=0)
|
5354
|
-
elif ftype.lower() == "fig":
|
5355
|
-
plt.savefig(fname, format="pdf", bbox_inches="tight", dpi=dpi, pad_inches=0)
|
5356
|
-
|
5436
|
+
plt.savefig(fname,format=ftype.lower(),dpi=dpi,pad_inches=pad_inches,bbox_inches=bbox_inches,facecolor=facecolor,edgecolor=edgecolor)
|
5437
|
+
elif ftype.lower() in ["emf","pdf","fig"]:
|
5438
|
+
plt.savefig(fname,format=ftype.lower(),dpi=dpi,pad_inches=pad_inches,bbox_inches=bbox_inches,facecolor=facecolor,edgecolor=edgecolor)
|
5357
5439
|
elif ftype.lower() == "ico":
|
5358
5440
|
# Ensure the image is in a format that can be saved as an icon (e.g., 32x32, 64x64, etc.)
|
5359
5441
|
if img is None: # If no image is provided, use the matplotlib figure
|
5360
|
-
img = plt.figure()
|
5361
|
-
|
5442
|
+
img = plt.figure()
|
5443
|
+
print(fname)
|
5444
|
+
img.savefig(fname,
|
5445
|
+
format="png",
|
5446
|
+
dpi=dpi,
|
5447
|
+
pad_inches=pad_inches,
|
5448
|
+
bbox_inches=bbox_inches,
|
5449
|
+
facecolor=facecolor,
|
5450
|
+
edgecolor=edgecolor )
|
5362
5451
|
img = Image.open(fname) # Load the saved figure image
|
5363
5452
|
|
5364
5453
|
# Resize the image to typical icon sizes and save it as .ico
|
5365
5454
|
icon_sizes = [(32, 32), (64, 64), (128, 128), (256, 256)]
|
5366
|
-
img = img.convert("RGBA")
|
5455
|
+
img = img.convert("RGBA")
|
5367
5456
|
img.save(fname, format="ICO", sizes=icon_sizes)
|
5368
5457
|
print(f"Icon saved @: {fname} with sizes: {icon_sizes}")
|
5369
|
-
print(f"\
|
5458
|
+
print(f"\n✅ Saved @: dpi={dpi}\n{fname}")
|
5370
5459
|
|
5371
5460
|
|
5372
5461
|
def is_str_color(s):
|
@@ -6772,39 +6861,39 @@ def finfo(fpath):
|
|
6772
6861
|
|
6773
6862
|
|
6774
6863
|
# ! format excel file
|
6775
|
-
def hex2argb(hex_color):
|
6776
|
-
"""
|
6777
|
-
Convert a hex color code to aARGB format required by openpyxl.
|
6778
6864
|
|
6779
|
-
:param hex_color: A hex color code in the format #RRGGBB, RRGGBB, or aARRGGBB.
|
6780
|
-
:return: A hex color code in the format aARRGGBB.
|
6781
6865
|
|
6782
|
-
|
6783
|
-
print(hex_to_argb("FFFF00")) # Outputs: FFFFFF00
|
6784
|
-
print(hex_to_argb("#DF4245")) # Outputs: FFFFFF00
|
6785
|
-
print(hex_to_argb("FF00FF00")) # Outputs: FF00FF00 (already in aARGB format)
|
6866
|
+
def hex2argb(color):
|
6786
6867
|
"""
|
6787
|
-
|
6788
|
-
if hex_color.startswith("#"):
|
6789
|
-
hex_color = hex_color[1:]
|
6868
|
+
Convert a color name or hex code to aARGB format required by openpyxl.
|
6790
6869
|
|
6791
|
-
|
6792
|
-
|
6793
|
-
return hex_color
|
6870
|
+
:param color: A color in the format: 'blue', '#RRGGBB', 'RRGGBB', 'aARRGGBB'
|
6871
|
+
:return: A hex color code in the format aARRGGBB.
|
6794
6872
|
|
6795
|
-
|
6796
|
-
|
6797
|
-
|
6798
|
-
|
6799
|
-
|
6800
|
-
|
6801
|
-
|
6802
|
-
|
6803
|
-
|
6804
|
-
|
6805
|
-
|
6806
|
-
|
6807
|
-
)
|
6873
|
+
Example:
|
6874
|
+
print(hex2argb("blue")) # Output: FF0000FF
|
6875
|
+
print(hex2argb("FFFF00")) # Output: FFFFFF00
|
6876
|
+
print(hex2argb("#DF4245")) # Output: FFDf4245
|
6877
|
+
print(hex2argb("FF00FF00")) # Output: FF00FF00 (already in aARGB format)
|
6878
|
+
"""
|
6879
|
+
import matplotlib.colors as mcolors
|
6880
|
+
import re
|
6881
|
+
color = color.lower().replace(" ", "") # 'light blue'
|
6882
|
+
# Convert color name (e.g., "blue") to hex
|
6883
|
+
if color.lower() in mcolors.CSS4_COLORS:
|
6884
|
+
color = mcolors.CSS4_COLORS[color.lower()].lstrip("#")
|
6885
|
+
color = color.lstrip("#").upper()# Remove '#' if present
|
6886
|
+
|
6887
|
+
# Validate hex format
|
6888
|
+
if not re.fullmatch(r"[A-F0-9]{6,8}", color):
|
6889
|
+
raise ValueError(f"格式错误❌: {color}, 应该使用 RRGGBB, #RRGGBB, or aARRGGBB format.")
|
6890
|
+
|
6891
|
+
# If already in aARRGGBB format (8 chars), return as is
|
6892
|
+
if len(color) == 8:
|
6893
|
+
return color
|
6894
|
+
|
6895
|
+
# If in RRGGBB format, add FF (full opacity) as alpha
|
6896
|
+
return f"FF{color}"
|
6808
6897
|
|
6809
6898
|
def extract_kwargs(func):
|
6810
6899
|
import inspect
|
@@ -6975,7 +7064,7 @@ def format_excel(
|
|
6975
7064
|
from openpyxl.worksheet.datavalidation import DataValidation
|
6976
7065
|
from openpyxl.comments import Comment
|
6977
7066
|
from openpyxl.formatting.rule import ColorScaleRule, DataBarRule, IconSetRule,IconSet
|
6978
|
-
|
7067
|
+
from openpyxl.utils import get_column_letter
|
6979
7068
|
def convert_indices_to_range(row_slice, col_slice):
|
6980
7069
|
"""Convert numerical row and column slices to Excel-style range strings."""
|
6981
7070
|
start_row = row_slice.start + 1
|
@@ -7000,9 +7089,17 @@ def format_excel(
|
|
7000
7089
|
sheet_name : str
|
7001
7090
|
The name of the sheet to style.
|
7002
7091
|
conditions : dict
|
7003
|
-
Dictionary defining conditions for text coloring.
|
7092
|
+
Dictionary defining conditions for text or background coloring.
|
7093
|
+
Example:
|
7094
|
+
{
|
7095
|
+
">10": "#FF0000", # Red if value is greater than 10
|
7096
|
+
"contains:Error": "#FFFF00", # Yellow if text contains 'Error'
|
7097
|
+
"startswith:Warn": "#FFA500" # Orange if text starts with 'Warn'
|
7098
|
+
}
|
7004
7099
|
cell_idx : tuple, optional
|
7005
7100
|
A tuple of slices defining the selected row and column range (only for DataFrame).
|
7101
|
+
where : str, default="text"
|
7102
|
+
"text" -> Apply color to text, "bg" -> Apply color to background.
|
7006
7103
|
|
7007
7104
|
Returns:
|
7008
7105
|
openpyxl.workbook.workbook.Workbook
|
@@ -7010,14 +7107,24 @@ def format_excel(
|
|
7010
7107
|
"""
|
7011
7108
|
def evaluate_condition(value, condition):
|
7012
7109
|
"""Evaluate the condition dynamically."""
|
7110
|
+
if not isinstance(conditions, dict):
|
7111
|
+
raise ValueError(f"condition必须是dict格式:e.g., {'x>=20':'#DD0531', 'startswith:Available':'#DD0531'}")
|
7013
7112
|
try:
|
7014
7113
|
if "x" in condition and re.search(r"[<>=!]=*", condition):
|
7015
7114
|
expr = condition.replace("x", str(value))
|
7115
|
+
return eval(expr)
|
7116
|
+
elif condition.startswith("startswith:") or condition.startswith("startwith:"):
|
7117
|
+
return value.startswith(condition.split(":", 1)[1])
|
7118
|
+
elif condition.startswith("endswith:") or condition.startswith("endwith:"):
|
7119
|
+
return value.endswith(condition.split(":", 1)[1])
|
7120
|
+
elif condition.startswith("contains:") or condition.startswith("contain:") or condition.startswith("include:"):
|
7121
|
+
return condition.split(":", 1)[1] in value
|
7122
|
+
elif condition.startswith("matches:") or condition.startswith("match:"):
|
7123
|
+
return re.search(condition.split(":", 1)[1], value) is not None
|
7016
7124
|
else:
|
7017
7125
|
expr = condition
|
7018
|
-
return
|
7019
|
-
except Exception as e:
|
7020
|
-
# print(f"Error evaluating condition {condition} for value {value}: {e}")
|
7126
|
+
return False
|
7127
|
+
except Exception as e:
|
7021
7128
|
return False
|
7022
7129
|
|
7023
7130
|
def apply_condition_to_cell_text_color(cell, value):
|
@@ -7446,12 +7553,12 @@ def format_excel(
|
|
7446
7553
|
kwargs.pop("sheet_name", 0) # 更好地跟df.to_excel结合使用
|
7447
7554
|
# 只有openpyxl才支持 append
|
7448
7555
|
mode = strcmp(kwargs.get("mode", "a"), ["a", "w","auto"])[0]
|
7449
|
-
print(f'mode="{mode}"')
|
7556
|
+
# print(f'mode="{mode}"')
|
7450
7557
|
kwargs.pop("mode", None)
|
7451
7558
|
engine = strcmp(kwargs.get("engine", "openpyxl"), ["xlsxwriter", "openpyxl"])[0]
|
7452
7559
|
# corr engine
|
7453
7560
|
engine="openpyxl" if mode=="a" else "xlsxwriter"
|
7454
|
-
print(f'engine="{engine}"')
|
7561
|
+
# print(f'engine="{engine}"')
|
7455
7562
|
if_sheet_exists=kwargs.get("if_sheet_exists","replace")
|
7456
7563
|
# 通常是不需要保存index的
|
7457
7564
|
index = kwargs.get("index", False)
|
@@ -7478,11 +7585,7 @@ def format_excel(
|
|
7478
7585
|
with pd.ExcelWriter(filename, mode="a", engine=engine, if_sheet_exists=if_sheet_exists) as writer:
|
7479
7586
|
for ws in df.worksheets: # Iterate through worksheets in the input workbook
|
7480
7587
|
ws_df = pd.DataFrame(ws.values)
|
7481
|
-
ws_df.to_excel(writer,
|
7482
|
-
sheet_name=sheet_name,
|
7483
|
-
index=index,
|
7484
|
-
header=header,
|
7485
|
-
**kwargs)
|
7588
|
+
ws_df.to_excel(writer,sheet_name=sheet_name,index=index,header=header,**kwargs)
|
7486
7589
|
# 重新打开刚更新过的数据
|
7487
7590
|
wb = load_workbook(filename)
|
7488
7591
|
if sheet_name in wb.sheetnames:
|
@@ -8008,21 +8111,20 @@ def format_excel(
|
|
8008
8111
|
pil_img=img_path = None
|
8009
8112
|
if isinstance(img_data, dict):
|
8010
8113
|
if "path" in img_data:
|
8011
|
-
|
8012
|
-
img_ = drawing.image.Image(img_path)
|
8114
|
+
img_ = drawing.image.Image(img_data["path"])# File path
|
8013
8115
|
elif "image" in img_data:
|
8014
|
-
|
8116
|
+
img_ = drawing.image.Image(img_data["image"])# PIL Image object
|
8015
8117
|
elif "array" in img_data:
|
8016
|
-
|
8118
|
+
img_ = drawing.image.Image(Image.fromarray(img_data["array"]))# Convert NumPy array to PIL Image
|
8017
8119
|
|
8018
8120
|
img_width = img_data.get("width", None)
|
8019
8121
|
img_height = img_data.get("height", None)
|
8020
8122
|
elif isinstance(img_data, str):
|
8021
|
-
|
8123
|
+
img_ = drawing.image.Image(img_data)# Direct file path
|
8022
8124
|
elif isinstance(img_data, (PIL.Image.Image,PIL.PngImagePlugin.PngImageFile)):
|
8023
|
-
|
8125
|
+
img_ = drawing.image.Image(img_data)# Direct PIL Image object
|
8024
8126
|
elif isinstance(img_data, np.ndarray):
|
8025
|
-
|
8127
|
+
img_ = drawing.image.Image(Image.fromarray(img_data))# Convert NumPy array to PIL Image
|
8026
8128
|
elif pil_img:
|
8027
8129
|
img_ = drawing.image.Image(pil_img)
|
8028
8130
|
|
@@ -8216,7 +8318,89 @@ def _df_outlier(
|
|
8216
8318
|
|
8217
8319
|
return processed_data
|
8218
8320
|
|
8321
|
+
def df_group(
|
8322
|
+
data: pd.DataFrame,
|
8323
|
+
columns: Union[str, list, None] = None,
|
8324
|
+
by: str = None,
|
8325
|
+
param: Dict[str, Any] = None,
|
8326
|
+
sep: Union[str, list] = [", ",","],
|
8327
|
+
dropna: bool = True,
|
8328
|
+
unique: bool = False,
|
8329
|
+
astype: type = str,
|
8330
|
+
merge: List[str] = None,
|
8331
|
+
merge_symbo_column:str=' & ',
|
8332
|
+
merge_symbo_cell:str='[]',# ["{}","()","[]"]
|
8333
|
+
) -> pd.DataFrame:
|
8334
|
+
"""
|
8335
|
+
Groups a dataframe based on a specified column and applies aggregation functions dynamically.
|
8336
|
+
|
8337
|
+
Parameters:
|
8338
|
+
data (pd.DataFrame): The dataframe to be grouped.
|
8339
|
+
columns (Union[str, list, None]): Columns to select; if None, all columns are selected.
|
8340
|
+
by (str): The column name to group by.
|
8341
|
+
param (dict): A dictionary specifying aggregation rules.
|
8342
|
+
sep (Union[str, list]): Separator for concatenated values. when sep is a list, then sep[0] used for general, sep[1] used in the merging
|
8343
|
+
dropna (bool): Whether to drop NaN values before aggregation.
|
8344
|
+
unique (bool): Whether to apply uniqueness before concatenation.
|
8345
|
+
astype (type): Data type to cast values before aggregation.
|
8346
|
+
merge (List[str]): List of columns to merge into a single paired column.
|
8347
|
+
merge_symbo_column:str: indicate in the columns, default ("&")
|
8348
|
+
merge_symbo_cell:str=default: '{}' or can select from ["{}","()","[]"]
|
8349
|
+
|
8350
|
+
Usage:
|
8351
|
+
data = pd.DataFrame({
|
8352
|
+
"Cage Tag": [1, 1, 2, 2, 3],
|
8353
|
+
"Physical Tag": ["A1", "A2", "B1", "B2", "C1"],
|
8354
|
+
"Sex": ["M", "F", "M", "M", "F"],
|
8355
|
+
"Date of Birth": ["2021-06-01", "2021-06-02", "2021-07-01", "2021-07-02", "2021-08-01"],
|
8356
|
+
"Age": [34, 35, 30, 31, 29],
|
8357
|
+
"State": ["Mating", "Resting", "Mating", "Resting", "Mating"],
|
8358
|
+
"Owner": ["Dr. Smith", "Dr. Smith", "Dr. Brown", "Dr. Brown", "Dr. Lee"],
|
8359
|
+
})
|
8360
|
+
display(data)
|
8361
|
+
result = df_group(data,
|
8362
|
+
# columns=["Sex", "Date of Birth", "Age", "State"],
|
8363
|
+
by="Cage Tag",
|
8364
|
+
merge=["Age", "State"],
|
8365
|
+
merge_symbo_column="|",
|
8366
|
+
# astype=str
|
8367
|
+
# sep=[',', '_'],
|
8368
|
+
merge_symbo_cell=None
|
8369
|
+
)
|
8370
|
+
result
|
8371
|
+
|
8372
|
+
|
8373
|
+
"""
|
8374
|
+
if param is None:
|
8375
|
+
param = {}
|
8376
|
+
if columns is None:
|
8377
|
+
columns = data.columns.tolist()
|
8378
|
+
elif isinstance(columns, str):
|
8379
|
+
columns = [columns]
|
8380
|
+
if not isinstance(sep, list):
|
8381
|
+
sep = [sep]
|
8382
|
+
sep.extend(sep) if len(sep)==1 else None
|
8219
8383
|
|
8384
|
+
# Merge specified columns into a single column
|
8385
|
+
if merge:
|
8386
|
+
merge_col_name = merge_symbo_column.join(merge)
|
8387
|
+
# data[merge_col_name] = data[merge].apply(lambda row: tuple(map(astype, row.dropna() if dropna else row)), axis=1)
|
8388
|
+
if merge_symbo_cell is None:
|
8389
|
+
data[merge_col_name] = data[merge].apply(lambda row: f"{sep[1].join(map(astype, row.dropna()))}" if dropna else f"{sep[1].join(map(astype, row))}", axis=1)
|
8390
|
+
elif len(merge_symbo_cell)==2:
|
8391
|
+
data[merge_col_name] = data[merge].apply(lambda row: f"{merge_symbo_cell[0]}{sep[1].join(map(astype, row.dropna()))}{merge_symbo_cell[1]}" if dropna else f"{merge_symbo_cell[0]}{sep[1].join(map(astype, row))}{merge_symbo_cell[1]}", axis=1)
|
8392
|
+
else:
|
8393
|
+
data[merge_col_name] = data[merge].apply(lambda row: f"[{sep[1].join(map(astype, row.dropna()))}]" if dropna else f"[{sep[1].join(map(astype, row))}]", axis=1)
|
8394
|
+
columns.append(merge_col_name)
|
8395
|
+
|
8396
|
+
default_aggregations = {
|
8397
|
+
col: (lambda x: sep[0].join(map(astype, x.dropna().unique() if unique else x.dropna())) if dropna else sep[0].join(map(astype, x.unique() if unique else x)))
|
8398
|
+
for col in columns if col != by and (merge is None or col not in merge)
|
8399
|
+
}
|
8400
|
+
aggregation_rules = {**default_aggregations, **param}
|
8401
|
+
|
8402
|
+
grouped_df = data.groupby(by).agg(aggregation_rules).reset_index()
|
8403
|
+
return grouped_df
|
8220
8404
|
def df_outlier(
|
8221
8405
|
data,
|
8222
8406
|
columns=None,
|
@@ -12506,3 +12690,83 @@ def py2installer(
|
|
12506
12690
|
raise
|
12507
12691
|
|
12508
12692
|
print("\nPackaging complete. Check the output directory for the executable.")
|
12693
|
+
|
12694
|
+
|
12695
|
+
def set_theme(
|
12696
|
+
context="paper",
|
12697
|
+
style="whitegrid",
|
12698
|
+
palette="deep",
|
12699
|
+
font="sans-serif",
|
12700
|
+
font_scale=1.0,
|
12701
|
+
color_codes=True,
|
12702
|
+
grid_alpha=0.5,
|
12703
|
+
grid_linewidth=0.8,
|
12704
|
+
grid_linestyle="--",
|
12705
|
+
tick_direction="out",
|
12706
|
+
# tick_length=4,
|
12707
|
+
spine_visibility=False,
|
12708
|
+
# figsize=(8, 6),
|
12709
|
+
# linewidth=2,
|
12710
|
+
dpi=100,
|
12711
|
+
rc=None,
|
12712
|
+
):
|
12713
|
+
"""
|
12714
|
+
to configure Seaborn theme with maximum flexibility.
|
12715
|
+
|
12716
|
+
# Example Usage
|
12717
|
+
set_sns_theme(font_scale=1.2, grid_alpha=0.8, tick_direction="in", dpi=150)
|
12718
|
+
|
12719
|
+
Parameters:
|
12720
|
+
- context: Plotting context ('notebook', 'paper', 'talk', 'poster')
|
12721
|
+
- style: Style of the plot ('darkgrid', 'whitegrid', 'dark', 'white', 'ticks')
|
12722
|
+
- palette: Color palette (string or list of colors)
|
12723
|
+
- font: Font family ('sans-serif', 'serif', etc.)
|
12724
|
+
- font_scale: Scaling factor for fonts
|
12725
|
+
- color_codes: Boolean, whether to use seaborn color codes
|
12726
|
+
- grid_alpha: Opacity of the grid lines
|
12727
|
+
- grid_linewidth: Thickness of grid lines
|
12728
|
+
- grid_linestyle: Style of grid lines ('-', '--', '-.', ':')
|
12729
|
+
- tick_direction: Direction of ticks ('in', 'out', 'inout')
|
12730
|
+
- tick_length: Length of ticks
|
12731
|
+
- spine_visibility: Whether to show plot spines (True/False)
|
12732
|
+
- figsize: Default figure size as tuple (width, height)
|
12733
|
+
- linewidth: Default line width for plots
|
12734
|
+
- dpi: Resolution of the figure
|
12735
|
+
- rc: Dictionary of additional rc settings
|
12736
|
+
"""
|
12737
|
+
import seaborn as sns
|
12738
|
+
import matplotlib.pyplot as plt
|
12739
|
+
|
12740
|
+
# Define additional rc parameters for fine-tuning
|
12741
|
+
rc_params = {
|
12742
|
+
# "axes.grid": True,
|
12743
|
+
"grid.alpha": grid_alpha,
|
12744
|
+
"grid.linewidth": grid_linewidth,
|
12745
|
+
"grid.linestyle": grid_linestyle,
|
12746
|
+
"xtick.direction": tick_direction,
|
12747
|
+
"ytick.direction": tick_direction,
|
12748
|
+
# "xtick.major.size": tick_length,
|
12749
|
+
# "ytick.major.size": tick_length,
|
12750
|
+
# "axes.linewidth": linewidth,
|
12751
|
+
# "figure.figsize": figsize,
|
12752
|
+
"figure.dpi": dpi,
|
12753
|
+
"axes.spines.top": spine_visibility,
|
12754
|
+
"axes.spines.right": spine_visibility,
|
12755
|
+
"axes.spines.bottom": spine_visibility,
|
12756
|
+
"axes.spines.left": spine_visibility,
|
12757
|
+
}
|
12758
|
+
|
12759
|
+
# Merge user-provided rc settings
|
12760
|
+
if rc:
|
12761
|
+
rc_params.update(rc)
|
12762
|
+
|
12763
|
+
# Apply the theme settings
|
12764
|
+
sns.set_theme(
|
12765
|
+
context=context,
|
12766
|
+
style=style,
|
12767
|
+
palette=palette,
|
12768
|
+
font=font,
|
12769
|
+
font_scale=font_scale,
|
12770
|
+
color_codes=color_codes,
|
12771
|
+
rc=rc_params,
|
12772
|
+
)
|