solarwindpy 0.0.1.dev0__py3-none-any.whl → 0.1.0__py3-none-any.whl

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.

Potentially problematic release.


This version of solarwindpy might be problematic. Click here for more details.

Files changed (412) hide show
  1. plans/.velocity/metrics.json +96 -0
  2. plans/0-overview-template.md +268 -0
  3. plans/N-phase-template.md +106 -0
  4. plans/PLAN_AUDIT_SUMMARY.md +173 -0
  5. plans/TEMPLATE-USAGE-GUIDE.md +198 -0
  6. plans/__init__.py +1 -0
  7. plans/abandoned/compaction-agent-system/0-Overview.md +123 -0
  8. plans/abandoned/compaction-agent-system/agents-index-update-plan.md +109 -0
  9. plans/abandoned/compaction-agent-system/compacted_state.md +85 -0
  10. plans/abandoned/compaction-agent-system/implementation-plan.md +107 -0
  11. plans/abandoned/compaction-agent-system/system-validation-report.md +159 -0
  12. plans/abandoned/compaction-agent-system/usage-guide.md +210 -0
  13. plans/abandoned/hook-system-enhancement/0-Overview.md +214 -0
  14. plans/abandoned/hook-system-enhancement/1-Phase1-Core-Infrastructure.md +313 -0
  15. plans/abandoned/hook-system-enhancement/2-Phase2-Intelligent-Testing.md +385 -0
  16. plans/abandoned/hook-system-enhancement/3-Phase3-Physics-Validation.md +444 -0
  17. plans/abandoned/hook-system-enhancement/4-Phase4-Performance-Monitoring.md +458 -0
  18. plans/abandoned/hook-system-enhancement/5-Phase5-Developer-Experience.md +532 -0
  19. plans/abandoned/hook-system-enhancement/6-Implementation-Timeline.md +274 -0
  20. plans/abandoned/hook-system-enhancement/7-Risk-Management.md +376 -0
  21. plans/abandoned/hook-system-enhancement/8-Testing-Strategy.md +579 -0
  22. plans/abandoned/readthedocs-automation/0-Overview.md +247 -0
  23. plans/abandoned/readthedocs-automation/1-Emergency-Documentation-Fixes.md +270 -0
  24. plans/abandoned/readthedocs-automation/2-Template-System-Enhancement.md +811 -0
  25. plans/abandoned/readthedocs-automation/3-Quality-Audit-ReadTheDocs-Integration.md +844 -0
  26. plans/abandoned/readthedocs-automation/4-Plan-Consolidation-Cleanup.md +632 -0
  27. plans/abandoned/readthedocs-automation/9-Closeout.md +207 -0
  28. plans/abandoned/readthedocs-automation/ABANDONMENT_REASON.md +72 -0
  29. plans/cicd-architecture-redesign/0-Overview.md +193 -0
  30. plans/cicd-architecture-redesign/1-Workflow-Creation.md +103 -0
  31. plans/cicd-architecture-redesign/2-Version-Detection.md +123 -0
  32. plans/cicd-architecture-redesign/3-Deployment-Gates.md +169 -0
  33. plans/cicd-architecture-redesign/4-RC-Testing.md +194 -0
  34. plans/cicd-architecture-redesign/5-TestPyPI-Validation.md +264 -0
  35. plans/cicd-architecture-redesign/6-Production-Release.md +263 -0
  36. plans/cicd-architecture-redesign/7-Cleanup.md +243 -0
  37. plans/cicd-architecture-redesign/8-Documentation.md +285 -0
  38. plans/cicd-architecture-redesign/Closeout.md +225 -0
  39. plans/closeout-template.md +259 -0
  40. plans/completed/circular-import-audit/0-Overview.md +152 -0
  41. plans/completed/circular-import-audit/1-Static-Dependency-Analysis.md +62 -0
  42. plans/completed/circular-import-audit/2-Dynamic-Import-Testing.md +56 -0
  43. plans/completed/circular-import-audit/3-Performance-Impact-Assessment.md +56 -0
  44. plans/completed/circular-import-audit/4-Issue-Remediation.md +78 -0
  45. plans/completed/circular-import-audit/5-Preventive-Infrastructure.md +89 -0
  46. plans/completed/claude-settings-ecosystem-alignment/0-Overview.md +162 -0
  47. plans/completed/claude-settings-ecosystem-alignment/1-Security-Foundation.md +148 -0
  48. plans/completed/claude-settings-ecosystem-alignment/2-Hook-Integration.md +158 -0
  49. plans/completed/claude-settings-ecosystem-alignment/3-Agent-System-Integration.md +177 -0
  50. plans/completed/claude-settings-ecosystem-alignment/4-Enhanced-Workflow-Automation.md +159 -0
  51. plans/completed/claude-settings-ecosystem-alignment/5-Validation-Monitoring.md +181 -0
  52. plans/completed/claude-settings-ecosystem-alignment/compacted_session_state.md +290 -0
  53. plans/completed/combined_plan_with_checklist_documentation/1-Overview-and-Goals.md +51 -0
  54. plans/completed/combined_plan_with_checklist_documentation/2-Toolchain-and-Hosting.md +69 -0
  55. plans/completed/combined_plan_with_checklist_documentation/3-Repository-Structure.md +61 -0
  56. plans/completed/combined_plan_with_checklist_documentation/4-Configuration-and-Standards.md +70 -0
  57. plans/completed/combined_plan_with_checklist_documentation/5-Documentation-Content.md +62 -0
  58. plans/completed/combined_plan_with_checklist_documentation/6-CI-CD-and-Validation.md +58 -0
  59. plans/completed/combined_plan_with_checklist_documentation/7-Maintenance.md +55 -0
  60. plans/completed/combined_test_plan_with_checklist_fitfunctions/0-Overview.md +135 -0
  61. plans/completed/combined_test_plan_with_checklist_fitfunctions/1-Common-fixtures.md +59 -0
  62. plans/completed/combined_test_plan_with_checklist_fitfunctions/10-power_laws.md +56 -0
  63. plans/completed/combined_test_plan_with_checklist_fitfunctions/2-core.py-FitFunction.md +118 -0
  64. plans/completed/combined_test_plan_with_checklist_fitfunctions/3-gaussians.py-Gaussian-GaussianNormalized-GaussianLn.md +69 -0
  65. plans/completed/combined_test_plan_with_checklist_fitfunctions/4-trend_fits.py-TrendFit.md +99 -0
  66. plans/completed/combined_test_plan_with_checklist_fitfunctions/5-plots.py-FFPlot.md +98 -0
  67. plans/completed/combined_test_plan_with_checklist_fitfunctions/6-tex_info.py-TeXinfo.md +79 -0
  68. plans/completed/combined_test_plan_with_checklist_fitfunctions/7-Justification.md +49 -0
  69. plans/completed/combined_test_plan_with_checklist_fitfunctions/8-exponentials.md +64 -0
  70. plans/completed/combined_test_plan_with_checklist_fitfunctions/9-lines.md +58 -0
  71. plans/completed/combined_test_plan_with_checklist_plotting/0-Overview.md +142 -0
  72. plans/completed/combined_test_plan_with_checklist_plotting/1-base.py.md +90 -0
  73. plans/completed/combined_test_plan_with_checklist_plotting/10-labels-special.py.md +102 -0
  74. plans/completed/combined_test_plan_with_checklist_plotting/11-labels-chemistry.py.md +212 -0
  75. plans/completed/combined_test_plan_with_checklist_plotting/12-labels-composition.py.md +242 -0
  76. plans/completed/combined_test_plan_with_checklist_plotting/13-labels-datetime.py.md +247 -0
  77. plans/completed/combined_test_plan_with_checklist_plotting/14-labels-elemental_abundance.py.md +274 -0
  78. plans/completed/combined_test_plan_with_checklist_plotting/15-visual-validation.md +256 -0
  79. plans/completed/combined_test_plan_with_checklist_plotting/16-integration-testing.md +266 -0
  80. plans/completed/combined_test_plan_with_checklist_plotting/17-performance-benchmarks.md +267 -0
  81. plans/completed/combined_test_plan_with_checklist_plotting/18-Fixtures-and-Utilities.md +86 -0
  82. plans/completed/combined_test_plan_with_checklist_plotting/2-agg_plot.py.md +90 -0
  83. plans/completed/combined_test_plan_with_checklist_plotting/3-histograms.py.md +201 -0
  84. plans/completed/combined_test_plan_with_checklist_plotting/4-scatter.py.md +167 -0
  85. plans/completed/combined_test_plan_with_checklist_plotting/5-spiral.py.md +216 -0
  86. plans/completed/combined_test_plan_with_checklist_plotting/6-orbits.py.md +108 -0
  87. plans/completed/combined_test_plan_with_checklist_plotting/7-tools.py.md +86 -0
  88. plans/completed/combined_test_plan_with_checklist_plotting/8-select_data_from_figure.py.md +97 -0
  89. plans/completed/combined_test_plan_with_checklist_plotting/9-labels-base.py.md +88 -0
  90. plans/completed/combined_test_plan_with_checklist_solar_activity/.gitkeep +0 -0
  91. plans/completed/combined_test_plan_with_checklist_solar_activity/0-Overview.md +170 -0
  92. plans/completed/combined_test_plan_with_checklist_solar_activity/1-Package-Entry-Point-__init__.py.md +121 -0
  93. plans/completed/combined_test_plan_with_checklist_solar_activity/2-Core-Base-Classes-base.py.md +142 -0
  94. plans/completed/combined_test_plan_with_checklist_solar_activity/3-Plotting-Helpers-plots.py.md +123 -0
  95. plans/completed/combined_test_plan_with_checklist_solar_activity/4-LISIRD-Sub-package.md +119 -0
  96. plans/completed/combined_test_plan_with_checklist_solar_activity/5-Extrema-Calculator.md +103 -0
  97. plans/completed/combined_test_plan_with_checklist_solar_activity/6-Sunspot-Number-Sub-package.md +163 -0
  98. plans/completed/combined_test_plan_with_checklist_solar_activity/7-Sunspot-Number-Init.py.md +217 -0
  99. plans/completed/combined_test_plan_with_checklist_solar_activity/compacted_state.md +52 -0
  100. plans/completed/compaction-agent-modernization/0-Overview.md +156 -0
  101. plans/completed/compaction-agent-modernization/1-Architecture-Audit-Gap-Analysis.md +132 -0
  102. plans/completed/compaction-agent-modernization/2-Token-Baseline-Recalibration.md +153 -0
  103. plans/completed/compaction-agent-modernization/3-Agent-Reference-Updates.md +184 -0
  104. plans/completed/compaction-agent-modernization/4-Compression-Algorithm-Modernization.md +238 -0
  105. plans/completed/compaction-agent-modernization/5-Workflow-Integration-Streamlining.md +252 -0
  106. plans/completed/compaction-agent-modernization/6-Template-Structure-Optimization.md +240 -0
  107. plans/completed/compaction-agent-modernization/7-Integration-Testing-Validation.md +292 -0
  108. plans/completed/compaction-hook-enhancement/0-Overview.md +150 -0
  109. plans/completed/compaction-hook-enhancement/1-Token-Estimation-Enhancement.md +179 -0
  110. plans/completed/compaction-hook-enhancement/2-Compression-Intelligence.md +294 -0
  111. plans/completed/compaction-hook-enhancement/3-Git-Integration-Metadata.md +310 -0
  112. plans/completed/compaction-hook-enhancement/4-Session-Continuity-Features.md +358 -0
  113. plans/completed/compaction-hook-enhancement/5-Testing-Strategy.md +404 -0
  114. plans/completed/compaction-hook-enhancement/6-Integration-Roadmap.md +319 -0
  115. plans/completed/compaction-hook-enhancement/compacted_state.md +142 -0
  116. plans/completed/docstring-audit-enhancement/0-Overview.md +274 -0
  117. plans/completed/docstring-audit-enhancement/1-Infrastructure-Setup-and-Validation-Tools.md +206 -0
  118. plans/completed/docstring-audit-enhancement/2-Core-Physics-Modules-Enhancement.md +237 -0
  119. plans/completed/docstring-audit-enhancement/3-Fitfunctions-Mathematical-Modules-Enhancement.md +188 -0
  120. plans/completed/docstring-audit-enhancement/4-Plotting-Visualization-Modules-Enhancement.md +243 -0
  121. plans/completed/docstring-audit-enhancement/5-Specialized-Modules-Enhancement.md +216 -0
  122. plans/completed/docstring-audit-enhancement/6-Validation-and-Integration.md +216 -0
  123. plans/completed/fitfunctions-testing-implementation/0-Overview.md +130 -0
  124. plans/completed/fitfunctions-testing-implementation/1-Test-Infrastructure-Setup.md +79 -0
  125. plans/completed/fitfunctions-testing-implementation/2-Common-Fixtures-Test-Utilities.md +104 -0
  126. plans/completed/fitfunctions-testing-implementation/3-Core-FitFunction-Testing.md +168 -0
  127. plans/completed/fitfunctions-testing-implementation/4-Specialized-Function-Classes.md +210 -0
  128. plans/completed/fitfunctions-testing-implementation/5-Advanced-Classes-Testing.md +214 -0
  129. plans/completed/fitfunctions-testing-implementation/6-Plotting-Integration-Testing.md +231 -0
  130. plans/completed/fitfunctions-testing-implementation/7-Extended-Coverage-BONUS.md +184 -0
  131. plans/completed/numpy-docstring-conversion-plan/numpy-docstring-conversion-plan.md +118 -0
  132. plans/completed/pr-review-remediation/0-Overview.md +138 -0
  133. plans/completed/pr-review-remediation/1-Critical-Safety-Improvements.md +179 -0
  134. plans/completed/pr-review-remediation/2-Smart-Timeouts-Validation.md +399 -0
  135. plans/completed/pr-review-remediation/3-Enhanced-GitHub-Integration.md +258 -0
  136. plans/completed/pr-review-remediation/compacted_state.md +66 -0
  137. plans/completed/python-310-migration/0-Overview.md +390 -0
  138. plans/completed/python-310-migration/1-Planning-Setup.md +164 -0
  139. plans/completed/python-310-migration/2-Implementation.md +256 -0
  140. plans/completed/python-310-migration/3-Testing-Validation.md +335 -0
  141. plans/completed/python-310-migration/4-Documentation-Release.md +274 -0
  142. plans/completed/python-310-migration/5-Closeout.md +252 -0
  143. plans/completed/requirements-management-consolidation/0-Overview.md +118 -0
  144. plans/completed/requirements-management-consolidation/1-Documentation-Validation-Environment-Setup.md +116 -0
  145. plans/completed/requirements-management-consolidation/2-Requirements-Consolidation.md +161 -0
  146. plans/completed/requirements-management-consolidation/3-Workflow-Automation-Final-Integration.md +196 -0
  147. plans/completed/single-ecosystem-plan-implementation/0-Overview.md +83 -0
  148. plans/completed/single-ecosystem-plan-implementation/1-Plan-Preservation-Session-Management.md +38 -0
  149. plans/completed/single-ecosystem-plan-implementation/2-File-Structure-Optimization.md +43 -0
  150. plans/completed/single-ecosystem-plan-implementation/3-Plan-Migration-Archive-Setup.md +82 -0
  151. plans/completed/single-ecosystem-plan-implementation/4-Agent-System-Transformation.md +108 -0
  152. plans/completed/single-ecosystem-plan-implementation/5-Template-System-Enhancement.md +131 -0
  153. plans/completed/single-ecosystem-plan-implementation/6-Final-Validation-Testing.md +120 -0
  154. plans/completed/test-directory-consolidation/0-Overview.md +51 -0
  155. plans/completed/test-directory-consolidation/1-Structure-Preparation.md +82 -0
  156. plans/completed/test-directory-consolidation/2-File-Migration.md +100 -0
  157. plans/completed/test-directory-consolidation/3-Import-Transformation.md +117 -0
  158. plans/completed/test-directory-consolidation/4-Configuration-Consolidation.md +140 -0
  159. plans/completed/test-directory-consolidation/5-Validation.md +152 -0
  160. plans/completed/test-directory-consolidation/6-Cleanup.md +156 -0
  161. plans/completed/test-planning-agents-architecture/0-Overview.md +79 -0
  162. plans/completed/test-planning-agents-architecture/1-Branch-Isolation-Testing.md +49 -0
  163. plans/completed/test-planning-agents-architecture/2-Cross-Branch-Coordination.md +51 -0
  164. plans/completed/test-planning-agents-architecture/3-Merge-Workflow-Testing.md +48 -0
  165. plans/deployment-semver-pypi-rtd/0-Overview.md +463 -0
  166. plans/deployment-semver-pypi-rtd/1-Semantic-Versioning-Foundation.md +136 -0
  167. plans/deployment-semver-pypi-rtd/2-PyPI-Deployment-Infrastructure.md +168 -0
  168. plans/deployment-semver-pypi-rtd/3-Release-Automation.md +214 -0
  169. plans/deployment-semver-pypi-rtd/4-Plan-Closeout.md +543 -0
  170. plans/deployment-semver-pypi-rtd/compacted_session_state.md +172 -0
  171. plans/deployment-semver-pypi-rtd/compacted_state.md +131 -0
  172. plans/documentation-code-audit/0-Overview.md +393 -0
  173. plans/documentation-code-audit/1-Discovery-Inventory.md +183 -0
  174. plans/documentation-code-audit/2-Execution-Environment-Setup.md +263 -0
  175. plans/documentation-code-audit/3-Systematic-Validation.md +322 -0
  176. plans/documentation-code-audit/4-Code-Example-Remediation.md +358 -0
  177. plans/documentation-code-audit/5-Physics-MultiIndex-Compliance.md +464 -0
  178. plans/documentation-code-audit/6-Doctest-Integration.md +523 -0
  179. plans/documentation-code-audit/7-Reporting-Documentation.md +498 -0
  180. plans/documentation-code-audit/8-Closeout.md +456 -0
  181. plans/documentation-rebuild-session/compacted_state.md +109 -0
  182. plans/documentation-rendering-fixes/0-Overview.md +104 -0
  183. plans/documentation-rendering-fixes/1-Sphinx-Build-Diagnostics-Warning-Audit.md +101 -0
  184. plans/documentation-rendering-fixes/2-Configuration-Infrastructure-Fixes.md +113 -0
  185. plans/documentation-rendering-fixes/3-Docstring-Syntax-Audit-Repair.md +131 -0
  186. plans/documentation-rendering-fixes/4-HTML-Page-Rendering-Verification.md +113 -0
  187. plans/documentation-rendering-fixes/5-Advanced-Documentation-Quality-Assurance.md +119 -0
  188. plans/documentation-rendering-fixes/6-Documentation-Build-Optimization-Testing.md +129 -0
  189. plans/documentation-rendering-fixes/compacted_state.md +132 -0
  190. plans/documentation-template-fix/0-Overview.md +197 -0
  191. plans/documentation-template-fix/1-Template-System-Analysis.md +269 -0
  192. plans/documentation-template-fix/2-Template-Modification.md +609 -0
  193. plans/documentation-template-fix/3-Build-System-Integration.md +766 -0
  194. plans/documentation-template-fix/4-Testing-Validation.md +1399 -0
  195. plans/documentation-template-fix/5-Documentation-Training.md +602 -0
  196. plans/documentation-workflow-fix/0-Overview.md +222 -0
  197. plans/documentation-workflow-fix/1-Immediate-Fixes.md +238 -0
  198. plans/documentation-workflow-fix/2-Configuration-Setup.md +298 -0
  199. plans/documentation-workflow-fix/3-Pre-commit-Integration.md +382 -0
  200. plans/documentation-workflow-fix/4-Workflow-Improvements.md +446 -0
  201. plans/documentation-workflow-fix/5-Documentation-and-Training.md +527 -0
  202. plans/duplicate-object-warnings-fix-plan.md +130 -0
  203. plans/github-issues-migration/0-Overview.md +510 -0
  204. plans/github-issues-migration/1-Foundation-Label-System.md +180 -0
  205. plans/github-issues-migration/2-Migration-Tool-Rewrite.md +235 -0
  206. plans/github-issues-migration/3-CLI-Integration-Automation.md +169 -0
  207. plans/github-issues-migration/4-Validated-Migration.md +252 -0
  208. plans/github-issues-migration/5-Documentation-Training.md +171 -0
  209. plans/github-issues-migration/6-Closeout.md +179 -0
  210. plans/github-workflows-repair/repair-plan.md +299 -0
  211. plans/issues_from_plans.py +342 -0
  212. plans/pr-270-doc-validation-fixes/0-Overview.md +354 -0
  213. plans/pr-270-doc-validation-fixes/1-Critical-PR-Fixes.md +117 -0
  214. plans/pr-270-doc-validation-fixes/2-Framework-Right-Sizing.md +129 -0
  215. plans/pr-270-doc-validation-fixes/3-Sustainable-Documentation.md +126 -0
  216. plans/pr-270-doc-validation-fixes/4-Closeout-Migration.md +143 -0
  217. plans/pr-270-doc-validation-fixes/PLAN_COMPLETED.md +149 -0
  218. plans/python-310-migration/0-Overview.md +390 -0
  219. plans/python-310-migration/1-Planning-Setup.md +164 -0
  220. plans/python-310-migration/2-Implementation.md +256 -0
  221. plans/python-310-migration/3-Testing-Validation.md +335 -0
  222. plans/python-310-migration/4-Documentation-Release.md +274 -0
  223. plans/python-310-migration/5-Closeout.md +252 -0
  224. plans/readthedocs-simplified/0-Overview.md +243 -0
  225. plans/readthedocs-simplified/1-Immediate-Fixes.md +216 -0
  226. plans/readthedocs-simplified/2-Template-Simplification.md +278 -0
  227. plans/readthedocs-simplified/3-ReadTheDocs-Setup.md +298 -0
  228. plans/readthedocs-simplified/4-Testing-Validation.md +328 -0
  229. plans/readthedocs-simplified/5-Closeout.md +231 -0
  230. plans/readthedocs-simplified/compacted_state.md +127 -0
  231. plans/session-compaction-2025-08-12/compacted_state.md +114 -0
  232. plans/session-compaction-2025-08-13/compacted_state.md +145 -0
  233. plans/session-continuity-protocol/0-Overview.md +35 -0
  234. plans/session-continuity-protocol/1-Core-Principles-Framework.md +40 -0
  235. plans/session-continuity-protocol/2-Pre-Session-Validation-System.md +79 -0
  236. plans/session-continuity-protocol/3-Context-Switching-Prevention.md +87 -0
  237. plans/session-continuity-protocol/4-Progress-Tracking-Recovery.md +100 -0
  238. plans/sphinx-warnings-analysis.md +222 -0
  239. plans/systemprompt-optimization/0-Overview.md +447 -0
  240. plans/systemprompt-optimization/1-Deploy-SystemPrompt.md +114 -0
  241. plans/systemprompt-optimization/2-Documentation-Alignment.md +198 -0
  242. plans/systemprompt-optimization/3-Monitoring-Infrastructure.md +396 -0
  243. plans/systemprompt-optimization/4-Implementation-Script.md +450 -0
  244. plans/systemprompt-optimization/9-Closeout.md +165 -0
  245. plans/systemprompt-optimization/compacted_state.md +143 -0
  246. plans/template-value-propositions/0-Overview.md +357 -0
  247. plans/template-value-propositions/1-Value-Proposition-Framework-Design.md +144 -0
  248. plans/template-value-propositions/2-Plan-Template-Enhancement.md +178 -0
  249. plans/template-value-propositions/3-Value-Generator-Hook-Implementation.md +291 -0
  250. plans/template-value-propositions/4-Value-Validator-Hook-Implementation.md +274 -0
  251. plans/template-value-propositions/5-Documentation-Agent-Updates.md +219 -0
  252. plans/template-value-propositions/6-Integration-Testing-Validation.md +247 -0
  253. plans/tests-audit/0-Overview.md +410 -0
  254. plans/tests-audit/1-Discovery-Inventory.md +170 -0
  255. plans/tests-audit/2-Physics-Validation-Audit.md +195 -0
  256. plans/tests-audit/3-Architecture-Compliance.md +195 -0
  257. plans/tests-audit/4-Numerical-Stability-Analysis.md +203 -0
  258. plans/tests-audit/5-Documentation-Enhancement.md +220 -0
  259. plans/tests-audit/6-Audit-Deliverables.md +220 -0
  260. plans/tests-audit/7-Closeout.md +252 -0
  261. plans/tests-audit/artifacts/ARCHITECTURE_COMPLIANCE_REPORT.md +315 -0
  262. plans/tests-audit/artifacts/ARCHITECTURE_RECOMMENDATIONS.md +943 -0
  263. plans/tests-audit/artifacts/COMPREHENSIVE_AUDIT_REPORT.md +356 -0
  264. plans/tests-audit/artifacts/CONTRIBUTING_ENHANCED_TEMPLATE.md +419 -0
  265. plans/tests-audit/artifacts/COVERAGE_GAP_ANALYSIS.md +152 -0
  266. plans/tests-audit/artifacts/DOCUMENTATION_ENHANCEMENT_REPORT.md +502 -0
  267. plans/tests-audit/artifacts/EXECUTIVE_AUDIT_SUMMARY.md +129 -0
  268. plans/tests-audit/artifacts/IMPLEMENTATION_ROADMAP.md +647 -0
  269. plans/tests-audit/artifacts/NUMERICAL_RECOMMENDATIONS.md +739 -0
  270. plans/tests-audit/artifacts/NUMERICAL_STABILITY_GUIDE_TEMPLATE.rst +451 -0
  271. plans/tests-audit/artifacts/NUMERICAL_STABILITY_REPORT.md +301 -0
  272. plans/tests-audit/artifacts/PHASE_3_SUMMARY.md +280 -0
  273. plans/tests-audit/artifacts/PHASE_4_SUMMARY.md +229 -0
  274. plans/tests-audit/artifacts/PHASE_5_SUMMARY.md +292 -0
  275. plans/tests-audit/artifacts/PHASE_6_CLOSEOUT.md +278 -0
  276. plans/tests-audit/artifacts/PHYSICS_GUIDE_TEMPLATE.rst +268 -0
  277. plans/tests-audit/artifacts/PHYSICS_VALIDATION_REPORT.md +235 -0
  278. plans/tests-audit/artifacts/TECHNICAL_DELIVERABLES_PACKAGE.md +2502 -0
  279. plans/tests-audit/artifacts/TEST_INVENTORY.csv +1204 -0
  280. plans/tests-audit/artifacts/TEST_INVENTORY.md +135 -0
  281. plans/tests-audit/artifacts/test_discovery_analysis.py +231 -0
  282. plans/tests-audit/artifacts/test_parser.py +395 -0
  283. solarwindpy/README.md +3 -0
  284. solarwindpy/Untitled.ipynb +54 -0
  285. solarwindpy/__init__.py +74 -0
  286. solarwindpy/core/__init__.py +23 -0
  287. solarwindpy/core/alfvenic_turbulence.py +804 -0
  288. solarwindpy/core/base.py +267 -0
  289. solarwindpy/core/ions.py +309 -0
  290. solarwindpy/core/plasma.py +2133 -0
  291. solarwindpy/core/spacecraft.py +256 -0
  292. solarwindpy/core/tensor.py +90 -0
  293. solarwindpy/core/units_constants.py +199 -0
  294. solarwindpy/core/vector.py +328 -0
  295. solarwindpy/fitfunctions/__init__.py +20 -0
  296. solarwindpy/fitfunctions/core.py +734 -0
  297. solarwindpy/fitfunctions/exponentials.py +188 -0
  298. solarwindpy/fitfunctions/gaussians.py +264 -0
  299. solarwindpy/fitfunctions/lines.py +116 -0
  300. solarwindpy/fitfunctions/moyal.py +71 -0
  301. solarwindpy/fitfunctions/plots.py +751 -0
  302. solarwindpy/fitfunctions/power_laws.py +209 -0
  303. solarwindpy/fitfunctions/tex_info.py +568 -0
  304. solarwindpy/fitfunctions/trend_fits.py +482 -0
  305. solarwindpy/instabilities/__init__.py +16 -0
  306. solarwindpy/instabilities/beta_ani.py +82 -0
  307. solarwindpy/instabilities/verscharen2016.py +631 -0
  308. solarwindpy/plotting/__init__.py +33 -0
  309. solarwindpy/plotting/agg_plot.py +489 -0
  310. solarwindpy/plotting/base.py +465 -0
  311. solarwindpy/plotting/hist1d.py +405 -0
  312. solarwindpy/plotting/hist2d.py +1035 -0
  313. solarwindpy/plotting/histograms.py +1845 -0
  314. solarwindpy/plotting/labels/__init__.py +104 -0
  315. solarwindpy/plotting/labels/base.py +686 -0
  316. solarwindpy/plotting/labels/chemistry.py +19 -0
  317. solarwindpy/plotting/labels/composition.py +100 -0
  318. solarwindpy/plotting/labels/datetime.py +235 -0
  319. solarwindpy/plotting/labels/elemental_abundance.py +73 -0
  320. solarwindpy/plotting/labels/special.py +794 -0
  321. solarwindpy/plotting/orbits.py +515 -0
  322. solarwindpy/plotting/scatter.py +99 -0
  323. solarwindpy/plotting/select_data_from_figure.py +329 -0
  324. solarwindpy/plotting/spiral.py +980 -0
  325. solarwindpy/plotting/tools.py +434 -0
  326. solarwindpy/scripts/__init__.py +1 -0
  327. solarwindpy/scripts/logs/.gitignore +1 -0
  328. solarwindpy/solar_activity/__init__.py +53 -0
  329. solarwindpy/solar_activity/base.py +605 -0
  330. solarwindpy/solar_activity/lisird/__init__.py +3 -0
  331. solarwindpy/solar_activity/lisird/extrema_calculator.py +394 -0
  332. solarwindpy/solar_activity/lisird/lisird.py +319 -0
  333. solarwindpy/solar_activity/plots.py +116 -0
  334. solarwindpy/solar_activity/sunspot_number/.DS_Store +0 -0
  335. solarwindpy/solar_activity/sunspot_number/__init__.py +3 -0
  336. solarwindpy/solar_activity/sunspot_number/sidc.py +556 -0
  337. solarwindpy/solar_activity/sunspot_number/ssn_extrema.csv +72 -0
  338. solarwindpy/solar_activity/sunspot_number/ssn_extrema.csv.silso +72 -0
  339. solarwindpy/tools/__init__.py +162 -0
  340. solarwindpy-0.1.0.dist-info/METADATA +181 -0
  341. solarwindpy-0.1.0.dist-info/RECORD +409 -0
  342. {solarwindpy-0.0.1.dev0.dist-info → solarwindpy-0.1.0.dist-info}/WHEEL +1 -1
  343. solarwindpy-0.1.0.dist-info/licenses/LICENSE.rst +32 -0
  344. solarwindpy-0.1.0.dist-info/top_level.txt +3 -0
  345. tests/__init__.py +1 -0
  346. tests/conftest.py +10 -0
  347. tests/core/__init__.py +1 -0
  348. tests/core/test_alfvenic_turbulence.py +544 -0
  349. tests/core/test_base.py +112 -0
  350. tests/core/test_base_head_tail.py +29 -0
  351. tests/core/test_base_mi_tuples.py +11 -0
  352. tests/core/test_core_verify_datetimeindex.py +32 -0
  353. tests/core/test_ions.py +325 -0
  354. tests/core/test_plasma.py +2581 -0
  355. tests/core/test_plasma_io.py +12 -0
  356. tests/core/test_quantities.py +507 -0
  357. tests/core/test_spacecraft.py +210 -0
  358. tests/core/test_units_constants.py +22 -0
  359. tests/data/epoch.csv +4 -0
  360. tests/data/plasma.csv +4 -0
  361. tests/data/spacecraft.csv +4 -0
  362. tests/fitfunctions/conftest.py +60 -0
  363. tests/fitfunctions/test_core.py +193 -0
  364. tests/fitfunctions/test_exponentials.py +342 -0
  365. tests/fitfunctions/test_gaussians.py +142 -0
  366. tests/fitfunctions/test_lines.py +349 -0
  367. tests/fitfunctions/test_moyal.py +258 -0
  368. tests/fitfunctions/test_plots.py +258 -0
  369. tests/fitfunctions/test_power_laws.py +365 -0
  370. tests/fitfunctions/test_tex_info.py +183 -0
  371. tests/fitfunctions/test_trend_fit_properties.py +31 -0
  372. tests/fitfunctions/test_trend_fits.py +244 -0
  373. tests/plotting/__init__.py +1 -0
  374. tests/plotting/labels/__init__.py +1 -0
  375. tests/plotting/labels/test_chemistry.py +243 -0
  376. tests/plotting/labels/test_composition.py +345 -0
  377. tests/plotting/labels/test_datetime.py +445 -0
  378. tests/plotting/labels/test_elemental_abundance.py +366 -0
  379. tests/plotting/labels/test_init.py +66 -0
  380. tests/plotting/labels/test_labels_base.py +347 -0
  381. tests/plotting/labels/test_special.py +550 -0
  382. tests/plotting/test_agg_plot.py +602 -0
  383. tests/plotting/test_base.py +752 -0
  384. tests/plotting/test_fixtures_utilities.py +775 -0
  385. tests/plotting/test_histograms.py +546 -0
  386. tests/plotting/test_integration.py +675 -0
  387. tests/plotting/test_orbits.py +435 -0
  388. tests/plotting/test_performance.py +708 -0
  389. tests/plotting/test_scatter.py +752 -0
  390. tests/plotting/test_select_data_from_figure.py +1209 -0
  391. tests/plotting/test_spiral.py +573 -0
  392. tests/plotting/test_tools.py +607 -0
  393. tests/plotting/test_visual_validation.py +465 -0
  394. tests/solar_activity/__init__.py +1 -0
  395. tests/solar_activity/lisird/__init__.py +1 -0
  396. tests/solar_activity/lisird/test_extrema_calculator.py +593 -0
  397. tests/solar_activity/lisird/test_lisird_id.py +187 -0
  398. tests/solar_activity/sunspot_number/__init__.py +1 -0
  399. tests/solar_activity/sunspot_number/test_init.py +399 -0
  400. tests/solar_activity/sunspot_number/test_sidc.py +465 -0
  401. tests/solar_activity/sunspot_number/test_sidc_id.py +223 -0
  402. tests/solar_activity/sunspot_number/test_sidc_loader.py +275 -0
  403. tests/solar_activity/sunspot_number/test_ssn_extrema.py +406 -0
  404. tests/solar_activity/test_base.py +656 -0
  405. tests/solar_activity/test_init.py +396 -0
  406. tests/solar_activity/test_plots.py +371 -0
  407. tests/test_circular_imports.py +408 -0
  408. tests/test_issue_titles.py +25 -0
  409. tests/test_statusline.py +298 -0
  410. solarwindpy-0.0.1.dev0.dist-info/METADATA +0 -14
  411. solarwindpy-0.0.1.dev0.dist-info/RECORD +0 -4
  412. solarwindpy-0.0.1.dev0.dist-info/top_level.txt +0 -1
@@ -0,0 +1,1035 @@
1
+ #!/usr/bin/env python
2
+ r"""Two-dimensional histogram and heatmap plotting utilities."""
3
+
4
+ import pdb # noqa: F401
5
+
6
+ import numpy as np
7
+ import pandas as pd
8
+ import matplotlib as mpl
9
+
10
+ from matplotlib import pyplot as plt
11
+ from collections import namedtuple
12
+ from scipy.signal import savgol_filter
13
+
14
+
15
+ from . import base
16
+ from . import labels as labels_module
17
+
18
+ # from .agg_plot import AggPlot
19
+ # from .hist1d import Hist1D
20
+
21
+ from . import agg_plot
22
+ from . import hist1d
23
+
24
+ AggPlot = agg_plot.AggPlot
25
+ Hist1D = hist1d.Hist1D
26
+
27
+ # import os
28
+ # import psutil
29
+
30
+
31
+ # def log_mem_usage():
32
+ # usage = psutil.Process(os.getpid()).memory_info()
33
+ # usage = "\n".join(
34
+ # ["{} {:.3f} GB".format(k, v * 1e-9) for k, v in usage._asdict().items()]
35
+ # )
36
+ # logging.getLogger("main").warning("Memory usage\n%s", usage)
37
+
38
+
39
+ # class Hist2D(base.Plot2D, AggPlot):
40
+ class Hist2D(base.PlotWithZdata, base.CbarMaker, AggPlot):
41
+ r"""Create a 2D histogram with an optional z-value using an equal number.
42
+
43
+ of bins along the x and y axis.
44
+
45
+ Parameters
46
+ ----------
47
+ x, y: pd.Series
48
+ x and y data to aggregate
49
+ z: None, pd.Series
50
+ If not None, the z-value to aggregate.
51
+ axnorm: str
52
+ Normalize the histogram.
53
+ key normalization
54
+ --- -------------
55
+ c column
56
+ r row
57
+ t total
58
+ d density
59
+ logx, logy: bool
60
+ If True, log10 scale the axis.
61
+
62
+ Attributes
63
+ ----------
64
+ data:
65
+ bins:
66
+ cut:
67
+ axnorm:
68
+ log<x,y>:
69
+ <x,y,z>label:
70
+ path: None, Path
71
+
72
+ Methods
73
+ -------
74
+ calc_bins:
75
+ calculate the x, y bins.
76
+ make_cut:
77
+ Utilize the calculated bins to convert (x, y) into pd.Categoral
78
+ or pd.Interval values used in aggregation.
79
+ set_[x,y,z]label:
80
+ Set the x, y, or z label.
81
+ agg:
82
+ Aggregate the data in the bins.
83
+ If z-value is None, count the number of points in each bin.
84
+ If z-value is not None, calculate the mean for each bin.
85
+ make_plot:
86
+ Make a 2D plot of the data with an optional color bar.
87
+ """
88
+
89
+ def __init__(
90
+ self,
91
+ x,
92
+ y,
93
+ z=None,
94
+ axnorm=None,
95
+ logx=False,
96
+ logy=False,
97
+ clip_data=False,
98
+ nbins=101,
99
+ bin_precision=None,
100
+ ):
101
+ super().__init__()
102
+ self.set_log(x=logx, y=logy)
103
+ self.set_data(x, y, z, clip_data)
104
+ self.set_labels(
105
+ x="x", y="y", z=labels_module.Count(norm=axnorm) if z is None else "z"
106
+ )
107
+
108
+ self.set_axnorm(axnorm)
109
+ self.calc_bins_intervals(nbins=nbins, precision=bin_precision)
110
+ self.make_cut()
111
+ self.set_clim(None, None)
112
+ self.set_alim(None, None)
113
+
114
+ @property
115
+ def _gb_axes(self):
116
+ return ("x", "y")
117
+
118
+ def _maybe_convert_to_log_scale(self, x, y):
119
+ if self.log.x:
120
+ x = 10.0**x
121
+ if self.log.y:
122
+ y = 10.0**y
123
+
124
+ return x, y
125
+
126
+ # def set_path(self, new, add_scale=True):
127
+ # # Bug: path doesn't auto-set log information.
128
+ # path, x, y, z, scale_info = super().set_path(new, add_scale)
129
+
130
+ # if new == "auto":
131
+ # path = path / x / y / z
132
+
133
+ # else:
134
+ # assert x is None
135
+ # assert y is None
136
+ # assert z is None
137
+
138
+ # if add_scale:
139
+ # assert scale_info is not None
140
+
141
+ # scale_info = "-".join(scale_info)
142
+
143
+ # if bool(len(path.parts)) and path.parts[-1].endswith("norm"):
144
+ # # Insert <norm> at end of path so scale order is (x, y, z).
145
+ # path = path.parts
146
+ # path = path[:-1] + (scale_info + "-" + path[-1],)
147
+ # path = Path(*path)
148
+ # else:
149
+ # path = path / scale_info
150
+
151
+ # self._path = path
152
+
153
+ # set_path.__doc__ = base.Base.set_path.__doc__
154
+
155
+ def set_labels(self, **kwargs):
156
+
157
+ z = kwargs.pop("z", self.labels.z)
158
+ if isinstance(z, labels_module.Count):
159
+ try:
160
+ z.set_axnorm(self.axnorm)
161
+ except AttributeError:
162
+ pass
163
+
164
+ z.build_label()
165
+
166
+ super().set_labels(z=z, **kwargs)
167
+
168
+ # def set_data(self, x, y, z, clip):
169
+ # data = pd.DataFrame(
170
+ # {
171
+ # "x": np.log10(np.abs(x)) if self.log.x else x,
172
+ # "y": np.log10(np.abs(y)) if self.log.y else y,
173
+ # }
174
+ # )
175
+ #
176
+ #
177
+ # if z is None:
178
+ # z = pd.Series(1, index=x.index)
179
+ #
180
+ # data.loc[:, "z"] = z
181
+ # data = data.dropna()
182
+ # if not data.shape[0]:
183
+ # raise ValueError(
184
+ # "You can't build a %s with data that is exclusively NaNs"
185
+ # % self.__class__.__name__
186
+ # )
187
+ #
188
+ # self._data = data
189
+ # self._clip = clip
190
+
191
+ def set_data(self, x, y, z, clip):
192
+ super().set_data(x, y, z, clip)
193
+ data = self.data
194
+ if self.log.x:
195
+ data.loc[:, "x"] = np.log10(np.abs(data.loc[:, "x"]))
196
+ if self.log.y:
197
+ data.loc[:, "y"] = np.log10(np.abs(data.loc[:, "y"]))
198
+ self._data = data
199
+
200
+ def set_axnorm(self, new):
201
+ r"""The method by which the gridded data is normalized.
202
+
203
+ ===== =============================================================
204
+ key description
205
+ ===== =============================================================
206
+ c Column normalize
207
+ d Density normalize
208
+ r Row normalize
209
+ t Total normalize
210
+ cd PDFs in each column
211
+ rd PDFs in each row
212
+ ===== ============================================================="""
213
+ if new is not None:
214
+ new = new.lower()
215
+ assert new in (
216
+ "c",
217
+ "r",
218
+ "t",
219
+ "d",
220
+ "cd",
221
+ "rd",
222
+ ), f"Unrecgonized axnorm `{new}`"
223
+
224
+ zlbl = self.labels.z
225
+ if isinstance(zlbl, labels_module.Count):
226
+ zlbl.set_axnorm(new)
227
+ zlbl.build_label()
228
+
229
+ self._axnorm = new
230
+
231
+ def _axis_normalizer(self, agg):
232
+ r"""Takes care of row, column, total, and density normaliation.
233
+
234
+ Written basically as `staticmethod` so that can be called in `OrbitHist2D`, but
235
+ as actual method with `self` passed so we have access to `self.log` for density
236
+ normalization.
237
+ """
238
+
239
+ axnorm = self.axnorm
240
+ if axnorm is None:
241
+ pass
242
+ elif axnorm == "c":
243
+ agg = agg.divide(agg.max(level="x"), level="x")
244
+ elif axnorm == "r":
245
+ agg = agg.divide(agg.max(level="y"), level="y")
246
+ elif axnorm == "t":
247
+ agg = agg.divide(agg.max())
248
+ elif axnorm == "d":
249
+ N = agg.sum().sum()
250
+ x = pd.IntervalIndex(agg.index.get_level_values("x").unique())
251
+ y = pd.IntervalIndex(agg.index.get_level_values("y").unique())
252
+ dx = pd.Series(
253
+ x.length, index=x
254
+ ) # dx = pd.Series(x.right - x.left, index=x)
255
+ dy = pd.Series(
256
+ y.length, index=y
257
+ ) # dy = pd.Series(y.right - y.left, index=y)
258
+
259
+ if self.log.x:
260
+ dx = 10.0**dx
261
+ if self.log.y:
262
+ dy = 10.0**dy
263
+
264
+ agg = agg.divide(dx, level="x").divide(dy, level="y").divide(N)
265
+
266
+ elif axnorm == "cd":
267
+ # raise NotImplementedError("Need to verify data alignment, especially `dx` values and index")
268
+ N = agg.sum(level="x")
269
+ dy = pd.IntervalIndex(
270
+ agg.index.get_level_values("y").unique()
271
+ ).sort_values()
272
+ dy = pd.Series(dy.length, index=dy).sort_index()
273
+ # Divide by total in each column and each row's width
274
+ agg = agg.divide(N, level="x").divide(dy, level="y")
275
+
276
+ elif axnorm == "rd":
277
+ # raise NotImplementedError("Need to verify data alignment, especially `dx` values and index")
278
+ N = agg.sum(level="y")
279
+ dx = pd.IntervalIndex(
280
+ agg.index.get_level_values("x").unique()
281
+ ).sort_values()
282
+ dx = pd.Series(dx.length, index=dx).sort_index()
283
+ # Divide by total in each column and each row's width
284
+ agg = agg.divide(N, level="y").divide(dx, level="x")
285
+
286
+ elif hasattr(axnorm, "__iter__"):
287
+ kind, fcn = axnorm
288
+ if kind == "c":
289
+ agg = agg.divide(agg.agg(fcn, level="x"), level="x")
290
+ elif kind == "r":
291
+ agg = agg.divide(agg.agg(fcn, level="y"), level="y")
292
+ else:
293
+ raise ValueError(f"Unrecognized axnorm with function ({kind}, {fcn})")
294
+ else:
295
+ raise ValueError(f"Unrecognized axnorm ({axnorm})")
296
+
297
+ return agg
298
+
299
+ def agg(self, **kwargs):
300
+ agg = super().agg(**kwargs)
301
+ agg = self._axis_normalizer(agg)
302
+ agg = self._agg_reindexer(agg)
303
+
304
+ a0, a1 = self.alim
305
+ if a0 is not None or a1 is not None:
306
+ tk = pd.Series(True, index=agg.index)
307
+ # tk = pd.DataFrame(True,
308
+ # index=agg.index,
309
+ # columns=agg.columns
310
+ # )
311
+ if a0 is not None:
312
+ tk = tk & (agg >= a0)
313
+ if a1 is not None:
314
+ tk = tk & (agg <= a1)
315
+
316
+ agg = agg.where(tk)
317
+
318
+ return agg
319
+
320
+ def _make_cbar(self, mappable, **kwargs):
321
+ ticks = kwargs.pop(
322
+ "ticks",
323
+ mpl.ticker.MultipleLocator(0.1) if self.axnorm in ("c", "r") else None,
324
+ )
325
+ return super()._make_cbar(mappable, ticks=ticks, **kwargs)
326
+
327
+ def _limit_color_norm(self, norm):
328
+ if self.axnorm in ("c", "r"):
329
+ # Don't limit us to (1%, 99%) interval.
330
+ return None
331
+
332
+ pct = self.data.loc[:, "z"].quantile([0.01, 0.99])
333
+ v0 = pct.loc[0.01]
334
+ v1 = pct.loc[0.99]
335
+ if norm.vmin is None:
336
+ norm.vmin = v0
337
+ if norm.vmax is None:
338
+ norm.vmax = v1
339
+ norm.clip = True
340
+
341
+ def make_plot(
342
+ self,
343
+ ax=None,
344
+ cbar=True,
345
+ limit_color_norm=False,
346
+ cbar_kwargs=None,
347
+ fcn=None,
348
+ alpha_fcn=None,
349
+ **kwargs,
350
+ ):
351
+ r"""Make a 2D plot on `ax` using `ax.pcolormesh`.
352
+
353
+ Parameters
354
+ ----------
355
+ ax: mpl.axes.Axes, None
356
+ If None, create an `Axes` instance from `plt.subplots`.
357
+ cbar: bool
358
+ If True, create color bar with `labels.z`.
359
+ limit_color_norm: bool
360
+ If True, limit the color range to 0.001 and 0.999 percentile range
361
+ of the z-value, count or otherwise.
362
+ cbar_kwargs: dict, None
363
+ If not None, kwargs passed to `self._make_cbar`.
364
+ fcn: FunctionType, None
365
+ Aggregation function. If None, automatically select in :py:meth:`agg`.
366
+ alpha_fcn: None, str
367
+ If not None, the function used to aggregate the data for setting alpha
368
+ value.
369
+ kwargs:
370
+ Passed to `ax.pcolormesh`.
371
+ If row or column normalized data, `norm` defaults to `mpl.colors.Normalize(0, 1)`.
372
+
373
+ Returns
374
+ -------
375
+ ax: mpl.axes.Axes
376
+ Axes upon which plot was made.
377
+ cbar_or_mappable: colorbar.Colorbar, mpl.collections.QuadMesh
378
+ If `cbar` is True, return the colorbar. Otherwise, return the `Quadmesh` used
379
+ to create the colorbar.
380
+ """
381
+ agg = self.agg(fcn=fcn).unstack("x")
382
+ x = self.edges["x"]
383
+ y = self.edges["y"]
384
+
385
+ # assert x.size == agg.shape[1] + 1
386
+ # assert y.size == agg.shape[0] + 1
387
+
388
+ # HACK: Works around `gb.agg(observed=False)` pandas bug. (GH32381)
389
+ if x.size != agg.shape[1] + 1:
390
+ # agg = agg.reindex(columns=self.intervals["x"])
391
+ agg = agg.reindex(columns=self.categoricals["x"])
392
+ if y.size != agg.shape[0] + 1:
393
+ # agg = agg.reindex(index=self.intervals["y"])
394
+ agg = agg.reindex(index=self.categoricals["y"])
395
+
396
+ if ax is None:
397
+ fig, ax = plt.subplots()
398
+
399
+ # if self.log.x:
400
+ # x = 10.0 ** x
401
+ # if self.log.y:
402
+ # y = 10.0 ** y
403
+ x, y = self._maybe_convert_to_log_scale(x, y)
404
+
405
+ axnorm = self.axnorm
406
+ default_norm = None
407
+ if axnorm in ("c", "r"):
408
+ default_norm = mpl.colors.BoundaryNorm(
409
+ np.linspace(0, 1, 11), 256, clip=True
410
+ )
411
+ elif axnorm in ("d", "cd", "rd"):
412
+ default_norm = mpl.colors.LogNorm(clip=True)
413
+ norm = kwargs.pop("norm", default_norm)
414
+
415
+ if limit_color_norm:
416
+ self._limit_color_norm(norm)
417
+
418
+ C = np.ma.masked_invalid(agg.values)
419
+ XX, YY = np.meshgrid(x, y)
420
+ pc = ax.pcolormesh(XX, YY, C, norm=norm, **kwargs)
421
+
422
+ cbar_or_mappable = pc
423
+ if cbar:
424
+ if cbar_kwargs is None:
425
+ cbar_kwargs = dict()
426
+
427
+ if "cax" not in cbar_kwargs.keys() and "ax" not in cbar_kwargs.keys():
428
+ cbar_kwargs["ax"] = ax
429
+
430
+ # Pass `norm` to `self._make_cbar` so that we can choose the ticks to use.
431
+ cbar = self._make_cbar(pc, **cbar_kwargs)
432
+ cbar_or_mappable = cbar
433
+
434
+ self._format_axis(ax)
435
+
436
+ color_plot = self.data.loc[:, self.agg_axes].dropna().unique().size > 1
437
+ if (alpha_fcn is not None) and color_plot:
438
+ self.logger.warning(
439
+ "Make sure you verify alpha actually set. I don't yet trust this."
440
+ )
441
+ alpha_agg = self.agg(fcn=alpha_fcn)
442
+ alpha_agg = alpha_agg.unstack("x")
443
+ alpha_agg = np.ma.masked_invalid(alpha_agg.values.ravel())
444
+ # Feature scale then invert so smallest STD
445
+ # is most opaque.
446
+ alpha = 1 - mpl.colors.Normalize()(alpha_agg)
447
+ self.logger.warning("Scaling alpha filter as alpha**0.25")
448
+ alpha = alpha**0.25
449
+
450
+ # Set masked values to zero. Otherwise, masked
451
+ # values are rendered as black.
452
+ alpha = alpha.filled(0)
453
+ # Must draw to initialize `facecolor`s
454
+ plt.draw()
455
+ # Remove `pc` from axis so we can redraw with std
456
+ # pc.remove()
457
+ colors = pc.get_facecolors()
458
+ colors[:, 3] = alpha
459
+ pc.set_facecolor(colors)
460
+ # ax.add_collection(pc)
461
+
462
+ elif alpha_fcn is not None:
463
+ self.logger.warning("Ignoring `alpha_fcn` because plotting counts")
464
+
465
+ return ax, cbar_or_mappable
466
+
467
+ def get_border(self):
468
+ r"""Get the top and bottom edges of the plot.
469
+
470
+ Returns
471
+ -------
472
+ border: namedtuple
473
+ Contains "top" and "bottom" fields, each with a :py:class:`pd.Series`.
474
+ """
475
+
476
+ Border = namedtuple("Border", "top,bottom")
477
+ top = {}
478
+ bottom = {}
479
+ for x, v in self.agg().unstack("x").items():
480
+ yt = v.last_valid_index()
481
+ if yt is not None:
482
+ z = v.loc[yt]
483
+ top[(yt, x)] = z
484
+
485
+ yb = v.first_valid_index()
486
+ if yb is not None:
487
+ z = v.loc[yb]
488
+ bottom[(yb, x)] = z
489
+
490
+ top = pd.Series(top)
491
+ bottom = pd.Series(bottom)
492
+ for edge in (top, bottom):
493
+ edge.index.names = ["y", "x"]
494
+
495
+ border = Border(top, bottom)
496
+ return border
497
+
498
+ def _plot_one_edge(
499
+ self,
500
+ ax,
501
+ edge,
502
+ smooth=False,
503
+ sg_kwargs=None,
504
+ xlim=(None, None),
505
+ ylim=(None, None),
506
+ **kwargs,
507
+ ):
508
+ x = edge.index.get_level_values("x").mid
509
+ y = edge.index.get_level_values("y").mid
510
+
511
+ if sg_kwargs is None:
512
+ sg_kwargs = dict()
513
+
514
+ if smooth:
515
+ wlength = sg_kwargs.pop("window_length", int(np.floor(y.shape[0] / 10)))
516
+ polyorder = sg_kwargs.pop("polyorder", 3)
517
+
518
+ if not wlength % 2:
519
+ wlength -= 1
520
+
521
+ y = savgol_filter(y, wlength, polyorder, **sg_kwargs)
522
+
523
+ if self.log.x:
524
+ x = 10.0**x
525
+ if self.log.y:
526
+ y = 10.0**y
527
+
528
+ x0, x1 = xlim
529
+ y0, y1 = ylim
530
+
531
+ tk = np.full_like(x, True, dtype=bool)
532
+ if x0 is not None:
533
+ tk = tk & (x0 <= x)
534
+ if x1 is not None:
535
+ tk = tk & (x <= x1)
536
+ if y0 is not None:
537
+ tk = tk & (y0 <= y)
538
+ if y1 is not None:
539
+ tk = tk & (y <= y1)
540
+
541
+ # if (~tk).any():
542
+ x = x[tk]
543
+ y = y[tk]
544
+
545
+ return ax.plot(x, y, **kwargs)
546
+
547
+ def plot_edges(self, ax, smooth=True, sg_kwargs=None, **kwargs):
548
+ """Overplot the edges.
549
+
550
+ Parameters
551
+ ----------
552
+ ax:
553
+ Axis on which to plot.
554
+ smooth: bool
555
+ If True, apply a Savitzky-Golay filter (:py:func:`scipy.signal.savgol_filter`)
556
+ to the y-values before plotting to smooth the curve.
557
+ sg_kwargs: dict, None
558
+ If not None, dict of kwargs passed to Savitzky-Golay filter. Also allows
559
+ for setting of `window_length` and `polyorder` as kwargs. They default to
560
+ 10% of the number of observations (`window_length`) and 3 (`polyorder`).
561
+ Note that because `window_length` must be odd, if the 10% value is even, we
562
+ take 1-window_length.
563
+ kwargs:
564
+ Passed to `ax.plot`
565
+ """
566
+
567
+ top, bottom = self.get_border()
568
+
569
+ color = kwargs.pop("color", "cyan")
570
+ label = kwargs.pop("label", None)
571
+ etop = self._plot_one_edge(
572
+ ax, top, smooth, sg_kwargs, color=color, label=label, **kwargs
573
+ )
574
+ ebottom = self._plot_one_edge(
575
+ ax, bottom, smooth, sg_kwargs, color=color, **kwargs
576
+ )
577
+
578
+ return etop, ebottom
579
+
580
+ def _get_contour_levels(self, levels):
581
+ if (levels is not None) or (self.axnorm is None):
582
+ pass
583
+
584
+ elif (levels is None) and (self.axnorm == "t"):
585
+ levels = [0.01, 0.1, 0.3, 0.7, 0.99]
586
+
587
+ elif (levels is None) and (self.axnorm == "d"):
588
+ levels = [3e-5, 1e-4, 3e-4, 1e-3, 1.7e-3, 2.3e-3]
589
+
590
+ elif (levels is None) and (self.axnorm in ["r", "c"]):
591
+ levels = [0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]
592
+
593
+ elif (levels is None) and (self.axnorm in ["cd", "rd"]):
594
+ levels = None
595
+
596
+ else:
597
+ raise ValueError(
598
+ f"Unrecognized axis normalization {self.axnorm} for default levels."
599
+ )
600
+
601
+ return levels
602
+
603
+ def _verify_contour_passthrough_kwargs(
604
+ self, ax, clabel_kwargs, edges_kwargs, cbar_kwargs
605
+ ):
606
+ if clabel_kwargs is None:
607
+ clabel_kwargs = dict()
608
+ if edges_kwargs is None:
609
+ edges_kwargs = dict()
610
+ if cbar_kwargs is None:
611
+ cbar_kwargs = dict()
612
+ if "cax" not in cbar_kwargs.keys() and "ax" not in cbar_kwargs.keys():
613
+ cbar_kwargs["ax"] = ax
614
+
615
+ return clabel_kwargs, edges_kwargs, cbar_kwargs
616
+
617
+ def plot_contours(
618
+ self,
619
+ ax=None,
620
+ label_levels=True,
621
+ cbar=True,
622
+ limit_color_norm=False,
623
+ cbar_kwargs=None,
624
+ fcn=None,
625
+ plot_edges=False,
626
+ edges_kwargs=None,
627
+ clabel_kwargs=None,
628
+ skip_max_clbl=True,
629
+ use_contourf=False,
630
+ gaussian_filter_std=0,
631
+ gaussian_filter_kwargs=None,
632
+ **kwargs,
633
+ ):
634
+ """Make a contour plot on `ax` using `ax.contour`.
635
+
636
+ Parameters
637
+ ----------
638
+ ax: mpl.axes.Axes, None
639
+ If None, create an `Axes` instance from `plt.subplots`.
640
+ label_levels: bool
641
+ If True, add labels to contours with `ax.clabel`.
642
+ cbar: bool
643
+ If True, create color bar with `labels.z`.
644
+ limit_color_norm: bool
645
+ If True, limit the color range to 0.001 and 0.999 percentile range
646
+ of the z-value, count or otherwise.
647
+ cbar_kwargs: dict, None
648
+ If not None, kwargs passed to `self._make_cbar`.
649
+ fcn: FunctionType, None
650
+ Aggregation function. If None, automatically select in :py:meth:`agg`.
651
+ plot_edges: bool
652
+ If True, plot the smoothed, extreme edges of the 2D histogram.
653
+ edges_kwargs: None, dict
654
+ Passed to {self.plot_edges!s}.
655
+ clabel_kwargs: None, dict
656
+ If not None, dictionary of kwargs passed to `ax.clabel`.
657
+ skip_max_clbl: bool
658
+ If True, don't label the maximum contour. Primarily used when the maximum
659
+ contour is, effectively, a point.
660
+ maximum_color:
661
+ The color for the maximum of the PDF.
662
+ use_contourf: bool
663
+ If True, use `ax.contourf`. Else use `ax.contour`.
664
+ gaussian_filter_std: int
665
+ If > 0, apply `scipy.ndimage.gaussian_filter` to the z-values using the
666
+ standard deviation specified by `gaussian_filter_std`.
667
+ gaussian_filter_kwargs: None, dict
668
+ If not None and gaussian_filter_std > 0, passed to :py:meth:`scipy.ndimage.gaussian_filter`
669
+ kwargs:
670
+ Passed to :py:meth:`ax.pcolormesh`.
671
+ If row or column normalized data, `norm` defaults to `mpl.colors.Normalize(0, 1)`.
672
+ """
673
+ levels = kwargs.pop("levels", None)
674
+ cmap = kwargs.pop("cmap", None)
675
+ norm = kwargs.pop(
676
+ "norm",
677
+ (
678
+ mpl.colors.BoundaryNorm(np.linspace(0, 1, 11), 256, clip=True)
679
+ if self.axnorm in ("c", "r")
680
+ else None
681
+ ),
682
+ )
683
+ linestyles = kwargs.pop(
684
+ "linestyles",
685
+ [
686
+ "-",
687
+ ":",
688
+ "--",
689
+ (0, (7, 3, 1, 3, 1, 3, 1, 3, 1, 3)),
690
+ "--",
691
+ ":",
692
+ "-",
693
+ (0, (7, 3, 1, 3, 1, 3)),
694
+ ],
695
+ )
696
+
697
+ if ax is None:
698
+ fig, ax = plt.subplots()
699
+
700
+ (
701
+ clabel_kwargs,
702
+ edges_kwargs,
703
+ cbar_kwargs,
704
+ ) = self._verify_contour_passthrough_kwargs(
705
+ ax, clabel_kwargs, edges_kwargs, cbar_kwargs
706
+ )
707
+
708
+ inline = clabel_kwargs.pop("inline", True)
709
+ inline_spacing = clabel_kwargs.pop("inline_spacing", -3)
710
+ fmt = clabel_kwargs.pop("fmt", "%s")
711
+
712
+ agg = self.agg(fcn=fcn).unstack("x")
713
+ x = self.intervals["x"].mid
714
+ y = self.intervals["y"].mid
715
+
716
+ # assert x.size == agg.shape[1]
717
+ # assert y.size == agg.shape[0]
718
+
719
+ # HACK: Works around `gb.agg(observed=False)` pandas bug. (GH32381)
720
+ if x.size != agg.shape[1]:
721
+ # agg = agg.reindex(columns=self.intervals["x"])
722
+ agg = agg.reindex(columns=self.categoricals["x"])
723
+ if y.size != agg.shape[0]:
724
+ # agg = agg.reindex(index=self.intervals["y"])
725
+ agg = agg.reindex(index=self.categoricals["y"])
726
+
727
+ x, y = self._maybe_convert_to_log_scale(x, y)
728
+
729
+ XX, YY = np.meshgrid(x, y)
730
+
731
+ C = agg.values
732
+ if gaussian_filter_std:
733
+ from scipy.ndimage import gaussian_filter
734
+
735
+ if gaussian_filter_kwargs is None:
736
+ gaussian_filter_kwargs = dict()
737
+
738
+ C = gaussian_filter(C, gaussian_filter_std, **gaussian_filter_kwargs)
739
+
740
+ C = np.ma.masked_invalid(C)
741
+
742
+ assert XX.shape == C.shape
743
+ assert YY.shape == C.shape
744
+
745
+ class nf(float):
746
+ # Source: https://matplotlib.org/3.1.0/gallery/images_contours_and_fields/contour_label_demo.html
747
+ # Define a class that forces representation of float to look a certain way
748
+ # This remove trailing zero so '1.0' becomes '1'
749
+ def __repr__(self):
750
+ return str(self).rstrip("0")
751
+
752
+ levels = self._get_contour_levels(levels)
753
+
754
+ if (norm is None) and (levels is not None):
755
+ norm = mpl.colors.BoundaryNorm(levels, 256, clip=True)
756
+
757
+ contour_fcn = ax.contour
758
+ if use_contourf:
759
+ contour_fcn = ax.contourf
760
+
761
+ if levels is None:
762
+ args = [XX, YY, C]
763
+ else:
764
+ args = [XX, YY, C, levels]
765
+
766
+ qset = contour_fcn(*args, linestyles=linestyles, cmap=cmap, norm=norm, **kwargs)
767
+
768
+ try:
769
+ args = (qset, levels[:-1] if skip_max_clbl else levels)
770
+ except TypeError:
771
+ # None can't be subscripted.
772
+ args = (qset,)
773
+
774
+ lbls = None
775
+ if label_levels:
776
+ qset.levels = [nf(level) for level in qset.levels]
777
+ lbls = ax.clabel(
778
+ *args,
779
+ inline=inline,
780
+ inline_spacing=inline_spacing,
781
+ fmt=fmt,
782
+ **clabel_kwargs,
783
+ )
784
+
785
+ if plot_edges:
786
+ etop, ebottom = self.plot_edges(ax, **edges_kwargs)
787
+
788
+ cbar_or_mappable = qset
789
+ if cbar:
790
+ # Pass `norm` to `self._make_cbar` so that we can choose the ticks to use.
791
+ cbar = self._make_cbar(qset, norm=norm, **cbar_kwargs)
792
+ cbar_or_mappable = cbar
793
+
794
+ self._format_axis(ax)
795
+
796
+ return ax, lbls, cbar_or_mappable, qset
797
+
798
+ def project_1d(self, axis, only_plotted=True, project_counts=False, **kwargs):
799
+ """Make a `Hist1D` from the data stored in this `His2D`.
800
+
801
+ Parameters
802
+ ----------
803
+ axis: str
804
+ "x" or "y", specifying the axis to project into 1D.
805
+ only_plotted: bool
806
+ If True, only pass data that appears in the {self.__class__.__name__} plot
807
+ to the :py:class:`Hist1D`.
808
+ project_counts: bool
809
+ If True, only send the variable plotted along `axis` to :py:class:`Hist1D`.
810
+ Otherwise, send both axes (but not z-values).
811
+ kwargs:
812
+ Passed to `Hist1D`. Primarily to allow specifying `bin_precision`.
813
+
814
+ Returns
815
+ -------
816
+ h1: :py:class:`Hist1D`
817
+ """
818
+ axis = axis.lower()
819
+ assert axis in ("x", "y")
820
+
821
+ data = self.data
822
+
823
+ if data.loc[:, "z"].unique().size >= 2:
824
+ # Either all 1 or 1 and NaN.
825
+ other = "z"
826
+ else:
827
+ possible_axes = {"x", "y"}
828
+ possible_axes.remove(axis)
829
+ other = possible_axes.pop()
830
+
831
+ logx = self.log._asdict()[axis]
832
+ x = self.data.loc[:, axis]
833
+ if logx:
834
+ # Need to convert back to regular from log-space for data setting.
835
+ x = 10.0**x
836
+
837
+ y = self.data.loc[:, other] if not project_counts else None
838
+ logy = False # Defined b/c project_counts option.
839
+ if y is not None and (other == "y"):
840
+ # Only select y-values plotted.
841
+ logy = self.log._asdict()[other]
842
+ yedges = self.edges[other].values
843
+ y = y.where((yedges[0] <= y) & (y <= yedges[-1]))
844
+ if logy:
845
+ y = 10.0**y
846
+
847
+ if only_plotted:
848
+ tk = self.get_plotted_data_boolean_series()
849
+ x = x.loc[tk]
850
+ if y is not None:
851
+ y = y.loc[tk]
852
+
853
+ h1 = Hist1D(
854
+ x,
855
+ y=y,
856
+ logx=logx,
857
+ clip_data=False, # Any clipping will be addressed by bins.
858
+ nbins=self.edges[axis].values,
859
+ **kwargs,
860
+ )
861
+
862
+ h1.set_log(y=logy) # Need to propagate logy.
863
+ h1.set_labels(x=self.labels._asdict()[axis])
864
+ if not project_counts:
865
+ h1.set_labels(y=self.labels._asdict()[other])
866
+
867
+ return h1
868
+
869
+ def make_joint_h2_h1_plot(
870
+ self, project_counts=True, kwargs_1d=None, fig_axes=None, **kwargs
871
+ ):
872
+ figsize = kwargs.pop("figsize", (5, 6))
873
+ height_ratios = kwargs.pop("height_ratios", [0.25, 1, 0.2, 0.1])
874
+ width_ratios = kwargs.pop("width_ratios", [1, 0.25])
875
+ hspace = kwargs.pop("hspace", 0)
876
+ wspace = kwargs.pop("wspace", 0)
877
+
878
+ # if fig_axes is not None:
879
+ # fig, axes = fig_axes
880
+ # hax, xax, yax, cax = axes
881
+ # else:
882
+ fig = plt.figure(figsize=figsize)
883
+ gs = mpl.gridspec.GridSpec(
884
+ 4,
885
+ 2,
886
+ height_ratios=height_ratios,
887
+ width_ratios=width_ratios,
888
+ hspace=hspace,
889
+ wspace=wspace,
890
+ )
891
+
892
+ hax = fig.add_subplot(gs[1, 0])
893
+ xax = fig.add_subplot(gs[0, 0], sharex=hax)
894
+ yax = fig.add_subplot(gs[1, 1], sharey=hax)
895
+ cax = fig.add_subplot(gs[3, 0])
896
+
897
+ cbar_kwargs = kwargs.pop("cbar_kwargs", dict())
898
+ cax = cbar_kwargs.pop("cax", cax)
899
+ orientation = cbar_kwargs.pop("orientation", "horizontal")
900
+ _, cbar = self.make_plot(
901
+ ax=hax,
902
+ cbar_kwargs=dict(cax=cax, orientation=orientation, **cbar_kwargs),
903
+ **kwargs,
904
+ )
905
+
906
+ if kwargs_1d is None:
907
+ kwargs_1d = dict()
908
+
909
+ self.project_1d("x", project_counts=project_counts).make_plot(
910
+ ax=xax, **kwargs_1d
911
+ )
912
+ self.project_1d("y", project_counts=project_counts).make_plot(
913
+ ax=yax, **kwargs_1d, transpose_axes=True
914
+ )
915
+
916
+ xax.label_outer()
917
+ # Mimic `ax.label_outer` for `yax`.
918
+ for label in yax.get_yticklabels(which="both"):
919
+ label.set_visible(False)
920
+ yax.get_yaxis().get_offset_text().set_visible(False)
921
+ yax.set_ylabel("")
922
+
923
+ log = self.log
924
+ if not log.x:
925
+ hax.xaxis.set_major_locator(
926
+ mpl.ticker.MaxNLocator(
927
+ nbins=hax.xaxis.get_ticklocs().size - 1, prune="upper"
928
+ )
929
+ )
930
+ if not log.y:
931
+ hax.yaxis.set_major_locator(
932
+ mpl.ticker.MaxNLocator(
933
+ nbins=hax.yaxis.get_ticklocs().size - 1, prune="upper"
934
+ )
935
+ )
936
+
937
+ return hax, xax, yax, cbar
938
+
939
+ def id_data_above_contour(self, level):
940
+ r"""Gets data above the `level`.
941
+
942
+ Parameters
943
+ ----------
944
+ level: scalar
945
+ The z-value above which to select data. Data is aggregated according
946
+ to `ax_norm`.
947
+
948
+ Returns
949
+ -------
950
+ above_contour: pd.Series
951
+ For data in a bin above `level`, indicates the x-`pd.Interval` within
952
+ which the observation falls. `NaN` are observations that are below
953
+ `level`. This object is purposely the same length as the data stored by
954
+ Hist2D and can be used in groupby operations.
955
+ """
956
+ x = self.data.x
957
+ y = self.data.y
958
+ above_contour = pd.Series(np.nan, self.data.index)
959
+ for k, v in self.agg().unstack("x").items():
960
+ tk = v >= level
961
+ left, right = k.left, k.right
962
+ bottom, top = v[tk].index.min().left, v[tk].index.max().right
963
+ above_contour_at_x = (left < x) & (x <= right) & (bottom < y) & (y <= top)
964
+ above_contour[above_contour_at_x] = k
965
+
966
+ above_contour = pd.Series(
967
+ pd.Categorical(above_contour), index=above_contour.index
968
+ )
969
+
970
+ return above_contour
971
+
972
+ def take_data_in_yrange_across_x(
973
+ self,
974
+ ranges_by_x,
975
+ get_x_bounds,
976
+ get_y_bounds,
977
+ ):
978
+ r"""Take data within y-ranges across x-values.
979
+
980
+ Parameters
981
+ ----------
982
+ ranges_by_x: iterable
983
+ An iterable with keys used to get the left and right bounds for the data
984
+ and values used to get the top and bottom bounds for the data.
985
+
986
+ get_x_bounds: function
987
+ First argument is one key of `ranges_by_x` and returns `left, right`.
988
+ Second argument is a kwarg (`expected_logx`) boolean to transform the returned values according
989
+ to whether or not the keys are :math:`log(x)` or :math:`x` in a manner
990
+ that matches data stored in Hist2D.
991
+
992
+ get_y_bounds: functions
993
+ Takes on value of `ranges_by_x` and returns `top, bottom`. Second argument
994
+ Second argument is a kwarg (`expected_logx`) boolean to transform the returned values according
995
+ to whether or not the keys are :math:`log(y)` or :math:`y` in a manner
996
+ that matches data stored in Hist2D.
997
+
998
+ Returns
999
+ -------
1000
+ taken: np.ndarray 1D
1001
+ Array of indices for selecting data in interval.
1002
+ """
1003
+
1004
+ available_x = self.agg().unstack("x").columns
1005
+ if ranges_by_x.index.symmetric_difference(available_x).size:
1006
+ drop = ranges_by_x.index.symmetric_difference(available_x)
1007
+ if not drop.isin(available_x).all():
1008
+ raise ValueError(
1009
+ "Need a way to drop values in selector that aren't available."
1010
+ )
1011
+ else:
1012
+ self.logger.warning(
1013
+ f"Dropping {drop.size} intervals from available for selecting."
1014
+ )
1015
+
1016
+ data = self.data
1017
+ logx = self.log.x
1018
+ logy = self.log.y
1019
+
1020
+ taken = []
1021
+ for x, at_x in ranges_by_x.iterrows():
1022
+ l, r = get_x_bounds(x, expected_logx=logx)
1023
+ b, t = get_y_bounds(at_x, expected_logy=logy)
1024
+
1025
+ assert l < r
1026
+ assert b < t
1027
+
1028
+ tkx = (l < data.x) & (data.x <= r)
1029
+ tky = (b < data.y) & (data.y <= t)
1030
+ tk = tkx & tky
1031
+ tk = tk.loc[tk].index
1032
+ taken.append(tk)
1033
+
1034
+ taken = np.sort(np.concatenate(taken))
1035
+ return taken