theriftlab / immanuel-python

Quickly produce both human-readable and JSON-formatted astrology chart data based on the Swiss Ephemeris and astro.com.
GNU Affero General Public License v3.0
42 stars 13 forks source link

Progressed Charts Question #1

Closed marcusgraf closed 10 months ago

marcusgraf commented 10 months ago

Hi,

first of all, awesome work you did there.

I just have a question regarding the progressed chart.

I have a person, born in Berlin on 1.1.1970

native = charts.Subject('1970-01-01 00:00', 52.490134, 13.3365914)

I want to calculate the daily horoscope for Tuesday - 17 January 2024, like on astro-seek.com:

Astroseek Example

So my approach is to do this:

progressed = charts.Progressed(native, '2024-01-17 00:00')

The birthchart is right, but for some reason i get very different data to astro.com & astro-seek.com for the progressed chart.

e.g. The Moon should be in the 7th house, but in the progressed chart its in the 11th house.

theriftlab commented 10 months ago

Thanks, I'm glad people are finding it useful!

It looks like you're running a transit chart rather than secondary progressions - running a progressed chart on astro.com with the same defaults as Immanuel (house system Placidus, progression method Naibod) shows the moon in the 11th house.

I'm guessing what you want is to return both the natal chart and the transits, and see the aspects between the two. In that case you would construct both charts, passing the transit chart instance into the natal chart's constructor:

from immanuel import charts
from immanuel.const import chart

lat = 52.490134
lon = 13.3365914

transit = charts.Subject('2024-01-17 01:00', lat, lon)    # add an hour to match astro.com since its dates are all UTC
native = charts.Subject('1970-01-01 00:00', lat, lon)

transit_chart = charts.Natal(transit)
natal_and_transits = charts.Natal(native, transit_chart)

print(natal_and_transits.objects[chart.MOON].house)
# Output: "1st House" - natal moon is in 1st house
print(natal_and_transits.aspects[chart.MOON][chart.MOON].type)
# Output: "Opposition" - transiting moon will oppose natal moon on Jan 17th, ie. 7th house

Unfortunately there is currently no easy way to pick a transiting planet and see which natal house it is in. I'll have a think about how viable that would be to add in somewhere. Currently you'd have to do something a little more hacky with the instances' private members, eg.:

from immanuel import charts
from immanuel.const import chart
from immanuel.tools import position

lat = 52.490134
lon = 13.3365914

transit = charts.Subject('2024-01-17 01:00', lat, lon)
native = charts.Subject('1970-01-01 00:00', lat, lon)

transit_chart = charts.Natal(transit)
natal_and_transits = charts.Natal(native, transit_chart)

transiting_moon_lon = transit_chart.objects[chart.MOON].longitude.raw
natal_houses = natal_and_transits._houses

print(position.house(transiting_moon_lon, natal_houses)['name'])
# Output: "7th House"
marcusgraf commented 10 months ago

Ah, yes, I also thought about that calculation. It's working, but I think a calculation for that would be awesome.

Also, something that would be really interesting is the duration of how long a transit lasts and how intense it is for the daily horoscope.

And last but not least, you should definitely include a 'buy me a coffee' link for this project. The work you've done here is awesome!

theriftlab commented 10 months ago

Ah, yes, I also thought about that calculation. It's working, but I think a calculation for that would be awesome.

The more I think about this, the more useful it looks - synastries and transits will both want it. I'll take a look at adding it in somewhere.

Also, something that would be really interesting is the duration of how long a transit lasts and how intense it is for the daily horoscope.

Re intensity, I'm currently steering clear of anything straying into interpretation & focusing on making this package pure data. Although transit duration would certainly fall under pure data if their orbs are used, it would be an expensive calculation involving polling the ephemeris at intervals to check all relevant aspects between each of both sets of planets (think changing speeds, retrogrades etc.) At least as things are now, this would be too unpredictable in terms of run-time to comfortably fit in.

And last but not least, you should definitely include a 'buy me a coffee' link for this project. The work you've done here is awesome!

Thanks for the support! I'll take a look at BMC.

theriftlab commented 9 months ago

@marcusgraf FYI I have pushed a new release with a few new features - relevant to this thread is a new Chart.house_for() method which takes a planet/object from any chart and returns the index of the current chart's containing house. This is the simplest solution for now until I can think of something more clever!

Updated example:

from immanuel import charts
from immanuel.const import chart

lat = 52.490134
lon = 13.3365914

transit = charts.Subject('2024-01-17 01:00', lat, lon)
native = charts.Subject('1970-01-01 00:00', lat, lon)

transit_chart = charts.Natal(transit)
natal_and_transits = charts.Natal(native, transit_chart)

index = natal_and_transits.house_for(transit_chart.objects[chart.MOON])
print(natal_and_transits.houses[index])
# Output: 7th House 05°56'14" in Aries
marcusgraf commented 9 months ago

Wow, that's very helpful. Thanks a lot!

marcusgraf commented 9 months ago

Hey, sorry its me again.

I stuck a bit with my calculations for my daily horoscope.

The solution you provided is already really good but i would like to calculate also the aspects & orbs.

My approach is this:

# Step 1: Creating Subjects for Natal and Transit Charts
transit = charts.Subject('2024-01-29 00:00', lat, lon)
native = charts.Subject('1970-01-01 00:00', lat, lon)
logging.info("Subjects created for transit and natal charts.")

# Step 2: Generating Natal and Transit Charts
natal_chart = charts.Natal(native)
print("Attributes and methods of natal_chart:", dir(natal_chart))
transit_chart = charts.Natal(transit)
natal_and_transits = charts.Natal(native, transit_chart)
logging.info("Natal and transit charts generated.")

# Step 3: Extracting Planetary Positions and House Information
try:
    planetary_positions = natal_chart.objects  # Access the planets and other celestial objects
    houses = natal_chart.houses  # Access the houses
    logging.info("Extracted planetary positions and houses.")
except Exception as e:
    logging.error(f"Error extracting planetary positions and houses: {e}")

# Step 4: Accessing Aspects
try:
    aspects = natal_chart.aspects  # Access the aspects
    # Further processing may be needed to extract specific aspect details and orbs
    logging.info("Accessed aspects.")
except Exception as e:
    logging.error(f"Error accessing aspects: {e}")

# Step 5: Formatting and Outputting the Data
try:
    chart_data = json.dumps(natal_and_transits.objects, cls=ToJSON, indent=4)
    print(chart_data)
    logging.info("Outputted chart data.")
except Exception as e:
    logging.error("Error outputting chart data: %s", e)

In the end i would like to have something like this: "Transit Sun trines Moon, Orb: 1°09’"

Is that possible or am i on the wrong way for kind of calculation?

theriftlab commented 9 months ago

When natal_and_transits gets constructed with transit_chart passed to the aspects_to argument, it generates a chart for native but calculates the aspects to transit_chart's objects instead of its own. This should do what you're looking for (using the lat/lon from your initial examples):

from immanuel import charts

lat = 52.490134
lon = 13.3365914

# Step 1: Creating Subjects for Natal and Transit Charts
transit = charts.Subject('2024-01-29 00:00', lat, lon)
native = charts.Subject('1970-01-01 00:00', lat, lon)

# Step 2: Generating Natal and Transit Charts
transit_chart = charts.Natal(transit)
natal_and_transits = charts.Natal(native, transit_chart)

# Step 3: Output Aspects Between Both
for index, aspects in natal_and_transits.aspects.items():
    print(f'Aspects for {natal_and_transits.objects[index].name}:')

    for aspect in aspects.values():
        print(f' - {aspect}')

You should see a long list of aspects for all objects, eg.:

Aspects for Sun:
 - Moon Sun Trine within -03°38'11" (Separative, Associate)
 - Mercury Sun Conjunction within 09°05'20" (Separative, Associate)
 - Venus Sun Conjunction within 03°13'44" (Applicative, Associate)
 - Sun Mars Conjunction within 08°11'45" (Applicative, Associate)
 - Sun Jupiter Trine within -03°07'57" (Separative, Associate)
 - Sun Saturn Sextile within -04°01'11" (Separative, Associate)
 - Sun Uranus Trine within 08°58'33" (Applicative, Associate)

In that snippet, all of the aspects are between the natal chart's Sun and the transit chart's objects. These are always in the format: {active} {passive} {type} within {orb} ({movement} {condition}).

If you need it to calculate & return fewer objects you can of course change settings.objects at the beginning of the script as per the docs here.

theriftlab commented 9 months ago

@marcusgraf tagging in case you didn't see ☝️