Stellium Report Generation Guide¶
This guide covers everything you need to know about generating professional astrological reports with Stellium, from simple terminal output to beautiful PDF documents.
Table of Contents¶
Quick Start¶
from stellium import ChartBuilder, ReportBuilder
# Calculate a chart
chart = ChartBuilder.from_notable("Albert Einstein").with_aspects().calculate()
# Generate a report and display in terminal
ReportBuilder().from_chart(chart).preset_standard().render()
# Generate chart SVG, then create a PDF report with the chart embedded
chart.draw("einstein_chart.svg").save()
ReportBuilder().from_chart(chart).preset_detailed().with_chart_image("einstein_chart.svg").render(
format="pdf",
file="einstein_report.pdf",
)
The ReportBuilder Pattern¶
ReportBuilder uses a fluent interface (method chaining) to construct reports. The pattern is:
Create a ReportBuilder
Set the chart with
.from_chart()Add sections with
.with_*()methods (or use a preset)Render with
.render()
from stellium import ChartBuilder, ReportBuilder
chart = ChartBuilder.from_notable("Marie Curie").with_aspects().calculate()
# Build a custom report
report = (
ReportBuilder()
.from_chart(chart)
.with_chart_overview()
.with_planet_positions(include_speed=True)
.with_aspects(mode="major")
.with_house_cusps()
.render(format="rich_table")
)
Method Chaining¶
Every .with_*() method returns self, so you can chain them:
# These are equivalent:
builder = ReportBuilder()
builder.from_chart(chart)
builder.with_chart_overview()
builder.with_planet_positions()
builder.render()
# Chained (preferred style):
ReportBuilder().from_chart(chart).with_chart_overview().with_planet_positions().render()
Report Sections¶
Chart Overview¶
Basic information about the chart: name, date, time, location, house system, zodiac type.
ReportBuilder().from_chart(chart).with_chart_overview().render()
Output includes:
Name (if available)
Date and time
Timezone
Location and coordinates
House system(s)
Zodiac type (Tropical/Sidereal)
Ayanamsa (for sidereal charts)
Chart sect (day/night, if dignities calculated)
For comparison charts, shows information for both charts plus the comparison type.
Planet Positions¶
Table of planetary positions with sign, degree, and optional house placement.
# Basic: just positions
ReportBuilder().from_chart(chart).with_planet_positions().render()
# With speed (shows retrograde status)
ReportBuilder().from_chart(chart).with_planet_positions(include_speed=True).render()
# With house placements
ReportBuilder().from_chart(chart).with_planet_positions(include_house=True).render()
# Specific house systems only
ReportBuilder().from_chart(chart).with_planet_positions(
include_house=True,
house_systems=["Placidus", "Whole Sign"]
).render()
# All options
ReportBuilder().from_chart(chart).with_planet_positions(
include_speed=True,
include_house=True,
house_systems="all" # Show all calculated systems
).render()
Parameters:
Parameter |
Type |
Default |
Description |
|---|---|---|---|
|
|
|
Show speed in longitude and retrograde status |
|
|
|
Show house placement |
|
|
|
Which house systems: |
Output columns:
Planet (with glyph)
Position (sign glyph + degree°minute’)
House (one column per system, if enabled)
Speed (degrees/day, if enabled)
Motion (Direct/Retrograde, if enabled)
Aspects¶
Table of aspects between planets.
# All aspects, sorted by orb (tightest first)
ReportBuilder().from_chart(chart).with_aspects().render()
# Major aspects only (conjunction, sextile, square, trine, opposition)
ReportBuilder().from_chart(chart).with_aspects(mode="major").render()
# Minor aspects only
ReportBuilder().from_chart(chart).with_aspects(mode="minor").render()
# Harmonic aspects only
ReportBuilder().from_chart(chart).with_aspects(mode="harmonic").render()
# Sort by planet instead of orb
ReportBuilder().from_chart(chart).with_aspects(sort_by="planet").render()
# Sort by aspect type
ReportBuilder().from_chart(chart).with_aspects(sort_by="aspect_type").render()
# Hide orb column
ReportBuilder().from_chart(chart).with_aspects(orbs=False).render()
Parameters:
Parameter |
Type |
Default |
Description |
|---|---|---|---|
|
|
|
Filter: |
|
|
|
Show orb and applying/separating indicator |
|
|
|
Sort order: |
Output columns:
Planet 1 (with glyph)
Aspect (with glyph)
Planet 2 (with glyph)
Orb (if enabled)
Applying (A→ or ←S, if enabled)
Cross-Chart Aspects¶
For comparison charts (synastry, transits), shows aspects between the two charts.
from stellium import ChartBuilder, MultiChartBuilder, ReportBuilder
# Create a synastry comparison
chart1 = ChartBuilder.from_notable("Albert Einstein").with_aspects().calculate()
chart2 = ChartBuilder.from_notable("Marie Curie").with_aspects().calculate()
multichart = MultiChartBuilder.synastry(chart1, chart2).calculate()
# Show cross-chart aspects
ReportBuilder().from_chart(multichart).with_cross_aspects().render()
# Major aspects only
ReportBuilder().from_chart(multichart).with_cross_aspects(mode="major").render()
Parameters: Same as with_aspects()
Output columns:
Chart 1 Planet (uses chart1_label)
Aspect
Chart 2 Planet (uses chart2_label)
Orb
Applying
House Cusps¶
Table of house cusp positions for each house system.
# All calculated house systems
ReportBuilder().from_chart(chart).with_house_cusps().render()
# Specific systems only
ReportBuilder().from_chart(chart).with_house_cusps(systems=["Placidus"]).render()
# Multiple specific systems
ReportBuilder().from_chart(chart).with_house_cusps(
systems=["Placidus", "Whole Sign", "Koch"]
).render()
Parameters:
Parameter |
Type |
Default |
Description |
|---|---|---|---|
|
|
|
Which house systems to show |
Output: 12 rows (houses 1-12), one column per house system showing degree + sign.
Declinations¶
Table showing planetary declinations (distance from the celestial equator).
ReportBuilder().from_chart(chart).with_declinations().render()
Output columns:
Planet (with glyph)
Declination (degrees)
Direction (North/South)
Out of Bounds (Yes/No - planets beyond ~23°27’)
Out-of-bounds planets are considered to have intensified or unconventional expression.
Moon Phase¶
Information about the lunar phase at the chart time.
ReportBuilder().from_chart(chart).with_moon_phase().render()
Output:
Phase name (New Moon, Waxing Crescent, First Quarter, etc.)
Phase angle
Illumination percentage
Days since/until new moon
Essential Dignities¶
Table of planetary dignities (requires DignityComponent).
from stellium.components import DignityComponent
# Calculate chart with dignities
chart = (
ChartBuilder.from_notable("Albert Einstein")
.with_aspects()
.add_component(DignityComponent())
.calculate()
)
# Show dignities
ReportBuilder().from_chart(chart).with_dignities().render()
# Traditional dignities only
ReportBuilder().from_chart(chart).with_dignities(essential="traditional").render()
# Modern dignities only
ReportBuilder().from_chart(chart).with_dignities(essential="modern").render()
# Show dignity names instead of just scores
ReportBuilder().from_chart(chart).with_dignities(show_details=True).render()
Parameters:
Parameter |
Type |
Default |
Description |
|---|---|---|---|
|
|
|
Which system: |
|
|
|
Show dignity names (Domicile, Exaltation, etc.) |
Aspect Patterns¶
Table of detected aspect patterns (requires AspectPatternAnalyzer).
from stellium import ChartBuilder, ReportBuilder
from stellium.engines.patterns import AspectPatternAnalyzer
# Calculate chart with pattern analysis
chart = (
ChartBuilder.from_notable("Albert Einstein")
.with_aspects()
.add_analyzer(AspectPatternAnalyzer())
.calculate()
)
# Show all patterns
ReportBuilder().from_chart(chart).with_aspect_patterns().render()
# Specific pattern types
ReportBuilder().from_chart(chart).with_aspect_patterns(
pattern_types=["Grand Trine", "T-Square"]
).render()
# Sort by element
ReportBuilder().from_chart(chart).with_aspect_patterns(sort_by="element").render()
Parameters:
Parameter |
Type |
Default |
Description |
|---|---|---|---|
|
|
|
Which patterns to show |
|
|
|
Sort: |
Detected patterns: Grand Trine, Grand Cross, T-Square, Yod, Kite, Mystic Rectangle, Stellium
Midpoints¶
Table of planetary midpoints (requires MidpointCalculator).
from stellium.components import MidpointCalculator
# Calculate chart with midpoints
chart = (
ChartBuilder.from_notable("Albert Einstein")
.with_aspects()
.add_component(MidpointCalculator())
.calculate()
)
# All midpoints
ReportBuilder().from_chart(chart).with_midpoints().render()
# Core midpoints only (Sun/Moon/ASC/MC)
ReportBuilder().from_chart(chart).with_midpoints(mode="core").render()
# Limit to top N midpoints
ReportBuilder().from_chart(chart).with_midpoints(threshold=20).render()
Parameters:
Parameter |
Type |
Default |
Description |
|---|---|---|---|
|
|
|
Filter: |
|
|
|
Limit to top N midpoints |
Transit Timeline (Natal Transits)¶
Show when transiting planets form aspects to natal positions, with orb entry/exit dates and multi-pass handling for retrograde transits. Two output modes:
TransitListSection— plain-text rows, one per transit eventTransitGanttSection— SVG horizontal bar chart (Gantt style), grouped by planet
Both sections are used via .with_section() since they require an explicit date range.
Plain-Text List¶
import datetime as dt
from stellium import ChartBuilder, ReportBuilder
from stellium.presentation.sections import TransitListSection
natal_chart = ChartBuilder.from_notable("Albert Einstein").calculate()
section = TransitListSection(
start=dt.datetime(2025, 12, 1),
end=dt.datetime(2026, 6, 1),
)
ReportBuilder().from_chart(natal_chart).with_section(section).render()
Example output:
Dec 2 – Mar 2 '26 — Jupiter △ natal Chiron
Dec 4 — Mercury □ natal Jupiter
Jan 8 – Feb 6 '26 — Uranus △ natal Neptune (2x: Jan 15, Feb 1)
Feb 10 – May 18 '26 — Saturn ☌ natal Moon
Multi-pass transits (retrograde creating 2–3 exact crossings) show all exact dates in parentheses.
Parameters:
Parameter |
Type |
Default |
Description |
|---|---|---|---|
|
|
required |
Start of transit window (UTC) |
|
|
required |
End of transit window (UTC) |
|
|
All 12 |
Planets to use as transits |
|
|
5 major + orbs |
|
|
|
All planets |
Limit which natal points to check |
|
|
|
Skip Sun, Moon, Mercury, Venus, Mars |
Gantt Chart (SVG)¶
from stellium.presentation.sections import TransitGanttSection
section = TransitGanttSection(
start=dt.datetime(2025, 12, 1),
end=dt.datetime(2026, 6, 1),
# By default, excludes fast planets (Sun/Moon/Mercury/Venus/Mars)
# for a readable chart. Set exclude_fast_planets=False to include them.
)
ReportBuilder().from_chart(natal_chart).with_section(section).render(
format="pdf", file="transits.pdf"
)
The SVG Gantt chart shows:
Each row = one transit event (aspect glyph + natal planet name)
Colored bars = orb window (color varies by aspect type)
White tick marks = exact date(s) within the bar
Rows grouped by transiting planet
Month grid lines and a dashed “today” marker
Parameters:
Parameter |
Type |
Default |
Description |
|---|---|---|---|
|
|
required |
Start of transit window (UTC) |
|
|
required |
End of transit window (UTC) |
|
|
All 12 |
Planets to use as transits |
|
|
5 major + orbs |
|
|
|
All planets |
Limit which natal points to check |
|
|
|
SVG width in pixels |
|
|
|
Height of each row in pixels |
|
|
|
Skip fast planets (default |
Custom Aspects and Orbs¶
# Only outer planet transits, conjunctions and squares, tighter orbs
section = TransitListSection(
start=dt.datetime(2025, 12, 1),
end=dt.datetime(2026, 12, 31),
transit_planets=["Jupiter", "Saturn", "Uranus", "Neptune", "Pluto"],
aspects={"Conjunction": 1.0, "Square": 1.5, "Opposition": 1.5},
exclude_fast_planets=True,
)
Accessing Structured Data¶
generate_data() returns both a formatted text string and a "periods" list of dicts
for custom rendering:
data = section.generate_data(natal_chart)
print(data["text"]) # Plain-text output
print(data["total_transits"]) # Count of transit events found
for period in data["periods"]:
print(period["transit_planet"], period["aspect_name"], period["natal_planet"])
print(" Start:", period["start"])
print(" End:", period["end"])
print(" Exact:", period["exact_dates"])
print(" Multi-pass:", period["is_multi_pass"])
Using calculate_transit_periods() Directly¶
For full control, call the core function directly:
from stellium.presentation.sections import calculate_transit_periods, TransitPeriod
periods: list[TransitPeriod] = calculate_transit_periods(
natal_chart=chart,
start=dt.datetime(2025, 12, 1),
end=dt.datetime(2026, 6, 1),
transit_planets=["Jupiter", "Saturn"],
aspects={"Trine": 2.0, "Square": 2.0},
)
for p in periods:
print(f"{p.transit_planet} {p.aspect_name} natal {p.natal_planet}")
print(f" In orb: {p.start} → {p.end}")
print(f" Exact: {', '.join(str(d.date()) for d in p.exact_dates)}")
print(f" Multi-pass: {p.is_multi_pass}")
Presets¶
Presets bundle common section combinations for convenience.
preset_minimal()¶
Just the basics: overview and positions.
ReportBuilder().from_chart(chart).preset_minimal().render()
Includes: Chart Overview, Planet Positions
preset_standard()¶
Common sections for everyday use.
ReportBuilder().from_chart(chart).preset_standard().render()
Includes: Chart Overview, Planet Positions (with houses), Major Aspects, House Cusps
preset_detailed()¶
Comprehensive report with all major sections.
ReportBuilder().from_chart(chart).preset_detailed().render()
Includes: Chart Overview, Moon Phase, Planet Positions (with speed and houses), Declinations, All Aspects, House Cusps, Dignities
preset_full()¶
Everything available.
from stellium import ChartBuilder, ReportBuilder
from stellium.components import DignityComponent, MidpointCalculator
from stellium.engines.patterns import AspectPatternAnalyzer
# Calculate with all components
chart = (
ChartBuilder.from_notable("Albert Einstein")
.with_aspects()
.add_component(DignityComponent())
.add_analyzer(AspectPatternAnalyzer())
.add_component(MidpointCalculator())
.calculate()
)
ReportBuilder().from_chart(chart).preset_full().render()
Includes: Everything in preset_detailed() plus Aspect Patterns and Midpoints
preset_positions_only()¶
Focus on planetary placements, no aspects.
ReportBuilder().from_chart(chart).preset_positions_only().render()
Includes: Chart Overview, Planet Positions (with speed and houses), Declinations, House Cusps
preset_aspects_only()¶
Focus on planetary relationships.
ReportBuilder().from_chart(chart).preset_aspects_only().render()
Includes: Chart Overview, All Aspects, Aspect Patterns
preset_synastry()¶
Optimized for relationship comparison charts.
multichart = MultiChartBuilder.synastry(chart1, chart2).calculate()
ReportBuilder().from_chart(multichart).preset_synastry().render()
Includes: Chart Overview (both charts), Planet Positions (side-by-side), Cross-Chart Aspects (major), House Cusps (side-by-side)
preset_transit()¶
Optimized for transit charts.
transit = MultiChartBuilder.transit(natal_chart, transit_datetime).calculate()
ReportBuilder().from_chart(transit).preset_transit().render()
Includes: Chart Overview, Planet Positions (side-by-side), Cross-Chart Aspects (all), House Cusps (side-by-side)
Output Formats¶
Terminal Output (Rich)¶
Beautiful colored tables in your terminal using the Rich library.
# Display in terminal (default)
ReportBuilder().from_chart(chart).preset_standard().render()
# Same as:
ReportBuilder().from_chart(chart).preset_standard().render(format="rich_table")
# Save to file AND display in terminal
ReportBuilder().from_chart(chart).preset_standard().render(
format="rich_table",
file="report.txt"
)
# Save to file without terminal display
ReportBuilder().from_chart(chart).preset_standard().render(
format="rich_table",
file="report.txt",
show=False
)
Plain Text¶
ASCII tables suitable for logs, emails, or systems without Rich.
ReportBuilder().from_chart(chart).preset_standard().render(format="plain_table")
# Save to file
ReportBuilder().from_chart(chart).preset_standard().render(
format="plain_table",
file="report.txt"
)
PDF with Typst¶
This is the star feature! Generate beautiful, professional-quality PDF reports using Typst.
# Basic PDF
ReportBuilder().from_chart(chart).preset_detailed().render(
format="pdf",
file="report.pdf"
)
# PDF with embedded chart wheel
chart.draw("chart.svg").save() # First, save the chart as SVG
ReportBuilder().from_chart(chart).preset_detailed().with_chart_image("chart.svg").render(
format="pdf",
file="report.pdf",
)
# Custom title
ReportBuilder().from_chart(chart).preset_detailed().with_chart_image("chart.svg").with_title("Albert Einstein — Natal Chart Analysis").render(
format="pdf",
file="report.pdf",
)
Typst PDF Features¶
Professional typography: Proper kerning, ligatures, and hyphenation
Beautiful fonts: Cinzel Decorative for headings, Crimson Pro for body text
Warm color palette: Deep purple headers, cream backgrounds, gold accents
Elegant design: Star dividers, rounded table corners, alternating row colors
Chart embedding: SVG chart wheels displayed on the title page
Page headers/footers: Automatic page numbering
Installing Typst¶
pip install typst
PDF Examples¶
Full natal chart report with chart wheel:
from stellium import ChartBuilder, ReportBuilder
from stellium.components import DignityComponent
# Calculate chart
chart = (
ChartBuilder.from_notable("Albert Einstein")
.with_aspects()
.add_component(DignityComponent())
.calculate()
)
# Generate chart wheel
chart.draw("einstein_chart.svg").with_theme("celestial").save()
# Generate PDF report
ReportBuilder().from_chart(chart).preset_detailed().with_chart_image("einstein_chart.svg").with_title("Albert Einstein — Natal Chart").render(
format="pdf",
file="einstein_report.pdf",
)
Synastry report for two people:
from stellium import ChartBuilder, MultiChartBuilder, ReportBuilder
# Calculate individual charts
einstein = ChartBuilder.from_notable("Albert Einstein").with_aspects().calculate()
curie = ChartBuilder.from_notable("Marie Curie").with_aspects().calculate()
# Create synastry comparison
synastry = MultiChartBuilder.synastry(
einstein, curie, label1="Albert Einstein", label2="Marie Curie"
).calculate()
# Generate biwheel chart
synastry.draw("synastry_chart.svg").with_theme("midnight").save()
# Generate synastry report
ReportBuilder().from_chart(synastry).preset_synastry().with_chart_image("synastry_chart.svg").with_title("Einstein & Curie — Synastry Analysis").render(
format="pdf",
file="synastry_report.pdf",
)
HTML¶
Generate HTML reports (useful for web applications).
ReportBuilder().from_chart(chart).preset_standard().render(
format="html",
file="report.html"
)
# With embedded chart
ReportBuilder().from_chart(chart).preset_standard().with_chart_image("chart.svg").render(
format="html",
file="report.html",
)
Comparison Chart Reports¶
Stellium fully supports comparison charts (synastry, transits, composites) in reports.
Side-by-Side Tables¶
When you pass a MultiChart object to ReportBuilder, sections that show chart data automatically render as side-by-side tables:
Planet Positions: Two tables, one for each chart
House Cusps: Two tables, one for each chart
The tables are labeled with the chart labels you provide to MultiChartBuilder.
Example: Complete Synastry Report¶
from stellium import ChartBuilder, MultiChartBuilder, ReportBuilder
from stellium.components import DignityComponent
# Calculate charts with dignities
chart1 = (
ChartBuilder.from_notable("Albert Einstein")
.with_aspects()
.add_component(DignityComponent())
.calculate()
)
chart2 = (
ChartBuilder.from_notable("Marie Curie")
.with_aspects()
.add_component(DignityComponent())
.calculate()
)
# Create multichart with meaningful labels
multichart = MultiChartBuilder.synastry(
chart1, chart2, label1="Albert", label2="Marie"
).calculate()
# Build custom synastry report
ReportBuilder().from_chart(multichart) \
.with_chart_overview() \
.with_planet_positions(include_house=True) \
.with_cross_aspects(mode="major", sort_by="orb") \
.with_house_cusps() \
.render(format="pdf", file="synastry.pdf")
Example: Transit Report¶
from datetime import datetime
from stellium import ChartBuilder, MultiChartBuilder, ReportBuilder
# Natal chart
natal = ChartBuilder.from_notable("Albert Einstein").with_aspects().calculate()
# Create transit comparison (uses natal chart's location automatically)
transits = MultiChartBuilder.transit(natal, datetime.now()).calculate()
# Generate transit report
ReportBuilder().from_chart(transits).preset_transit().with_title("Current Transits for Albert Einstein").render(
format="pdf",
file="transits.pdf",
)
Custom Sections¶
You can create custom sections by implementing the ReportSection protocol.
The Protocol¶
from typing import Any
from stellium.core.models import CalculatedChart
class ReportSection:
@property
def section_name(self) -> str:
"""Return the section title."""
...
def generate_data(self, chart: CalculatedChart) -> dict[str, Any]:
"""Generate section data from the chart."""
...
Data Types¶
Your generate_data() method should return a dictionary with a type key:
Table:
{
"type": "table",
"headers": ["Column 1", "Column 2", "Column 3"],
"rows": [
["Row 1 Col 1", "Row 1 Col 2", "Row 1 Col 3"],
["Row 2 Col 1", "Row 2 Col 2", "Row 2 Col 3"],
]
}
Key-Value:
{
"type": "key_value",
"data": {
"Key 1": "Value 1",
"Key 2": "Value 2",
}
}
Text:
{
"type": "text",
"text": "Plain text content here."
}
Side-by-Side Tables (for comparisons):
{
"type": "side_by_side_tables",
"tables": [
{
"title": "Table 1 Title",
"headers": ["Col 1", "Col 2"],
"rows": [["A", "B"], ["C", "D"]]
},
{
"title": "Table 2 Title",
"headers": ["Col 1", "Col 2"],
"rows": [["E", "F"], ["G", "H"]]
}
]
}
Example: Custom Section¶
from stellium.core.models import CalculatedChart, ObjectType
class ElementBalanceSection:
"""Custom section showing element distribution."""
@property
def section_name(self) -> str:
return "Element Balance"
def generate_data(self, chart: CalculatedChart) -> dict:
# Count planets in each element
elements = {"Fire": 0, "Earth": 0, "Air": 0, "Water": 0}
element_signs = {
"Fire": ["Aries", "Leo", "Sagittarius"],
"Earth": ["Taurus", "Virgo", "Capricorn"],
"Air": ["Gemini", "Libra", "Aquarius"],
"Water": ["Cancer", "Scorpio", "Pisces"],
}
for pos in chart.positions:
if pos.object_type == ObjectType.PLANET:
for element, signs in element_signs.items():
if pos.sign in signs:
elements[element] += 1
break
return {
"type": "key_value",
"data": {
f"{element}": f"{count} planets"
for element, count in elements.items()
}
}
# Use it
ReportBuilder().from_chart(chart) \
.with_chart_overview() \
.with_section(ElementBalanceSection()) \
.render()
Complete Examples¶
Example 1: Quick Terminal Report¶
from stellium import ChartBuilder, ReportBuilder
chart = ChartBuilder.from_notable("Frida Kahlo").with_aspects().calculate()
ReportBuilder().from_chart(chart).preset_standard().render()
Example 2: Full PDF Report with Everything¶
from stellium import ChartBuilder, ReportBuilder
from stellium.components import DignityComponent, MidpointCalculator
from stellium.engines import PlacidusHouses, WholeSignHouses
from stellium.engines.patterns import AspectPatternAnalyzer
# Calculate chart with all components and multiple house systems
chart = (
ChartBuilder.from_notable("Carl Jung")
.with_house_systems([PlacidusHouses(), WholeSignHouses()])
.with_aspects()
.add_component(DignityComponent())
.add_analyzer(AspectPatternAnalyzer())
.add_component(MidpointCalculator())
.calculate()
)
# Generate chart wheel with styling
chart.draw("jung_chart.svg") \
.with_theme("midnight") \
.with_zodiac_palette("rainbow_midnight") \
.with_moon_phase(position="bottom-left") \
.with_chart_info(position="top-left") \
.save()
# Generate comprehensive PDF report
ReportBuilder().from_chart(chart).preset_full().with_chart_image("jung_chart.svg").with_title("Carl Jung — Complete Natal Analysis").render(
format="pdf",
file="jung_report.pdf",
)
Example 3: Comparison Report (Synastry)¶
from stellium import ChartBuilder, MultiChartBuilder, ReportBuilder
# Two charts
person1 = ChartBuilder.from_notable("John Lennon").with_aspects().calculate()
person2 = ChartBuilder.from_notable("Yoko Ono").with_aspects().calculate()
# Synastry comparison
synastry = MultiChartBuilder.synastry(
person1, person2, label1="John Lennon", label2="Yoko Ono"
).calculate()
# Generate biwheel
synastry.draw("lennon_ono_biwheel.svg").with_theme("celestial").save()
# Generate report
ReportBuilder().from_chart(synastry).preset_synastry().with_chart_image("lennon_ono_biwheel.svg").with_title("John Lennon & Yoko Ono — Synastry").render(
format="pdf",
file="lennon_ono_synastry.pdf",
)
Example 4: Custom Report with Selected Sections¶
from stellium import ChartBuilder, ReportBuilder
chart = ChartBuilder.from_notable("Nikola Tesla").with_aspects().calculate()
# Pick exactly what you want
ReportBuilder().from_chart(chart) \
.with_chart_overview() \
.with_planet_positions(include_speed=True, include_house=True) \
.with_declinations() \
.with_aspects(mode="major", sort_by="planet") \
.render(format="pdf", file="tesla_custom.pdf")
Example 5: Batch Report Generation¶
from stellium import ChartBuilder, ReportBuilder
notables = ["Albert Einstein", "Marie Curie", "Nikola Tesla", "Frida Kahlo"]
for name in notables:
chart = ChartBuilder.from_notable(name).with_aspects().calculate()
# Safe filename
filename = name.lower().replace(" ", "_")
# Generate chart
chart.draw(f"{filename}_chart.svg").with_theme("celestial").save()
# Generate report
ReportBuilder().from_chart(chart).preset_detailed().with_chart_image(f"{filename}_chart.svg").with_title(f"{name} — Natal Chart").render(
format="pdf",
file=f"{filename}_report.pdf",
)
print(f"Generated report for {name}")
API Reference¶
ReportBuilder Methods¶
Method |
Description |
|---|---|
|
Set the chart to report on |
|
Add chart info section |
|
Add planet positions table |
|
Add aspects table |
|
Add cross-chart aspects (comparisons) |
|
Add house cusps table |
|
Add declinations table |
|
Add moon phase info |
|
Add essential dignities |
|
Add aspect patterns |
|
Add midpoints table |
|
Add custom section |
|
Apply minimal preset |
|
Apply standard preset |
|
Apply detailed preset |
|
Apply full preset |
|
Apply positions-only preset |
|
Apply aspects-only preset |
|
Apply synastry preset |
|
Apply transit preset |
|
Generate output |
render() Parameters¶
Parameter |
Type |
Default |
Description |
|---|---|---|---|
|
|
|
Output format |
|
|
|
Save to file |
|
|
|
Display in terminal (defaults to |
Note: Chart images and titles are configured via builder methods (
.with_chart_image(path)and.with_title(title)), not asrender()parameters.
Output Formats¶
Format |
Description |
Terminal |
File |
|---|---|---|---|
|
Colored terminal tables |
Yes |
.txt |
|
ASCII tables |
Yes |
.txt |
|
Plain text |
Yes |
.txt |
|
Typst PDF |
No |
|
|
HTML document |
No |
.html |
Troubleshooting¶
“Typst library not available”¶
Install Typst:
pip install typst
“No chart set”¶
You must call .from_chart(chart) before .render():
# Wrong
ReportBuilder().preset_standard().render()
# Right
ReportBuilder().from_chart(chart).preset_standard().render()
Missing dignities/patterns/midpoints¶
These sections require components to be added during chart calculation:
from stellium.components import DignityComponent, MidpointCalculator
from stellium.engines.patterns import AspectPatternAnalyzer
chart = (
ChartBuilder.from_native(native)
.with_aspects()
.add_component(DignityComponent()) # For .with_dignities()
.add_analyzer(AspectPatternAnalyzer()) # For .with_aspect_patterns()
.add_component(MidpointCalculator()) # For .with_midpoints()
.calculate()
)
PDF fonts look wrong¶
The Typst renderer uses Cinzel Decorative and Crimson Pro fonts. These are included in assets/fonts/. If fonts don’t render correctly, ensure the font files are present.
Happy charting!