py2ls 0.2.5.8__tar.gz → 0.2.5.10__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.
Files changed (259) hide show
  1. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/PKG-INFO +1 -1
  2. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/ips.py +349 -90
  3. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/plot.py +65 -56
  4. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/pyproject.toml +1 -1
  5. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/README.md +0 -0
  6. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.DS_Store +0 -0
  7. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/.DS_Store +0 -0
  8. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/COMMIT_EDITMSG +0 -0
  9. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/FETCH_HEAD +0 -0
  10. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/HEAD +0 -0
  11. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/config +0 -0
  12. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/description +0 -0
  13. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/hooks/applypatch-msg.sample +0 -0
  14. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/hooks/commit-msg.sample +0 -0
  15. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/hooks/fsmonitor-watchman.sample +0 -0
  16. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/hooks/post-update.sample +0 -0
  17. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/hooks/pre-applypatch.sample +0 -0
  18. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/hooks/pre-commit.sample +0 -0
  19. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/hooks/pre-merge-commit.sample +0 -0
  20. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/hooks/pre-push.sample +0 -0
  21. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/hooks/pre-rebase.sample +0 -0
  22. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/hooks/pre-receive.sample +0 -0
  23. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/hooks/prepare-commit-msg.sample +0 -0
  24. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/hooks/push-to-checkout.sample +0 -0
  25. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/hooks/update.sample +0 -0
  26. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/index +0 -0
  27. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/info/exclude +0 -0
  28. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/logs/HEAD +0 -0
  29. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/logs/refs/heads/main +0 -0
  30. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/logs/refs/remotes/origin/HEAD +0 -0
  31. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/logs/refs/remotes/origin/main +0 -0
  32. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/.DS_Store +0 -0
  33. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/01/d5bd8065e6860c0bd23ff9fa57161806a099e1 +0 -0
  34. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/09/08da26de58c114225ad81f484b80bf5d351b34 +0 -0
  35. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/0b/409e1bc918277010f5679b402d1d1dda53e15c +0 -0
  36. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/12/c2808a1b3a4d0892a4154dfba1e2ae3770fa73 +0 -0
  37. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/14/449a0e6ba4ea2f1a73acf63ef91c9c6193f9ed +0 -0
  38. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/15/a8e468aacfcb440e090020f36d0b985d45da23 +0 -0
  39. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/1a/b4585881a6a42889f01aa0cfe25fd5acfaf46f +0 -0
  40. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/1c/3f92adda34344bcbbbf9d409c79855ae2aaea8 +0 -0
  41. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/1c/9314c5f69b9390068a2a8616875d974849d71f +0 -0
  42. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/1d/fe9d9633b24ea560354f4f93d39c6e5f163ea0 +0 -0
  43. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/20/72c28e83f4347959d29f7b3a6c1fc3e4ee6b59 +0 -0
  44. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/24/6b368b986f758630c46dc02b7fa512b53422f7 +0 -0
  45. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/25/b796accd261b9135fd32a2c00785f68edf6c46 +0 -0
  46. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/27/aa6074f652bc6f7078f8647489d9ee8e24f0e2 +0 -0
  47. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/28/c2969d785c1b892c2a96b3f00eba63a59811b3 +0 -0
  48. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/2a/ae95d517d213b660bf4f65a4e0cfae7bb893eb +0 -0
  49. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/2a/fdf45791a26d42ccead35ace76a8f0b2a56561 +0 -0
  50. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/30/a2f8da47ee947811dc8d993f5a06a45de374f4 +0 -0
  51. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/32/fd627b62fad7cf3b2f9e34ab9777126a0987ad +0 -0
  52. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/34/9e31b6a3634cea102ce5588b98c11cc1738605 +0 -0
  53. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/34/b6f3a2ee84f39bed4eee57f2c0e0afb994feb1 +0 -0
  54. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/35/1a5f491ab97eee9d1ee699478d75a8bb5d3dc2 +0 -0
  55. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/36/b4a1b7403abc6c360f8fe2cb656ab945254971 +0 -0
  56. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/36/e56a361f526eafa59c5235a5c990bf288b5f9c +0 -0
  57. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/36/ef43e50009e59db11812c258846d9e38718173 +0 -0
  58. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/39/7ead045fbbcfb17c62019eb18fe21ed05dbee5 +0 -0
  59. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/39/b13be65125556784e44c7a1d9821703c7ab67e +0 -0
  60. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/3b/507acc7f23391644cc0b824b1e79fd2677a362 +0 -0
  61. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/3b/bd972aa7ad680858f8dfbd0f7fcd97756f0d6f +0 -0
  62. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/3c/bbe5f4173d165127b9ad96119f1ec24c306ffc +0 -0
  63. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/3d/9d10d27724657a436c65a6254bfd213d4b3562 +0 -0
  64. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/3f/d6561300938afbb3d11976cf9c8f29549280d9 +0 -0
  65. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/41/dcf4b3bf0460946b2da93776cf9e836d62178f +0 -0
  66. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/43/dbd49b2ee367c5434dd545e3b5795434f2ef0b +0 -0
  67. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/45/b1b6178bacbfc997811a998b5cc60c1ea7fac8 +0 -0
  68. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/47/6cbd5a7c5e35cddef2f8a38bdc4896d403b095 +0 -0
  69. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/48/a88fc5806305d0bb0755ee6801161b79696972 +0 -0
  70. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/4f/7afb40dff2153d857fc85748c2eecb85125042 +0 -0
  71. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/50/08ddfcf53c02e82d7eee2e57c38e5672ef89f6 +0 -0
  72. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/53/e0deb1cb4c2c606bced6e7f9a66b0fda60980d +0 -0
  73. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/56/e4e8b2d5545e0256090f45aa8fc42c5fe067d0 +0 -0
  74. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/57/63d0c52f5c9c69e89d514a1f96034947abe21a +0 -0
  75. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/57/bd1c0199483ab316235b094543b85edec6c35e +0 -0
  76. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/58/20a729045d4dc7e37ccaf8aa8eec126850afe2 +0 -0
  77. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/59/380c4c26bdcd4d9b71ae3e2e35f05b3f26c5ab +0 -0
  78. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/5a/192565abf89c9d765af846ce6d53a92b1ce7ad +0 -0
  79. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/60/f273eb1c412d916fa3f11318a7da7a9911b52a +0 -0
  80. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/61/570cec8c061abe74121f27f5face6c69b98f99 +0 -0
  81. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/62/4488173ed2c8936fa5cea3cf5dd3f26a30b86e +0 -0
  82. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/62/7c81b23b4e56e87b042b650b0103653cc9e34a +0 -0
  83. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/62/d90ccf8cbefdc2e4fd475e7c6f4f76e9fdf801 +0 -0
  84. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/63/100154b27846e8010e55b6bf4b3d7762c14c5f +0 -0
  85. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/64/27a4edff08f93d98f511418423f09f2ab90bcd +0 -0
  86. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/66/6227eeeba24073e63811e89f1449f3d958f183 +0 -0
  87. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/66/c998778721d424bd0aae80602dabbffa93af2e +0 -0
  88. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/68/6df3072c8b025fb18106ed2df505994ad062a9 +0 -0
  89. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/69/13c452ca319f7cbf6a0836dc10a5bb033c84e4 +0 -0
  90. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/6a/52e747a2b349b128d1490d9e896d2323818eb7 +0 -0
  91. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/6b/7fde264d93a7a0986d394c46c7650d0ce2ab92 +0 -0
  92. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/6c/cebb29b7f3f5b0c889f6dadbf9ff066554587d +0 -0
  93. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/6d/c2cdf4a84e538e5d4777486aeff87e42f41799 +0 -0
  94. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/6d/ee29dbdcc84edeeacede105110446f3ccac963 +0 -0
  95. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/71/36b2074a2754be8b58127d82250e5b37e3c373 +0 -0
  96. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/72/245a05b0966011cb381e6b32b0465000e969ab +0 -0
  97. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/72/e4179337639859678ddaecf38b16f33aaec8e1 +0 -0
  98. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/78/063f4c863fc371ec0313303c0a81283b35d9b6 +0 -0
  99. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/78/3d4167bc95c9d2175e0df03ef1c1c880ba75ab +0 -0
  100. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/79/7ae089b2212a937840e215276005ce76881307 +0 -0
  101. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/7e/5956c806b5edc344d46dab599dec337891ba1f +0 -0
  102. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/81/8f26b7bf042269729020cf944fc362d66ba27e +0 -0
  103. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/82/70b319ce4046854fbe7dc41054b6c2d112dab2 +0 -0
  104. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/84/59071b722a255b774a80b27746033f8141ab39 +0 -0
  105. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/85/aee46f478e9afdb84d50a05242c53b04ed2e21 +0 -0
  106. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/86/e288b46f8fe179907e4413f665aeb5053fddb1 +0 -0
  107. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/87/ef1fc3f7f1ddc4d0ab9b3e65381ce9f3388621 +0 -0
  108. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/8b/84f56978e1de8f2ae82abce5f8b3e182d365cd +0 -0
  109. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/8e/55a7d2b96184030211f20c9b9af201eefcac82 +0 -0
  110. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/91/c69ad88fe0ba94aa7859fb5f7edac5e6f1a3f7 +0 -0
  111. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/94/74152b4b463d70ae5ad07f0c658be3e296026b +0 -0
  112. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/94/f7dbe88e80c4205a901b71eb8f181974376bba +0 -0
  113. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/97/1aef09ea939f46b60b9646f8d524c78a9220f4 +0 -0
  114. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/9b/ec5ee2236ee2d5532c36bfd132e23c58fdb69c +0 -0
  115. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/9d/0df52899fe95279059286d9c0ec42287edc168 +0 -0
  116. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/a1/5389729850729fc7bd78a54f26fce77f30be12 +0 -0
  117. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/a1/906da89d1174f74867800c74c43af36253bd5e +0 -0
  118. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/a4/63fdd23e5efd713db8a71f316f3a1c7bd60916 +0 -0
  119. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/a5/ec8f74642fbba27f7ea78c53b372ae0c7dedce +0 -0
  120. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/a7/3e13eafee65c5b8d73ad2d3ea46d0eee82f0d3 +0 -0
  121. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/b0/56be4be89ba6b76949dd641df45bb7036050c8 +0 -0
  122. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/b0/9cd7856d58590578ee1a4f3ad45d1310a97f87 +0 -0
  123. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/b2/18e6a0f0f1c4df8cdefa9852058348abc713b7 +0 -0
  124. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/b3/4f7f271c6d6105e35a6556ffda71d03afe8c96 +0 -0
  125. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/b3/69579064bde9de9a19d114fc33e4e48cc8c0e4 +0 -0
  126. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/b5/61831c7dce8ea51e7ee6b6fa35745f14d8242d +0 -0
  127. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/b7/2c9e75ab7d0afe594664650aa8f6c772f5ac64 +0 -0
  128. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/bb/81ccc0513f18fc160b54a82861e9a80d23f4f6 +0 -0
  129. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/bb/934eb33bc1a8b85630bf680caffd99560c1b8f +0 -0
  130. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/bf/67907e337021ebff434e02b19b30a741c144af +0 -0
  131. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/bf/b54d65922ce1dfda1aaa014913a54e7172d0bc +0 -0
  132. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/c1/20fc812b9ad311c34a3608512d6a9d976bb48e +0 -0
  133. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/c1/397c6ed72c4e20ef6b9ab83163e9a6baba5b45 +0 -0
  134. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/c4/cba65f1163661999ee4b8ed23342b63bc1300c +0 -0
  135. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/c6/7f17e5707313600efcb85e9a3fedea35dba591 +0 -0
  136. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/c6/f32aced880bd165a251cb52b26b0c1107e2141 +0 -0
  137. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/cc/45df1d317a2eb63ff1ff3a5f3b4a9f98fd92b5 +0 -0
  138. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/cd/822b3574a88ebdd1ed82fd6983f37e626d52b4 +0 -0
  139. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/cf/0c0d9c6fb09473aaeb7f7e2edbd770c3f2ef3d +0 -0
  140. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/d2/992df305f4b56a466a2f221aeb182ddd20f418 +0 -0
  141. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/d6/39e8af592cd75a318d8affddd1bcc70c2095f2 +0 -0
  142. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/d6/9ab1c4aadf279936dd778e8346ba60f74705b6 +0 -0
  143. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/d8/4688b54c0040a30976b3a6540bc47adf7ce680 +0 -0
  144. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/d9/005f2cc7fc4e65f14ed5518276007c08cf2fd0 +0 -0
  145. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/d9/c2403fd166ce791b4e9d0c6792ed8342c71fcd +0 -0
  146. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/d9/dfa5aee51e92a541b707e8e7baea6f06deff98 +0 -0
  147. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/db/141dbaa93594df2a8156182f361ee4db829359 +0 -0
  148. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/db/3f2cd643292057936230b95cf7ec3046affe11 +0 -0
  149. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/db/ffa8ea7bda721d0cee7b9e4ce5b2ef927733ff +0 -0
  150. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/dc/c2bdbafb3296e09d9ee4955cfa55d275825f94 +0 -0
  151. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/dc/cdbd4266765d840be2ae35ab1752a0fa312c16 +0 -0
  152. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/dd/87fb5f606fe380d81e6fe3a2c98f9f99e3e09b +0 -0
  153. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/de/214c626ac2dd2685bfaa0bc0fc20f528d014d7 +0 -0
  154. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/df/e0770424b2a19faf507a501ebfc23be8f54e7b +0 -0
  155. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/e2/f2f8f4c25e62a297fc55f36acc6b01cfbab76f +0 -0
  156. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/e3/1356f90ea6dd0577b5e0b40b206319adcbf085 +0 -0
  157. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/e3/5a4dafc50850cacac7bf76c56db2715cbda2c4 +0 -0
  158. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/e4/6c715352db9fe3c887a635f1916df4ca1f4ff9 +0 -0
  159. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/e5/0580a0bd1e1b3d29f834382b80fceb61d5cf0c +0 -0
  160. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/e9/391ffe371f1cc43b42ef09b705d9c767c2e14f +0 -0
  161. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/ea/3a18cc75e53792744ef754e05d3f4481768c13 +0 -0
  162. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/ec/40fd8bf8e4c342534a9fc020289e402ba6bc9d +0 -0
  163. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/ec/d980279432b13f0374b90ca439a6329cdece0f +0 -0
  164. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/ee/cee64eacaff022dcdc509c0c2b1da492f21060 +0 -0
  165. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/f1/e50757fddc28b445545dc7e2759b54cdd0f42e +0 -0
  166. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/f4/b64d3107b39e3ad6f540c6607004ea34e6c024 +0 -0
  167. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/f4/ba7f815b886797b73fede071d86e0c134d2bc7 +0 -0
  168. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/f5/61c3c1bf1c9ea9c9d1f556a7be2869f71f3bdf +0 -0
  169. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/f6/44a8ff56fa035105fc517cbb1ac46c3d8e349a +0 -0
  170. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/f7/c98ba5c2f903e603b1f5e63d49fbc8a43815cc +0 -0
  171. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/f9/045a08e96eb76848fc4d68e3e3e687cca39a2d +0 -0
  172. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/fa/147e6bb78a2e8db241d231295fd7f1ed061af8 +0 -0
  173. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/objects/fc/292e793ecfd42240ac43be407023bd731fa9e7 +0 -0
  174. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/refs/.DS_Store +0 -0
  175. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/refs/heads/main +0 -0
  176. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/refs/remotes/origin/HEAD +0 -0
  177. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.git/refs/remotes/origin/main +0 -0
  178. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.gitattributes +0 -0
  179. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/.gitignore +0 -0
  180. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/LICENSE +0 -0
  181. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/README.md +0 -0
  182. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/__init__.py +0 -0
  183. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/batman.py +0 -0
  184. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/bio.py +0 -0
  185. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/brain_atlas.py +0 -0
  186. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/chat.py +0 -0
  187. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/corr.py +0 -0
  188. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/correlators.py +0 -0
  189. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/data/.DS_Store +0 -0
  190. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/data/db2ls_sql_chtsht.json +0 -0
  191. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/data/docs_links.json +0 -0
  192. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/data/email/email_html_template.html +0 -0
  193. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/data/hyper_param_autogluon_zeroshot2024.json +0 -0
  194. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/data/hyper_param_tabrepo_2024.py +0 -0
  195. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/data/lang_code_iso639.json +0 -0
  196. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/data/mygenes_fields_241022.txt +0 -0
  197. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/data/sns_info.json +0 -0
  198. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/data/styles/.DS_Store +0 -0
  199. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/data/styles/example/.DS_Store +0 -0
  200. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/data/styles/example/style1.pdf +0 -0
  201. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/data/styles/example/style2.pdf +0 -0
  202. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/data/styles/example/style3.pdf +0 -0
  203. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/data/styles/example/style4.pdf +0 -0
  204. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/data/styles/example/style5.pdf +0 -0
  205. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/data/styles/example/style6.pdf +0 -0
  206. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/data/styles/example/style7.pdf +0 -0
  207. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/data/styles/example/style8.pdf +0 -0
  208. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/data/styles/example/style9.pdf +0 -0
  209. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/data/styles/style1.json +0 -0
  210. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/data/styles/style10.json +0 -0
  211. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/data/styles/style11.json +0 -0
  212. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/data/styles/style12.json +0 -0
  213. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/data/styles/style2.json +0 -0
  214. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/data/styles/style3.json +0 -0
  215. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/data/styles/style4.json +0 -0
  216. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/data/styles/style5.json +0 -0
  217. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/data/styles/style6.json +0 -0
  218. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/data/styles/style7.json +0 -0
  219. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/data/styles/style8.json +0 -0
  220. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/data/styles/style9.json +0 -0
  221. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/data/styles/stylelib/.DS_Store +0 -0
  222. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/data/styles/stylelib/grid.mplstyle +0 -0
  223. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/data/styles/stylelib/high-contrast.mplstyle +0 -0
  224. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/data/styles/stylelib/high-vis.mplstyle +0 -0
  225. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/data/styles/stylelib/ieee.mplstyle +0 -0
  226. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/data/styles/stylelib/light.mplstyl +0 -0
  227. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/data/styles/stylelib/muted.mplstyle +0 -0
  228. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/data/styles/stylelib/nature-reviews-latex.mplstyle +0 -0
  229. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/data/styles/stylelib/nature-reviews.mplstyle +0 -0
  230. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/data/styles/stylelib/nature.mplstyle +0 -0
  231. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/data/styles/stylelib/no-latex.mplstyle +0 -0
  232. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/data/styles/stylelib/notebook.mplstyle +0 -0
  233. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/data/styles/stylelib/paper.mplstyle +0 -0
  234. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/data/styles/stylelib/retro.mplstyle +0 -0
  235. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/data/styles/stylelib/sans.mplstyle +0 -0
  236. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/data/styles/stylelib/scatter.mplstyle +0 -0
  237. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/data/styles/stylelib/science.mplstyle +0 -0
  238. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/data/styles/stylelib/std-colors.mplstyle +0 -0
  239. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/data/styles/stylelib/vibrant.mplstyle +0 -0
  240. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/data/tiles.csv +0 -0
  241. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/data/usages_pd.json +0 -0
  242. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/data/usages_sns.json +0 -0
  243. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/db2ls.py +0 -0
  244. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/doc.py +0 -0
  245. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/ec2ls.py +0 -0
  246. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/export_requirements.py +0 -0
  247. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/fetch_update.py +0 -0
  248. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/freqanalysis.py +0 -0
  249. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/ich2ls.py +0 -0
  250. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/ml2ls.py +0 -0
  251. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/mol.py +0 -0
  252. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/netfinder.py +0 -0
  253. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/nl2ls.py +0 -0
  254. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/ocr.py +0 -0
  255. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/setuptools-70.1.0-py3-none-any.whl +0 -0
  256. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/sleep_events_detectors.py +0 -0
  257. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/stats.py +0 -0
  258. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/translator.py +0 -0
  259. {py2ls-0.2.5.8 → py2ls-0.2.5.10}/py2ls/wb_detector.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: py2ls
3
- Version: 0.2.5.8
3
+ Version: 0.2.5.10
4
4
  Summary: py(thon)2(too)ls
5
5
  Author: Jianfeng
6
6
  Author-email: Jianfeng.Liu0413@gmail.com
@@ -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
 
@@ -3589,6 +3589,7 @@ def fload(fpath, kind=None, **kwargs):
3589
3589
 
3590
3590
  # https://github.com/eyurtsev/fcsparser
3591
3591
  meta, data = fcsparser.parse(fpath, reformat_meta=True)
3592
+ print("meta, data = fload(*.fcs)")
3592
3593
  return meta, data
3593
3594
 
3594
3595
  elif kind == "mplstyle":
@@ -5245,63 +5246,169 @@ def split_path(fpath):
5245
5246
  dir_ch = "".join(fpath.split(f_slash)[-1:])
5246
5247
  return dir_par, dir_ch
5247
5248
 
5249
+ from pathlib import Path
5250
+ import matplotlib.pyplot as plt
5251
+ from PIL import Image
5252
+ import numpy as np
5253
+ import cv2
5248
5254
 
5249
- def figsave(*args, dpi=300):
5250
- import matplotlib.pyplot as plt
5251
- from PIL import Image
5255
+ def figsave(*args, dpi=300, **kwargs):
5256
+ bbox_inches = kwargs.pop("bbox_inches", "tight")
5257
+ pad_inches = kwargs.pop("pad_inches", 0)
5258
+ facecolor = kwargs.pop("facecolor", "white")
5259
+ edgecolor = kwargs.pop("edgecolor", "auto")
5252
5260
 
5253
5261
  dir_save = None
5254
5262
  fname = None
5255
5263
  img = None
5256
- f_slash = "/" if "mac" in get_os().lower() else "\\"
5264
+
5257
5265
  for arg in args:
5258
5266
  if isinstance(arg, str):
5259
- if f_slash in arg:
5260
- dir_save = arg
5267
+ path = Path(arg)
5268
+ if path.suffix: # Has file extension
5269
+ fname = path.name
5270
+ dir_save = path.parent
5261
5271
  else:
5262
- fname = arg
5272
+ dir_save = path
5263
5273
  elif isinstance(arg, (Image.Image, np.ndarray)):
5264
- img = arg # Store the PIL image if provided
5274
+ img = arg # Store PIL image or numpy array
5265
5275
 
5266
- if dir_save is None:
5267
- dir_save = "./"
5276
+ # Set default save directory
5277
+ dir_save = Path(dir_save) if dir_save else Path(".")
5278
+ dir_save.mkdir(parents=True, exist_ok=True)
5279
+
5280
+ # Handle filename and extension
5281
+ if fname is None:
5282
+ fname = "figure"
5283
+ fname = dir_save / fname
5284
+ if fname.suffix == "":
5285
+ fname = fname.with_suffix(".pdf") # Default format
5268
5286
 
5269
- # dir_save=dir_save+f_slash if not dir_save.endswith(f_slash) else dir_save
5270
- dir_par = f_slash.join(dir_save.split(f_slash)[:-1])
5271
- dir_ch = "".join(dir_save.split(f_slash)[-1:])
5272
- if not dir_par.endswith(f_slash):
5273
- dir_par += f_slash
5287
+ ftype = fname.suffix.lstrip(".").lower()
5288
+
5289
+ # Save figure based on file type
5290
+ if ftype == "eps":
5291
+ plt.savefig(fname, format="eps", bbox_inches=bbox_inches)
5292
+ plt.savefig(fname.with_suffix(".pdf"), format="pdf", dpi=dpi,
5293
+ pad_inches=pad_inches, bbox_inches=bbox_inches,
5294
+ facecolor=facecolor, edgecolor=edgecolor)
5295
+ elif ftype == "pdf":
5296
+ plt.savefig(fname, format="pdf", dpi=dpi, pad_inches=pad_inches,
5297
+ bbox_inches=bbox_inches, facecolor=facecolor, edgecolor=edgecolor)
5298
+ elif ftype in ["jpg", "jpeg", "png", "tiff", "tif"]:
5299
+ if img is not None: # If an image is provided
5300
+ if isinstance(img, Image.Image):
5301
+ img = img.convert("RGB") if img.mode == "RGBA" else img
5302
+ img.save(fname, format=ftype.upper(), dpi=(dpi, dpi))
5303
+ elif isinstance(img, np.ndarray):
5304
+ if img.ndim == 2:
5305
+ Image.fromarray(img).save(fname, format=ftype.upper(), dpi=(dpi, dpi))
5306
+ elif img.ndim == 3:
5307
+ if img.shape[2] == 3:
5308
+ img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
5309
+ elif img.shape[2] == 4:
5310
+ img = cv2.cvtColor(img, cv2.COLOR_BGRA2RGBA)
5311
+ Image.fromarray(img).save(fname, format=ftype.upper(), dpi=(dpi, dpi))
5312
+ else:
5313
+ raise ValueError("Unexpected image dimensions.")
5314
+ else:
5315
+ plt.savefig(fname, format=ftype, dpi=dpi, pad_inches=pad_inches,
5316
+ bbox_inches=bbox_inches, facecolor=facecolor, edgecolor=edgecolor)
5317
+ elif ftype == "ico":
5318
+ if img is None:
5319
+ plt.savefig(fname, dpi=dpi, pad_inches=pad_inches,
5320
+ bbox_inches=bbox_inches, facecolor=facecolor, edgecolor=edgecolor)
5321
+ img = Image.open(fname)
5322
+ img = img.convert("RGBA")
5323
+ icon_sizes = [(32, 32), (64, 64), (128, 128), (256, 256)]
5324
+ img.save(fname, format="ICO", sizes=icon_sizes)
5325
+ print(f"Icon saved @: {fname} with sizes: {icon_sizes}")
5326
+ else:
5327
+ raise ValueError(f"Unsupported file format: {ftype}")
5328
+
5329
+ print(f"\nSaved @ {fname} (dpi={dpi})")
5330
+
5331
+ def figsave(*args, dpi=300, **kwargs):
5332
+ """
5333
+ Save a Matplotlib figure or image file in various formats.
5334
+
5335
+ This function automatically determines whether to save a Matplotlib figure
5336
+ or an image (PIL or NumPy array) and handles different file formats, including:
5337
+ - PDF, EPS, PNG, JPG, TIFF, ICO, EMF
5338
+
5339
+ Parameters:
5340
+ -----------
5341
+ *args : str, PIL.Image, np.ndarray
5342
+ - File path (directory and/or filename) to save the figure.
5343
+ - If an image is provided (PIL or NumPy), it will be saved accordingly.
5344
+
5345
+ dpi : int, optional (default=300)
5346
+ - Resolution (dots per inch) for saved figures.
5347
+
5348
+ **kwargs : dict
5349
+ - Additional keyword arguments for `matplotlib.pyplot.savefig()`, including:
5350
+ - bbox_inches (str, default="tight"): Bounding box for figure.
5351
+ - pad_inches (float, default=0): Padding around figure.
5352
+ - facecolor (str, default="white"): Background color.
5353
+ - edgecolor (str, default="auto"): Edge color.
5354
+
5355
+ Supported Formats:
5356
+ ------------------
5357
+ - Vector: `pdf`, `eps`, `emf`
5358
+ - Raster: `png`, `jpg`, `jpeg`, `tiff`, `tif`, `ico`
5359
+
5360
+ Example Usage:
5361
+ --------------
5362
+ >>> figsave("output_plot.pdf")
5363
+ >>> figsave("figs/plot.png", dpi=600)
5364
+ >>> figsave("./results/figure", format="pdf")
5365
+ >>> figsave("icons/logo.ico", image) # Save an image file as an icon
5366
+
5367
+ Returns:
5368
+ --------
5369
+ None
5370
+ """
5371
+ import matplotlib.pyplot as plt
5372
+ from PIL import Image
5373
+ from pathlib import Path
5374
+
5375
+ bbox_inches=kwargs.pop("bbox_inches","tight")
5376
+ pad_inches=kwargs.pop("pad_inches",0)
5377
+ facecolor=kwargs.pop("facecolor",'white')
5378
+ edgecolor=kwargs.pop("edgecolor",'auto')
5379
+
5380
+ dir_save = None
5381
+ fname = None
5382
+ img = None
5383
+ for arg in args:
5384
+ if isinstance(arg, str):
5385
+ path = Path(arg)
5386
+ if path.suffix: # Has file extension
5387
+ fname = path.name
5388
+ dir_save = path.parent
5389
+ else:
5390
+ dir_save = path
5391
+ elif isinstance(arg, (Image.Image, np.ndarray)):
5392
+ img = arg # Store PIL image or numpy array
5274
5393
 
5394
+ dir_save = Path(dir_save) if dir_save else Path(".")
5395
+ dir_save.mkdir(parents=True, exist_ok=True)
5396
+ # Handle filename and extension
5275
5397
  if fname is None:
5276
- fname = dir_ch
5277
- mkdir(dir_par)
5278
- ftype = fname.split(".")[-1]
5279
- if len(fname.split(".")) == 1:
5280
- ftype = "nofmt"
5281
- fname = dir_par + fname + "." + ftype
5398
+ fname = dir_save
5282
5399
  else:
5283
- fname = dir_par + fname
5400
+ fname = dir_save / fname
5401
+ if fname.suffix == "":
5402
+ fname = fname.with_suffix(".pdf") # Default format
5403
+
5404
+ ftype = fname.suffix.lstrip(".").lower()
5284
5405
 
5285
5406
  # Save figure based on file type
5286
- if ftype.lower() == "eps":
5287
- plt.savefig(fname, format="eps", bbox_inches="tight")
5288
- plt.savefig(
5289
- fname.replace(".eps", ".pdf"),
5290
- format="pdf",
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)
5407
+ if ftype == "eps":
5408
+ plt.savefig(fname, format="eps", bbox_inches=bbox_inches)
5409
+ plt.savefig(fname.with_suffix(".pdf"), format="pdf", dpi=dpi,
5410
+ pad_inches=pad_inches, bbox_inches=bbox_inches,
5411
+ facecolor=facecolor, edgecolor=edgecolor)
5305
5412
  elif ftype.lower() in ["jpg", "jpeg", "png", "tiff", "tif"]:
5306
5413
  if img is not None: # If a PIL image is provided
5307
5414
  if isinstance(img, Image.Image):
@@ -5310,63 +5417,46 @@ def figsave(*args, dpi=300):
5310
5417
  img.save(fname, format=ftype.upper(), dpi=(dpi, dpi))
5311
5418
  elif isinstance(img, np.ndarray):
5312
5419
  import cv2
5313
-
5314
- # Check the shape of the image to determine color mode
5315
5420
  if img.ndim == 2:
5316
5421
  # Grayscale image
5317
- Image.fromarray(img).save(
5318
- fname, format=ftype.upper(), dpi=(dpi, dpi)
5319
- )
5422
+ Image.fromarray(img).save(fname, format=ftype.upper(), dpi=(dpi, dpi))
5320
5423
  elif img.ndim == 3:
5321
5424
  if img.shape[2] == 3:
5322
5425
  # RGB image
5323
5426
  img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
5324
- Image.fromarray(img).save(
5325
- fname, format=ftype.upper(), dpi=(dpi, dpi)
5326
- )
5427
+ Image.fromarray(img).save(fname, format=ftype.upper(), dpi=(dpi, dpi))
5327
5428
  elif img.shape[2] == 4:
5328
5429
  # RGBA image
5329
- img = cv2.cvtColor(
5330
- img, cv2.COLOR_BGRA2RGBA
5331
- ) # Convert BGRA to RGBA
5332
- Image.fromarray(img).save(
5333
- fname, format=ftype.upper(), dpi=(dpi, dpi)
5334
- )
5430
+ img = cv2.cvtColor(img, cv2.COLOR_BGRA2RGBA) # Convert BGRA to RGBA
5431
+ Image.fromarray(img).save(fname, format=ftype.upper(), dpi=(dpi, dpi))
5335
5432
  else:
5336
- raise ValueError(
5337
- "Unexpected number of channels in the image array."
5338
- )
5433
+ raise ValueError("Unexpected number of channels in the image array.")
5339
5434
  else:
5340
- raise ValueError(
5341
- "Image array has an unexpected number of dimensions."
5342
- )
5435
+ raise ValueError("Image array has an unexpected number of dimensions.")
5343
5436
  else:
5344
- plt.savefig(
5345
- fname,
5346
- format=ftype.lower(),
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
-
5437
+ plt.savefig(fname,format=ftype.lower(),dpi=dpi,pad_inches=pad_inches,bbox_inches=bbox_inches,facecolor=facecolor,edgecolor=edgecolor)
5438
+ elif ftype.lower() in ["emf","pdf","fig"]:
5439
+ plt.savefig(fname,format=ftype.lower(),dpi=dpi,pad_inches=pad_inches,bbox_inches=bbox_inches,facecolor=facecolor,edgecolor=edgecolor)
5357
5440
  elif ftype.lower() == "ico":
5358
5441
  # Ensure the image is in a format that can be saved as an icon (e.g., 32x32, 64x64, etc.)
5359
5442
  if img is None: # If no image is provided, use the matplotlib figure
5360
- img = plt.figure()
5361
- img.savefig(fname, dpi=dpi, format="png", bbox_inches="tight")
5443
+ img = plt.figure()
5444
+ print(fname)
5445
+ img.savefig(fname,
5446
+ format="png",
5447
+ dpi=dpi,
5448
+ pad_inches=pad_inches,
5449
+ bbox_inches=bbox_inches,
5450
+ facecolor=facecolor,
5451
+ edgecolor=edgecolor )
5362
5452
  img = Image.open(fname) # Load the saved figure image
5363
5453
 
5364
5454
  # Resize the image to typical icon sizes and save it as .ico
5365
5455
  icon_sizes = [(32, 32), (64, 64), (128, 128), (256, 256)]
5366
- img = img.convert("RGBA") # Ensure it has an alpha channel for transparency
5456
+ img = img.convert("RGBA")
5367
5457
  img.save(fname, format="ICO", sizes=icon_sizes)
5368
5458
  print(f"Icon saved @: {fname} with sizes: {icon_sizes}")
5369
- print(f"\nSaved @: dpi={dpi}\n{fname}")
5459
+ print(f"\n✅ Saved @: dpi={dpi}\n{fname}")
5370
5460
 
5371
5461
 
5372
5462
  def is_str_color(s):
@@ -8022,21 +8112,20 @@ def format_excel(
8022
8112
  pil_img=img_path = None
8023
8113
  if isinstance(img_data, dict):
8024
8114
  if "path" in img_data:
8025
- img_path = img_data["path"] # File path
8026
- img_ = drawing.image.Image(img_path)
8115
+ img_ = drawing.image.Image(img_data["path"])# File path
8027
8116
  elif "image" in img_data:
8028
- pil_img = img_data["image"] # PIL Image object
8117
+ img_ = drawing.image.Image(img_data["image"])# PIL Image object
8029
8118
  elif "array" in img_data:
8030
- pil_img = Image.fromarray(img_data["array"]) # Convert NumPy array to PIL Image
8119
+ img_ = drawing.image.Image(Image.fromarray(img_data["array"]))# Convert NumPy array to PIL Image
8031
8120
 
8032
8121
  img_width = img_data.get("width", None)
8033
8122
  img_height = img_data.get("height", None)
8034
8123
  elif isinstance(img_data, str):
8035
- img_path = img_data # Direct file path
8124
+ img_ = drawing.image.Image(img_data)# Direct file path
8036
8125
  elif isinstance(img_data, (PIL.Image.Image,PIL.PngImagePlugin.PngImageFile)):
8037
- pil_img = img_data # Direct PIL Image object
8126
+ img_ = drawing.image.Image(img_data)# Direct PIL Image object
8038
8127
  elif isinstance(img_data, np.ndarray):
8039
- pil_img = Image.fromarray(img_data) # Convert NumPy array to PIL Image
8128
+ img_ = drawing.image.Image(Image.fromarray(img_data))# Convert NumPy array to PIL Image
8040
8129
  elif pil_img:
8041
8130
  img_ = drawing.image.Image(pil_img)
8042
8131
 
@@ -8230,7 +8319,89 @@ def _df_outlier(
8230
8319
 
8231
8320
  return processed_data
8232
8321
 
8322
+ def df_group(
8323
+ data: pd.DataFrame,
8324
+ columns: Union[str, list, None] = None,
8325
+ by: str = None,
8326
+ param: Dict[str, Any] = None,
8327
+ sep: Union[str, list] = [", ",","],
8328
+ dropna: bool = True,
8329
+ unique: bool = False,
8330
+ astype: type = str,
8331
+ merge: List[str] = None,
8332
+ merge_symbo_column:str=' & ',
8333
+ merge_symbo_cell:str='[]',# ["{}","()","[]"]
8334
+ ) -> pd.DataFrame:
8335
+ """
8336
+ Groups a dataframe based on a specified column and applies aggregation functions dynamically.
8337
+
8338
+ Parameters:
8339
+ data (pd.DataFrame): The dataframe to be grouped.
8340
+ columns (Union[str, list, None]): Columns to select; if None, all columns are selected.
8341
+ by (str): The column name to group by.
8342
+ param (dict): A dictionary specifying aggregation rules.
8343
+ 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
8344
+ dropna (bool): Whether to drop NaN values before aggregation.
8345
+ unique (bool): Whether to apply uniqueness before concatenation.
8346
+ astype (type): Data type to cast values before aggregation.
8347
+ merge (List[str]): List of columns to merge into a single paired column.
8348
+ merge_symbo_column:str: indicate in the columns, default ("&")
8349
+ merge_symbo_cell:str=default: '{}' or can select from ["{}","()","[]"]
8233
8350
 
8351
+ Usage:
8352
+ data = pd.DataFrame({
8353
+ "Cage Tag": [1, 1, 2, 2, 3],
8354
+ "Physical Tag": ["A1", "A2", "B1", "B2", "C1"],
8355
+ "Sex": ["M", "F", "M", "M", "F"],
8356
+ "Date of Birth": ["2021-06-01", "2021-06-02", "2021-07-01", "2021-07-02", "2021-08-01"],
8357
+ "Age": [34, 35, 30, 31, 29],
8358
+ "State": ["Mating", "Resting", "Mating", "Resting", "Mating"],
8359
+ "Owner": ["Dr. Smith", "Dr. Smith", "Dr. Brown", "Dr. Brown", "Dr. Lee"],
8360
+ })
8361
+ display(data)
8362
+ result = df_group(data,
8363
+ # columns=["Sex", "Date of Birth", "Age", "State"],
8364
+ by="Cage Tag",
8365
+ merge=["Age", "State"],
8366
+ merge_symbo_column="|",
8367
+ # astype=str
8368
+ # sep=[',', '_'],
8369
+ merge_symbo_cell=None
8370
+ )
8371
+ result
8372
+
8373
+
8374
+ """
8375
+ if param is None:
8376
+ param = {}
8377
+ if columns is None:
8378
+ columns = data.columns.tolist()
8379
+ elif isinstance(columns, str):
8380
+ columns = [columns]
8381
+ if not isinstance(sep, list):
8382
+ sep = [sep]
8383
+ sep.extend(sep) if len(sep)==1 else None
8384
+
8385
+ # Merge specified columns into a single column
8386
+ if merge:
8387
+ merge_col_name = merge_symbo_column.join(merge)
8388
+ # data[merge_col_name] = data[merge].apply(lambda row: tuple(map(astype, row.dropna() if dropna else row)), axis=1)
8389
+ if merge_symbo_cell is None:
8390
+ 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)
8391
+ elif len(merge_symbo_cell)==2:
8392
+ 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)
8393
+ else:
8394
+ 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)
8395
+ columns.append(merge_col_name)
8396
+
8397
+ default_aggregations = {
8398
+ 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)))
8399
+ for col in columns if col != by and (merge is None or col not in merge)
8400
+ }
8401
+ aggregation_rules = {**default_aggregations, **param}
8402
+
8403
+ grouped_df = data.groupby(by).agg(aggregation_rules).reset_index()
8404
+ return grouped_df
8234
8405
  def df_outlier(
8235
8406
  data,
8236
8407
  columns=None,
@@ -10208,11 +10379,19 @@ def get_df_format(data, threshold_unique=0.5, verbose=False):
10208
10379
  from sklearn.cluster import AgglomerativeClustering
10209
10380
  from sklearn.preprocessing import StandardScaler
10210
10381
 
10211
- long_score = 0
10212
- wide_score = 0
10213
-
10382
+ long_score,wide_score,fs = 0,0,500
10214
10383
  n_rows, n_cols = data.shape
10215
-
10384
+ # -----to reduce memory, only check 500 rows/columns----
10385
+ if n_rows > fs:
10386
+ if verbose:
10387
+ print(f"Sampling {fs} rows from {n_rows} rows.")
10388
+ data = data.sample(n=fs, random_state=1)
10389
+ if n_cols > fs:
10390
+ if verbose:
10391
+ print(f"Using first {fs} columns out of {n_cols} columns.")
10392
+ data = data.iloc[:, :fs]
10393
+ n_rows, n_cols = data.shape
10394
+
10216
10395
  # Step 1: Row-Column Ratio Heuristic
10217
10396
  if n_rows > 3 * n_cols:
10218
10397
  long_score += 2
@@ -12520,3 +12699,83 @@ def py2installer(
12520
12699
  raise
12521
12700
 
12522
12701
  print("\nPackaging complete. Check the output directory for the executable.")
12702
+
12703
+
12704
+ def set_theme(
12705
+ context="paper",
12706
+ style="whitegrid",
12707
+ palette="deep",
12708
+ font="sans-serif",
12709
+ font_scale=1.0,
12710
+ color_codes=True,
12711
+ grid_alpha=0.5,
12712
+ grid_linewidth=0.8,
12713
+ grid_linestyle="--",
12714
+ tick_direction="out",
12715
+ # tick_length=4,
12716
+ spine_visibility=False,
12717
+ # figsize=(8, 6),
12718
+ # linewidth=2,
12719
+ dpi=100,
12720
+ rc=None,
12721
+ ):
12722
+ """
12723
+ to configure Seaborn theme with maximum flexibility.
12724
+
12725
+ # Example Usage
12726
+ set_sns_theme(font_scale=1.2, grid_alpha=0.8, tick_direction="in", dpi=150)
12727
+
12728
+ Parameters:
12729
+ - context: Plotting context ('notebook', 'paper', 'talk', 'poster')
12730
+ - style: Style of the plot ('darkgrid', 'whitegrid', 'dark', 'white', 'ticks')
12731
+ - palette: Color palette (string or list of colors)
12732
+ - font: Font family ('sans-serif', 'serif', etc.)
12733
+ - font_scale: Scaling factor for fonts
12734
+ - color_codes: Boolean, whether to use seaborn color codes
12735
+ - grid_alpha: Opacity of the grid lines
12736
+ - grid_linewidth: Thickness of grid lines
12737
+ - grid_linestyle: Style of grid lines ('-', '--', '-.', ':')
12738
+ - tick_direction: Direction of ticks ('in', 'out', 'inout')
12739
+ - tick_length: Length of ticks
12740
+ - spine_visibility: Whether to show plot spines (True/False)
12741
+ - figsize: Default figure size as tuple (width, height)
12742
+ - linewidth: Default line width for plots
12743
+ - dpi: Resolution of the figure
12744
+ - rc: Dictionary of additional rc settings
12745
+ """
12746
+ import seaborn as sns
12747
+ import matplotlib.pyplot as plt
12748
+
12749
+ # Define additional rc parameters for fine-tuning
12750
+ rc_params = {
12751
+ # "axes.grid": True,
12752
+ "grid.alpha": grid_alpha,
12753
+ "grid.linewidth": grid_linewidth,
12754
+ "grid.linestyle": grid_linestyle,
12755
+ "xtick.direction": tick_direction,
12756
+ "ytick.direction": tick_direction,
12757
+ # "xtick.major.size": tick_length,
12758
+ # "ytick.major.size": tick_length,
12759
+ # "axes.linewidth": linewidth,
12760
+ # "figure.figsize": figsize,
12761
+ "figure.dpi": dpi,
12762
+ "axes.spines.top": spine_visibility,
12763
+ "axes.spines.right": spine_visibility,
12764
+ "axes.spines.bottom": spine_visibility,
12765
+ "axes.spines.left": spine_visibility,
12766
+ }
12767
+
12768
+ # Merge user-provided rc settings
12769
+ if rc:
12770
+ rc_params.update(rc)
12771
+
12772
+ # Apply the theme settings
12773
+ sns.set_theme(
12774
+ context=context,
12775
+ style=style,
12776
+ palette=palette,
12777
+ font=font,
12778
+ font_scale=font_scale,
12779
+ color_codes=color_codes,
12780
+ rc=rc_params,
12781
+ )