solarwindpy 0.0.1.dev0__py3-none-any.whl → 0.1.1__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.
- plans/.velocity/metrics.json +96 -0
- plans/0-overview-template.md +268 -0
- plans/N-phase-template.md +106 -0
- plans/PLAN_AUDIT_SUMMARY.md +173 -0
- plans/TEMPLATE-USAGE-GUIDE.md +198 -0
- plans/__init__.py +1 -0
- plans/abandoned/compaction-agent-system/0-Overview.md +123 -0
- plans/abandoned/compaction-agent-system/agents-index-update-plan.md +109 -0
- plans/abandoned/compaction-agent-system/compacted_state.md +85 -0
- plans/abandoned/compaction-agent-system/implementation-plan.md +107 -0
- plans/abandoned/compaction-agent-system/system-validation-report.md +159 -0
- plans/abandoned/compaction-agent-system/usage-guide.md +210 -0
- plans/abandoned/hook-system-enhancement/0-Overview.md +214 -0
- plans/abandoned/hook-system-enhancement/1-Phase1-Core-Infrastructure.md +313 -0
- plans/abandoned/hook-system-enhancement/2-Phase2-Intelligent-Testing.md +385 -0
- plans/abandoned/hook-system-enhancement/3-Phase3-Physics-Validation.md +444 -0
- plans/abandoned/hook-system-enhancement/4-Phase4-Performance-Monitoring.md +458 -0
- plans/abandoned/hook-system-enhancement/5-Phase5-Developer-Experience.md +532 -0
- plans/abandoned/hook-system-enhancement/6-Implementation-Timeline.md +274 -0
- plans/abandoned/hook-system-enhancement/7-Risk-Management.md +376 -0
- plans/abandoned/hook-system-enhancement/8-Testing-Strategy.md +579 -0
- plans/abandoned/readthedocs-automation/0-Overview.md +247 -0
- plans/abandoned/readthedocs-automation/1-Emergency-Documentation-Fixes.md +270 -0
- plans/abandoned/readthedocs-automation/2-Template-System-Enhancement.md +811 -0
- plans/abandoned/readthedocs-automation/3-Quality-Audit-ReadTheDocs-Integration.md +844 -0
- plans/abandoned/readthedocs-automation/4-Plan-Consolidation-Cleanup.md +632 -0
- plans/abandoned/readthedocs-automation/9-Closeout.md +207 -0
- plans/abandoned/readthedocs-automation/ABANDONMENT_REASON.md +72 -0
- plans/cicd-architecture-redesign/0-Overview.md +193 -0
- plans/cicd-architecture-redesign/1-Workflow-Creation.md +103 -0
- plans/cicd-architecture-redesign/2-Version-Detection.md +123 -0
- plans/cicd-architecture-redesign/3-Deployment-Gates.md +169 -0
- plans/cicd-architecture-redesign/4-RC-Testing.md +194 -0
- plans/cicd-architecture-redesign/5-TestPyPI-Validation.md +264 -0
- plans/cicd-architecture-redesign/6-Production-Release.md +263 -0
- plans/cicd-architecture-redesign/7-Cleanup.md +243 -0
- plans/cicd-architecture-redesign/8-Documentation.md +285 -0
- plans/cicd-architecture-redesign/Closeout.md +225 -0
- plans/closeout-template.md +259 -0
- plans/completed/circular-import-audit/0-Overview.md +152 -0
- plans/completed/circular-import-audit/1-Static-Dependency-Analysis.md +62 -0
- plans/completed/circular-import-audit/2-Dynamic-Import-Testing.md +56 -0
- plans/completed/circular-import-audit/3-Performance-Impact-Assessment.md +56 -0
- plans/completed/circular-import-audit/4-Issue-Remediation.md +78 -0
- plans/completed/circular-import-audit/5-Preventive-Infrastructure.md +89 -0
- plans/completed/claude-settings-ecosystem-alignment/0-Overview.md +162 -0
- plans/completed/claude-settings-ecosystem-alignment/1-Security-Foundation.md +148 -0
- plans/completed/claude-settings-ecosystem-alignment/2-Hook-Integration.md +158 -0
- plans/completed/claude-settings-ecosystem-alignment/3-Agent-System-Integration.md +177 -0
- plans/completed/claude-settings-ecosystem-alignment/4-Enhanced-Workflow-Automation.md +159 -0
- plans/completed/claude-settings-ecosystem-alignment/5-Validation-Monitoring.md +181 -0
- plans/completed/claude-settings-ecosystem-alignment/compacted_session_state.md +290 -0
- plans/completed/combined_plan_with_checklist_documentation/1-Overview-and-Goals.md +51 -0
- plans/completed/combined_plan_with_checklist_documentation/2-Toolchain-and-Hosting.md +69 -0
- plans/completed/combined_plan_with_checklist_documentation/3-Repository-Structure.md +61 -0
- plans/completed/combined_plan_with_checklist_documentation/4-Configuration-and-Standards.md +70 -0
- plans/completed/combined_plan_with_checklist_documentation/5-Documentation-Content.md +62 -0
- plans/completed/combined_plan_with_checklist_documentation/6-CI-CD-and-Validation.md +58 -0
- plans/completed/combined_plan_with_checklist_documentation/7-Maintenance.md +55 -0
- plans/completed/combined_test_plan_with_checklist_fitfunctions/0-Overview.md +135 -0
- plans/completed/combined_test_plan_with_checklist_fitfunctions/1-Common-fixtures.md +59 -0
- plans/completed/combined_test_plan_with_checklist_fitfunctions/10-power_laws.md +56 -0
- plans/completed/combined_test_plan_with_checklist_fitfunctions/2-core.py-FitFunction.md +118 -0
- plans/completed/combined_test_plan_with_checklist_fitfunctions/3-gaussians.py-Gaussian-GaussianNormalized-GaussianLn.md +69 -0
- plans/completed/combined_test_plan_with_checklist_fitfunctions/4-trend_fits.py-TrendFit.md +99 -0
- plans/completed/combined_test_plan_with_checklist_fitfunctions/5-plots.py-FFPlot.md +98 -0
- plans/completed/combined_test_plan_with_checklist_fitfunctions/6-tex_info.py-TeXinfo.md +79 -0
- plans/completed/combined_test_plan_with_checklist_fitfunctions/7-Justification.md +49 -0
- plans/completed/combined_test_plan_with_checklist_fitfunctions/8-exponentials.md +64 -0
- plans/completed/combined_test_plan_with_checklist_fitfunctions/9-lines.md +58 -0
- plans/completed/combined_test_plan_with_checklist_plotting/0-Overview.md +142 -0
- plans/completed/combined_test_plan_with_checklist_plotting/1-base.py.md +90 -0
- plans/completed/combined_test_plan_with_checklist_plotting/10-labels-special.py.md +102 -0
- plans/completed/combined_test_plan_with_checklist_plotting/11-labels-chemistry.py.md +212 -0
- plans/completed/combined_test_plan_with_checklist_plotting/12-labels-composition.py.md +242 -0
- plans/completed/combined_test_plan_with_checklist_plotting/13-labels-datetime.py.md +247 -0
- plans/completed/combined_test_plan_with_checklist_plotting/14-labels-elemental_abundance.py.md +274 -0
- plans/completed/combined_test_plan_with_checklist_plotting/15-visual-validation.md +256 -0
- plans/completed/combined_test_plan_with_checklist_plotting/16-integration-testing.md +266 -0
- plans/completed/combined_test_plan_with_checklist_plotting/17-performance-benchmarks.md +267 -0
- plans/completed/combined_test_plan_with_checklist_plotting/18-Fixtures-and-Utilities.md +86 -0
- plans/completed/combined_test_plan_with_checklist_plotting/2-agg_plot.py.md +90 -0
- plans/completed/combined_test_plan_with_checklist_plotting/3-histograms.py.md +201 -0
- plans/completed/combined_test_plan_with_checklist_plotting/4-scatter.py.md +167 -0
- plans/completed/combined_test_plan_with_checklist_plotting/5-spiral.py.md +216 -0
- plans/completed/combined_test_plan_with_checklist_plotting/6-orbits.py.md +108 -0
- plans/completed/combined_test_plan_with_checklist_plotting/7-tools.py.md +86 -0
- plans/completed/combined_test_plan_with_checklist_plotting/8-select_data_from_figure.py.md +97 -0
- plans/completed/combined_test_plan_with_checklist_plotting/9-labels-base.py.md +88 -0
- plans/completed/combined_test_plan_with_checklist_solar_activity/.gitkeep +0 -0
- plans/completed/combined_test_plan_with_checklist_solar_activity/0-Overview.md +170 -0
- plans/completed/combined_test_plan_with_checklist_solar_activity/1-Package-Entry-Point-__init__.py.md +121 -0
- plans/completed/combined_test_plan_with_checklist_solar_activity/2-Core-Base-Classes-base.py.md +142 -0
- plans/completed/combined_test_plan_with_checklist_solar_activity/3-Plotting-Helpers-plots.py.md +123 -0
- plans/completed/combined_test_plan_with_checklist_solar_activity/4-LISIRD-Sub-package.md +119 -0
- plans/completed/combined_test_plan_with_checklist_solar_activity/5-Extrema-Calculator.md +103 -0
- plans/completed/combined_test_plan_with_checklist_solar_activity/6-Sunspot-Number-Sub-package.md +163 -0
- plans/completed/combined_test_plan_with_checklist_solar_activity/7-Sunspot-Number-Init.py.md +217 -0
- plans/completed/combined_test_plan_with_checklist_solar_activity/compacted_state.md +52 -0
- plans/completed/compaction-agent-modernization/0-Overview.md +156 -0
- plans/completed/compaction-agent-modernization/1-Architecture-Audit-Gap-Analysis.md +132 -0
- plans/completed/compaction-agent-modernization/2-Token-Baseline-Recalibration.md +153 -0
- plans/completed/compaction-agent-modernization/3-Agent-Reference-Updates.md +184 -0
- plans/completed/compaction-agent-modernization/4-Compression-Algorithm-Modernization.md +238 -0
- plans/completed/compaction-agent-modernization/5-Workflow-Integration-Streamlining.md +252 -0
- plans/completed/compaction-agent-modernization/6-Template-Structure-Optimization.md +240 -0
- plans/completed/compaction-agent-modernization/7-Integration-Testing-Validation.md +292 -0
- plans/completed/compaction-hook-enhancement/0-Overview.md +150 -0
- plans/completed/compaction-hook-enhancement/1-Token-Estimation-Enhancement.md +179 -0
- plans/completed/compaction-hook-enhancement/2-Compression-Intelligence.md +294 -0
- plans/completed/compaction-hook-enhancement/3-Git-Integration-Metadata.md +310 -0
- plans/completed/compaction-hook-enhancement/4-Session-Continuity-Features.md +358 -0
- plans/completed/compaction-hook-enhancement/5-Testing-Strategy.md +404 -0
- plans/completed/compaction-hook-enhancement/6-Integration-Roadmap.md +319 -0
- plans/completed/compaction-hook-enhancement/compacted_state.md +142 -0
- plans/completed/docstring-audit-enhancement/0-Overview.md +274 -0
- plans/completed/docstring-audit-enhancement/1-Infrastructure-Setup-and-Validation-Tools.md +206 -0
- plans/completed/docstring-audit-enhancement/2-Core-Physics-Modules-Enhancement.md +237 -0
- plans/completed/docstring-audit-enhancement/3-Fitfunctions-Mathematical-Modules-Enhancement.md +188 -0
- plans/completed/docstring-audit-enhancement/4-Plotting-Visualization-Modules-Enhancement.md +243 -0
- plans/completed/docstring-audit-enhancement/5-Specialized-Modules-Enhancement.md +216 -0
- plans/completed/docstring-audit-enhancement/6-Validation-and-Integration.md +216 -0
- plans/completed/fitfunctions-testing-implementation/0-Overview.md +130 -0
- plans/completed/fitfunctions-testing-implementation/1-Test-Infrastructure-Setup.md +79 -0
- plans/completed/fitfunctions-testing-implementation/2-Common-Fixtures-Test-Utilities.md +104 -0
- plans/completed/fitfunctions-testing-implementation/3-Core-FitFunction-Testing.md +168 -0
- plans/completed/fitfunctions-testing-implementation/4-Specialized-Function-Classes.md +210 -0
- plans/completed/fitfunctions-testing-implementation/5-Advanced-Classes-Testing.md +214 -0
- plans/completed/fitfunctions-testing-implementation/6-Plotting-Integration-Testing.md +231 -0
- plans/completed/fitfunctions-testing-implementation/7-Extended-Coverage-BONUS.md +184 -0
- plans/completed/numpy-docstring-conversion-plan/numpy-docstring-conversion-plan.md +118 -0
- plans/completed/pr-review-remediation/0-Overview.md +138 -0
- plans/completed/pr-review-remediation/1-Critical-Safety-Improvements.md +179 -0
- plans/completed/pr-review-remediation/2-Smart-Timeouts-Validation.md +399 -0
- plans/completed/pr-review-remediation/3-Enhanced-GitHub-Integration.md +258 -0
- plans/completed/pr-review-remediation/compacted_state.md +66 -0
- plans/completed/python-310-migration/0-Overview.md +390 -0
- plans/completed/python-310-migration/1-Planning-Setup.md +164 -0
- plans/completed/python-310-migration/2-Implementation.md +256 -0
- plans/completed/python-310-migration/3-Testing-Validation.md +335 -0
- plans/completed/python-310-migration/4-Documentation-Release.md +274 -0
- plans/completed/python-310-migration/5-Closeout.md +252 -0
- plans/completed/requirements-management-consolidation/0-Overview.md +118 -0
- plans/completed/requirements-management-consolidation/1-Documentation-Validation-Environment-Setup.md +116 -0
- plans/completed/requirements-management-consolidation/2-Requirements-Consolidation.md +161 -0
- plans/completed/requirements-management-consolidation/3-Workflow-Automation-Final-Integration.md +196 -0
- plans/completed/single-ecosystem-plan-implementation/0-Overview.md +83 -0
- plans/completed/single-ecosystem-plan-implementation/1-Plan-Preservation-Session-Management.md +38 -0
- plans/completed/single-ecosystem-plan-implementation/2-File-Structure-Optimization.md +43 -0
- plans/completed/single-ecosystem-plan-implementation/3-Plan-Migration-Archive-Setup.md +82 -0
- plans/completed/single-ecosystem-plan-implementation/4-Agent-System-Transformation.md +108 -0
- plans/completed/single-ecosystem-plan-implementation/5-Template-System-Enhancement.md +131 -0
- plans/completed/single-ecosystem-plan-implementation/6-Final-Validation-Testing.md +120 -0
- plans/completed/test-directory-consolidation/0-Overview.md +51 -0
- plans/completed/test-directory-consolidation/1-Structure-Preparation.md +82 -0
- plans/completed/test-directory-consolidation/2-File-Migration.md +100 -0
- plans/completed/test-directory-consolidation/3-Import-Transformation.md +117 -0
- plans/completed/test-directory-consolidation/4-Configuration-Consolidation.md +140 -0
- plans/completed/test-directory-consolidation/5-Validation.md +152 -0
- plans/completed/test-directory-consolidation/6-Cleanup.md +156 -0
- plans/completed/test-planning-agents-architecture/0-Overview.md +79 -0
- plans/completed/test-planning-agents-architecture/1-Branch-Isolation-Testing.md +49 -0
- plans/completed/test-planning-agents-architecture/2-Cross-Branch-Coordination.md +51 -0
- plans/completed/test-planning-agents-architecture/3-Merge-Workflow-Testing.md +48 -0
- plans/deployment-semver-pypi-rtd/0-Overview.md +463 -0
- plans/deployment-semver-pypi-rtd/1-Semantic-Versioning-Foundation.md +136 -0
- plans/deployment-semver-pypi-rtd/2-PyPI-Deployment-Infrastructure.md +168 -0
- plans/deployment-semver-pypi-rtd/3-Release-Automation.md +214 -0
- plans/deployment-semver-pypi-rtd/4-Plan-Closeout.md +543 -0
- plans/deployment-semver-pypi-rtd/compacted_session_state.md +172 -0
- plans/deployment-semver-pypi-rtd/compacted_state.md +131 -0
- plans/documentation-code-audit/0-Overview.md +393 -0
- plans/documentation-code-audit/1-Discovery-Inventory.md +183 -0
- plans/documentation-code-audit/2-Execution-Environment-Setup.md +263 -0
- plans/documentation-code-audit/3-Systematic-Validation.md +322 -0
- plans/documentation-code-audit/4-Code-Example-Remediation.md +358 -0
- plans/documentation-code-audit/5-Physics-MultiIndex-Compliance.md +464 -0
- plans/documentation-code-audit/6-Doctest-Integration.md +523 -0
- plans/documentation-code-audit/7-Reporting-Documentation.md +498 -0
- plans/documentation-code-audit/8-Closeout.md +456 -0
- plans/documentation-rebuild-session/compacted_state.md +109 -0
- plans/documentation-rendering-fixes/0-Overview.md +104 -0
- plans/documentation-rendering-fixes/1-Sphinx-Build-Diagnostics-Warning-Audit.md +101 -0
- plans/documentation-rendering-fixes/2-Configuration-Infrastructure-Fixes.md +113 -0
- plans/documentation-rendering-fixes/3-Docstring-Syntax-Audit-Repair.md +131 -0
- plans/documentation-rendering-fixes/4-HTML-Page-Rendering-Verification.md +113 -0
- plans/documentation-rendering-fixes/5-Advanced-Documentation-Quality-Assurance.md +119 -0
- plans/documentation-rendering-fixes/6-Documentation-Build-Optimization-Testing.md +129 -0
- plans/documentation-rendering-fixes/compacted_state.md +132 -0
- plans/documentation-template-fix/0-Overview.md +197 -0
- plans/documentation-template-fix/1-Template-System-Analysis.md +269 -0
- plans/documentation-template-fix/2-Template-Modification.md +609 -0
- plans/documentation-template-fix/3-Build-System-Integration.md +766 -0
- plans/documentation-template-fix/4-Testing-Validation.md +1399 -0
- plans/documentation-template-fix/5-Documentation-Training.md +602 -0
- plans/documentation-workflow-fix/0-Overview.md +222 -0
- plans/documentation-workflow-fix/1-Immediate-Fixes.md +238 -0
- plans/documentation-workflow-fix/2-Configuration-Setup.md +298 -0
- plans/documentation-workflow-fix/3-Pre-commit-Integration.md +382 -0
- plans/documentation-workflow-fix/4-Workflow-Improvements.md +446 -0
- plans/documentation-workflow-fix/5-Documentation-and-Training.md +527 -0
- plans/duplicate-object-warnings-fix-plan.md +130 -0
- plans/github-issues-migration/0-Overview.md +510 -0
- plans/github-issues-migration/1-Foundation-Label-System.md +180 -0
- plans/github-issues-migration/2-Migration-Tool-Rewrite.md +235 -0
- plans/github-issues-migration/3-CLI-Integration-Automation.md +169 -0
- plans/github-issues-migration/4-Validated-Migration.md +252 -0
- plans/github-issues-migration/5-Documentation-Training.md +171 -0
- plans/github-issues-migration/6-Closeout.md +179 -0
- plans/github-workflows-repair/repair-plan.md +299 -0
- plans/issues_from_plans.py +342 -0
- plans/pr-270-doc-validation-fixes/0-Overview.md +354 -0
- plans/pr-270-doc-validation-fixes/1-Critical-PR-Fixes.md +117 -0
- plans/pr-270-doc-validation-fixes/2-Framework-Right-Sizing.md +129 -0
- plans/pr-270-doc-validation-fixes/3-Sustainable-Documentation.md +126 -0
- plans/pr-270-doc-validation-fixes/4-Closeout-Migration.md +143 -0
- plans/pr-270-doc-validation-fixes/PLAN_COMPLETED.md +149 -0
- plans/python-310-migration/0-Overview.md +390 -0
- plans/python-310-migration/1-Planning-Setup.md +164 -0
- plans/python-310-migration/2-Implementation.md +256 -0
- plans/python-310-migration/3-Testing-Validation.md +335 -0
- plans/python-310-migration/4-Documentation-Release.md +274 -0
- plans/python-310-migration/5-Closeout.md +252 -0
- plans/readthedocs-simplified/0-Overview.md +243 -0
- plans/readthedocs-simplified/1-Immediate-Fixes.md +216 -0
- plans/readthedocs-simplified/2-Template-Simplification.md +278 -0
- plans/readthedocs-simplified/3-ReadTheDocs-Setup.md +298 -0
- plans/readthedocs-simplified/4-Testing-Validation.md +328 -0
- plans/readthedocs-simplified/5-Closeout.md +231 -0
- plans/readthedocs-simplified/compacted_state.md +127 -0
- plans/session-compaction-2025-08-12/compacted_state.md +114 -0
- plans/session-compaction-2025-08-13/compacted_state.md +145 -0
- plans/session-continuity-protocol/0-Overview.md +35 -0
- plans/session-continuity-protocol/1-Core-Principles-Framework.md +40 -0
- plans/session-continuity-protocol/2-Pre-Session-Validation-System.md +79 -0
- plans/session-continuity-protocol/3-Context-Switching-Prevention.md +87 -0
- plans/session-continuity-protocol/4-Progress-Tracking-Recovery.md +100 -0
- plans/sphinx-warnings-analysis.md +222 -0
- plans/systemprompt-optimization/0-Overview.md +447 -0
- plans/systemprompt-optimization/1-Deploy-SystemPrompt.md +114 -0
- plans/systemprompt-optimization/2-Documentation-Alignment.md +198 -0
- plans/systemprompt-optimization/3-Monitoring-Infrastructure.md +396 -0
- plans/systemprompt-optimization/4-Implementation-Script.md +450 -0
- plans/systemprompt-optimization/9-Closeout.md +165 -0
- plans/systemprompt-optimization/compacted_state.md +143 -0
- plans/template-value-propositions/0-Overview.md +357 -0
- plans/template-value-propositions/1-Value-Proposition-Framework-Design.md +144 -0
- plans/template-value-propositions/2-Plan-Template-Enhancement.md +178 -0
- plans/template-value-propositions/3-Value-Generator-Hook-Implementation.md +291 -0
- plans/template-value-propositions/4-Value-Validator-Hook-Implementation.md +274 -0
- plans/template-value-propositions/5-Documentation-Agent-Updates.md +219 -0
- plans/template-value-propositions/6-Integration-Testing-Validation.md +247 -0
- plans/tests-audit/0-Overview.md +410 -0
- plans/tests-audit/1-Discovery-Inventory.md +170 -0
- plans/tests-audit/2-Physics-Validation-Audit.md +195 -0
- plans/tests-audit/3-Architecture-Compliance.md +195 -0
- plans/tests-audit/4-Numerical-Stability-Analysis.md +203 -0
- plans/tests-audit/5-Documentation-Enhancement.md +220 -0
- plans/tests-audit/6-Audit-Deliverables.md +220 -0
- plans/tests-audit/7-Closeout.md +252 -0
- plans/tests-audit/artifacts/ARCHITECTURE_COMPLIANCE_REPORT.md +315 -0
- plans/tests-audit/artifacts/ARCHITECTURE_RECOMMENDATIONS.md +943 -0
- plans/tests-audit/artifacts/COMPREHENSIVE_AUDIT_REPORT.md +356 -0
- plans/tests-audit/artifacts/CONTRIBUTING_ENHANCED_TEMPLATE.md +419 -0
- plans/tests-audit/artifacts/COVERAGE_GAP_ANALYSIS.md +152 -0
- plans/tests-audit/artifacts/DOCUMENTATION_ENHANCEMENT_REPORT.md +502 -0
- plans/tests-audit/artifacts/EXECUTIVE_AUDIT_SUMMARY.md +129 -0
- plans/tests-audit/artifacts/IMPLEMENTATION_ROADMAP.md +647 -0
- plans/tests-audit/artifacts/NUMERICAL_RECOMMENDATIONS.md +739 -0
- plans/tests-audit/artifacts/NUMERICAL_STABILITY_GUIDE_TEMPLATE.rst +451 -0
- plans/tests-audit/artifacts/NUMERICAL_STABILITY_REPORT.md +301 -0
- plans/tests-audit/artifacts/PHASE_3_SUMMARY.md +280 -0
- plans/tests-audit/artifacts/PHASE_4_SUMMARY.md +229 -0
- plans/tests-audit/artifacts/PHASE_5_SUMMARY.md +292 -0
- plans/tests-audit/artifacts/PHASE_6_CLOSEOUT.md +278 -0
- plans/tests-audit/artifacts/PHYSICS_GUIDE_TEMPLATE.rst +268 -0
- plans/tests-audit/artifacts/PHYSICS_VALIDATION_REPORT.md +235 -0
- plans/tests-audit/artifacts/TECHNICAL_DELIVERABLES_PACKAGE.md +2502 -0
- plans/tests-audit/artifacts/TEST_INVENTORY.csv +1204 -0
- plans/tests-audit/artifacts/TEST_INVENTORY.md +135 -0
- plans/tests-audit/artifacts/test_discovery_analysis.py +231 -0
- plans/tests-audit/artifacts/test_parser.py +395 -0
- solarwindpy/README.md +3 -0
- solarwindpy/Untitled.ipynb +54 -0
- solarwindpy/__init__.py +74 -0
- solarwindpy/core/__init__.py +23 -0
- solarwindpy/core/alfvenic_turbulence.py +804 -0
- solarwindpy/core/base.py +267 -0
- solarwindpy/core/ions.py +309 -0
- solarwindpy/core/plasma.py +2133 -0
- solarwindpy/core/spacecraft.py +256 -0
- solarwindpy/core/tensor.py +90 -0
- solarwindpy/core/units_constants.py +199 -0
- solarwindpy/core/vector.py +328 -0
- solarwindpy/fitfunctions/__init__.py +20 -0
- solarwindpy/fitfunctions/core.py +734 -0
- solarwindpy/fitfunctions/exponentials.py +188 -0
- solarwindpy/fitfunctions/gaussians.py +264 -0
- solarwindpy/fitfunctions/lines.py +116 -0
- solarwindpy/fitfunctions/moyal.py +71 -0
- solarwindpy/fitfunctions/plots.py +751 -0
- solarwindpy/fitfunctions/power_laws.py +209 -0
- solarwindpy/fitfunctions/tex_info.py +568 -0
- solarwindpy/fitfunctions/trend_fits.py +482 -0
- solarwindpy/instabilities/__init__.py +16 -0
- solarwindpy/instabilities/beta_ani.py +82 -0
- solarwindpy/instabilities/verscharen2016.py +631 -0
- solarwindpy/plotting/__init__.py +33 -0
- solarwindpy/plotting/agg_plot.py +489 -0
- solarwindpy/plotting/base.py +465 -0
- solarwindpy/plotting/hist1d.py +405 -0
- solarwindpy/plotting/hist2d.py +1035 -0
- solarwindpy/plotting/histograms.py +1845 -0
- solarwindpy/plotting/labels/__init__.py +104 -0
- solarwindpy/plotting/labels/base.py +686 -0
- solarwindpy/plotting/labels/chemistry.py +19 -0
- solarwindpy/plotting/labels/composition.py +100 -0
- solarwindpy/plotting/labels/datetime.py +235 -0
- solarwindpy/plotting/labels/elemental_abundance.py +73 -0
- solarwindpy/plotting/labels/special.py +794 -0
- solarwindpy/plotting/orbits.py +515 -0
- solarwindpy/plotting/scatter.py +99 -0
- solarwindpy/plotting/select_data_from_figure.py +329 -0
- solarwindpy/plotting/spiral.py +980 -0
- solarwindpy/plotting/tools.py +434 -0
- solarwindpy/scripts/__init__.py +1 -0
- solarwindpy/scripts/logs/.gitignore +1 -0
- solarwindpy/solar_activity/__init__.py +53 -0
- solarwindpy/solar_activity/base.py +605 -0
- solarwindpy/solar_activity/lisird/__init__.py +3 -0
- solarwindpy/solar_activity/lisird/extrema_calculator.py +394 -0
- solarwindpy/solar_activity/lisird/lisird.py +319 -0
- solarwindpy/solar_activity/plots.py +116 -0
- solarwindpy/solar_activity/sunspot_number/.DS_Store +0 -0
- solarwindpy/solar_activity/sunspot_number/__init__.py +3 -0
- solarwindpy/solar_activity/sunspot_number/sidc.py +556 -0
- solarwindpy/solar_activity/sunspot_number/ssn_extrema.csv +72 -0
- solarwindpy/solar_activity/sunspot_number/ssn_extrema.csv.silso +72 -0
- solarwindpy/tools/__init__.py +162 -0
- solarwindpy-0.1.1.dist-info/METADATA +181 -0
- solarwindpy-0.1.1.dist-info/RECORD +409 -0
- {solarwindpy-0.0.1.dev0.dist-info → solarwindpy-0.1.1.dist-info}/WHEEL +1 -1
- solarwindpy-0.1.1.dist-info/licenses/LICENSE.rst +32 -0
- solarwindpy-0.1.1.dist-info/top_level.txt +3 -0
- tests/__init__.py +1 -0
- tests/conftest.py +10 -0
- tests/core/__init__.py +1 -0
- tests/core/test_alfvenic_turbulence.py +544 -0
- tests/core/test_base.py +112 -0
- tests/core/test_base_head_tail.py +29 -0
- tests/core/test_base_mi_tuples.py +11 -0
- tests/core/test_core_verify_datetimeindex.py +32 -0
- tests/core/test_ions.py +325 -0
- tests/core/test_plasma.py +2581 -0
- tests/core/test_plasma_io.py +12 -0
- tests/core/test_quantities.py +507 -0
- tests/core/test_spacecraft.py +210 -0
- tests/core/test_units_constants.py +22 -0
- tests/data/epoch.csv +4 -0
- tests/data/plasma.csv +4 -0
- tests/data/spacecraft.csv +4 -0
- tests/fitfunctions/conftest.py +60 -0
- tests/fitfunctions/test_core.py +193 -0
- tests/fitfunctions/test_exponentials.py +342 -0
- tests/fitfunctions/test_gaussians.py +142 -0
- tests/fitfunctions/test_lines.py +349 -0
- tests/fitfunctions/test_moyal.py +258 -0
- tests/fitfunctions/test_plots.py +258 -0
- tests/fitfunctions/test_power_laws.py +365 -0
- tests/fitfunctions/test_tex_info.py +183 -0
- tests/fitfunctions/test_trend_fit_properties.py +31 -0
- tests/fitfunctions/test_trend_fits.py +244 -0
- tests/plotting/__init__.py +1 -0
- tests/plotting/labels/__init__.py +1 -0
- tests/plotting/labels/test_chemistry.py +243 -0
- tests/plotting/labels/test_composition.py +345 -0
- tests/plotting/labels/test_datetime.py +445 -0
- tests/plotting/labels/test_elemental_abundance.py +366 -0
- tests/plotting/labels/test_init.py +66 -0
- tests/plotting/labels/test_labels_base.py +347 -0
- tests/plotting/labels/test_special.py +550 -0
- tests/plotting/test_agg_plot.py +602 -0
- tests/plotting/test_base.py +752 -0
- tests/plotting/test_fixtures_utilities.py +775 -0
- tests/plotting/test_histograms.py +546 -0
- tests/plotting/test_integration.py +675 -0
- tests/plotting/test_orbits.py +435 -0
- tests/plotting/test_performance.py +708 -0
- tests/plotting/test_scatter.py +752 -0
- tests/plotting/test_select_data_from_figure.py +1209 -0
- tests/plotting/test_spiral.py +573 -0
- tests/plotting/test_tools.py +607 -0
- tests/plotting/test_visual_validation.py +465 -0
- tests/solar_activity/__init__.py +1 -0
- tests/solar_activity/lisird/__init__.py +1 -0
- tests/solar_activity/lisird/test_extrema_calculator.py +593 -0
- tests/solar_activity/lisird/test_lisird_id.py +187 -0
- tests/solar_activity/sunspot_number/__init__.py +1 -0
- tests/solar_activity/sunspot_number/test_init.py +399 -0
- tests/solar_activity/sunspot_number/test_sidc.py +465 -0
- tests/solar_activity/sunspot_number/test_sidc_id.py +223 -0
- tests/solar_activity/sunspot_number/test_sidc_loader.py +275 -0
- tests/solar_activity/sunspot_number/test_ssn_extrema.py +406 -0
- tests/solar_activity/test_base.py +656 -0
- tests/solar_activity/test_init.py +396 -0
- tests/solar_activity/test_plots.py +371 -0
- tests/test_circular_imports.py +408 -0
- tests/test_issue_titles.py +25 -0
- tests/test_statusline.py +298 -0
- solarwindpy-0.0.1.dev0.dist-info/METADATA +0 -14
- solarwindpy-0.0.1.dev0.dist-info/RECORD +0 -4
- solarwindpy-0.0.1.dev0.dist-info/top_level.txt +0 -1
|
@@ -0,0 +1,607 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""Tests for solarwindpy.plotting.tools module.
|
|
3
|
+
|
|
4
|
+
This module provides comprehensive test coverage for matplotlib utility functions
|
|
5
|
+
including subplot creation, figure saving, legends, and colorbar management.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import pytest
|
|
9
|
+
import logging
|
|
10
|
+
import numpy as np
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from unittest.mock import patch, MagicMock, call
|
|
13
|
+
from datetime import datetime
|
|
14
|
+
import tempfile
|
|
15
|
+
import os
|
|
16
|
+
|
|
17
|
+
import matplotlib
|
|
18
|
+
|
|
19
|
+
matplotlib.use("Agg") # Use non-interactive backend
|
|
20
|
+
from matplotlib import pyplot as plt
|
|
21
|
+
from matplotlib.figure import Figure
|
|
22
|
+
from matplotlib.axes import Axes
|
|
23
|
+
from matplotlib.legend import Legend
|
|
24
|
+
import matplotlib.gridspec
|
|
25
|
+
|
|
26
|
+
import solarwindpy.plotting.tools as tools_module
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class TestToolsModuleStructure:
|
|
30
|
+
"""Test tools module structure and imports."""
|
|
31
|
+
|
|
32
|
+
def test_module_imports(self):
|
|
33
|
+
"""Test that all required imports are accessible."""
|
|
34
|
+
assert hasattr(tools_module, "np")
|
|
35
|
+
assert hasattr(tools_module, "mpl")
|
|
36
|
+
assert hasattr(tools_module, "plt")
|
|
37
|
+
assert hasattr(tools_module, "logging")
|
|
38
|
+
assert hasattr(tools_module, "Path")
|
|
39
|
+
assert hasattr(tools_module, "datetime")
|
|
40
|
+
|
|
41
|
+
def test_functions_available(self):
|
|
42
|
+
"""Test that all utility functions are accessible."""
|
|
43
|
+
expected_functions = [
|
|
44
|
+
"subplots",
|
|
45
|
+
"save",
|
|
46
|
+
"joint_legend",
|
|
47
|
+
"multipanel_figure_shared_cbar",
|
|
48
|
+
"build_ax_array_with_common_colorbar",
|
|
49
|
+
"calculate_nrows_ncols",
|
|
50
|
+
]
|
|
51
|
+
|
|
52
|
+
for func_name in expected_functions:
|
|
53
|
+
assert hasattr(tools_module, func_name)
|
|
54
|
+
assert callable(getattr(tools_module, func_name))
|
|
55
|
+
|
|
56
|
+
def test_module_docstring(self):
|
|
57
|
+
"""Test that module has comprehensive docstring."""
|
|
58
|
+
assert tools_module.__doc__ is not None
|
|
59
|
+
assert len(tools_module.__doc__.strip()) > 0
|
|
60
|
+
assert "matplotlib" in tools_module.__doc__
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class TestSubplotsFunction:
|
|
64
|
+
"""Test subplots utility function."""
|
|
65
|
+
|
|
66
|
+
def test_subplots_default_parameters(self):
|
|
67
|
+
"""Test subplots with default parameters."""
|
|
68
|
+
fig, ax = tools_module.subplots()
|
|
69
|
+
|
|
70
|
+
assert isinstance(fig, Figure)
|
|
71
|
+
assert isinstance(ax, Axes)
|
|
72
|
+
|
|
73
|
+
# Clean up
|
|
74
|
+
plt.close(fig)
|
|
75
|
+
|
|
76
|
+
def test_subplots_multiple_rows_cols(self):
|
|
77
|
+
"""Test subplots with multiple rows and columns."""
|
|
78
|
+
fig, axes = tools_module.subplots(nrows=2, ncols=3)
|
|
79
|
+
|
|
80
|
+
assert isinstance(fig, Figure)
|
|
81
|
+
assert isinstance(axes, np.ndarray)
|
|
82
|
+
assert axes.shape == (2, 3)
|
|
83
|
+
|
|
84
|
+
# All elements should be Axes
|
|
85
|
+
for ax in axes.flat:
|
|
86
|
+
assert isinstance(ax, Axes)
|
|
87
|
+
|
|
88
|
+
plt.close(fig)
|
|
89
|
+
|
|
90
|
+
def test_subplots_scaling(self):
|
|
91
|
+
"""Test figure size scaling."""
|
|
92
|
+
fig1, ax1 = tools_module.subplots(scale_width=1.0, scale_height=1.0)
|
|
93
|
+
fig2, ax2 = tools_module.subplots(scale_width=2.0, scale_height=1.5)
|
|
94
|
+
|
|
95
|
+
# Scaled figure should be larger
|
|
96
|
+
assert fig2.get_figwidth() > fig1.get_figwidth()
|
|
97
|
+
assert fig2.get_figheight() > fig1.get_figheight()
|
|
98
|
+
|
|
99
|
+
plt.close(fig1)
|
|
100
|
+
plt.close(fig2)
|
|
101
|
+
|
|
102
|
+
def test_subplots_with_kwargs(self):
|
|
103
|
+
"""Test subplots with additional kwargs."""
|
|
104
|
+
fig, axes = tools_module.subplots(nrows=1, ncols=2, figsize=(10, 5))
|
|
105
|
+
|
|
106
|
+
assert isinstance(fig, Figure)
|
|
107
|
+
# Note: figsize may be scaled by the function
|
|
108
|
+
assert fig.get_figwidth() >= 10 # May be scaled up
|
|
109
|
+
assert fig.get_figheight() >= 5 # May be scaled up
|
|
110
|
+
|
|
111
|
+
plt.close(fig)
|
|
112
|
+
|
|
113
|
+
def test_subplots_single_row_col(self):
|
|
114
|
+
"""Test subplots with single row/column returns array."""
|
|
115
|
+
fig, axes = tools_module.subplots(nrows=1, ncols=3)
|
|
116
|
+
|
|
117
|
+
assert isinstance(axes, np.ndarray)
|
|
118
|
+
assert axes.shape == (3,)
|
|
119
|
+
|
|
120
|
+
plt.close(fig)
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
class TestSaveFunction:
|
|
124
|
+
"""Test save utility function."""
|
|
125
|
+
|
|
126
|
+
def setup_method(self):
|
|
127
|
+
"""Set up temporary directory for save tests."""
|
|
128
|
+
self.temp_dir = Path(tempfile.mkdtemp())
|
|
129
|
+
self.test_path = self.temp_dir / "test_figure"
|
|
130
|
+
|
|
131
|
+
def teardown_method(self):
|
|
132
|
+
"""Clean up temporary files."""
|
|
133
|
+
import shutil
|
|
134
|
+
|
|
135
|
+
if self.temp_dir.exists():
|
|
136
|
+
shutil.rmtree(self.temp_dir)
|
|
137
|
+
|
|
138
|
+
def test_save_figure_basic(self):
|
|
139
|
+
"""Test basic figure saving."""
|
|
140
|
+
fig, ax = plt.subplots()
|
|
141
|
+
ax.plot([1, 2, 3], [1, 4, 2])
|
|
142
|
+
|
|
143
|
+
tools_module.save(fig, self.test_path, log=False)
|
|
144
|
+
|
|
145
|
+
# Check that files were created
|
|
146
|
+
assert (self.test_path.with_suffix(".pdf")).exists()
|
|
147
|
+
assert (self.test_path.with_suffix(".png")).exists()
|
|
148
|
+
|
|
149
|
+
plt.close(fig)
|
|
150
|
+
|
|
151
|
+
def test_save_axes_input(self):
|
|
152
|
+
"""Test saving with Axes input instead of Figure."""
|
|
153
|
+
fig, ax = plt.subplots()
|
|
154
|
+
ax.plot([1, 2, 3], [1, 4, 2])
|
|
155
|
+
|
|
156
|
+
tools_module.save(ax, self.test_path, log=False)
|
|
157
|
+
|
|
158
|
+
# Should work the same as passing the figure
|
|
159
|
+
assert (self.test_path.with_suffix(".pdf")).exists()
|
|
160
|
+
assert (self.test_path.with_suffix(".png")).exists()
|
|
161
|
+
|
|
162
|
+
plt.close(fig)
|
|
163
|
+
|
|
164
|
+
def test_save_pdf_only(self):
|
|
165
|
+
"""Test saving PDF only."""
|
|
166
|
+
fig, ax = plt.subplots()
|
|
167
|
+
ax.plot([1, 2, 3], [1, 4, 2])
|
|
168
|
+
|
|
169
|
+
tools_module.save(fig, self.test_path, pdf=True, png=False, log=False)
|
|
170
|
+
|
|
171
|
+
assert (self.test_path.with_suffix(".pdf")).exists()
|
|
172
|
+
assert not (self.test_path.with_suffix(".png")).exists()
|
|
173
|
+
|
|
174
|
+
plt.close(fig)
|
|
175
|
+
|
|
176
|
+
def test_save_png_only(self):
|
|
177
|
+
"""Test saving PNG only."""
|
|
178
|
+
fig, ax = plt.subplots()
|
|
179
|
+
ax.plot([1, 2, 3], [1, 4, 2])
|
|
180
|
+
|
|
181
|
+
tools_module.save(fig, self.test_path, pdf=False, png=True, log=False)
|
|
182
|
+
|
|
183
|
+
assert not (self.test_path.with_suffix(".pdf")).exists()
|
|
184
|
+
assert (self.test_path.with_suffix(".png")).exists()
|
|
185
|
+
|
|
186
|
+
plt.close(fig)
|
|
187
|
+
|
|
188
|
+
def test_save_with_info(self):
|
|
189
|
+
"""Test saving with attribution info."""
|
|
190
|
+
fig, ax = plt.subplots()
|
|
191
|
+
ax.plot([1, 2, 3], [1, 4, 2])
|
|
192
|
+
|
|
193
|
+
tools_module.save(fig, self.test_path, add_info=True, log=False)
|
|
194
|
+
|
|
195
|
+
# Files should exist (info is added to PNG)
|
|
196
|
+
assert (self.test_path.with_suffix(".pdf")).exists()
|
|
197
|
+
assert (self.test_path.with_suffix(".png")).exists()
|
|
198
|
+
|
|
199
|
+
plt.close(fig)
|
|
200
|
+
|
|
201
|
+
@patch("logging.getLogger")
|
|
202
|
+
def test_save_with_logging(self, mock_get_logger):
|
|
203
|
+
"""Test save function with logging enabled."""
|
|
204
|
+
mock_logger = MagicMock()
|
|
205
|
+
mock_get_logger.return_value = mock_logger
|
|
206
|
+
|
|
207
|
+
fig, ax = plt.subplots()
|
|
208
|
+
ax.plot([1, 2, 3], [1, 4, 2])
|
|
209
|
+
|
|
210
|
+
tools_module.save(fig, self.test_path, log=True)
|
|
211
|
+
|
|
212
|
+
# Should have logged save information
|
|
213
|
+
mock_logger.info.assert_called()
|
|
214
|
+
|
|
215
|
+
plt.close(fig)
|
|
216
|
+
|
|
217
|
+
def test_save_input_validation(self):
|
|
218
|
+
"""Test save function input validation."""
|
|
219
|
+
fig, ax = plt.subplots()
|
|
220
|
+
|
|
221
|
+
# Should work with Figure
|
|
222
|
+
tools_module.save(fig, self.test_path, log=False)
|
|
223
|
+
|
|
224
|
+
# Should work with Axes
|
|
225
|
+
tools_module.save(ax, self.test_path, log=False)
|
|
226
|
+
|
|
227
|
+
# Path should be a Path object (assertion in function)
|
|
228
|
+
with pytest.raises(AssertionError):
|
|
229
|
+
tools_module.save(fig, "string_path", log=False)
|
|
230
|
+
|
|
231
|
+
plt.close(fig)
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
class TestJointLegendFunction:
|
|
235
|
+
"""Test joint_legend utility function."""
|
|
236
|
+
|
|
237
|
+
def test_joint_legend_basic(self):
|
|
238
|
+
"""Test basic joint legend functionality."""
|
|
239
|
+
fig, axes = plt.subplots(1, 2)
|
|
240
|
+
|
|
241
|
+
axes[0].plot([1, 2, 3], [1, 4, 2], label="Line A")
|
|
242
|
+
axes[1].plot([1, 2, 3], [2, 3, 1], label="Line B")
|
|
243
|
+
|
|
244
|
+
legend = tools_module.joint_legend(axes[0], axes[1])
|
|
245
|
+
|
|
246
|
+
assert isinstance(legend, Legend)
|
|
247
|
+
|
|
248
|
+
# Check that legend contains both labels
|
|
249
|
+
legend_labels = [text.get_text() for text in legend.get_texts()]
|
|
250
|
+
assert "Line A" in legend_labels
|
|
251
|
+
assert "Line B" in legend_labels
|
|
252
|
+
|
|
253
|
+
plt.close(fig)
|
|
254
|
+
|
|
255
|
+
def test_joint_legend_duplicate_labels(self):
|
|
256
|
+
"""Test joint legend with duplicate labels."""
|
|
257
|
+
fig, axes = plt.subplots(1, 2)
|
|
258
|
+
|
|
259
|
+
axes[0].plot([1, 2, 3], [1, 4, 2], label="Same Label")
|
|
260
|
+
axes[1].plot([1, 2, 3], [2, 3, 1], label="Same Label")
|
|
261
|
+
|
|
262
|
+
legend = tools_module.joint_legend(axes[0], axes[1])
|
|
263
|
+
|
|
264
|
+
# Should only have one entry for duplicate labels
|
|
265
|
+
legend_labels = [text.get_text() for text in legend.get_texts()]
|
|
266
|
+
assert legend_labels.count("Same Label") == 1
|
|
267
|
+
|
|
268
|
+
plt.close(fig)
|
|
269
|
+
|
|
270
|
+
def test_joint_legend_custom_idx(self):
|
|
271
|
+
"""Test joint legend with custom axis index."""
|
|
272
|
+
fig, axes = plt.subplots(1, 3)
|
|
273
|
+
|
|
274
|
+
for i, ax in enumerate(axes):
|
|
275
|
+
ax.plot([1, 2, 3], [i, i + 1, i + 2], label=f"Line {i}")
|
|
276
|
+
|
|
277
|
+
legend = tools_module.joint_legend(*axes, idx_for_legend=1)
|
|
278
|
+
|
|
279
|
+
assert isinstance(legend, Legend)
|
|
280
|
+
|
|
281
|
+
plt.close(fig)
|
|
282
|
+
|
|
283
|
+
def test_joint_legend_with_kwargs(self):
|
|
284
|
+
"""Test joint legend with additional kwargs."""
|
|
285
|
+
fig, axes = plt.subplots(1, 2)
|
|
286
|
+
|
|
287
|
+
axes[0].plot([1, 2, 3], [1, 4, 2], label="Line A")
|
|
288
|
+
axes[1].plot([1, 2, 3], [2, 3, 1], label="Line B")
|
|
289
|
+
|
|
290
|
+
legend = tools_module.joint_legend(
|
|
291
|
+
axes[0], axes[1], loc="upper right", frameon=True, ncol=2
|
|
292
|
+
)
|
|
293
|
+
|
|
294
|
+
assert isinstance(legend, Legend)
|
|
295
|
+
|
|
296
|
+
plt.close(fig)
|
|
297
|
+
|
|
298
|
+
def test_joint_legend_errorbar_handling(self):
|
|
299
|
+
"""Test joint legend with errorbar containers."""
|
|
300
|
+
fig, axes = plt.subplots(1, 2)
|
|
301
|
+
|
|
302
|
+
x = [1, 2, 3]
|
|
303
|
+
y = [1, 4, 2]
|
|
304
|
+
yerr = [0.1, 0.2, 0.1]
|
|
305
|
+
|
|
306
|
+
axes[0].errorbar(x, y, yerr=yerr, label="Error Line")
|
|
307
|
+
axes[1].plot(x, [2, 3, 1], label="Regular Line")
|
|
308
|
+
|
|
309
|
+
legend = tools_module.joint_legend(axes[0], axes[1])
|
|
310
|
+
|
|
311
|
+
assert isinstance(legend, Legend)
|
|
312
|
+
|
|
313
|
+
plt.close(fig)
|
|
314
|
+
|
|
315
|
+
def test_joint_legend_sorting(self):
|
|
316
|
+
"""Test that legend labels are sorted alphabetically."""
|
|
317
|
+
fig, axes = plt.subplots(1, 2)
|
|
318
|
+
|
|
319
|
+
axes[0].plot([1, 2, 3], [1, 4, 2], label="Z Line")
|
|
320
|
+
axes[1].plot([1, 2, 3], [2, 3, 1], label="A Line")
|
|
321
|
+
|
|
322
|
+
legend = tools_module.joint_legend(axes[0], axes[1])
|
|
323
|
+
|
|
324
|
+
legend_labels = [text.get_text() for text in legend.get_texts()]
|
|
325
|
+
assert legend_labels == ["A Line", "Z Line"]
|
|
326
|
+
|
|
327
|
+
plt.close(fig)
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
class TestMultipanelFigureSharedCbar:
|
|
331
|
+
"""Test multipanel_figure_shared_cbar function."""
|
|
332
|
+
|
|
333
|
+
def test_multipanel_function_exists(self):
|
|
334
|
+
"""Test that multipanel function exists and is callable."""
|
|
335
|
+
assert hasattr(tools_module, "multipanel_figure_shared_cbar")
|
|
336
|
+
assert callable(tools_module.multipanel_figure_shared_cbar)
|
|
337
|
+
|
|
338
|
+
def test_multipanel_basic_structure(self):
|
|
339
|
+
"""Test basic multipanel figure structure."""
|
|
340
|
+
try:
|
|
341
|
+
fig, axes, cax = tools_module.multipanel_figure_shared_cbar(1, 1)
|
|
342
|
+
|
|
343
|
+
assert isinstance(fig, Figure)
|
|
344
|
+
assert isinstance(cax, Axes)
|
|
345
|
+
# axes might be ndarray or single Axes depending on input
|
|
346
|
+
|
|
347
|
+
plt.close(fig)
|
|
348
|
+
except AttributeError:
|
|
349
|
+
# Skip if matplotlib version incompatibility
|
|
350
|
+
pytest.skip("Matplotlib version incompatibility with axis sharing")
|
|
351
|
+
|
|
352
|
+
def test_multipanel_parameters(self):
|
|
353
|
+
"""Test multipanel parameter handling."""
|
|
354
|
+
# Test that function accepts the expected parameters
|
|
355
|
+
try:
|
|
356
|
+
fig, axes, cax = tools_module.multipanel_figure_shared_cbar(
|
|
357
|
+
1, 1, vertical_cbar=True, sharex=False, sharey=False
|
|
358
|
+
)
|
|
359
|
+
plt.close(fig)
|
|
360
|
+
except AttributeError:
|
|
361
|
+
pytest.skip("Matplotlib version incompatibility")
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
class TestBuildAxArrayWithCommonColorbar:
|
|
365
|
+
"""Test build_ax_array_with_common_colorbar function."""
|
|
366
|
+
|
|
367
|
+
def test_build_ax_array_function_exists(self):
|
|
368
|
+
"""Test that build_ax_array function exists and is callable."""
|
|
369
|
+
assert hasattr(tools_module, "build_ax_array_with_common_colorbar")
|
|
370
|
+
assert callable(tools_module.build_ax_array_with_common_colorbar)
|
|
371
|
+
|
|
372
|
+
def test_build_ax_array_basic_interface(self):
|
|
373
|
+
"""Test basic interface without axis sharing."""
|
|
374
|
+
try:
|
|
375
|
+
fig, axes, cax = tools_module.build_ax_array_with_common_colorbar(
|
|
376
|
+
1, 1, gs_kwargs={"sharex": False, "sharey": False}
|
|
377
|
+
)
|
|
378
|
+
|
|
379
|
+
assert isinstance(fig, Figure)
|
|
380
|
+
assert isinstance(cax, Axes)
|
|
381
|
+
|
|
382
|
+
plt.close(fig)
|
|
383
|
+
except AttributeError:
|
|
384
|
+
pytest.skip("Matplotlib version incompatibility with axis sharing")
|
|
385
|
+
|
|
386
|
+
def test_build_ax_array_invalid_location(self):
|
|
387
|
+
"""Test invalid colorbar location raises error."""
|
|
388
|
+
with pytest.raises(ValueError):
|
|
389
|
+
tools_module.build_ax_array_with_common_colorbar(2, 2, cbar_loc="invalid")
|
|
390
|
+
|
|
391
|
+
def test_build_ax_array_location_validation(self):
|
|
392
|
+
"""Test colorbar location validation."""
|
|
393
|
+
valid_locations = ["top", "bottom", "left", "right"]
|
|
394
|
+
|
|
395
|
+
for loc in valid_locations:
|
|
396
|
+
try:
|
|
397
|
+
fig, axes, cax = tools_module.build_ax_array_with_common_colorbar(
|
|
398
|
+
1, 1, cbar_loc=loc, gs_kwargs={"sharex": False, "sharey": False}
|
|
399
|
+
)
|
|
400
|
+
plt.close(fig)
|
|
401
|
+
except AttributeError:
|
|
402
|
+
# Skip if matplotlib incompatibility
|
|
403
|
+
continue
|
|
404
|
+
|
|
405
|
+
|
|
406
|
+
class TestCalculateNrowsNcols:
|
|
407
|
+
"""Test calculate_nrows_ncols utility function."""
|
|
408
|
+
|
|
409
|
+
def test_calculate_perfect_squares(self):
|
|
410
|
+
"""Test calculation for perfect squares."""
|
|
411
|
+
# Perfect squares should give nearly square layouts
|
|
412
|
+
nrows, ncols = tools_module.calculate_nrows_ncols(4)
|
|
413
|
+
assert nrows * ncols >= 4
|
|
414
|
+
assert abs(nrows - ncols) <= 1
|
|
415
|
+
|
|
416
|
+
nrows, ncols = tools_module.calculate_nrows_ncols(9)
|
|
417
|
+
assert nrows * ncols >= 9
|
|
418
|
+
|
|
419
|
+
nrows, ncols = tools_module.calculate_nrows_ncols(16)
|
|
420
|
+
assert nrows * ncols >= 16
|
|
421
|
+
|
|
422
|
+
def test_calculate_prime_numbers(self):
|
|
423
|
+
"""Test calculation for prime numbers."""
|
|
424
|
+
# Prime numbers should get bumped up to next composite
|
|
425
|
+
nrows, ncols = tools_module.calculate_nrows_ncols(7)
|
|
426
|
+
assert nrows * ncols >= 7
|
|
427
|
+
|
|
428
|
+
nrows, ncols = tools_module.calculate_nrows_ncols(11)
|
|
429
|
+
assert nrows * ncols >= 11
|
|
430
|
+
|
|
431
|
+
def test_calculate_small_numbers(self):
|
|
432
|
+
"""Test calculation for small numbers."""
|
|
433
|
+
test_cases = [1, 2, 3, 4, 5, 6]
|
|
434
|
+
|
|
435
|
+
for n in test_cases:
|
|
436
|
+
nrows, ncols = tools_module.calculate_nrows_ncols(n)
|
|
437
|
+
assert nrows * ncols >= n
|
|
438
|
+
assert nrows > 0
|
|
439
|
+
assert ncols > 0
|
|
440
|
+
|
|
441
|
+
def test_calculate_larger_numbers(self):
|
|
442
|
+
"""Test calculation for larger numbers."""
|
|
443
|
+
test_cases = [15, 20, 24, 30, 36]
|
|
444
|
+
|
|
445
|
+
for n in test_cases:
|
|
446
|
+
nrows, ncols = tools_module.calculate_nrows_ncols(n)
|
|
447
|
+
assert nrows * ncols >= n
|
|
448
|
+
assert nrows > 0
|
|
449
|
+
assert ncols > 0
|
|
450
|
+
|
|
451
|
+
def test_calculate_aspect_ratio_preference(self):
|
|
452
|
+
"""Test that function prefers wider layouts."""
|
|
453
|
+
nrows, ncols = tools_module.calculate_nrows_ncols(6)
|
|
454
|
+
# Should prefer wider layout (fewer rows, more columns)
|
|
455
|
+
assert ncols >= nrows
|
|
456
|
+
|
|
457
|
+
def test_calculate_edge_cases(self):
|
|
458
|
+
"""Test edge cases."""
|
|
459
|
+
# Test very small numbers
|
|
460
|
+
nrows, ncols = tools_module.calculate_nrows_ncols(1)
|
|
461
|
+
assert nrows * ncols >= 1
|
|
462
|
+
|
|
463
|
+
# Test numbers that require adjustment
|
|
464
|
+
nrows, ncols = tools_module.calculate_nrows_ncols(5)
|
|
465
|
+
assert nrows * ncols >= 5
|
|
466
|
+
|
|
467
|
+
|
|
468
|
+
class TestToolsIntegration:
|
|
469
|
+
"""Test integration between different tools functions."""
|
|
470
|
+
|
|
471
|
+
def test_subplots_save_integration(self):
|
|
472
|
+
"""Test integration between subplots and save."""
|
|
473
|
+
with tempfile.TemporaryDirectory() as temp_dir:
|
|
474
|
+
temp_path = Path(temp_dir) / "integration_test"
|
|
475
|
+
|
|
476
|
+
fig, axes = tools_module.subplots(2, 2, scale_width=1.5)
|
|
477
|
+
|
|
478
|
+
for i, ax in enumerate(axes.flat):
|
|
479
|
+
ax.plot([1, 2, 3], [i, i + 1, i + 2], label=f"Line {i}")
|
|
480
|
+
|
|
481
|
+
tools_module.save(fig, temp_path, log=False)
|
|
482
|
+
|
|
483
|
+
assert temp_path.with_suffix(".pdf").exists()
|
|
484
|
+
assert temp_path.with_suffix(".png").exists()
|
|
485
|
+
|
|
486
|
+
plt.close(fig)
|
|
487
|
+
|
|
488
|
+
def test_multipanel_joint_legend_integration(self):
|
|
489
|
+
"""Test integration between multipanel and joint legend."""
|
|
490
|
+
try:
|
|
491
|
+
fig, axes, cax = tools_module.multipanel_figure_shared_cbar(
|
|
492
|
+
1, 3, sharex=False, sharey=False
|
|
493
|
+
)
|
|
494
|
+
|
|
495
|
+
# Handle case where axes might be 1D array or single Axes
|
|
496
|
+
if isinstance(axes, np.ndarray):
|
|
497
|
+
for i, ax in enumerate(axes.flat):
|
|
498
|
+
ax.plot([1, 2, 3], [i, i + 1, i + 2], label=f"Series {i}")
|
|
499
|
+
legend = tools_module.joint_legend(*axes.flat)
|
|
500
|
+
else:
|
|
501
|
+
axes.plot([1, 2, 3], [1, 2, 3], label="Series")
|
|
502
|
+
legend = tools_module.joint_legend(axes)
|
|
503
|
+
|
|
504
|
+
assert isinstance(legend, Legend)
|
|
505
|
+
|
|
506
|
+
plt.close(fig)
|
|
507
|
+
except AttributeError:
|
|
508
|
+
pytest.skip("Matplotlib version incompatibility")
|
|
509
|
+
|
|
510
|
+
def test_calculate_nrows_ncols_with_basic_plotting(self):
|
|
511
|
+
"""Test using calculate_nrows_ncols with basic plotting."""
|
|
512
|
+
n_plots = 6
|
|
513
|
+
nrows, ncols = tools_module.calculate_nrows_ncols(n_plots)
|
|
514
|
+
|
|
515
|
+
# Test with basic subplots instead of multipanel
|
|
516
|
+
fig, axes = tools_module.subplots(nrows, ncols)
|
|
517
|
+
|
|
518
|
+
assert nrows * ncols >= n_plots
|
|
519
|
+
|
|
520
|
+
plt.close(fig)
|
|
521
|
+
|
|
522
|
+
|
|
523
|
+
class TestToolsErrorHandling:
|
|
524
|
+
"""Test error handling in tools functions."""
|
|
525
|
+
|
|
526
|
+
def test_save_invalid_inputs(self):
|
|
527
|
+
"""Test save function with invalid inputs."""
|
|
528
|
+
fig, ax = plt.subplots()
|
|
529
|
+
|
|
530
|
+
# Invalid figure type
|
|
531
|
+
with pytest.raises(AssertionError):
|
|
532
|
+
tools_module.save("not_a_figure", Path("test"), log=False)
|
|
533
|
+
|
|
534
|
+
# Invalid path type
|
|
535
|
+
with pytest.raises(AssertionError):
|
|
536
|
+
tools_module.save(fig, "not_a_path_object", log=False)
|
|
537
|
+
|
|
538
|
+
plt.close(fig)
|
|
539
|
+
|
|
540
|
+
def test_multipanel_invalid_parameters(self):
|
|
541
|
+
"""Test multipanel with edge case parameters."""
|
|
542
|
+
try:
|
|
543
|
+
# Test with minimal parameters
|
|
544
|
+
fig, axes, cax = tools_module.multipanel_figure_shared_cbar(
|
|
545
|
+
1, 1, sharex=False, sharey=False
|
|
546
|
+
)
|
|
547
|
+
plt.close(fig)
|
|
548
|
+
except AttributeError:
|
|
549
|
+
pytest.skip("Matplotlib version incompatibility")
|
|
550
|
+
|
|
551
|
+
def test_build_ax_array_basic_validation(self):
|
|
552
|
+
"""Test build_ax_array basic validation."""
|
|
553
|
+
try:
|
|
554
|
+
fig, axes, cax = tools_module.build_ax_array_with_common_colorbar(
|
|
555
|
+
1, 1, gs_kwargs={"sharex": False, "sharey": False}
|
|
556
|
+
)
|
|
557
|
+
|
|
558
|
+
# Should return valid matplotlib objects
|
|
559
|
+
assert isinstance(fig, Figure)
|
|
560
|
+
assert isinstance(cax, Axes)
|
|
561
|
+
|
|
562
|
+
plt.close(fig)
|
|
563
|
+
except AttributeError:
|
|
564
|
+
pytest.skip("Matplotlib version incompatibility")
|
|
565
|
+
|
|
566
|
+
|
|
567
|
+
class TestToolsDocumentation:
|
|
568
|
+
"""Test documentation and examples in tools functions."""
|
|
569
|
+
|
|
570
|
+
def test_function_docstrings(self):
|
|
571
|
+
"""Test that all functions have comprehensive docstrings."""
|
|
572
|
+
functions = [
|
|
573
|
+
tools_module.subplots,
|
|
574
|
+
tools_module.save,
|
|
575
|
+
tools_module.joint_legend,
|
|
576
|
+
tools_module.multipanel_figure_shared_cbar,
|
|
577
|
+
tools_module.build_ax_array_with_common_colorbar,
|
|
578
|
+
tools_module.calculate_nrows_ncols,
|
|
579
|
+
]
|
|
580
|
+
|
|
581
|
+
for func in functions:
|
|
582
|
+
assert func.__doc__ is not None
|
|
583
|
+
assert len(func.__doc__.strip()) > 0
|
|
584
|
+
# Should have Parameters section
|
|
585
|
+
assert "Parameters" in func.__doc__
|
|
586
|
+
# Should have Returns section (for most functions)
|
|
587
|
+
if func != tools_module.save: # save returns None
|
|
588
|
+
assert "Returns" in func.__doc__
|
|
589
|
+
|
|
590
|
+
def test_docstring_examples(self):
|
|
591
|
+
"""Test that functions have usage examples in docstrings."""
|
|
592
|
+
functions_with_examples = [
|
|
593
|
+
tools_module.subplots,
|
|
594
|
+
tools_module.save,
|
|
595
|
+
tools_module.joint_legend,
|
|
596
|
+
tools_module.multipanel_figure_shared_cbar,
|
|
597
|
+
tools_module.build_ax_array_with_common_colorbar,
|
|
598
|
+
tools_module.calculate_nrows_ncols,
|
|
599
|
+
]
|
|
600
|
+
|
|
601
|
+
for func in functions_with_examples:
|
|
602
|
+
assert "Examples" in func.__doc__
|
|
603
|
+
assert ">>>" in func.__doc__
|
|
604
|
+
|
|
605
|
+
|
|
606
|
+
if __name__ == "__main__":
|
|
607
|
+
pytest.main([__file__])
|