Charting entries
The charting methods of the Astro class, re-anchoring, and the semantic text projection.
Charting is where everything starts: give a birth date, hour and gender, get an Astrolabe.
from x_iztro import Astro
astro = Astro()Astro holds no internal state, so instantiate it once and use it everywhere — or construct one per
call.
Every entry point raises IztroError on invalid input (it subclasses ValueError, so
except ValueError catches it too). Date format and existence, the solar year range and the hour
index are validated up front in the core; string values such as gender, language and palace name are
validated in the binding layer.
The exception carries a machine-readable classification in .code — see
Error handling.
ChartConfig
The charting configuration: six switches plus two optional override tables. It is a frozen dataclass
in which every field has a default, and the defaults match JS iztro — ChartConfig() is equivalent to
passing no config at all.
| Field | Type | Default | Values (matching enum) |
|---|---|---|---|
year_divide | str | "normal" | normal lunar New Year's Day / exact Beginning of Spring (YearDivide) |
horoscope_divide | str | "normal" | normal first of the month / exact solar term (HoroscopeDivide) |
age_divide | str | "normal" | normal increments at the turn of the year / birthday increments on the birthday (AgeDivide) |
day_divide | str | "forward" | forward the late Zi hour belongs to the next day / current to the current day (DayDivide) |
algorithm | str | "default" | default / zhongzhou (Algorithm) |
astro_type | str | "heaven" | heaven heaven chart / earth earth chart / human human chart (AstroType) |
mutagens | dict[str, list[str]] | None | None | Stem key → four star keys (Lu, Quan, Ke, Ji) |
brightness | dict[str, list[str]] | None | None | Star key → twelve brightness keys; index 0 is the Yin palace, an empty string means no brightness in that palace |
For what the six switches mean and the schools behind them, see Config in depth.
Methods
| Method | Description |
|---|---|
to_dict() -> dict | Convert to the camelCase config object the binding layer accepts; either table is omitted from the result when it is None |
Example
from x_iztro import Astro, ChartConfig, AstroType, HeavenlyStem, MajorStar
cfg = ChartConfig(
astro_type="earth",
mutagens={HeavenlyStem.GENG: [MajorStar.TAIYANG, MajorStar.WUQU,
MajorStar.TIANFU, MajorStar.TIANTONG]},
)
print(cfg.to_dict())
chart = Astro().by_solar("2000-8-16", 2, "female", language="en-US", config=cfg)
print(chart.five_elements_class, chart.config.astro_type)
print(chart.palace("soulPalace").mutagen_star_keys)Output
{'yearDivide': 'normal', 'horoscopeDivide': 'normal', 'ageDivide': 'normal', 'dayDivide': 'forward', 'algorithm': 'default', 'astroType': 'earth', 'mutagens': {'gengHeavenly': ['taiyangMaj', 'wuquMaj', 'tianfuMaj', 'tiantongMaj']}}
earth 5th earth
['tiantongMaj', 'tianjiMaj', 'wenchangMin', 'lianzhenMaj']The earth chart's Soul palace lands on the original chart's body palace (Career, bing-xu), so the palace-stem mutagens are taken from the bing stem.
Edge cases and pitfalls
by_solar
Purpose Chart a natal chart from a solar date.
Zi Wei meaning Zi Wei Dou Shu computes on the lunar calendar, but most people only remember their
solar birthday. This method converts solar to lunar first (including the year, month, day and hour
pillars) and places the stars from there.
When the year turns over is governed by year_divide — for someone born between lunar New Year and
the Beginning of Spring, the two settings give different year pillars, which in turn affects the
mutagens, the soul and body stars, and every year-based star.
Signature
def by_solar(
self,
solar_date: str,
time_index: TimeIndexType,
gender: GenderType,
*,
fix_leap: bool = True,
language: LanguageType = "zh-CN",
config: ChartConfig | None = None,
) -> AstrolabeParameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
solar_date | str | Yes | — | Solar date in YYYY-M-D; month and day need no zero padding. Years 1583–9999 |
time_index | int | Yes | — | Hour index 0–12. 0 is the early Zi hour (00:00–01:00), 12 the late Zi hour (23:00–24:00) |
gender | str | Yes | — | "male" or "female". Sets the direction of the decadal scope and of the Changsheng and Boshi gods |
fix_leap | bool | No | True | Keyword-only. Whether to correct for lunar leap months. When true, days from the sixteenth of a leap month onward count as the next month (the late Zi hour excepted, see below) |
language | str | No | "zh-CN" | Output language; affects every translated field. The *_key fields are unaffected |
config | ChartConfig | None | No | None | Charting configuration; None takes the defaults |
Return value Astrolabe — a complete chart with the twelve palaces, the four pillars, the soul
and body stars and the five elements class.
Example
from x_iztro import Astro
chart = Astro().by_solar("2000-8-16", 2, "female", language="en-US")
print(chart.solar_date, "|", chart.lunar_date, "|", chart.chinese_date)
print(chart.sign, chart.zodiac, chart.five_elements_class)
print("soul", chart.soul, "body", chart.body)Output
2000-8-16 | 二〇〇〇年七月十七 | geng chen - jia shen - bing woo - geng yin
leo dragon wood 3rd
soul rebel body scholarEdge cases and pitfalls
by_lunar
Purpose Chart a natal chart from a lunar date.
Zi Wei meaning The lunar date is Zi Wei Dou Shu's native input, and this skips the solar
conversion. Anyone who knows their lunar birthday can use it directly; the result is identical to
calling by_solar with the corresponding solar date.
Signature
def by_lunar(
self,
lunar_date: str,
time_index: TimeIndexType,
gender: GenderType,
*,
is_leap_month: bool = False,
fix_leap: bool = True,
language: LanguageType = "zh-CN",
config: ChartConfig | None = None,
) -> AstrolabeParameters Identical to by_solar apart from the following. Everything after gender is
keyword-only — is_leap_month and fix_leap sit next to each other, and swapping them positionally
would raise no error while silently shifting the chart by a month.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
lunar_date | str | Yes | — | Lunar date in YYYY-M-D; write the month as a positive number (leap months are flagged by the next parameter) |
is_leap_month | bool | No | False | Keyword-only. Whether that lunar month is a leap month. Has no effect if that month in that year has no leap month to begin with |
Return value Same as by_solar.
Example
a = Astro().by_lunar("2000-7-17", 2, "female", language="en-US")
b = Astro().by_solar("2000-8-16", 2, "female", language="en-US")
print(a.solar_date, a.solar_date == b.solar_date)Output
2000-8-16 TrueEdge cases and pitfalls
The silent no-op of is_leap_month
Pass True when that month is not a leap month and the parameter is silently ignored rather than
raising an error. If you need strict validation, confirm the leap month exists for that year and month
before calling.
get_horoscope
Purpose Compute the horoscope for a target date, starting from a natal chart.
Signature
def get_horoscope(
self,
astrolabe: Astrolabe,
target_date: str | None = None,
target_time_index: TimeIndexType | None = None,
) -> HoroscopeParameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
astrolabe | Astrolabe | Yes | — | The natal chart |
target_date | str | None | No | None | Target solar date; today when omitted |
target_time_index | int | None | No | None | Target hour index; the current hour when omitted |
Return value Horoscope, holding the chart passed in. Details on
the horoscope object.
Example
chart = Astro().by_solar("2000-8-16", 2, "female", language="en-US")
h = Astro().get_horoscope(chart, "2025-6-1", 0)
print(h.decadal.heavenly_stem + h.decadal.earthly_branch)
print(h.yearly.heavenly_stem + h.yearly.earthly_branch)Output
gengchen
yisiEdge cases and pitfalls
There is an equivalent method on the chart
chart.horoscope("2025-6-1", 0) is exactly equivalent and needs no Astro instance in hand.
Astro.get_horoscope exists so that "every entry point on one class" also works as a usage style.
rearranged
Purpose Re-anchor the chart on a given stem and branch as the Soul palace and return a new chart; the original is untouched.
Zi Wei meaning The Zhongzhou school reads one set of birth data as three charts: the heaven chart anchors the five elements class on the Soul palace's pillar, the earth chart on the body palace's, the human chart on the Spirit palace's. Change the anchoring pillar and the class changes, and with it the placement of Ziwei and Tianfu, the twelve palace names, the Changsheng gods and the decadal and age scopes are all recomputed. This method opens that capability up to any stem and branch.
Signature
def rearranged(self, from_stem: str, from_branch: str) -> AstrolabeThis is a method on Astrolabe, not on the Astro class.
Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
from_stem | str | Yes | — | Stem key of the new Soul palace, from the HeavenlyStem enum's value set |
from_branch | str | Yes | — | Branch key of the new Soul palace, from the EarthlyBranch enum's value set |
Return value A new Astrolabe. Recomputed: the Soul and body palaces, the five elements class,
the fourteen major stars, the twelve palace names, the Changsheng gods, the decadal and age scopes,
the soul star, plus Tianshang, Tianshi and Tiancai, which follow the Soul palace.
Carried over from the original chart: minor stars, the remaining adjective stars, the Boshi gods, the
Sui-qian and Jiang-qian gods, and the body star.
On the rearranged chart, patterns(), horoscope queries and the to_text projection all compute from
the rearranged layout — the five elements class, soul palace and decadal ranges follow the
new starting stem-branch; the birth data (dates and four pillars) stays unchanged.
Example
chart = Astro().by_solar("2000-8-16", 2, "female", language="en-US")
# anchor on the original chart's body palace pillar — equivalent to the earth chart
body = next(p for p in chart.palaces if p.is_body_palace)
earth = chart.rearranged(body.heavenly_stem_key, body.earthly_branch_key)
print("heaven", chart.five_elements_class, "→ earth", earth.five_elements_class)Output
heaven wood 3rd → earth earth 5thEdge cases and pitfalls
The three standard charts do not need this method
For the heaven, earth and human charts just chart with ChartConfig(astro_type="earth"); both
charting entry points support it. rearranged exists for anchoring on an arbitrary stem and branch.
Semantic text (to_text)
Purpose Project a chart or a horoscope into semantic text — the chart's facts in
natural-language form, for a language model or a person. Alongside to_dict/to_json (machine
structure) and the translated fields (display), it is the third projection of the same object.
Signature The text projection lives on the objects themselves, not on Astro:
chart.to_text() # natal chart; str(chart) is equivalent
chart.horoscope("2025-1-1", 0).to_text() # horoscope; str(h) is equivalent
chart.palace("soul").to_text() # one palace
chart.surrounded_palaces("soul").to_text() # surrounded palaces
chart.patterns_to_text() # natal patternsReturn value str — sectioned plain text in the chart's own charting language; the natal text
closes with a patterns section, and each horoscope scope carries a patterns line and flowing-star
lines from its own perspective.
Example
astro = Astro()
chart = astro.by_solar("2000-8-16", 2, "female", language="en-US")
print(chart.to_text()[:77])Output
=== Basic Info ===
Gender: female
Solar Date: 2000-8-16
Lunar Date: 二〇〇〇年七月十七Edge cases and pitfalls
The output language follows the chart's language and is not set separately. For English text,
chart in English.