py2ls 0.2.4.1__tar.gz → 0.2.4.3__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 (228) hide show
  1. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/PKG-INFO +1 -1
  2. py2ls-0.2.4.3/py2ls/bio.py +513 -0
  3. py2ls-0.2.4.3/py2ls/data/usages_pd copy.json +1105 -0
  4. py2ls-0.2.4.3/py2ls/data/usages_pd.json +1417 -0
  5. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/fetch_update.py +45 -27
  6. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/ips.py +680 -168
  7. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/plot.py +104 -77
  8. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/pyproject.toml +1 -1
  9. py2ls-0.2.4.1/py2ls/data/usages_pd.json +0 -56
  10. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/README.md +0 -0
  11. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.DS_Store +0 -0
  12. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/COMMIT_EDITMSG +0 -0
  13. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/FETCH_HEAD +0 -0
  14. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/HEAD +0 -0
  15. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/config +0 -0
  16. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/description +0 -0
  17. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/hooks/applypatch-msg.sample +0 -0
  18. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/hooks/commit-msg.sample +0 -0
  19. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/hooks/fsmonitor-watchman.sample +0 -0
  20. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/hooks/post-update.sample +0 -0
  21. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/hooks/pre-applypatch.sample +0 -0
  22. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/hooks/pre-commit.sample +0 -0
  23. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/hooks/pre-merge-commit.sample +0 -0
  24. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/hooks/pre-push.sample +0 -0
  25. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/hooks/pre-rebase.sample +0 -0
  26. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/hooks/pre-receive.sample +0 -0
  27. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/hooks/prepare-commit-msg.sample +0 -0
  28. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/hooks/push-to-checkout.sample +0 -0
  29. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/hooks/update.sample +0 -0
  30. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/index +0 -0
  31. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/info/exclude +0 -0
  32. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/logs/HEAD +0 -0
  33. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/logs/refs/heads/main +0 -0
  34. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/logs/refs/remotes/origin/HEAD +0 -0
  35. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/logs/refs/remotes/origin/main +0 -0
  36. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/01/d5bd8065e6860c0bd23ff9fa57161806a099e1 +0 -0
  37. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/09/08da26de58c114225ad81f484b80bf5d351b34 +0 -0
  38. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/0b/409e1bc918277010f5679b402d1d1dda53e15c +0 -0
  39. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/12/c2808a1b3a4d0892a4154dfba1e2ae3770fa73 +0 -0
  40. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/14/449a0e6ba4ea2f1a73acf63ef91c9c6193f9ed +0 -0
  41. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/15/a8e468aacfcb440e090020f36d0b985d45da23 +0 -0
  42. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/1a/b4585881a6a42889f01aa0cfe25fd5acfaf46f +0 -0
  43. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/1c/3f92adda34344bcbbbf9d409c79855ae2aaea8 +0 -0
  44. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/1c/9314c5f69b9390068a2a8616875d974849d71f +0 -0
  45. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/1d/fe9d9633b24ea560354f4f93d39c6e5f163ea0 +0 -0
  46. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/20/72c28e83f4347959d29f7b3a6c1fc3e4ee6b59 +0 -0
  47. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/24/6b368b986f758630c46dc02b7fa512b53422f7 +0 -0
  48. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/25/b796accd261b9135fd32a2c00785f68edf6c46 +0 -0
  49. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/27/aa6074f652bc6f7078f8647489d9ee8e24f0e2 +0 -0
  50. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/28/c2969d785c1b892c2a96b3f00eba63a59811b3 +0 -0
  51. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/2a/ae95d517d213b660bf4f65a4e0cfae7bb893eb +0 -0
  52. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/2a/fdf45791a26d42ccead35ace76a8f0b2a56561 +0 -0
  53. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/30/a2f8da47ee947811dc8d993f5a06a45de374f4 +0 -0
  54. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/32/fd627b62fad7cf3b2f9e34ab9777126a0987ad +0 -0
  55. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/34/9e31b6a3634cea102ce5588b98c11cc1738605 +0 -0
  56. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/34/b6f3a2ee84f39bed4eee57f2c0e0afb994feb1 +0 -0
  57. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/35/1a5f491ab97eee9d1ee699478d75a8bb5d3dc2 +0 -0
  58. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/36/b4a1b7403abc6c360f8fe2cb656ab945254971 +0 -0
  59. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/36/e56a361f526eafa59c5235a5c990bf288b5f9c +0 -0
  60. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/36/ef43e50009e59db11812c258846d9e38718173 +0 -0
  61. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/39/7ead045fbbcfb17c62019eb18fe21ed05dbee5 +0 -0
  62. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/39/b13be65125556784e44c7a1d9821703c7ab67e +0 -0
  63. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/3b/507acc7f23391644cc0b824b1e79fd2677a362 +0 -0
  64. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/3b/bd972aa7ad680858f8dfbd0f7fcd97756f0d6f +0 -0
  65. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/3c/bbe5f4173d165127b9ad96119f1ec24c306ffc +0 -0
  66. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/3d/9d10d27724657a436c65a6254bfd213d4b3562 +0 -0
  67. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/3f/d6561300938afbb3d11976cf9c8f29549280d9 +0 -0
  68. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/41/dcf4b3bf0460946b2da93776cf9e836d62178f +0 -0
  69. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/43/dbd49b2ee367c5434dd545e3b5795434f2ef0b +0 -0
  70. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/45/b1b6178bacbfc997811a998b5cc60c1ea7fac8 +0 -0
  71. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/47/6cbd5a7c5e35cddef2f8a38bdc4896d403b095 +0 -0
  72. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/48/a88fc5806305d0bb0755ee6801161b79696972 +0 -0
  73. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/4f/7afb40dff2153d857fc85748c2eecb85125042 +0 -0
  74. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/50/08ddfcf53c02e82d7eee2e57c38e5672ef89f6 +0 -0
  75. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/53/e0deb1cb4c2c606bced6e7f9a66b0fda60980d +0 -0
  76. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/56/e4e8b2d5545e0256090f45aa8fc42c5fe067d0 +0 -0
  77. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/57/63d0c52f5c9c69e89d514a1f96034947abe21a +0 -0
  78. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/57/bd1c0199483ab316235b094543b85edec6c35e +0 -0
  79. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/58/20a729045d4dc7e37ccaf8aa8eec126850afe2 +0 -0
  80. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/59/380c4c26bdcd4d9b71ae3e2e35f05b3f26c5ab +0 -0
  81. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/5a/192565abf89c9d765af846ce6d53a92b1ce7ad +0 -0
  82. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/60/f273eb1c412d916fa3f11318a7da7a9911b52a +0 -0
  83. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/61/570cec8c061abe74121f27f5face6c69b98f99 +0 -0
  84. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/62/4488173ed2c8936fa5cea3cf5dd3f26a30b86e +0 -0
  85. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/62/7c81b23b4e56e87b042b650b0103653cc9e34a +0 -0
  86. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/62/d90ccf8cbefdc2e4fd475e7c6f4f76e9fdf801 +0 -0
  87. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/63/100154b27846e8010e55b6bf4b3d7762c14c5f +0 -0
  88. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/64/27a4edff08f93d98f511418423f09f2ab90bcd +0 -0
  89. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/66/6227eeeba24073e63811e89f1449f3d958f183 +0 -0
  90. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/66/c998778721d424bd0aae80602dabbffa93af2e +0 -0
  91. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/68/6df3072c8b025fb18106ed2df505994ad062a9 +0 -0
  92. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/69/13c452ca319f7cbf6a0836dc10a5bb033c84e4 +0 -0
  93. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/6a/52e747a2b349b128d1490d9e896d2323818eb7 +0 -0
  94. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/6b/7fde264d93a7a0986d394c46c7650d0ce2ab92 +0 -0
  95. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/6c/cebb29b7f3f5b0c889f6dadbf9ff066554587d +0 -0
  96. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/6d/c2cdf4a84e538e5d4777486aeff87e42f41799 +0 -0
  97. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/6d/ee29dbdcc84edeeacede105110446f3ccac963 +0 -0
  98. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/71/36b2074a2754be8b58127d82250e5b37e3c373 +0 -0
  99. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/72/245a05b0966011cb381e6b32b0465000e969ab +0 -0
  100. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/72/e4179337639859678ddaecf38b16f33aaec8e1 +0 -0
  101. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/78/063f4c863fc371ec0313303c0a81283b35d9b6 +0 -0
  102. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/78/3d4167bc95c9d2175e0df03ef1c1c880ba75ab +0 -0
  103. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/79/7ae089b2212a937840e215276005ce76881307 +0 -0
  104. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/7e/5956c806b5edc344d46dab599dec337891ba1f +0 -0
  105. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/81/8f26b7bf042269729020cf944fc362d66ba27e +0 -0
  106. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/82/70b319ce4046854fbe7dc41054b6c2d112dab2 +0 -0
  107. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/84/59071b722a255b774a80b27746033f8141ab39 +0 -0
  108. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/85/aee46f478e9afdb84d50a05242c53b04ed2e21 +0 -0
  109. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/86/e288b46f8fe179907e4413f665aeb5053fddb1 +0 -0
  110. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/87/ef1fc3f7f1ddc4d0ab9b3e65381ce9f3388621 +0 -0
  111. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/8b/84f56978e1de8f2ae82abce5f8b3e182d365cd +0 -0
  112. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/8e/55a7d2b96184030211f20c9b9af201eefcac82 +0 -0
  113. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/91/c69ad88fe0ba94aa7859fb5f7edac5e6f1a3f7 +0 -0
  114. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/94/74152b4b463d70ae5ad07f0c658be3e296026b +0 -0
  115. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/94/f7dbe88e80c4205a901b71eb8f181974376bba +0 -0
  116. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/97/1aef09ea939f46b60b9646f8d524c78a9220f4 +0 -0
  117. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/9b/ec5ee2236ee2d5532c36bfd132e23c58fdb69c +0 -0
  118. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/9d/0df52899fe95279059286d9c0ec42287edc168 +0 -0
  119. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/a1/5389729850729fc7bd78a54f26fce77f30be12 +0 -0
  120. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/a1/906da89d1174f74867800c74c43af36253bd5e +0 -0
  121. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/a4/63fdd23e5efd713db8a71f316f3a1c7bd60916 +0 -0
  122. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/a5/ec8f74642fbba27f7ea78c53b372ae0c7dedce +0 -0
  123. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/a7/3e13eafee65c5b8d73ad2d3ea46d0eee82f0d3 +0 -0
  124. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/b0/56be4be89ba6b76949dd641df45bb7036050c8 +0 -0
  125. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/b0/9cd7856d58590578ee1a4f3ad45d1310a97f87 +0 -0
  126. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/b2/18e6a0f0f1c4df8cdefa9852058348abc713b7 +0 -0
  127. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/b3/4f7f271c6d6105e35a6556ffda71d03afe8c96 +0 -0
  128. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/b3/69579064bde9de9a19d114fc33e4e48cc8c0e4 +0 -0
  129. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/b5/61831c7dce8ea51e7ee6b6fa35745f14d8242d +0 -0
  130. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/b7/2c9e75ab7d0afe594664650aa8f6c772f5ac64 +0 -0
  131. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/bb/81ccc0513f18fc160b54a82861e9a80d23f4f6 +0 -0
  132. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/bb/934eb33bc1a8b85630bf680caffd99560c1b8f +0 -0
  133. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/bf/67907e337021ebff434e02b19b30a741c144af +0 -0
  134. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/bf/b54d65922ce1dfda1aaa014913a54e7172d0bc +0 -0
  135. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/c1/20fc812b9ad311c34a3608512d6a9d976bb48e +0 -0
  136. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/c1/397c6ed72c4e20ef6b9ab83163e9a6baba5b45 +0 -0
  137. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/c4/cba65f1163661999ee4b8ed23342b63bc1300c +0 -0
  138. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/c6/7f17e5707313600efcb85e9a3fedea35dba591 +0 -0
  139. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/c6/f32aced880bd165a251cb52b26b0c1107e2141 +0 -0
  140. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/cc/45df1d317a2eb63ff1ff3a5f3b4a9f98fd92b5 +0 -0
  141. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/cd/822b3574a88ebdd1ed82fd6983f37e626d52b4 +0 -0
  142. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/cf/0c0d9c6fb09473aaeb7f7e2edbd770c3f2ef3d +0 -0
  143. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/d2/992df305f4b56a466a2f221aeb182ddd20f418 +0 -0
  144. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/d6/39e8af592cd75a318d8affddd1bcc70c2095f2 +0 -0
  145. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/d6/9ab1c4aadf279936dd778e8346ba60f74705b6 +0 -0
  146. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/d8/4688b54c0040a30976b3a6540bc47adf7ce680 +0 -0
  147. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/d9/005f2cc7fc4e65f14ed5518276007c08cf2fd0 +0 -0
  148. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/d9/c2403fd166ce791b4e9d0c6792ed8342c71fcd +0 -0
  149. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/d9/dfa5aee51e92a541b707e8e7baea6f06deff98 +0 -0
  150. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/db/141dbaa93594df2a8156182f361ee4db829359 +0 -0
  151. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/db/3f2cd643292057936230b95cf7ec3046affe11 +0 -0
  152. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/db/ffa8ea7bda721d0cee7b9e4ce5b2ef927733ff +0 -0
  153. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/dc/c2bdbafb3296e09d9ee4955cfa55d275825f94 +0 -0
  154. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/dc/cdbd4266765d840be2ae35ab1752a0fa312c16 +0 -0
  155. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/dd/87fb5f606fe380d81e6fe3a2c98f9f99e3e09b +0 -0
  156. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/de/214c626ac2dd2685bfaa0bc0fc20f528d014d7 +0 -0
  157. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/df/e0770424b2a19faf507a501ebfc23be8f54e7b +0 -0
  158. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/e2/f2f8f4c25e62a297fc55f36acc6b01cfbab76f +0 -0
  159. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/e3/1356f90ea6dd0577b5e0b40b206319adcbf085 +0 -0
  160. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/e3/5a4dafc50850cacac7bf76c56db2715cbda2c4 +0 -0
  161. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/e4/6c715352db9fe3c887a635f1916df4ca1f4ff9 +0 -0
  162. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/e5/0580a0bd1e1b3d29f834382b80fceb61d5cf0c +0 -0
  163. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/e9/391ffe371f1cc43b42ef09b705d9c767c2e14f +0 -0
  164. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/ea/3a18cc75e53792744ef754e05d3f4481768c13 +0 -0
  165. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/ec/40fd8bf8e4c342534a9fc020289e402ba6bc9d +0 -0
  166. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/ec/d980279432b13f0374b90ca439a6329cdece0f +0 -0
  167. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/ee/cee64eacaff022dcdc509c0c2b1da492f21060 +0 -0
  168. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/f1/e50757fddc28b445545dc7e2759b54cdd0f42e +0 -0
  169. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/f4/b64d3107b39e3ad6f540c6607004ea34e6c024 +0 -0
  170. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/f4/ba7f815b886797b73fede071d86e0c134d2bc7 +0 -0
  171. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/f5/61c3c1bf1c9ea9c9d1f556a7be2869f71f3bdf +0 -0
  172. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/f6/44a8ff56fa035105fc517cbb1ac46c3d8e349a +0 -0
  173. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/f7/c98ba5c2f903e603b1f5e63d49fbc8a43815cc +0 -0
  174. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/f9/045a08e96eb76848fc4d68e3e3e687cca39a2d +0 -0
  175. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/fa/147e6bb78a2e8db241d231295fd7f1ed061af8 +0 -0
  176. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/objects/fc/292e793ecfd42240ac43be407023bd731fa9e7 +0 -0
  177. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/refs/heads/main +0 -0
  178. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/refs/remotes/origin/HEAD +0 -0
  179. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.git/refs/remotes/origin/main +0 -0
  180. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.gitattributes +0 -0
  181. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/.gitignore +0 -0
  182. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/LICENSE +0 -0
  183. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/README.md +0 -0
  184. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/__init__.py +0 -0
  185. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/batman.py +0 -0
  186. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/brain_atlas.py +0 -0
  187. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/chat.py +0 -0
  188. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/correlators.py +0 -0
  189. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/data/.DS_Store +0 -0
  190. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/data/db2ls_sql_chtsht.json +0 -0
  191. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/data/docs_links.json +0 -0
  192. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/data/email/email_html_template.html +0 -0
  193. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/data/lang_code_iso639.json +0 -0
  194. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/data/sns_info.json +0 -0
  195. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/data/styles/example/style1.pdf +0 -0
  196. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/data/styles/example/style2.pdf +0 -0
  197. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/data/styles/example/style3.pdf +0 -0
  198. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/data/styles/example/style4.pdf +0 -0
  199. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/data/styles/example/style5.pdf +0 -0
  200. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/data/styles/example/style6.pdf +0 -0
  201. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/data/styles/example/style7.pdf +0 -0
  202. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/data/styles/example/style8.pdf +0 -0
  203. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/data/styles/example/style9.pdf +0 -0
  204. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/data/styles/style1.json +0 -0
  205. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/data/styles/style10.json +0 -0
  206. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/data/styles/style11.json +0 -0
  207. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/data/styles/style12.json +0 -0
  208. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/data/styles/style2.json +0 -0
  209. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/data/styles/style3.json +0 -0
  210. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/data/styles/style4.json +0 -0
  211. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/data/styles/style5.json +0 -0
  212. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/data/styles/style6.json +0 -0
  213. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/data/styles/style7.json +0 -0
  214. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/data/styles/style8.json +0 -0
  215. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/data/styles/style9.json +0 -0
  216. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/data/usages_sns.json +0 -0
  217. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/db2ls.py +0 -0
  218. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/doc.py +0 -0
  219. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/export_requirements.py +0 -0
  220. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/freqanalysis.py +0 -0
  221. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/ich2ls.py +0 -0
  222. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/netfinder.py +0 -0
  223. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/ocr.py +0 -0
  224. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/setuptools-70.1.0-py3-none-any.whl +0 -0
  225. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/sleep_events_detectors.py +0 -0
  226. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/stats.py +0 -0
  227. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/translator.py +0 -0
  228. {py2ls-0.2.4.1 → py2ls-0.2.4.3}/py2ls/wb_detector.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: py2ls
3
- Version: 0.2.4.1
3
+ Version: 0.2.4.3
4
4
  Summary: py(thon)2(too)ls
5
5
  Author: Jianfeng
6
6
  Author-email: Jianfeng.Liu0413@gmail.com
@@ -0,0 +1,513 @@
1
+ import GEOparse
2
+ from typing import Union
3
+ import pandas as pd
4
+ import os
5
+ import logging
6
+ from . import ips
7
+ from . import plot
8
+ import matplotlib.pyplot as plt
9
+
10
+ def load_geo(
11
+ datasets: Union[list, str] = ["GSE00000", "GSE00001"],
12
+ dir_save: str = "./datasets",
13
+ verbose=False,
14
+ ) -> dict:
15
+ """
16
+ Check if GEO datasets are already in the directory, and download them if not.
17
+
18
+ Parameters:
19
+ datasets (list): List of GEO dataset IDs to download.
20
+ dir_save (str): Directory where datasets will be stored.
21
+
22
+ Returns:
23
+ dict: A dictionary containing the GEO objects for each dataset.
24
+ """
25
+ use_str = """
26
+ get_meta(geo: dict, dataset: str = "GSE25097")
27
+ get_expression_data(geo: dict, dataset: str = "GSE25097")
28
+ get_probe(geo: dict, dataset: str = "GSE25097", platform_id: str = "GPL10687")
29
+ get_data(geo: dict, dataset: str = "GSE25097")
30
+ """
31
+ print(f"you could do further: \n{use_str}")
32
+ if not verbose:
33
+ logging.getLogger("GEOparse").setLevel(logging.WARNING)
34
+ else:
35
+ logging.getLogger("GEOparse").setLevel(logging.DEBUG)
36
+ # Create the directory if it doesn't exist
37
+ if not os.path.exists(dir_save):
38
+ os.makedirs(dir_save)
39
+ print(f"Created directory: {dir_save}")
40
+ if isinstance(datasets, str):
41
+ datasets = [datasets]
42
+ geo_data = {}
43
+ for dataset in datasets:
44
+ # Check if the dataset file already exists in the directory
45
+ dataset_file = os.path.join(dir_save, f"{dataset}_family.soft.gz")
46
+
47
+ if not os.path.isfile(dataset_file):
48
+ print(f"\n\nDataset {dataset} not found locally. Downloading...")
49
+ geo = GEOparse.get_GEO(geo=dataset, destdir=dir_save)
50
+ else:
51
+ print(f"\n\nDataset {dataset} already exists locally. Loading...")
52
+ geo = GEOparse.get_GEO(filepath=dataset_file)
53
+
54
+ geo_data[dataset] = geo
55
+
56
+ return geo_data
57
+
58
+
59
+ def get_meta(geo: dict, dataset: str = "GSE25097", verbose=True) -> pd.DataFrame:
60
+ """
61
+ df_meta = get_meta(geo, dataset="GSE25097")
62
+ Extracts metadata from a specific GEO dataset and returns it as a DataFrame.
63
+ The function dynamically extracts all available metadata fields from the given dataset.
64
+
65
+ Parameters:
66
+ geo (dict): A dictionary containing the GEO objects for different datasets.
67
+ dataset (str): The name of the dataset to extract metadata from (default is "GSE25097").
68
+
69
+ Returns:
70
+ pd.DataFrame: A DataFrame containing structured metadata from the specified GEO dataset.
71
+ """
72
+ # Check if the dataset is available in the provided GEO dictionary
73
+ if dataset not in geo:
74
+ raise ValueError(f"Dataset '{dataset}' not found in the provided GEO data.")
75
+
76
+ # List to store metadata dictionaries
77
+ meta_list = []
78
+
79
+ # Extract the GEO object for the specified dataset
80
+ geo_obj = geo[dataset]
81
+
82
+ # Overall Study Metadata
83
+ study_meta = geo_obj.metadata
84
+ study_metadata = {key: study_meta[key] for key in study_meta.keys()}
85
+
86
+ # Platform Metadata
87
+ for platform_id, platform in geo_obj.gpls.items():
88
+ platform_metadata = {
89
+ key: platform.metadata[key] for key in platform.metadata.keys()
90
+ }
91
+ platform_metadata["platform_id"] = platform_id # Include platform ID
92
+
93
+ # Sample Metadata
94
+ for sample_id, sample in geo_obj.gsms.items():
95
+ sample_metadata = {
96
+ key: sample.metadata[key] for key in sample.metadata.keys()
97
+ }
98
+ sample_metadata["sample_id"] = sample_id # Include sample ID
99
+ # Combine all metadata into a single dictionary
100
+ combined_meta = {
101
+ "dataset": dataset,
102
+ **{
103
+ k: (
104
+ v[0]
105
+ if isinstance(v, list) and len(v) == 1
106
+ else ", ".join(map(str, v))
107
+ )
108
+ for k, v in study_metadata.items()
109
+ }, # Flatten study metadata
110
+ **platform_metadata, # Unpack platform metadata
111
+ **{
112
+ k: (
113
+ v[0]
114
+ if isinstance(v, list) and len(v) == 1
115
+ else "".join(map(str, v))
116
+ )
117
+ for k, v in sample_metadata.items()
118
+ }, # Flatten sample metadata
119
+ }
120
+
121
+ # Append the combined metadata to the list
122
+ meta_list.append(combined_meta)
123
+
124
+ # Convert the list of dictionaries to a DataFrame
125
+ meta_df = pd.DataFrame(meta_list)
126
+ if verbose:
127
+ print(
128
+ f"Meta info columns for dataset '{dataset}': \n{sorted(meta_df.columns.tolist())}"
129
+ )
130
+ display(meta_df[:3].T)
131
+ return meta_df
132
+
133
+
134
+ def get_probe(
135
+ geo: dict, dataset: str = "GSE25097", platform_id: str = None, verbose=True
136
+ ):
137
+ """
138
+ df_probe = get_probe(geo, dataset="GSE25097", platform_id: str = "GPL10687")
139
+ """
140
+ # try to find the platform_id from meta
141
+ if platform_id is None:
142
+ df_meta = get_meta(geo=geo, dataset=dataset, verbose=False)
143
+ platform_id = df_meta["platform_id"].unique().tolist()
144
+ platform_id = platform_id[0] if len(platform_id) == 1 else platform_id
145
+ print(platform_id)
146
+ df_probe = geo[dataset].gpls[platform_id].table
147
+ if df_probe.empty:
148
+ print(
149
+ f"above is meta info, failed to find the probe info. 看一下是不是在单独的文件中包含了probe信息"
150
+ )
151
+ return get_meta(geo, dataset, verbose=True)
152
+ if verbose:
153
+ print(f"columns in the probe table: \n{sorted(df_probe.columns.tolist())}")
154
+ return df_probe
155
+
156
+
157
+ def get_expression_data(geo: dict, dataset: str = "GSE25097") -> pd.DataFrame:
158
+ """
159
+ df_expression = get_expression_data(geo,dataset="GSE25097")
160
+ 只包含表达量数据,并没有考虑它的probe和其它的meta
161
+
162
+ Extracts expression values from GEO datasets and returns it as a DataFrame.
163
+
164
+ Parameters:
165
+ geo (dict): A dictionary containing GEO objects for each dataset.
166
+
167
+ Returns:
168
+ pd.DataFrame: A DataFrame containing expression data from the GEO datasets.
169
+ """
170
+ expression_dataframes = []
171
+ try:
172
+ expression_values = geo[dataset].pivot_samples("VALUE")
173
+ except:
174
+ for sample_id, sample in geo[dataset].gsms.items():
175
+ if hasattr(sample, "table"):
176
+ expression_values = (
177
+ sample.table.T
178
+ ) # Transpose for easier DataFrame creation
179
+ expression_values["dataset"] = dataset
180
+ expression_values["sample_id"] = sample_id
181
+ return expression_values
182
+
183
+
184
+ def get_data(geo: dict, dataset: str = "GSE25097", verbose=True):
185
+ # get probe info
186
+ df_probe = get_probe(geo, dataset=dataset, verbose=False)
187
+ # get expression values
188
+ df_expression = get_expression_data(geo, dataset=dataset)
189
+ print(
190
+ f"df_expression.shape: {df_expression.shape} \ndf_probe.shape: {df_probe.shape}"
191
+ )
192
+ if any([df_probe.empty, df_expression.empty]):
193
+ print(
194
+ f"above is meta info, failed to find the probe info. 看一下是不是在单独的文件中包含了probe信息"
195
+ )
196
+ return get_meta(geo, dataset, verbose=True)
197
+ df_exp = pd.merge(
198
+ df_probe,
199
+ df_expression,
200
+ left_on=df_probe.columns.tolist()[0],
201
+ right_index=True,
202
+ how="outer",
203
+ )
204
+
205
+ # get meta info
206
+ df_meta = get_meta(geo, dataset=dataset, verbose=False)
207
+ col_rm = [
208
+ "channel_count",
209
+ "contact_web_link",
210
+ "contact_address",
211
+ "contact_city",
212
+ "contact_country",
213
+ "contact_department",
214
+ "contact_email",
215
+ "contact_institute",
216
+ "contact_laboratory",
217
+ "contact_name",
218
+ "contact_phone",
219
+ "contact_state",
220
+ "contact_zip/postal_code",
221
+ "contributor",
222
+ "manufacture_protocol",
223
+ "taxid",
224
+ "web_link",
225
+ ]
226
+ # rm unrelavent columns
227
+ df_meta = df_meta.drop(columns=[col for col in col_rm if col in df_meta.columns])
228
+ # sorte columns
229
+ df_meta = df_meta.reindex(sorted(df_meta.columns), axis=1)
230
+ # find a proper column
231
+ col_sample_id = ips.strcmp("sample_id", df_meta.columns.tolist())[0]
232
+ df_meta.set_index(col_sample_id, inplace=True) # set gene symbol as index
233
+
234
+ col_gene_symbol = ips.strcmp("GeneSymbol", df_exp.columns.tolist())[0]
235
+ # select the 'GSM' columns
236
+ col_gsm = df_exp.columns[df_exp.columns.str.startswith("GSM")].tolist()
237
+ df_exp.set_index(col_gene_symbol, inplace=True)
238
+ df_exp = df_exp[col_gsm].T # transpose, so that could add meta info
239
+
240
+ df_merged = ips.df_merge(df_meta, df_exp)
241
+ if verbose:
242
+ print(
243
+ f"\ndataset:'{dataset}' n_sample = {df_merged.shape[0]}, n_gene={df_exp.shape[1]}"
244
+ )
245
+ display(df_merged.sample(5))
246
+ return df_merged
247
+
248
+
249
+ def split_at_lower_upper(lst):
250
+ """
251
+ 将一串list,从全是lowercase,然后就是大写或者nan的地方分隔成两个list
252
+ """
253
+ for i in range(len(lst) - 1):
254
+ if isinstance(lst[i], str) and lst[i].islower():
255
+ next_item = lst[i + 1]
256
+ if isinstance(next_item, str) and next_item.isupper():
257
+ # Found the split point: lowercase followed by uppercase
258
+ return lst[: i + 1], lst[i + 1 :]
259
+ elif pd.isna(next_item):
260
+ # NaN case after a lowercase string
261
+ return lst[: i + 1], lst[i + 1 :]
262
+ return lst, []
263
+
264
+
265
+ def add_condition(
266
+ data: pd.DataFrame,
267
+ column: str = "characteristics_ch1", # 在哪一行进行分类
268
+ column_new: str = "condition", # 新col的命名
269
+ by: str = "tissue: tumor liver", # 通过by来命名
270
+ by_not: str = ": tumor", # 健康的选择条件
271
+ by_name: str = "non-tumor", # 健康的命名
272
+ by_not_name: str = "tumor", # 不健康的命名
273
+ inplace: bool = True, # replace the data
274
+ verbose: bool = True,
275
+ ):
276
+ """
277
+ Add a new column to the DataFrame based on the presence of a specific substring in another column.
278
+
279
+ Parameters
280
+ ----------
281
+ data : pd.DataFrame
282
+ The input DataFrame containing the data.
283
+ column : str, optional
284
+ The name of the column in which to search for the substring (default is 'characteristics_ch1').
285
+ column_new : str, optional
286
+ The name of the new column to be created (default is 'condition').
287
+ by : str, optional
288
+ The substring to search for in the specified column (default is 'heal').
289
+
290
+ """
291
+ # first check the content in column
292
+ content = data[column].unique().tolist()
293
+ if verbose:
294
+ if len(content) > 10:
295
+ display(content[:10])
296
+ else:
297
+ display(content)
298
+ # 优先by
299
+ if by:
300
+ data[column_new] = data[column].apply(
301
+ lambda x: by_name if by in x else by_not_name
302
+ )
303
+ elif by_not:
304
+ data[column_new] = data[column].apply(
305
+ lambda x: by_not_name if not by_not in x else by_name
306
+ )
307
+ if verbose:
308
+ display(data)
309
+ if not inplace:
310
+ return data
311
+
312
+
313
+ def add_condition_multi(
314
+ data: pd.DataFrame,
315
+ column: str = "characteristics_ch1", # Column to classify
316
+ column_new: str = "condition", # New column name
317
+ conditions: dict = {
318
+ "low": "low",
319
+ "high": "high",
320
+ "intermediate": "intermediate",
321
+ }, # A dictionary where keys are substrings and values are condition names
322
+ default_name: str = "unknown", # Default name if no condition matches
323
+ inplace: bool = True, # Whether to replace the data
324
+ verbose: bool = True,
325
+ ):
326
+ """
327
+ Add a new column to the DataFrame based on the presence of specific substrings in another column.
328
+
329
+ Parameters
330
+ ----------
331
+ data : pd.DataFrame
332
+ The input DataFrame containing the data.
333
+ column : str, optional
334
+ The name of the column in which to search for the substrings (default is 'characteristics_ch1').
335
+ column_new : str, optional
336
+ The name of the new column to be created (default is 'condition').
337
+ conditions : dict, optional
338
+ A dictionary where keys are substrings to search for and values are the corresponding labels.
339
+ default_name : str, optional
340
+ The name to assign if no condition matches (default is 'unknown').
341
+ inplace : bool, optional
342
+ Whether to modify the original DataFrame (default is True).
343
+ verbose : bool, optional
344
+ Whether to display the unique values and final DataFrame (default is True).
345
+ """
346
+
347
+ # Display the unique values in the column
348
+ content = data[column].unique().tolist()
349
+ if verbose:
350
+ if len(content) > 10:
351
+ display(content[:10])
352
+ else:
353
+ display(content)
354
+
355
+ # Check if conditions are provided
356
+ if conditions is None:
357
+ raise ValueError(
358
+ "Conditions must be provided as a dictionary with substrings and corresponding labels."
359
+ )
360
+
361
+ # Define a helper function to map the conditions
362
+ def map_condition(value):
363
+ for substring, label in conditions.items():
364
+ if substring in value:
365
+ return label
366
+ return default_name # If no condition matches, return the default name
367
+
368
+ # Apply the mapping function to create the new column
369
+ data[column_new] = data[column].apply(map_condition)
370
+
371
+ # Display the updated DataFrame if verbose is True
372
+ if verbose:
373
+ display(data)
374
+
375
+ if not inplace:
376
+ return data
377
+
378
+ def clean_dataset(
379
+ data: pd.DataFrame, dataset: str = "GSE25097", condition: str = "condition",sep="///"
380
+ ):
381
+ """
382
+ #* it has been involved in bio.batch_effects(), but default: False
383
+ 1. clean data set and prepare super_datasets
384
+ 2. if "///" in index, then extend it, or others.
385
+ 3. drop duplicates and dropna()
386
+ 4. add the 'condition' and 'dataset info' to the columns
387
+ 5. set genes as index
388
+ """
389
+ #! (4.1) clean data set and prepare super_datasets
390
+ # df_data_2, 左边的列是meta,右边的列是gene_symbol
391
+ col_gene = split_at_lower_upper(data.columns.tolist())[1][0]
392
+ idx = ips.strcmp(col_gene, data.columns.tolist())[1]
393
+ df_gene = data.iloc[:, idx:].T # keep the last 'condition'
394
+
395
+ #! if "///" in index, then extend it, or others.
396
+ print(f"before extend shape: {df_gene.shape}")
397
+ df = df_gene.reset_index()
398
+ df_gene = ips.df_extend(df, column="index", sep=sep)
399
+ # reset 'index' column as index
400
+ # df_gene = df_gene.set_index("index")
401
+ print(f"after extended by '{sep}' shape: {df_gene.shape}")
402
+
403
+ # *alternative:
404
+ # df_unique = df.reset_index().drop_duplicates(subset="index").set_index("index")
405
+ #! 4.2 drop duplicates and dropna()
406
+ df_gene = df_gene.drop_duplicates(subset=["index"]).dropna()
407
+ print(f"drop duplicates and dropna: shape: {df_gene.shape}")
408
+
409
+ #! add the 'condition' and 'dataset info' to the columns
410
+ ds = [data["dataset"][0]] * len(df_gene.columns[1:])
411
+ samp = df_gene.columns.tolist()[1:]
412
+ cond = df_gene[df_gene["index"] == condition].values.tolist()[0][1:]
413
+ df_gene.columns = ["index"] + [
414
+ f"{ds}_{sam}_{cond}" for (ds, sam, cond) in zip(ds, samp, cond)
415
+ ]
416
+ df_gene.drop(df_gene[df_gene["index"] == condition].index, inplace=True)
417
+ #! set genes as index
418
+ df_gene.set_index("index",inplace=True)
419
+ display(df_gene.head())
420
+ return df_gene
421
+
422
+ def batch_effect(
423
+ data: list = "[df_gene_1, df_gene_2, df_gene_3]",
424
+ datasets: list = ["GSE25097", "GSE62232", "GSE65372"],
425
+ clean_data:bool=False, # default, not do data cleaning
426
+ top_genes:int=10,# only for plotting
427
+ plot_=True,
428
+ dir_save="./res/",
429
+ kws_clean_dataset:dict={},
430
+ **kwargs
431
+ ):
432
+ """
433
+ usage 1:
434
+ bio.batch_effect(
435
+ data=[df_gene_1, df_gene_2, df_gene_3],
436
+ datasets=["GSE25097", "GSE62232", "GSE65372"],
437
+ clean_data=False,
438
+ dir_save="./res/")
439
+
440
+ #! # or conbine clean_dataset and batch_effect together
441
+ # # data = [bio.clean_dataset(data=dt, dataset=ds) for (dt, ds) in zip(data, datasets)]
442
+ data_common = bio.batch_effect(
443
+ data=[df_data_1, df_data_2, df_data_3],
444
+ datasets=["GSE25097", "GSE62232", "GSE65372"], clean_data=True
445
+ )
446
+ """
447
+ # data = [df_gene_1, df_gene_2, df_gene_3]
448
+ # datasets = ["GSE25097", "GSE62232", "GSE65372"]
449
+ # top_genes = 10 # show top 10 genes
450
+ # plot_ = True
451
+ from combat.pycombat import pycombat
452
+ if clean_data:
453
+ data=[clean_dataset(data=dt,dataset=ds,**kws_clean_dataset) for (dt,ds) in zip(data,datasets)]
454
+ #! prepare data
455
+ # the datasets are dataframes where:
456
+ # the indexes correspond to the gene names
457
+ # the column names correspond to the sample names
458
+ #! merge batchs
459
+ # https://epigenelabs.github.io/pyComBat/
460
+ # we merge all the datasets into one, by keeping the common genes only
461
+ df_expression_common_genes = pd.concat(data, join="inner", axis=1)
462
+ #! convert to float
463
+ ips.df_astype(df_expression_common_genes, astype="float", inplace=True)
464
+
465
+ #!to visualise results, use Mini datasets, only take the first 10 samples of each batch(dataset)
466
+ if plot_:
467
+ col2plot = []
468
+ for ds in datasets:
469
+ # select the first 10 samples to plot, to see the diff
470
+ dat_tmp = df_expression_common_genes.columns[
471
+ df_expression_common_genes.columns.str.startswith(ds)
472
+ ][:top_genes].tolist()
473
+ col2plot.extend(dat_tmp)
474
+ # visualise results
475
+ _, axs = plt.subplots(2, 1, figsize=(15, 10))
476
+ plot.plotxy(
477
+ ax=axs[0],
478
+ data=df_expression_common_genes.loc[:, col2plot],
479
+ kind="bar",
480
+ figsets=dict(
481
+ title="Samples expression distribution (non-correction)",
482
+ ylabel="Observations",
483
+ xangle=90,
484
+ ),
485
+ )
486
+ # prepare batch list
487
+ batch = [
488
+ ips.ssplit(i, by="_")[0] for i in df_expression_common_genes.columns.tolist()
489
+ ]
490
+ # run pyComBat
491
+ df_corrected = pycombat(df_expression_common_genes, batch, **kwargs)
492
+ print(f"df_corrected.shape: {df_corrected.shape}")
493
+ display(df_corrected.head())
494
+ # visualise results again
495
+ if plot_:
496
+
497
+ plot.plotxy(
498
+ ax=axs[1],
499
+ data=df_corrected.loc[:, col2plot],
500
+ kind="bar",
501
+ figsets=dict(
502
+ title="Samples expression distribution (corrected)",
503
+ ylabel="Observations",
504
+ xangle=90,
505
+ ),
506
+ )
507
+ if dir_save is not None:
508
+ ips.figsave(dir_save + "batch_sample_exp_distri.pdf")
509
+ return df_corrected
510
+
511
+ def get_common_genes(elment1, elment2):
512
+ common_genes=ips.shared(elment1, elment2)
513
+ return common_genes