Astrolabe object

The fields of Astrolabe, its lookup methods, and the surrounded-palace predicates.

Astrolabe is what charting produces and the entry point for every query. It is a frozen=True dataclass holding all the data of the twelve palaces along with chart-level information such as the four pillars, the soul and body stars and the five elements class.

chart = Astro().by_solar("2000-8-16", 2, "female", language="en-US")

The examples on this page all chart in en-US, so the display values in the output are the English translations. Charting in another language changes those strings and nothing else — the *_key identifiers and the results of every predicate method stay the same.

Fields


palace

Purpose Fetch a palace by index, by name, or as the body or original palace.

Zi Wei meaning The twelve palaces are the skeleton of a chart. Once the Soul palace is fixed the other eleven follow counterclockwise in a fixed order. The "body palace" is whichever of the twelve also carries that flag, marking where acquired effort concentrates; the "palace of origin" is the one whose stem matches the birth-year stem, marking where matters originate.

Signature

def palace(self, index_or_name: int | PalaceName | str) -> Palace | None

Parameters

ParameterTypeRequiredDefaultDescription
index_or_nameint | strYesFour spellings, see the table below
SpellingExampleMeaning
Indexchart.palace(0)Palace index 0–11, where 0 is the Yin palace
Name keychart.palace("soulPalace")One of the twelve palace-name keys, i.e. the value set of PalaceName
Palace name in the charting languagechart.palace("soul")The palace-name text as translated for the chart's language
Body palacechart.palace("bodyPalace")Whichever palace carries the body-palace flag
Palace of originchart.palace("originalPalace")The palace whose stem matches the birth-year stem

Return value Palace | None. An out-of-range index or a misspelled name returns None; the name, body-palace and origin-palace spellings all resolve on any chart as long as they are spelled correctly.

Example

soul = chart.palace("soulPalace")
print(soul.name, soul.heavenly_stem + soul.earthly_branch)

print("body palace falls in", chart.palace("bodyPalace").name)
print("palace of origin is", chart.palace("originalPalace").name)
print("the Yin palace is", chart.palace(0).name)

Output

soul renwoo
body palace falls in career
palace of origin is spouse
the Yin palace is wealth

Edge cases and pitfalls


star / star_in_palace

Purpose Find a star by key, or get it together with the palace it sits in.

Signature

def star(self, star: str) -> Star | None
def star_in_palace(self, star: str) -> tuple[Star, Palace] | None

Parameters

ParameterTypeRequiredDefaultDescription
starstrYesA star key (such as "ziweiMaj"), or the star name in the chart's charting language (such as "emperor")

Return value None when the star is not on this chart. star_in_palace returns a (star, palace) tuple, sparing a further call to star.palace().

Example

ziwei = chart.star("ziweiMaj")

print(ziwei.name, "sits in", ziwei.palace().name)
print("its opposite palace is", ziwei.opposite_palace().name)
print("brightness", ziwei.brightness, "mutagen", ziwei.mutagen)

star, palace = chart.star_in_palace("ziweiMaj")
print(star.key, palace.name_key)

Output

emperor sits in soul
its opposite palace is surface
brightness [+3] mutagen None
ziweiMaj soulPalace

Edge cases and pitfalls

The search covers only the three groups of major, minor and adjective stars. The Changsheng, Boshi, Sui-qian and Jiang-qian gods are one-per-palace marks rather than star lists — read them from fields like palace.changsheng12_key.


surrounded_palaces

Purpose Fetch the surrounded palaces of a target palace.

Zi Wei meaning The surrounded set is the most commonly used reading scope in Zi Wei Dou Shu: the palace itself, its opposite (index +6), the career position (+4) and the wealth position (+8). The four are read together rather than the palace alone, because the stars of the opposite and trine palaces bear on the palace's affairs just as much.

Signature

def surrounded_palaces(self, index_or_name: int | PalaceName | str) -> SurroundedPalaces | None

Parameters Same as palace; all four spellings are supported.

Return value SurroundedPalaces | None, holding the four Palaces target / opposite / wealth / career. Returns None when the palace cannot be located (out-of-range index or misspelled name). Its predicates are on Surrounded palaces.

Example

sp = chart.surrounded_palaces("soulPalace")

print(sp.target.name, sp.opposite.name, sp.wealth.name, sp.career.name)
print("Ziwei in the surrounded set:", sp.have(["ziweiMaj"]))

Output

soul surface wealth career
Ziwei in the surrounded set: True

is_surrounded / is_surrounded_one_of / not_surrounded

Purpose Test the surrounded palaces of a palace straight from the chart, skipping the step of fetching the set first.

Signature

def is_surrounded(self, index_or_name: int | PalaceName | str, stars: list[str]) -> bool
def is_surrounded_one_of(self, index_or_name: int | PalaceName | str, stars: list[str]) -> bool
def not_surrounded(self, index_or_name: int | PalaceName | str, stars: list[str]) -> bool

Parameters

ParameterTypeRequiredDefaultDescription
index_or_nameint | strYesLocated the same way as in palace
starslist[str]YesA list of star keys

Return value

MethodMeaning
is_surroundedEvery star in the list is in the surrounded set
is_surrounded_one_ofAt least one star in the list is in the surrounded set
not_surroundedNone of the stars in the list is in the surrounded set

Example

print(chart.is_surrounded("soulPalace", ["ziweiMaj", "tianxiangMaj"]))
print(chart.is_surrounded_one_of("soulPalace", ["qishaMaj", "pojunMaj"]))
print(chart.not_surrounded("soulPalace", ["huoxingMin"]))

Output

True
False
True

The Soul palace holds only Ziwei, while Tianxiang sits in the Wealth palace, one of the trine — hence the first line is true. Neither Qisha nor Pojun is in any of the four, hence the second is false.

Edge cases and pitfalls

What an empty list returns

With an empty stars list, is_surrounded and not_surrounded return True ("all elements satisfy" and "no element fails" both hold vacuously) while is_surrounded_one_of returns False. Make sure the list is non-empty before calling.


horoscope

Purpose Compute the horoscope for a target date, starting from this chart.

Signature

def horoscope(
    self,
    target_date: str | None = None,
    target_time_index: int | None = None,
) -> Horoscope

Parameters

ParameterTypeRequiredDefaultDescription
target_datestr | NoneNoNoneTarget solar date; today when omitted
target_time_indexint | NoneNoNoneTarget hour index; the current hour when omitted

Return value Horoscope — a horoscope object holding this chart, so palace lookups across the six scopes need not be passed the astrolabe again. Details on the horoscope object.

Example

h = chart.horoscope("2025-6-1", 0)

print("decadal", h.decadal.heavenly_stem + h.decadal.earthly_branch)
print("yearly ", h.yearly.heavenly_stem + h.yearly.earthly_branch)

# both parameters can be omitted for right now
now = chart.horoscope()

Output

decadal gengchen
yearly  yisi

to_text

Purpose The chart's semantic text: a complete description for language models and people; str(chart) is equivalent.

Signature

def to_text(self) -> str

Return value str — sectioned plain text in the charting language: basic info, the twelve palaces, and the pattern hits. The full format is on Semantic text.

Example

print(chart.to_text()[:77])

Output

=== Basic Info ===
Gender: female
Solar Date: 2000-8-16
Lunar Date: 二〇〇〇年七月十七

For single-palace and surrounded-palace text see palace(...).to_text() and surrounded_palaces(...).to_text(); for pattern text see patterns_to_text on Patterns.


to_dict / to_json

Purpose Export the chart as JSON matching the field contract of JS iztro.

Signature

def to_dict(self) -> dict[str, Any]
def to_json(self, **kwargs: Any) -> str

Parameters

ParameterTypeRequiredDefaultDescription
kwargsNoto_json only: forwarded to json.dumps, e.g. indent=2, sort_keys=True

to_json defaults to ensure_ascii=False, so non-ASCII characters land in the output directly rather than as \uXXXX.

Return value to_dict returns a deep copy of the underlying DTO — camelCase keys, values translated for the charting language, plus the *Key language-independent identifiers and the charting context. Mutating it does not affect the chart. to_json returns the same data as a JSON string, matching iztro's JSON.stringify(astrolabe) key for key and value for value.

Example

d = chart.to_dict()
print(d["solarDate"], d["palaces"][4]["nameKey"])
print(d["config"]["yearDivide"], d["genderKey"], d["timeIndex"])

import json
print(json.dumps({k: d[k] for k in ("gender", "solarDate", "lunarDate")},
                 ensure_ascii=False))
print(len(chart.to_json()) > 10000, chart.to_json()[:1])

Output

2000-8-16 soulPalace
normal female 2
{"gender": "female", "solarDate": "2000-8-16", "lunarDate": "二〇〇〇年七月十七"}
True {

The key order is lexicographic

When the native extension converts the underlying DTO into a Python dict the keys come out sorted by name, so the top-level keys of to_dict() / to_json() run body, bodyKey, chineseDate, … rather than in iztro's declaration order. The names and values correspond one for one; only the arrangement differs. For a fixed order, pick out the keys you need yourself.

Edge cases and pitfalls

Do not export with dataclasses.asdict

Astrolabe, Palace and Star are all dataclasses, but palaces and stars each hold a reference back to the chart (_astrolabe / _palace). dataclasses.asdict(chart) follows that back-reference into infinite recursion and ends in RecursionError.

Always export through to_dict() / to_json() — they take the underlying DTO directly, so they neither recurse nor lose fields.

The override tables are not in the export

config echoes only the six switches. The custom mutagen and brightness tables passed in at charting time are input rather than result and do not enter the DTO — matching the field contract of JS iztro. To record which tables were used, keep your ChartConfig on your own call site.

Horoscope carries a pair of methods by the same names and the same shape; see the horoscope object.

On this page