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,752 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""Tests for solarwindpy.plotting.scatter module.
|
|
3
|
+
|
|
4
|
+
This module provides comprehensive test coverage for the Scatter class used for creating
|
|
5
|
+
scatter plots with optional color mapping functionality.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import pytest
|
|
9
|
+
import logging
|
|
10
|
+
import pandas as pd
|
|
11
|
+
import numpy as np
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
from unittest.mock import patch, MagicMock, call
|
|
14
|
+
|
|
15
|
+
import matplotlib
|
|
16
|
+
|
|
17
|
+
matplotlib.use("Agg") # Use non-interactive backend
|
|
18
|
+
from matplotlib import pyplot as plt
|
|
19
|
+
from matplotlib.collections import PathCollection
|
|
20
|
+
|
|
21
|
+
import solarwindpy.plotting.scatter as scatter_module
|
|
22
|
+
from solarwindpy.plotting.scatter import Scatter
|
|
23
|
+
from solarwindpy.plotting.base import PlotWithZdata, CbarMaker, AxesLabels, LogAxes
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class TestScatterModuleStructure:
|
|
27
|
+
"""Test scatter module structure and imports."""
|
|
28
|
+
|
|
29
|
+
def test_module_imports(self):
|
|
30
|
+
"""Test that all required imports are accessible."""
|
|
31
|
+
# Test basic imports
|
|
32
|
+
assert hasattr(scatter_module, "base")
|
|
33
|
+
assert hasattr(scatter_module, "plt")
|
|
34
|
+
assert hasattr(scatter_module, "Scatter")
|
|
35
|
+
|
|
36
|
+
def test_scatter_class_available(self):
|
|
37
|
+
"""Test that Scatter class is accessible from module."""
|
|
38
|
+
assert hasattr(scatter_module, "Scatter")
|
|
39
|
+
assert callable(scatter_module.Scatter)
|
|
40
|
+
|
|
41
|
+
def test_scatter_inheritance(self):
|
|
42
|
+
"""Test that Scatter inherits from correct base classes."""
|
|
43
|
+
assert issubclass(Scatter, PlotWithZdata)
|
|
44
|
+
assert issubclass(Scatter, CbarMaker)
|
|
45
|
+
|
|
46
|
+
# Test MRO (Method Resolution Order)
|
|
47
|
+
mro = Scatter.__mro__
|
|
48
|
+
assert PlotWithZdata in mro
|
|
49
|
+
assert CbarMaker in mro
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class TestScatterInitialization:
|
|
53
|
+
"""Test Scatter class initialization."""
|
|
54
|
+
|
|
55
|
+
def setup_method(self):
|
|
56
|
+
"""Set up test data for each test method."""
|
|
57
|
+
self.x_data = pd.Series([1, 2, 3, 4, 5], name="x_values")
|
|
58
|
+
self.y_data = pd.Series([2, 4, 6, 8, 10], name="y_values")
|
|
59
|
+
self.z_data = pd.Series([10, 20, 30, 40, 50], name="z_values")
|
|
60
|
+
|
|
61
|
+
def test_basic_initialization(self):
|
|
62
|
+
"""Test basic initialization with x, y data only."""
|
|
63
|
+
scatter = Scatter(self.x_data, self.y_data)
|
|
64
|
+
|
|
65
|
+
assert scatter is not None
|
|
66
|
+
assert hasattr(scatter, "data")
|
|
67
|
+
assert hasattr(scatter, "_labels")
|
|
68
|
+
assert hasattr(scatter, "_log")
|
|
69
|
+
assert hasattr(scatter, "clip")
|
|
70
|
+
|
|
71
|
+
def test_initialization_with_z_data(self):
|
|
72
|
+
"""Test initialization with z data for color mapping."""
|
|
73
|
+
scatter = Scatter(self.x_data, self.y_data, self.z_data)
|
|
74
|
+
|
|
75
|
+
assert scatter is not None
|
|
76
|
+
assert "z" in scatter.data.columns
|
|
77
|
+
assert scatter._labels.z == "z"
|
|
78
|
+
|
|
79
|
+
def test_initialization_with_clip_data_true(self):
|
|
80
|
+
"""Test initialization with clip_data=True."""
|
|
81
|
+
scatter = Scatter(self.x_data, self.y_data, clip_data=True)
|
|
82
|
+
|
|
83
|
+
assert scatter.clip is True
|
|
84
|
+
|
|
85
|
+
def test_initialization_with_clip_data_false(self):
|
|
86
|
+
"""Test initialization with clip_data=False."""
|
|
87
|
+
scatter = Scatter(self.x_data, self.y_data, clip_data=False)
|
|
88
|
+
|
|
89
|
+
assert scatter.clip is False
|
|
90
|
+
|
|
91
|
+
def test_labels_initialization(self):
|
|
92
|
+
"""Test that labels are properly initialized."""
|
|
93
|
+
# Without z data
|
|
94
|
+
scatter = Scatter(self.x_data, self.y_data)
|
|
95
|
+
assert scatter._labels.x == "x"
|
|
96
|
+
assert scatter._labels.y == "y"
|
|
97
|
+
assert scatter._labels.z is None
|
|
98
|
+
|
|
99
|
+
# With z data
|
|
100
|
+
scatter_z = Scatter(self.x_data, self.y_data, self.z_data)
|
|
101
|
+
assert scatter_z._labels.x == "x"
|
|
102
|
+
assert scatter_z._labels.y == "y"
|
|
103
|
+
assert scatter_z._labels.z == "z"
|
|
104
|
+
|
|
105
|
+
def test_log_initialization(self):
|
|
106
|
+
"""Test that log axes are properly initialized."""
|
|
107
|
+
scatter = Scatter(self.x_data, self.y_data)
|
|
108
|
+
|
|
109
|
+
assert hasattr(scatter, "_log")
|
|
110
|
+
assert scatter._log.x is False
|
|
111
|
+
assert scatter._log.y is False
|
|
112
|
+
|
|
113
|
+
def test_path_initialization(self):
|
|
114
|
+
"""Test that path is initialized to None."""
|
|
115
|
+
scatter = Scatter(self.x_data, self.y_data)
|
|
116
|
+
|
|
117
|
+
assert hasattr(scatter, "_path")
|
|
118
|
+
|
|
119
|
+
def test_invalid_input_types(self):
|
|
120
|
+
"""Test behavior with non-pandas Series inputs."""
|
|
121
|
+
# Lists are actually converted to Series internally
|
|
122
|
+
scatter = Scatter([1, 2, 3], self.y_data[:3])
|
|
123
|
+
assert len(scatter.data) == 3
|
|
124
|
+
|
|
125
|
+
# Both as lists
|
|
126
|
+
scatter2 = Scatter([1, 2, 3], [4, 5, 6])
|
|
127
|
+
assert len(scatter2.data) == 3
|
|
128
|
+
|
|
129
|
+
def test_empty_data_handling(self):
|
|
130
|
+
"""Test behavior with empty pandas Series."""
|
|
131
|
+
empty_x = pd.Series([], dtype=float)
|
|
132
|
+
empty_y = pd.Series([], dtype=float)
|
|
133
|
+
|
|
134
|
+
with pytest.raises(ValueError, match="exclusively NaNs"):
|
|
135
|
+
Scatter(empty_x, empty_y)
|
|
136
|
+
|
|
137
|
+
def test_mismatched_data_lengths(self):
|
|
138
|
+
"""Test error handling for different length x, y, z."""
|
|
139
|
+
short_data = pd.Series([1, 2])
|
|
140
|
+
|
|
141
|
+
# This should work - pandas will align indices
|
|
142
|
+
scatter = Scatter(short_data, self.y_data)
|
|
143
|
+
assert len(scatter.data) == 2 # Should keep only aligned data
|
|
144
|
+
|
|
145
|
+
def test_nan_data_handling(self):
|
|
146
|
+
"""Test handling of NaN values in data."""
|
|
147
|
+
x_with_nan = pd.Series([1, 2, np.nan, 4, 5])
|
|
148
|
+
y_with_nan = pd.Series([2, np.nan, 6, 8, 10])
|
|
149
|
+
|
|
150
|
+
scatter = Scatter(x_with_nan, y_with_nan)
|
|
151
|
+
|
|
152
|
+
# NaN rows should be dropped
|
|
153
|
+
assert not scatter.data.isnull().any().any()
|
|
154
|
+
assert len(scatter.data) < 5
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
class TestScatterDataManagement:
|
|
158
|
+
"""Test data management methods and properties."""
|
|
159
|
+
|
|
160
|
+
def setup_method(self):
|
|
161
|
+
"""Set up test data for each test method."""
|
|
162
|
+
self.x_data = pd.Series([1, 2, 3, 4, 5], name="x_values")
|
|
163
|
+
self.y_data = pd.Series([2, 4, 6, 8, 10], name="y_values")
|
|
164
|
+
self.z_data = pd.Series([10, 20, 30, 40, 50], name="z_values")
|
|
165
|
+
|
|
166
|
+
def test_set_data_method(self):
|
|
167
|
+
"""Test the set_data method."""
|
|
168
|
+
scatter = Scatter(self.x_data, self.y_data)
|
|
169
|
+
|
|
170
|
+
# Test basic data assignment
|
|
171
|
+
assert "x" in scatter.data.columns
|
|
172
|
+
assert "y" in scatter.data.columns
|
|
173
|
+
assert "z" in scatter.data.columns # Should be filled with 1s
|
|
174
|
+
|
|
175
|
+
def test_set_data_with_z(self):
|
|
176
|
+
"""Test set_data with z data."""
|
|
177
|
+
scatter = Scatter(self.x_data, self.y_data, self.z_data)
|
|
178
|
+
|
|
179
|
+
assert "z" in scatter.data.columns
|
|
180
|
+
assert not (scatter.data["z"] == 1).all() # Should not be all 1s
|
|
181
|
+
|
|
182
|
+
def test_data_property_access(self):
|
|
183
|
+
"""Test access to stored data via properties."""
|
|
184
|
+
scatter = Scatter(self.x_data, self.y_data, self.z_data)
|
|
185
|
+
|
|
186
|
+
data = scatter.data
|
|
187
|
+
assert isinstance(data, pd.DataFrame)
|
|
188
|
+
assert "x" in data.columns
|
|
189
|
+
assert "y" in data.columns
|
|
190
|
+
assert "z" in data.columns
|
|
191
|
+
|
|
192
|
+
def test_data_integrity(self):
|
|
193
|
+
"""Test that data remains unchanged after storage."""
|
|
194
|
+
scatter = Scatter(self.x_data, self.y_data, self.z_data)
|
|
195
|
+
|
|
196
|
+
# Check that original values are preserved
|
|
197
|
+
np.testing.assert_array_equal(scatter.data["x"].values, self.x_data.values)
|
|
198
|
+
np.testing.assert_array_equal(scatter.data["y"].values, self.y_data.values)
|
|
199
|
+
np.testing.assert_array_equal(scatter.data["z"].values, self.z_data.values)
|
|
200
|
+
|
|
201
|
+
def test_clip_property(self):
|
|
202
|
+
"""Test the clip property."""
|
|
203
|
+
scatter_no_clip = Scatter(self.x_data, self.y_data, clip_data=False)
|
|
204
|
+
scatter_with_clip = Scatter(self.x_data, self.y_data, clip_data=True)
|
|
205
|
+
|
|
206
|
+
assert scatter_no_clip.clip is False
|
|
207
|
+
assert scatter_with_clip.clip is True
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
class TestScatterLabelsAndAxes:
|
|
211
|
+
"""Test label and axis configuration."""
|
|
212
|
+
|
|
213
|
+
def setup_method(self):
|
|
214
|
+
"""Set up test data for each test method."""
|
|
215
|
+
self.x_data = pd.Series([1, 2, 3, 4, 5], name="x_values")
|
|
216
|
+
self.y_data = pd.Series([2, 4, 6, 8, 10], name="y_values")
|
|
217
|
+
self.z_data = pd.Series([10, 20, 30, 40, 50], name="z_values")
|
|
218
|
+
|
|
219
|
+
def test_default_labels(self):
|
|
220
|
+
"""Test that default labels are set correctly."""
|
|
221
|
+
scatter = Scatter(self.x_data, self.y_data)
|
|
222
|
+
|
|
223
|
+
assert scatter._labels.x == "x"
|
|
224
|
+
assert scatter._labels.y == "y"
|
|
225
|
+
assert scatter._labels.z is None
|
|
226
|
+
|
|
227
|
+
def test_labels_with_z_data(self):
|
|
228
|
+
"""Test labels when z data is provided."""
|
|
229
|
+
scatter = Scatter(self.x_data, self.y_data, self.z_data)
|
|
230
|
+
|
|
231
|
+
assert scatter._labels.x == "x"
|
|
232
|
+
assert scatter._labels.y == "y"
|
|
233
|
+
assert scatter._labels.z == "z"
|
|
234
|
+
|
|
235
|
+
def test_label_customization(self):
|
|
236
|
+
"""Test updating axis labels via namedtuple replacement."""
|
|
237
|
+
scatter = Scatter(self.x_data, self.y_data, self.z_data)
|
|
238
|
+
|
|
239
|
+
# AxesLabels is a namedtuple, so we need to replace it entirely
|
|
240
|
+
original_labels = scatter._labels
|
|
241
|
+
new_labels = scatter._labels._replace(x="Custom X", y="Custom Y", z="Custom Z")
|
|
242
|
+
scatter._labels = new_labels
|
|
243
|
+
|
|
244
|
+
assert scatter._labels.x == "Custom X"
|
|
245
|
+
assert scatter._labels.y == "Custom Y"
|
|
246
|
+
assert scatter._labels.z == "Custom Z"
|
|
247
|
+
|
|
248
|
+
def test_label_persistence(self):
|
|
249
|
+
"""Test that labels maintain values across operations."""
|
|
250
|
+
scatter = Scatter(self.x_data, self.y_data)
|
|
251
|
+
|
|
252
|
+
original_x = scatter._labels.x
|
|
253
|
+
original_y = scatter._labels.y
|
|
254
|
+
|
|
255
|
+
# Perform some operation (access data)
|
|
256
|
+
_ = scatter.data
|
|
257
|
+
|
|
258
|
+
# Labels should persist
|
|
259
|
+
assert scatter._labels.x == original_x
|
|
260
|
+
assert scatter._labels.y == original_y
|
|
261
|
+
|
|
262
|
+
def test_log_scale_defaults(self):
|
|
263
|
+
"""Test default log scale settings."""
|
|
264
|
+
scatter = Scatter(self.x_data, self.y_data)
|
|
265
|
+
|
|
266
|
+
assert scatter._log.x is False
|
|
267
|
+
assert scatter._log.y is False
|
|
268
|
+
|
|
269
|
+
def test_log_scale_configuration(self):
|
|
270
|
+
"""Test setting logarithmic scales via namedtuple replacement."""
|
|
271
|
+
scatter = Scatter(self.x_data, self.y_data)
|
|
272
|
+
|
|
273
|
+
# LogAxes is a namedtuple, so we need to replace it entirely
|
|
274
|
+
new_log = scatter._log._replace(x=True, y=True)
|
|
275
|
+
scatter._log = new_log
|
|
276
|
+
|
|
277
|
+
assert scatter._log.x is True
|
|
278
|
+
assert scatter._log.y is True
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
class TestScatterPlotGeneration:
|
|
282
|
+
"""Test plot generation and matplotlib integration."""
|
|
283
|
+
|
|
284
|
+
def setup_method(self):
|
|
285
|
+
"""Set up test data for each test method."""
|
|
286
|
+
self.x_data = pd.Series([1, 2, 3, 4, 5], name="x_values")
|
|
287
|
+
self.y_data = pd.Series([2, 4, 6, 8, 10], name="y_values")
|
|
288
|
+
self.z_data = pd.Series([10, 20, 30, 40, 50], name="z_values")
|
|
289
|
+
|
|
290
|
+
@patch("matplotlib.pyplot.subplots")
|
|
291
|
+
def test_make_plot_basic(self, mock_subplots):
|
|
292
|
+
"""Test basic scatter plot generation."""
|
|
293
|
+
# Setup mock
|
|
294
|
+
mock_fig = MagicMock()
|
|
295
|
+
mock_ax = MagicMock()
|
|
296
|
+
mock_collection = MagicMock(spec=PathCollection)
|
|
297
|
+
mock_subplots.return_value = (mock_fig, mock_ax)
|
|
298
|
+
mock_ax.scatter.return_value = mock_collection
|
|
299
|
+
|
|
300
|
+
scatter = Scatter(self.x_data, self.y_data)
|
|
301
|
+
ax, cbar = scatter.make_plot()
|
|
302
|
+
|
|
303
|
+
# Verify scatter plot was called
|
|
304
|
+
mock_ax.scatter.assert_called_once()
|
|
305
|
+
assert ax == mock_ax
|
|
306
|
+
assert cbar is None # No colorbar for 2D plot
|
|
307
|
+
|
|
308
|
+
@patch("matplotlib.pyplot.subplots")
|
|
309
|
+
def test_make_plot_with_z_data(self, mock_subplots):
|
|
310
|
+
"""Test scatter plot generation with z data."""
|
|
311
|
+
# Setup mock
|
|
312
|
+
mock_fig = MagicMock()
|
|
313
|
+
mock_ax = MagicMock()
|
|
314
|
+
mock_collection = MagicMock(spec=PathCollection)
|
|
315
|
+
mock_subplots.return_value = (mock_fig, mock_ax)
|
|
316
|
+
mock_ax.scatter.return_value = mock_collection
|
|
317
|
+
|
|
318
|
+
scatter = Scatter(self.x_data, self.y_data, self.z_data)
|
|
319
|
+
|
|
320
|
+
# Mock the _make_cbar method
|
|
321
|
+
with patch.object(scatter, "_make_cbar") as mock_make_cbar:
|
|
322
|
+
mock_cbar = MagicMock()
|
|
323
|
+
mock_make_cbar.return_value = mock_cbar
|
|
324
|
+
|
|
325
|
+
ax, cbar = scatter.make_plot()
|
|
326
|
+
|
|
327
|
+
# Verify scatter plot was called
|
|
328
|
+
mock_ax.scatter.assert_called_once()
|
|
329
|
+
# Verify colorbar was created
|
|
330
|
+
mock_make_cbar.assert_called_once()
|
|
331
|
+
assert ax == mock_ax
|
|
332
|
+
assert cbar == mock_cbar
|
|
333
|
+
|
|
334
|
+
@patch("matplotlib.pyplot.subplots")
|
|
335
|
+
def test_make_plot_with_provided_ax(self, mock_subplots):
|
|
336
|
+
"""Test plot generation with provided axes."""
|
|
337
|
+
# Setup mock
|
|
338
|
+
provided_ax = MagicMock()
|
|
339
|
+
mock_collection = MagicMock(spec=PathCollection)
|
|
340
|
+
provided_ax.scatter.return_value = mock_collection
|
|
341
|
+
|
|
342
|
+
scatter = Scatter(self.x_data, self.y_data)
|
|
343
|
+
ax, cbar = scatter.make_plot(ax=provided_ax)
|
|
344
|
+
|
|
345
|
+
# Should not create new subplot
|
|
346
|
+
mock_subplots.assert_not_called()
|
|
347
|
+
# Should use provided axes
|
|
348
|
+
provided_ax.scatter.assert_called_once()
|
|
349
|
+
assert ax == provided_ax
|
|
350
|
+
|
|
351
|
+
@patch("matplotlib.pyplot.subplots")
|
|
352
|
+
def test_make_plot_no_colorbar(self, mock_subplots):
|
|
353
|
+
"""Test plot generation with colorbar disabled."""
|
|
354
|
+
# Setup mock
|
|
355
|
+
mock_fig = MagicMock()
|
|
356
|
+
mock_ax = MagicMock()
|
|
357
|
+
mock_collection = MagicMock(spec=PathCollection)
|
|
358
|
+
mock_subplots.return_value = (mock_fig, mock_ax)
|
|
359
|
+
mock_ax.scatter.return_value = mock_collection
|
|
360
|
+
|
|
361
|
+
scatter = Scatter(self.x_data, self.y_data, self.z_data)
|
|
362
|
+
ax, cbar = scatter.make_plot(cbar=False)
|
|
363
|
+
|
|
364
|
+
assert cbar is None
|
|
365
|
+
|
|
366
|
+
@patch("matplotlib.pyplot.subplots")
|
|
367
|
+
def test_make_plot_kwargs_passed(self, mock_subplots):
|
|
368
|
+
"""Test that kwargs are passed to ax.scatter."""
|
|
369
|
+
# Setup mock
|
|
370
|
+
mock_fig = MagicMock()
|
|
371
|
+
mock_ax = MagicMock()
|
|
372
|
+
mock_collection = MagicMock(spec=PathCollection)
|
|
373
|
+
mock_subplots.return_value = (mock_fig, mock_ax)
|
|
374
|
+
mock_ax.scatter.return_value = mock_collection
|
|
375
|
+
|
|
376
|
+
scatter = Scatter(self.x_data, self.y_data)
|
|
377
|
+
scatter.make_plot(s=50, alpha=0.7, marker="s")
|
|
378
|
+
|
|
379
|
+
# Check that kwargs were passed
|
|
380
|
+
call_args = mock_ax.scatter.call_args
|
|
381
|
+
assert "s" in call_args.kwargs
|
|
382
|
+
assert "alpha" in call_args.kwargs
|
|
383
|
+
assert "marker" in call_args.kwargs
|
|
384
|
+
assert call_args.kwargs["s"] == 50
|
|
385
|
+
assert call_args.kwargs["alpha"] == 0.7
|
|
386
|
+
assert call_args.kwargs["marker"] == "s"
|
|
387
|
+
|
|
388
|
+
def test_format_axis_method(self):
|
|
389
|
+
"""Test the _format_axis method."""
|
|
390
|
+
scatter = Scatter(self.x_data, self.y_data)
|
|
391
|
+
|
|
392
|
+
# Setup mock axes and collection
|
|
393
|
+
mock_ax = MagicMock()
|
|
394
|
+
mock_collection = MagicMock()
|
|
395
|
+
mock_collection.sticky_edges.x = [0, 0]
|
|
396
|
+
mock_collection.sticky_edges.y = [0, 0]
|
|
397
|
+
|
|
398
|
+
# Test the method
|
|
399
|
+
scatter._format_axis(mock_ax, mock_collection)
|
|
400
|
+
|
|
401
|
+
# Verify axes methods were called
|
|
402
|
+
mock_ax.update_datalim.assert_called_once()
|
|
403
|
+
mock_ax.autoscale_view.assert_called_once()
|
|
404
|
+
|
|
405
|
+
# Verify sticky edges were set
|
|
406
|
+
assert mock_collection.sticky_edges.x[0] == self.x_data.min()
|
|
407
|
+
assert mock_collection.sticky_edges.x[1] == self.x_data.max()
|
|
408
|
+
assert mock_collection.sticky_edges.y[0] == self.y_data.min()
|
|
409
|
+
assert mock_collection.sticky_edges.y[1] == self.y_data.max()
|
|
410
|
+
|
|
411
|
+
|
|
412
|
+
class TestScatterColorMapping:
|
|
413
|
+
"""Test color mapping and colorbar functionality."""
|
|
414
|
+
|
|
415
|
+
def setup_method(self):
|
|
416
|
+
"""Set up test data for each test method."""
|
|
417
|
+
self.x_data = pd.Series([1, 2, 3, 4, 5], name="x_values")
|
|
418
|
+
self.y_data = pd.Series([2, 4, 6, 8, 10], name="y_values")
|
|
419
|
+
self.z_data = pd.Series([10, 20, 30, 40, 50], name="z_values")
|
|
420
|
+
self.uniform_z = pd.Series([5, 5, 5, 5, 5], name="uniform_z")
|
|
421
|
+
|
|
422
|
+
@patch("matplotlib.pyplot.subplots")
|
|
423
|
+
def test_colorbar_creation_with_z_data(self, mock_subplots):
|
|
424
|
+
"""Test colorbar creation when z data is provided."""
|
|
425
|
+
# Setup mock
|
|
426
|
+
mock_fig = MagicMock()
|
|
427
|
+
mock_ax = MagicMock()
|
|
428
|
+
mock_collection = MagicMock(spec=PathCollection)
|
|
429
|
+
mock_subplots.return_value = (mock_fig, mock_ax)
|
|
430
|
+
mock_ax.scatter.return_value = mock_collection
|
|
431
|
+
|
|
432
|
+
scatter = Scatter(self.x_data, self.y_data, self.z_data)
|
|
433
|
+
|
|
434
|
+
with patch.object(scatter, "_make_cbar") as mock_make_cbar:
|
|
435
|
+
mock_cbar = MagicMock()
|
|
436
|
+
mock_make_cbar.return_value = mock_cbar
|
|
437
|
+
|
|
438
|
+
ax, cbar = scatter.make_plot(cbar=True)
|
|
439
|
+
|
|
440
|
+
mock_make_cbar.assert_called_once()
|
|
441
|
+
assert cbar == mock_cbar
|
|
442
|
+
|
|
443
|
+
@patch("matplotlib.pyplot.subplots")
|
|
444
|
+
def test_no_colorbar_with_uniform_z(self, mock_subplots):
|
|
445
|
+
"""Test no colorbar when z data is uniform."""
|
|
446
|
+
# Setup mock
|
|
447
|
+
mock_fig = MagicMock()
|
|
448
|
+
mock_ax = MagicMock()
|
|
449
|
+
mock_collection = MagicMock(spec=PathCollection)
|
|
450
|
+
mock_subplots.return_value = (mock_fig, mock_ax)
|
|
451
|
+
mock_ax.scatter.return_value = mock_collection
|
|
452
|
+
|
|
453
|
+
scatter = Scatter(self.x_data, self.y_data, self.uniform_z)
|
|
454
|
+
ax, cbar = scatter.make_plot()
|
|
455
|
+
|
|
456
|
+
# No colorbar should be created for uniform z data
|
|
457
|
+
assert cbar is None
|
|
458
|
+
|
|
459
|
+
@patch("matplotlib.pyplot.subplots")
|
|
460
|
+
def test_colorbar_kwargs_passed(self, mock_subplots):
|
|
461
|
+
"""Test that colorbar kwargs are passed correctly."""
|
|
462
|
+
# Setup mock
|
|
463
|
+
mock_fig = MagicMock()
|
|
464
|
+
mock_ax = MagicMock()
|
|
465
|
+
mock_collection = MagicMock(spec=PathCollection)
|
|
466
|
+
mock_subplots.return_value = (mock_fig, mock_ax)
|
|
467
|
+
mock_ax.scatter.return_value = mock_collection
|
|
468
|
+
|
|
469
|
+
scatter = Scatter(self.x_data, self.y_data, self.z_data)
|
|
470
|
+
|
|
471
|
+
cbar_kwargs = {"orientation": "horizontal", "shrink": 0.8}
|
|
472
|
+
|
|
473
|
+
with patch.object(scatter, "_make_cbar") as mock_make_cbar:
|
|
474
|
+
mock_cbar = MagicMock()
|
|
475
|
+
mock_make_cbar.return_value = mock_cbar
|
|
476
|
+
|
|
477
|
+
scatter.make_plot(cbar_kwargs=cbar_kwargs)
|
|
478
|
+
|
|
479
|
+
# Check that kwargs were passed
|
|
480
|
+
call_args = mock_make_cbar.call_args
|
|
481
|
+
assert "orientation" in call_args.kwargs
|
|
482
|
+
assert "shrink" in call_args.kwargs
|
|
483
|
+
|
|
484
|
+
|
|
485
|
+
class TestScatterInheritance:
|
|
486
|
+
"""Test integration with base classes."""
|
|
487
|
+
|
|
488
|
+
def setup_method(self):
|
|
489
|
+
"""Set up test data for each test method."""
|
|
490
|
+
self.x_data = pd.Series([1, 2, 3, 4, 5], name="x_values")
|
|
491
|
+
self.y_data = pd.Series([2, 4, 6, 8, 10], name="y_values")
|
|
492
|
+
self.z_data = pd.Series([10, 20, 30, 40, 50], name="z_values")
|
|
493
|
+
|
|
494
|
+
def test_plot_with_z_data_inheritance(self):
|
|
495
|
+
"""Test inheritance from PlotWithZdata."""
|
|
496
|
+
scatter = Scatter(self.x_data, self.y_data, self.z_data)
|
|
497
|
+
|
|
498
|
+
# Should have PlotWithZdata methods and properties
|
|
499
|
+
assert hasattr(scatter, "data")
|
|
500
|
+
assert hasattr(scatter, "clip")
|
|
501
|
+
assert hasattr(scatter, "set_data")
|
|
502
|
+
|
|
503
|
+
# Test inherited functionality
|
|
504
|
+
assert isinstance(scatter.data, pd.DataFrame)
|
|
505
|
+
assert isinstance(scatter.clip, bool)
|
|
506
|
+
|
|
507
|
+
def test_cbar_maker_inheritance(self):
|
|
508
|
+
"""Test inheritance from CbarMaker."""
|
|
509
|
+
scatter = Scatter(self.x_data, self.y_data, self.z_data)
|
|
510
|
+
|
|
511
|
+
# Should have CbarMaker methods
|
|
512
|
+
assert hasattr(scatter, "_make_cbar")
|
|
513
|
+
|
|
514
|
+
# Test that _make_cbar is callable
|
|
515
|
+
assert callable(scatter._make_cbar)
|
|
516
|
+
|
|
517
|
+
def test_base_class_properties_accessible(self):
|
|
518
|
+
"""Test that base class properties are accessible."""
|
|
519
|
+
scatter = Scatter(self.x_data, self.y_data, self.z_data)
|
|
520
|
+
|
|
521
|
+
# Should have Base class properties
|
|
522
|
+
assert hasattr(scatter, "labels")
|
|
523
|
+
assert hasattr(scatter, "log")
|
|
524
|
+
|
|
525
|
+
# Test property access
|
|
526
|
+
labels = scatter.labels
|
|
527
|
+
log_settings = scatter.log
|
|
528
|
+
assert labels is not None
|
|
529
|
+
assert log_settings is not None
|
|
530
|
+
|
|
531
|
+
|
|
532
|
+
class TestScatterErrorHandling:
|
|
533
|
+
"""Test error handling and edge cases."""
|
|
534
|
+
|
|
535
|
+
def setup_method(self):
|
|
536
|
+
"""Set up test data for each test method."""
|
|
537
|
+
self.x_data = pd.Series([1, 2, 3, 4, 5], name="x_values")
|
|
538
|
+
self.y_data = pd.Series([2, 4, 6, 8, 10], name="y_values")
|
|
539
|
+
self.z_data = pd.Series([10, 20, 30, 40, 50], name="z_values")
|
|
540
|
+
|
|
541
|
+
def test_invalid_data_types(self):
|
|
542
|
+
"""Test handling of non-pandas Series data types."""
|
|
543
|
+
# Lists are actually converted to Series internally
|
|
544
|
+
scatter1 = Scatter([1, 2, 3], self.y_data[:3])
|
|
545
|
+
assert len(scatter1.data) == 3
|
|
546
|
+
|
|
547
|
+
scatter2 = Scatter(self.x_data[:3], [4, 5, 6])
|
|
548
|
+
assert len(scatter2.data) == 3
|
|
549
|
+
|
|
550
|
+
scatter3 = Scatter(self.x_data, self.y_data, [7, 8, 9, 10, 11])
|
|
551
|
+
assert len(scatter3.data) == 5
|
|
552
|
+
|
|
553
|
+
def test_nan_inf_handling(self):
|
|
554
|
+
"""Test handling of NaN and infinite values."""
|
|
555
|
+
x_with_inf = pd.Series([1, 2, np.inf, 4, 5])
|
|
556
|
+
y_with_nan = pd.Series([2, np.nan, 6, 8, 10])
|
|
557
|
+
|
|
558
|
+
# NaN rows are dropped, but inf values may remain
|
|
559
|
+
scatter = Scatter(x_with_inf, y_with_nan)
|
|
560
|
+
|
|
561
|
+
# Check that NaN values are removed
|
|
562
|
+
assert not scatter.data.isnull().any().any()
|
|
563
|
+
|
|
564
|
+
# Inf values might remain in the data (this is the actual behavior)
|
|
565
|
+
assert len(scatter.data) == 4 # Row with NaN is dropped
|
|
566
|
+
|
|
567
|
+
def test_missing_data(self):
|
|
568
|
+
"""Test behavior with incomplete data."""
|
|
569
|
+
# Test with missing indices
|
|
570
|
+
x_missing = pd.Series([1, 3, 5], index=[0, 2, 4])
|
|
571
|
+
y_missing = pd.Series([2, 6, 10], index=[0, 2, 4])
|
|
572
|
+
|
|
573
|
+
scatter = Scatter(x_missing, y_missing)
|
|
574
|
+
|
|
575
|
+
# Should handle missing indices correctly
|
|
576
|
+
assert len(scatter.data) == 3
|
|
577
|
+
assert list(scatter.data.index) == [0, 2, 4]
|
|
578
|
+
|
|
579
|
+
def test_single_point_data(self):
|
|
580
|
+
"""Test handling of single data point."""
|
|
581
|
+
single_x = pd.Series([1])
|
|
582
|
+
single_y = pd.Series([2])
|
|
583
|
+
|
|
584
|
+
scatter = Scatter(single_x, single_y)
|
|
585
|
+
|
|
586
|
+
assert len(scatter.data) == 1
|
|
587
|
+
assert scatter.data.iloc[0]["x"] == 1
|
|
588
|
+
assert scatter.data.iloc[0]["y"] == 2
|
|
589
|
+
|
|
590
|
+
def test_negative_values_with_log(self):
|
|
591
|
+
"""Test behavior with negative values when log scale is set."""
|
|
592
|
+
negative_x = pd.Series([-1, -2, -3])
|
|
593
|
+
positive_y = pd.Series([1, 2, 3])
|
|
594
|
+
|
|
595
|
+
scatter = Scatter(negative_x, positive_y)
|
|
596
|
+
# Set log scale using namedtuple replacement
|
|
597
|
+
new_log = scatter._log._replace(x=True)
|
|
598
|
+
scatter._log = new_log
|
|
599
|
+
|
|
600
|
+
# This should not raise an error during initialization
|
|
601
|
+
# The error would occur during plotting, which matplotlib handles
|
|
602
|
+
assert scatter._log.x is True
|
|
603
|
+
|
|
604
|
+
def test_empty_data_after_processing(self):
|
|
605
|
+
"""Test handling when data becomes empty after processing."""
|
|
606
|
+
# Create data that becomes empty after NaN removal
|
|
607
|
+
all_nan_x = pd.Series([np.nan, np.nan, np.nan])
|
|
608
|
+
all_nan_y = pd.Series([np.nan, np.nan, np.nan])
|
|
609
|
+
|
|
610
|
+
with pytest.raises(ValueError, match="exclusively NaNs"):
|
|
611
|
+
Scatter(all_nan_x, all_nan_y)
|
|
612
|
+
|
|
613
|
+
|
|
614
|
+
class TestScatterPerformanceAndMemory:
|
|
615
|
+
"""Test performance and memory usage."""
|
|
616
|
+
|
|
617
|
+
def test_large_datasets(self):
|
|
618
|
+
"""Test performance with large datasets."""
|
|
619
|
+
# Create large dataset
|
|
620
|
+
n_points = 10000
|
|
621
|
+
large_x = pd.Series(np.random.randn(n_points))
|
|
622
|
+
large_y = pd.Series(np.random.randn(n_points))
|
|
623
|
+
large_z = pd.Series(np.random.randn(n_points))
|
|
624
|
+
|
|
625
|
+
# Should handle large datasets without issues
|
|
626
|
+
scatter = Scatter(large_x, large_y, large_z)
|
|
627
|
+
|
|
628
|
+
assert len(scatter.data) == n_points
|
|
629
|
+
assert "x" in scatter.data.columns
|
|
630
|
+
assert "y" in scatter.data.columns
|
|
631
|
+
assert "z" in scatter.data.columns
|
|
632
|
+
|
|
633
|
+
def test_memory_usage(self):
|
|
634
|
+
"""Test efficient memory usage."""
|
|
635
|
+
scatter = Scatter(self.x_data, self.y_data)
|
|
636
|
+
|
|
637
|
+
# Data should be stored efficiently
|
|
638
|
+
data_memory = scatter.data.memory_usage(deep=True).sum()
|
|
639
|
+
assert data_memory > 0 # Should use some memory
|
|
640
|
+
|
|
641
|
+
# Should not create excessive copies
|
|
642
|
+
original_data = scatter.data
|
|
643
|
+
accessed_data = scatter.data
|
|
644
|
+
assert original_data is accessed_data # Should be same object
|
|
645
|
+
|
|
646
|
+
def setup_method(self):
|
|
647
|
+
"""Set up test data for each test method."""
|
|
648
|
+
self.x_data = pd.Series([1, 2, 3, 4, 5], name="x_values")
|
|
649
|
+
self.y_data = pd.Series([2, 4, 6, 8, 10], name="y_values")
|
|
650
|
+
|
|
651
|
+
|
|
652
|
+
class TestScatterDocumentation:
|
|
653
|
+
"""Test documentation and examples."""
|
|
654
|
+
|
|
655
|
+
def test_class_docstring_exists(self):
|
|
656
|
+
"""Test that class has docstring."""
|
|
657
|
+
assert Scatter.__doc__ is not None
|
|
658
|
+
assert len(Scatter.__doc__.strip()) > 0
|
|
659
|
+
|
|
660
|
+
def test_init_docstring_exists(self):
|
|
661
|
+
"""Test that __init__ method has docstring."""
|
|
662
|
+
assert Scatter.__init__.__doc__ is not None
|
|
663
|
+
assert len(Scatter.__init__.__doc__.strip()) > 0
|
|
664
|
+
|
|
665
|
+
def test_make_plot_docstring_exists(self):
|
|
666
|
+
"""Test that make_plot method has docstring."""
|
|
667
|
+
assert Scatter.make_plot.__doc__ is not None
|
|
668
|
+
assert len(Scatter.make_plot.__doc__.strip()) > 0
|
|
669
|
+
|
|
670
|
+
def test_docstring_parameter_documentation(self):
|
|
671
|
+
"""Test that parameters are documented in docstrings."""
|
|
672
|
+
init_doc = Scatter.__init__.__doc__
|
|
673
|
+
|
|
674
|
+
# Check that key parameters are documented
|
|
675
|
+
assert "x" in init_doc
|
|
676
|
+
assert "y" in init_doc
|
|
677
|
+
assert "z" in init_doc
|
|
678
|
+
assert "clip_data" in init_doc
|
|
679
|
+
|
|
680
|
+
make_plot_doc = Scatter.make_plot.__doc__
|
|
681
|
+
assert "ax" in make_plot_doc
|
|
682
|
+
assert "cbar" in make_plot_doc
|
|
683
|
+
|
|
684
|
+
|
|
685
|
+
class TestScatterIntegration:
|
|
686
|
+
"""Integration tests for full scatter plot workflow."""
|
|
687
|
+
|
|
688
|
+
def setup_method(self):
|
|
689
|
+
"""Set up test data for each test method."""
|
|
690
|
+
self.x_data = pd.Series([1, 2, 3, 4, 5], name="x_values")
|
|
691
|
+
self.y_data = pd.Series([2, 4, 6, 8, 10], name="y_values")
|
|
692
|
+
self.z_data = pd.Series([10, 20, 30, 40, 50], name="z_values")
|
|
693
|
+
|
|
694
|
+
@patch("matplotlib.pyplot.subplots")
|
|
695
|
+
def test_full_workflow_2d(self, mock_subplots):
|
|
696
|
+
"""Test complete workflow for 2D scatter plot."""
|
|
697
|
+
# Setup mock
|
|
698
|
+
mock_fig = MagicMock()
|
|
699
|
+
mock_ax = MagicMock()
|
|
700
|
+
mock_collection = MagicMock(spec=PathCollection)
|
|
701
|
+
mock_subplots.return_value = (mock_fig, mock_ax)
|
|
702
|
+
mock_ax.scatter.return_value = mock_collection
|
|
703
|
+
|
|
704
|
+
# Create scatter plot
|
|
705
|
+
scatter = Scatter(self.x_data, self.y_data)
|
|
706
|
+
|
|
707
|
+
# Customize labels using namedtuple replacement
|
|
708
|
+
new_labels = scatter._labels._replace(x="X Values", y="Y Values")
|
|
709
|
+
scatter._labels = new_labels
|
|
710
|
+
|
|
711
|
+
# Generate plot
|
|
712
|
+
ax, cbar = scatter.make_plot()
|
|
713
|
+
|
|
714
|
+
# Verify workflow
|
|
715
|
+
assert ax is not None
|
|
716
|
+
assert cbar is None
|
|
717
|
+
mock_ax.scatter.assert_called_once()
|
|
718
|
+
|
|
719
|
+
@patch("matplotlib.pyplot.subplots")
|
|
720
|
+
def test_full_workflow_3d_with_colorbar(self, mock_subplots):
|
|
721
|
+
"""Test complete workflow for 3D scatter plot with colorbar."""
|
|
722
|
+
# Setup mock
|
|
723
|
+
mock_fig = MagicMock()
|
|
724
|
+
mock_ax = MagicMock()
|
|
725
|
+
mock_collection = MagicMock(spec=PathCollection)
|
|
726
|
+
mock_subplots.return_value = (mock_fig, mock_ax)
|
|
727
|
+
mock_ax.scatter.return_value = mock_collection
|
|
728
|
+
|
|
729
|
+
scatter = Scatter(self.x_data, self.y_data, self.z_data)
|
|
730
|
+
|
|
731
|
+
with patch.object(scatter, "_make_cbar") as mock_make_cbar:
|
|
732
|
+
mock_cbar = MagicMock()
|
|
733
|
+
mock_make_cbar.return_value = mock_cbar
|
|
734
|
+
|
|
735
|
+
# Customize labels using namedtuple replacement
|
|
736
|
+
new_labels = scatter._labels._replace(
|
|
737
|
+
x="X Values", y="Y Values", z="Color Values"
|
|
738
|
+
)
|
|
739
|
+
scatter._labels = new_labels
|
|
740
|
+
|
|
741
|
+
# Generate plot with colorbar
|
|
742
|
+
ax, cbar = scatter.make_plot(cbar=True)
|
|
743
|
+
|
|
744
|
+
# Verify workflow
|
|
745
|
+
assert ax is not None
|
|
746
|
+
assert cbar is not None
|
|
747
|
+
mock_ax.scatter.assert_called_once()
|
|
748
|
+
mock_make_cbar.assert_called_once()
|
|
749
|
+
|
|
750
|
+
|
|
751
|
+
if __name__ == "__main__":
|
|
752
|
+
pytest.main([__file__])
|