Source code for vedic_numerology.analysis

"""
High-level numerology+astrology integration class used across the repo.
"""

from __future__ import annotations

from datetime import date, datetime, time
from typing import Any, Dict, Optional, Union

from vedic_astrology_core import VedicAstrologyChart
from vedic_astrology_core.config.constants import PLANET_NAMES, Planet

from .numerology import calculate_bhagyanka, calculate_mulanka


[docs] class VedicNumerologyAstrology: """ Combines Vedic numerology (Mulanka/Bhagyanka) with astrological dignity scoring. This provides a stable API for: - Streamlit app (`app.py`) - docs examples - tests (`tests/test_integration.py`) """
[docs] def __init__( self, birth_date: Union[str, date], birth_time: Optional[Union[str, time]] = None, latitude: float = 28.6139, longitude: float = 77.1025, timezone: str = "Asia/Kolkata", ayanamsa_system: str = "lahiri", ) -> None: self._birth_date = self._parse_birth_date(birth_date) self._birth_time = self._parse_birth_time(birth_time) if birth_time else None self.latitude = latitude self.longitude = longitude self.timezone = timezone self.ayanamsa_system = ayanamsa_system self._astro = VedicAstrologyChart( birth_date=self._birth_date, birth_time=self._birth_time, latitude=self.latitude, longitude=self.longitude, timezone=self.timezone, ayanamsa_system=self.ayanamsa_system.upper(), )
@property def birth_datetime(self) -> datetime: """Get the combined birth date and time.""" if self._birth_time: return datetime.combine(self._birth_date, self._birth_time) return datetime.combine(self._birth_date, time.min) def _parse_birth_date(self, d: Union[str, date]) -> date: if isinstance(d, str): return datetime.strptime(d, "%Y-%m-%d").date() if isinstance(d, date): return d raise TypeError(f"birth_date must be str or date, got {type(d)}") def _parse_birth_time(self, t: Union[str, time]) -> time: if isinstance(t, str): try: return datetime.strptime(t, "%H:%M:%S").time() except ValueError: return datetime.strptime(t, "%H:%M").time() if isinstance(t, time): return t raise TypeError(f"birth_time must be str or time, got {type(t)}")
[docs] def calculate_mulanka(self) -> Dict[str, Any]: number, planet = calculate_mulanka( self._birth_date, self._birth_time, self.latitude, self.longitude ) return {"number": number, "planet": planet}
[docs] def calculate_bhagyanka(self) -> Dict[str, Any]: number, planet = calculate_bhagyanka(self._birth_date) return {"number": number, "planet": planet}
[docs] def score_dignity(self, planet: Union[Planet, str]) -> Dict[str, Any]: return self._astro.score_dignity(planet)
[docs] def analyze_support_contradiction(self) -> Dict[str, Any]: mulanka = self.calculate_mulanka() bhagyanka = self.calculate_bhagyanka() mul_score = self.score_dignity(mulanka["planet"]) bha_score = self.score_dignity(bhagyanka["planet"]) def _support_level(score: float) -> str: if score >= 75: return "Excellent" if score >= 50: return "Good" if score >= 40: return "Neutral" if score >= 25: return "Weak" return "Poor" mul_level = _support_level(float(mul_score["score"])) bha_level = _support_level(float(bha_score["score"])) avg = (float(mul_score["score"]) + float(bha_score["score"])) / 2.0 overall = _support_level(avg) return { "mulanka": { "planet": mulanka["planet"], "score": float(mul_score["score"]), "support_level": mul_level, "dignity_type": mul_score.get("dignity_type"), "details": mul_score, }, "bhagyanka": { "planet": bhagyanka["planet"], "score": float(bha_score["score"]), "support_level": bha_level, "dignity_type": bha_score.get("dignity_type"), "details": bha_score, }, "overall": { "average_score": avg, "harmony_level": overall, "harmony_score": avg, "support_level": overall, }, }
[docs] def plot_dignity_analysis( self, planet: Union[Planet, str], use_plotly: bool = True ) -> Any: return self._astro.plot_dignity_analysis(planet=planet, use_plotly=use_plotly)
[docs] def plot_temporal_support( self, start_date: Union[str, datetime], end_date: Union[str, datetime], planet: Union[Planet, str], use_plotly: bool = True, ) -> Any: if isinstance(start_date, str): start_dt = datetime.strptime(start_date, "%Y-%m-%d") else: start_dt = start_date if isinstance(end_date, str): end_dt = datetime.strptime(end_date, "%Y-%m-%d") else: end_dt = end_date return self._astro.plot_temporal_support( start_date=start_dt, end_date=end_dt, planet=planet, use_plotly=use_plotly )
[docs] def plot_numerology_comparison(self, use_plotly: bool = True) -> Any: """ Plot numerology vs astrology strength over time for the Mulanka planet for the next year starting today. """ from datetime import date as _date from vedic_astrology_core.time_series import compute_combined_series from vedic_numerology.visualization import plot_numerology_comparison today = _date.today() end = today.replace(year=today.year + 1) df = compute_combined_series(today, end, step_days=1) mulanka_planet = self.calculate_mulanka()["planet"] return plot_numerology_comparison( df, planet=mulanka_planet, use_plotly=use_plotly )
[docs] def generate_report(self) -> str: mul = self.calculate_mulanka() bha = self.calculate_bhagyanka() support = self.analyze_support_contradiction() lines = [] lines.append("=" * 70) lines.append("VEDIC NUMEROLOGY-ASTROLOGY ANALYSIS REPORT") lines.append("=" * 70) lines.append("") lines.append("BIRTH DATA:") lines.append(f" Date: {self._birth_date.isoformat()}") if self._birth_time is not None: lines.append(f" Time: {self._birth_time.isoformat()}") lines.append(f" Location: {self.latitude:.4f}, {self.longitude:.4f}") lines.append(f" Ayanamsa: {self.ayanamsa_system}") lines.append("") lines.append("NUMEROLOGY CALCULATIONS:") lines.append( f" Mulanka (Birth Number): {mul['number']} ({PLANET_NAMES[mul['planet']]})" ) lines.append( f" Bhagyanka (Destiny Number): {bha['number']} ({PLANET_NAMES[bha['planet']]})" ) lines.append("") lines.append("PLANETARY SUPPORT ANALYSIS:") lines.append( f" Mulanka planet dignity: {support['mulanka']['score']:.1f}/100 ({support['mulanka']['support_level']})" ) lines.append( f" Bhagyanka planet dignity: {support['bhagyanka']['score']:.1f}/100 ({support['bhagyanka']['support_level']})" ) lines.append( f" Overall: {support['overall']['average_score']:.1f}/100 ({support['overall']['harmony_level']})" ) lines.append("") lines.append("=" * 70) return "\n".join(lines)
[docs] def analyze_birth_chart( birth_date: Union[str, date], birth_time: Optional[Union[str, time]] = None, latitude: float = 28.6139, longitude: float = 77.1025, timezone: str = "Asia/Kolkata", ayanamsa_system: str = "lahiri", ) -> VedicNumerologyAstrology: return VedicNumerologyAstrology( birth_date=birth_date, birth_time=birth_time, latitude=latitude, longitude=longitude, timezone=timezone, ayanamsa_system=ayanamsa_system, )