mirror of
https://github.com/kmein/niveum
synced 2026-03-18 02:51:08 +01:00
feat: add transits script
This commit is contained in:
181
packages/scripts/horoscope/transits.py
Normal file
181
packages/scripts/horoscope/transits.py
Normal file
@@ -0,0 +1,181 @@
|
||||
from flatlib import aspects, const
|
||||
from flatlib.chart import Chart
|
||||
from flatlib.datetime import Datetime
|
||||
import pytz
|
||||
from flatlib.geopos import GeoPos
|
||||
import timezonefinder
|
||||
import operator
|
||||
import click
|
||||
import itertools
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
tf = timezonefinder.TimezoneFinder()
|
||||
|
||||
planets = [
|
||||
const.SUN,
|
||||
const.MOON,
|
||||
const.MERCURY,
|
||||
const.VENUS,
|
||||
const.MARS,
|
||||
const.JUPITER,
|
||||
const.SATURN,
|
||||
const.URANUS,
|
||||
const.NEPTUNE,
|
||||
const.PLUTO,
|
||||
]
|
||||
|
||||
planet_symbols = {
|
||||
const.SUN: "☉",
|
||||
const.MOON: "☽",
|
||||
const.MERCURY: "☿",
|
||||
const.VENUS: "♀",
|
||||
const.MARS: "♂",
|
||||
const.JUPITER: "♃",
|
||||
const.SATURN: "♄",
|
||||
const.URANUS: "♅",
|
||||
const.NEPTUNE: "♆",
|
||||
const.PLUTO: "⯓",
|
||||
}
|
||||
|
||||
aspect_symbols = {
|
||||
const.NO_ASPECT: " ",
|
||||
const.CONJUNCTION: "☌",
|
||||
const.SEXTILE: "⚹",
|
||||
const.SQUARE: "□",
|
||||
const.TRINE: "△",
|
||||
const.OPPOSITION: "☍",
|
||||
}
|
||||
|
||||
|
||||
def convert_into_stupid_flatlib_format(dt):
|
||||
return Datetime(
|
||||
dt.strftime("%Y/%m/%d"),
|
||||
dt.strftime("%H:%M"),
|
||||
dt.utcoffset().total_seconds() / 3600,
|
||||
)
|
||||
|
||||
|
||||
here_latitude = 52.52
|
||||
here_longitude = 13.4
|
||||
|
||||
|
||||
def get_aspects(chart1, chart2, *, threshold):
|
||||
for planet1 in chart1.objects:
|
||||
for planet2 in chart2.objects:
|
||||
aspect = aspects.getAspect(planet1, planet2, const.MAJOR_ASPECTS)
|
||||
if aspect.exists() and aspect.orb <= threshold:
|
||||
yield aspect
|
||||
|
||||
|
||||
def get_chart(position, dt_naive):
|
||||
timezone = pytz.timezone(tf.timezone_at(lat=position.lat, lng=position.lon))
|
||||
dt_aware = timezone.localize(dt_naive)
|
||||
return Chart(convert_into_stupid_flatlib_format(dt_aware), position, IDs=planets)
|
||||
|
||||
|
||||
def show_aspect(aspect):
|
||||
return " ".join(
|
||||
[
|
||||
planet_symbols[aspect.active.id],
|
||||
aspect_symbols[aspect.type],
|
||||
planet_symbols[aspect.passive.id],
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
@click.command()
|
||||
@click.option("--natal-latitude", type=click.FLOAT, default=here_latitude)
|
||||
@click.option("--natal-longitude", type=click.FLOAT, default=here_longitude)
|
||||
@click.option("--natal-date", type=click.DateTime(), default=datetime.now())
|
||||
@click.option("--transit-latitude", type=click.FLOAT, default=here_latitude)
|
||||
@click.option("--transit-longitude", type=click.FLOAT, default=here_longitude)
|
||||
@click.option("--transit-date", type=click.DateTime(), default=datetime.now())
|
||||
@click.option("--threshold", type=click.FLOAT, default=5)
|
||||
def forecast(
|
||||
natal_latitude: float,
|
||||
natal_longitude: float,
|
||||
natal_date: datetime,
|
||||
transit_latitude: float,
|
||||
transit_longitude: float,
|
||||
transit_date: datetime,
|
||||
threshold: float,
|
||||
):
|
||||
transit_position = GeoPos(transit_latitude, transit_longitude)
|
||||
natal_position = GeoPos(natal_latitude, natal_longitude)
|
||||
natal_chart = get_chart(natal_position, natal_date)
|
||||
transit_chart = get_chart(transit_position, transit_date)
|
||||
|
||||
offset = 0
|
||||
previous_aspects = set(
|
||||
show_aspect(a)
|
||||
for a in get_aspects(natal_chart, transit_chart, threshold=threshold)
|
||||
)
|
||||
while True:
|
||||
then = transit_date + timedelta(minutes=offset)
|
||||
current_chart = get_chart(transit_position, then)
|
||||
current_aspects = set(
|
||||
show_aspect(a)
|
||||
for a in get_aspects(natal_chart, current_chart, threshold=threshold)
|
||||
)
|
||||
entered = current_aspects - previous_aspects
|
||||
exited = previous_aspects - current_aspects
|
||||
if entered or exited:
|
||||
print(
|
||||
then.strftime("%Y-%m-%d %H:%M"),
|
||||
"".join([" | +" + a for a in entered] + [" | -" + a for a in exited]),
|
||||
sep="",
|
||||
)
|
||||
previous_aspects = current_aspects
|
||||
offset += 1
|
||||
|
||||
|
||||
@click.command()
|
||||
@click.option("--natal-latitude", type=click.FLOAT, default=here_latitude)
|
||||
@click.option("--natal-longitude", type=click.FLOAT, default=here_longitude)
|
||||
@click.option("--natal-date", "-D", type=click.DateTime(), default=datetime.now())
|
||||
@click.option("--transit-latitude", type=click.FLOAT, default=here_latitude)
|
||||
@click.option("--transit-longitude", type=click.FLOAT, default=here_longitude)
|
||||
@click.option("--transit-date", "-d", type=click.DateTime(), default=datetime.now())
|
||||
@click.option("--threshold", "-t", type=click.FLOAT, default=5)
|
||||
def current(
|
||||
natal_latitude: float,
|
||||
natal_longitude: float,
|
||||
natal_date: datetime,
|
||||
transit_latitude: float,
|
||||
transit_longitude: float,
|
||||
transit_date: datetime,
|
||||
threshold: float,
|
||||
):
|
||||
transit_position = GeoPos(transit_latitude, transit_longitude)
|
||||
natal_position = GeoPos(natal_latitude, natal_longitude)
|
||||
natal_chart = get_chart(natal_position, natal_date)
|
||||
transit_chart = get_chart(transit_position, transit_date)
|
||||
|
||||
relevant_aspects = list(
|
||||
get_aspects(natal_chart, transit_chart, threshold=threshold)
|
||||
)
|
||||
|
||||
def aspect_switch_date(aspect, *, direction=1, threshold):
|
||||
offset = 0
|
||||
while True:
|
||||
then = transit_date + direction * timedelta(days=offset)
|
||||
current_chart = get_chart(transit_position, then)
|
||||
aspects = [
|
||||
show_aspect(a)
|
||||
for a in get_aspects(natal_chart, current_chart, threshold=threshold)
|
||||
]
|
||||
if aspect not in aspects:
|
||||
return then.date()
|
||||
offset += 1
|
||||
|
||||
for aspect in sorted(relevant_aspects, key=operator.attrgetter("orb")):
|
||||
aspect_string = show_aspect(aspect)
|
||||
print(
|
||||
aspect_switch_date(
|
||||
aspect_string, direction=-1, threshold=threshold
|
||||
).isoformat(),
|
||||
aspect_switch_date(
|
||||
aspect_string, direction=1, threshold=threshold
|
||||
).isoformat(),
|
||||
aspect_string,
|
||||
)
|
||||
Reference in New Issue
Block a user