House Systems

House systems divide the celestial sphere into twelve segments, called houses, starting from the Ascendant (the eastern horizon at the moment of birth). Each system uses a different mathematical projection to do this division, which is why the same chart can look markedly different depending on which system you choose. Ketu ships six systems and lets you register additional ones.

Supported Systems

The six built-in systems are exposed in the SYSTEMS dict:

Key

Name

Description

placidus

Placidus

Time-based; most common in modern western practice

koch

Koch

Birthplace system; similar to Placidus at mid-latitudes

porphyry

Porphyry

Divides quadrants into thirds; works at high latitudes

whole_sign

Whole Sign

Each house = one full sign; oldest recorded system

equal

Equal

Houses of 30° each, starting from the Ascendant

regiomontanus

Regiomontanus

Space-based; common in horary astrology

from ketu.houses import SYSTEMS

print(list(SYSTEMS.keys()))
# ['placidus', 'koch', 'porphyry', 'whole_sign', 'equal', 'regiomontanus']

calculate_houses

calculate_houses(jd, lat, lon, system="placidus", polar_fallback="raise")

Computes the twelve house cusps and the angles (Ascendant, Midheaven, ARMC, Vertex) for a given moment and location. Returns a NumPy structured array of HOUSES_DTYPE.

Parameters

  • jd — Julian Day (float, UTC)

  • lat — geographic latitude in degrees (+N / -S)

  • lon — geographic longitude in degrees (+E / -W)

  • system — one of the six keys above (default "placidus")

  • polar_fallback — behaviour above the Arctic/Antarctic circles (see below)

Example — Paris chart at J2000

from ketu.houses import calculate_houses, house_of, SYSTEMS, HOUSES_DTYPE, HighLatitudeError

jd = 2451545.0       # J2000: 2000-01-01 12:00 UTC
lat = 48.8566        # Paris latitude
lon = 2.3522         # Paris longitude

h = calculate_houses(jd, lat, lon, system="placidus")

print(h["asc"])      # Ascendant longitude (degrees)
print(h["mc"])       # Midheaven longitude (degrees)
print(h["cusps"])    # Array of 12 cusp longitudes

Switching systems

for system in SYSTEMS:
    h = calculate_houses(jd, lat, lon, system=system)
    print(f"{system:16s}  ASC={h['asc']:.2f}  MC={h['mc']:.2f}")

house_of

house_of(planet_lon, cusps)

Places one or more planet longitudes into a house number (1–12), vectorised over an array of longitudes.

from ketu.houses import calculate_houses, house_of

jd = 2451545.0
h = calculate_houses(jd, 48.8566, 2.3522)
cusps = h["cusps"]

# Single planet
sun_lon = 280.5
print(house_of(sun_lon, cusps))   # e.g. 10

# Multiple planets at once
import numpy as np
planet_lons = np.array([280.5, 45.3, 123.7, 198.2])
houses = house_of(planet_lons, cusps)
print(houses)   # array of house numbers 1–12

HOUSES_DTYPE

The structured array returned by calculate_houses has the following fields:

Field

Type

Description

jd

float64

Julian Day of the calculation

lat

float64

Geographic latitude

lon

float64

Geographic longitude

system

U20

House system name

cusps

float64[12]

Twelve house cusp longitudes (degrees)

asc

float64

Ascendant longitude (degrees)

mc

float64

Midheaven longitude (degrees)

armc

float64

ARMC (sidereal time angle)

vertex

float64

Vertex longitude (degrees)

High-Latitude Handling

Projection-based systems (Placidus, Koch) break down at extreme latitudes (roughly above 66° N or below 66° S) because the ecliptic can fail to intersect the prime vertical.

polar_fallback="raise" (default) — raises HighLatitudeError when the calculation is geometrically impossible.

Alternative fallback — pass the name of another system to use as a fallback:

from ketu.houses import calculate_houses, HighLatitudeError

# Attempt Placidus; fall back to Porphyry at high latitudes
try:
    h = calculate_houses(jd, 70.0, 25.0, system="placidus", polar_fallback="porphyry")
except HighLatitudeError:
    # polar_fallback="raise" and the location is beyond the polar circle
    pass

Whole Sign and Equal never raise HighLatitudeError — they work everywhere.

Registering Custom Systems

from ketu.houses import register

@register("my_system")
def my_system_calculator(jd, lat, lon):
    # Returns (cusps_array[12], asc, mc, armc, vertex)
    ...

After registration, "my_system" is available as a system= argument to calculate_houses.

Next Steps