Printing a Chart

This tutorial combines the concepts from Zodiacal Position (swe.calc_ut(), swe.split_deg()) and Angles and Houses (swe.houses()). You can feel free to skip all the commented-out print() statements; they’re mostly here for verification, especially if you’re using the Python interpreter in interactive mode.

Define constants and calculate Julian day

We’re going to calculate the zodiacal positions of the 10 planets, ascendant and midheaven of the initial release of the Swiss Ephemeris C library underlying pyswisseph, which has the following birth information:

  • 1997 September 30

  • 4:00 p.m. CEST (UTC+2) -> 14:00 UTC

  • Zollikon, Switzerland -> 47.33 N, 8.58 E

import swisseph as swe
from datetime import datetime, timezone

lat = 47.33
lng = 8.58
hsys = b"W"
date = datetime(1997, 9, 30, 14, 0, 0, tzinfo=timezone.utc)

jd_ut, jd_tt = swe.utc_to_jd(
    date.year, date.month, date.day, date.hour, date.minute, date.second
)

# print(f"Julian day: {jd_tt}")

# Output:
# Julian day: 2450722.0833377214
  • b'W': This is the byte character for whole sign houses, but anything works here since cusps are irrelevant to this tutorial.

  • swe.utc_to_jd(): Explained in Quickstart that jd_tt is more accurate than jd_ut given by swe.julday.

Calculate ascendant and midheaven longitudes

cusps, ascmc = swe.houses(jd_tt, lat, lng, hsys)
angles = [ascmc[0], ascmc[1]]

# print(f"Ascendant: {angles[0]}")
# print(f"Midheaven: {angles[1]}")

# Output:
# Ascendant: 290.4375225094583
# Midheaven: 230.37565140999195
  • swe.houses(): We only need the tuple at index 1, ascmc, and only its first two elements, so we unpack them into a new list called angles for later concatenation.

Calculate planetary longitudes

PLANET_IDS = {
    "Sun": swe.SUN,
    "Moon": swe.MOON,
    "Mercury": swe.MERCURY,
    "Venus": swe.VENUS,
    "Mars": swe.MARS,
    "Jupiter": swe.JUPITER,
    "Saturn": swe.SATURN,
    "Uranus": swe.URANUS,
    "Neptune": swe.NEPTUNE,
    "Pluto": swe.PLUTO,
}

planets = []
for name, id_val in PLANET_IDS.items():
    coords, flag, _ = swe.calc_ut(jd_tt, id_val)    # returns coordinates, flags, and error messages
    longitude = coords[0]
    planets.append(longitude)

# for name, planet in zip(PLANET_IDS.keys(), planets):
#    print(f"{name}: {planet}")

# Output:
# Sun: 187.44207682576493
# Moon: 175.3108433704147
# Mercury: 177.03456720228542
# Venus: 231.25169861097027
# Mars: 241.1545702632383
# Jupiter: 312.18899266331294
# Saturn: 17.660024903370054
# Uranus: 304.81633539199663
# Neptune: 297.20035476146546
# Pluto: 243.46074212504317
  • PLANET_IDS: This dictionary explicitly uses constants, but you can easily loop over a range as described in Bodies.

  • swe.calc_ut(): coords[0] gives ecliptic longitude.

Convert longitudes to DMS

objects = planets + angles

zodiacal = []
for point in objects:
    dms_split = swe.split_deg(point, swe.SPLIT_DEG_ZODIACAL)
    zodiacal.append(dms_split)

# print(zodiacal)

# Output:
# [(7, 26, 31, 0.47657275374280417, 6), (25, 18, 39, 0.03613349287529388, 5), (27, 2, 4, 0.44192822749755756, 5), (21, 15, 6, 0.11499949295648548, 7), (1, 9, 16, 0.45294765787414093, 8), (12, 11, 20, 0.373587926601477, 10), (17, 39, 36, 0.08965213219526191, 0), (4, 48, 58, 0.8074111878721197, 10), (27, 12, 1, 0.2771412 7566374014, 9), (3, 27, 38, 0.6716501554064536, 8), (20, 26, 15, 0.08103404984462159, 9), (20, 22, 32, 0.34507597100455456, 7)]

SIGNS = (
    "Ari",
    "Tau",
    "Gem",
    "Can",
    "Leo",
    "Vir",
    "Lib",
    "Sco",
    "Sag",
    "Cap",
    "Aqu",
    "Pis",
)
  • swe.split_deg(): Described in Zodiacal Position. This tuple is (degrees, minutes, seconds, fraction_of_seconds, sign index) where sign_index is an integer from 0 to 11.

  • SIGNS: This tuple makes sign_index legible in printing.

Format and print output

OBJECT_NAMES = list(PLANET_IDS.keys()) + ["AC", "MC"]

print(f"--- Chart Positions (System: {hsys.decode()}) ---")

for name, dms_split in zip(OBJECT_NAMES, zodiacal):
    deg, minute, sec, f_of_s, sign_index = dms_split
    sign = SIGNS[int(sign_index)]
    position_string = f"{name:<8} {deg:2.0f} {sign} {minute:02} {sec:02.0f}"
    print(position_string)
  • OBJECT_NAMES: Concatenates the dictionary keys from PLANET_IDS with our angles list.

  • dms_split: This is where we get sign_index at index 4.

Expected output

If you ran the complete script (tutorial.py), the final output should look like this:

--- Chart Positions (System: W) ---
Sun       7 Lib 26 31
Moon     25 Vir 18 39
Mercury  27 Vir 02 04
Venus    21 Sco 15 06
Mars      1 Sag 09 16
Jupiter  12 Aqu 11 20
Saturn   17 Ari 39 36
Uranus    4 Aqu 48 58
Neptune  27 Cap 12 01
Pluto     3 Sag 27 38
AC       20 Cap 26 15
MC       20 Sco 22 32

Tutorial app

You can input your own birth information in the if __name__ = "__main__" block of tutorial_app.py:

if __name__ == "__main__":
    # User inputs here!
    BIRTH_DATA = {
        "date": datetime(1997, 7, 19, 12, 0, 0, tzinfo=timezone.utc),
        "lat": 35.6897,
        "lng": 139.69,
        "hsys": b"W",
    }