| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836 |
- """
- Chart rendering tools for astro-mcp.
- Render visual chart wheels (SVG/PNG/JPG) from calculated chart data.
- Combines calculation + rendering in one step.
- """
- from __future__ import annotations
- from typing import Any
- from .server import mcp
- from .chart_renderer import (
- render_natal_wheel,
- render_transit_wheel,
- render_synastry_wheel,
- )
- from .chart_tools import (
- calculate_natal_chart,
- calculate_transit_chart,
- calculate_synastry_chart,
- calculate_composite_chart,
- calculate_davison_chart,
- )
- from .by_id_tools import (
- calculate_natal_chart_by_id,
- calculate_transit_chart_by_id,
- calculate_synastry_chart_by_id,
- calculate_composite_chart_by_id,
- calculate_davison_chart_by_id,
- )
- # ═══════════════════════════════════════════════════════════════════════
- # CHART RENDERING TOOLS
- # ═══════════════════════════════════════════════════════════════════════
- # These tools render visual chart wheels from birth data.
- # They combine calculation + rendering in one step.
- # For data-only output, use the calculate_* tools instead.
- # ═══════════════════════════════════════════════════════════════════════
- # ── Shared render options (used by all render_* tools) ────────────────
- _RENDER_STYLE_HELP = (
- "Chart visual style: 'modern' (clean, minimal), 'traditional' "
- "(ornate, classical), or 'minimal' (bare bones)."
- )
- _RENDER_COLOR_HELP = (
- "Color mode: 'color' (full color with element-themed zodiac ring), "
- "'bw' (black/white, aspect lines distinguished by style), or "
- "'dark' (dark background for web display)."
- )
- _RENDER_SIZE_HELP = "SVG width/height in pixels (default: 600)."
- _RENDER_TABLE_HELP = "Include an aspect table below the wheel."
- _RENDER_PLANETS_HELP = "Include a planet data table below the wheel."
- _RENDER_HOUSES_HELP = "Include a house cusp table below the wheel."
- _RENDER_TITLE_HELP = "Custom chart title. Auto-generated if not provided."
- # ── render_natal_chart ────────────────────────────────────────────────
- @mcp.tool()
- async def render_natal_chart(
- # ── Birth data (same as calculate_natal_chart) ──────────────────
- birth_datetime: str,
- latitude: float,
- longitude: float,
- elevation: float = 0.0,
- house_system: str = "placidus",
- orb_limits: dict[str, float] | None = None,
- top_n_aspects: int | None = None,
- # ── Rendering options ───────────────────────────────────────────
- style: str = "modern",
- color_mode: str = "color",
- size: int = 600,
- table_position: str = "none",
- include_planets: bool = False,
- include_houses: bool = False,
- title: str | None = None,
- subtitle: str | None = None,
- format: str = "svg",
- ) -> dict[str, Any]:
- """Render a natal chart wheel.
- Calculates planetary positions and renders a visual zodiac wheel with
- planets, houses, and aspect lines. Output as SVG or raster image (PNG/JPG).
- BIRTH DATA (required):
- birth_datetime: ISO 8601 datetime with timezone (e.g. "1990-05-15T10:30:00+01:00").
- latitude: Birth latitude in decimal degrees (-90 to 90).
- longitude: Birth longitude in decimal degrees (-180 to 180).
- BIRTH DATA (optional):
- elevation: Birth elevation in meters (default: 0).
- house_system: "placidus" (default), "equal", or "whole_sign".
- orb_limits: Per-aspect orb overrides, e.g. {"conjunction": 10}.
- top_n_aspects: Limit aspects to the N tightest by orb.
- RENDERING OPTIONS:
- style: {_RENDER_STYLE_HELP}
- color_mode: {_RENDER_COLOR_HELP}
- size: {_RENDER_SIZE_HELP}
- table_position: "none" (wheel only), "below" (portrait layout with tables
- under the wheel), or "right" (landscape layout with tables to the right).
- include_planets: Include a planet data table (requires table_position != "none").
- include_houses: Include a house cusp table (requires table_position != "none").
- title: Custom chart title. Auto-generated if not provided.
- subtitle: Custom subtitle. Auto-generated from birth data if not provided.
- format: Output format — "svg" (default), "png", or "jpg".
- Returns:
- Dict with "content", "format", "content_type", "width", "height",
- and "included" (list of what's in the chart).
- """
- from .chart_renderer import render_natal_wheel
- chart_data = await calculate_natal_chart(
- birth_datetime=birth_datetime,
- latitude=latitude,
- longitude=longitude,
- elevation=elevation,
- house_system=house_system,
- orb_limits=orb_limits,
- top_n_aspects=top_n_aspects,
- )
- if "error" in chart_data:
- return chart_data
- result = render_natal_wheel(
- chart_data,
- style=style,
- color_mode=color_mode,
- size=size,
- table_position=table_position,
- include_planets=include_planets,
- include_houses=include_houses,
- title=title,
- subtitle=subtitle,
- format=format,
- )
- result["included"] = _included_list(table_position, include_planets, include_houses)
- return result
- # ── render_natal_chart_by_id ──────────────────────────────────────────
- @mcp.tool()
- async def render_natal_chart_by_id(
- # ── Person lookup (same as calculate_natal_chart_by_id) ─────────
- person_id: str,
- house_system: str = "placidus",
- orb_limits: dict[str, float] | None = None,
- top_n_aspects: int | None = None,
- # ── Rendering options ───────────────────────────────────────────
- style: str = "modern",
- color_mode: str = "color",
- size: int = 600,
- table_position: str = "none",
- include_planets: bool = False,
- include_houses: bool = False,
- title: str | None = None,
- format: str = "svg",
- ) -> dict[str, Any]:
- """Render a natal chart wheel for a person from the database.
- Looks up birth data by person_id or nickname, calculates the chart,
- and renders it as a wheel. Output as SVG or raster image (PNG/JPG).
- PERSON LOOKUP (required):
- person_id: ID or nickname of a person in the persons database.
- PERSON LOOKUP (optional):
- house_system: "placidus" (default), "equal", or "whole_sign".
- orb_limits: Per-aspect orb overrides.
- top_n_aspects: Limit aspects to the N tightest by orb.
- RENDERING OPTIONS:
- style: {_RENDER_STYLE_HELP}
- color_mode: {_RENDER_COLOR_HELP}
- size: {_RENDER_SIZE_HELP}
- table_position: "none" (wheel only), "below" (portrait), or "right" (landscape).
- include_planets: {_RENDER_PLANETS_HELP}
- include_houses: {_RENDER_HOUSES_HELP}
- title: {_RENDER_TITLE_HELP}
- Returns:
- Dict with "svg" (SVG string), "format", "width", "height", "included".
- """
- from .chart_renderer import render_natal_wheel
- chart_data = await calculate_natal_chart_by_id(
- person_id=person_id,
- house_system=house_system,
- orb_limits=orb_limits,
- top_n_aspects=top_n_aspects,
- )
- if "error" in chart_data:
- return chart_data
- result = render_natal_wheel(
- chart_data,
- style=style,
- color_mode=color_mode,
- size=size,
- table_position=table_position,
- include_planets=include_planets,
- include_houses=include_houses,
- title=title,
- format=format,
- )
- result["included"] = _included_list(table_position, include_planets, include_houses)
- return result
- # ── render_transit_chart ──────────────────────────────────────────────
- @mcp.tool()
- async def render_transit_chart(
- # ── Birth data + transit date (same as calculate_transit_chart) ─
- birth_datetime: str,
- transit_datetime: str,
- latitude: float,
- longitude: float,
- transit_latitude: float | None = None,
- transit_longitude: float | None = None,
- elevation: float = 0.0,
- house_system: str = "placidus",
- orb_limits: dict[str, float] | None = None,
- # ── Rendering options ───────────────────────────────────────────
- style: str = "modern",
- color_mode: str = "color",
- size: int = 600,
- title: str | None = None,
- format: str = "svg",
- ) -> dict[str, Any]:
- """Render a transit chart as a bi-wheel (natal inner, transit outer).
- Calculates natal and transiting planet positions, then renders a bi-wheel
- showing natal planets inside and transiting planets outside, with
- transit-to-natal aspect lines. Output as SVG or raster image (PNG/JPG).
- BIRTH DATA (required):
- birth_datetime: ISO 8601 birth datetime with timezone.
- transit_datetime: ISO 8601 transit datetime (the "now" or future date).
- latitude: Birth latitude in decimal degrees.
- longitude: Birth longitude in decimal degrees.
- TRANSIT LOCATION (optional):
- transit_latitude: Location latitude for transit calculation. Defaults to birth latitude.
- transit_longitude: Location longitude for transit calculation. Defaults to birth longitude.
- CHART OPTIONS:
- elevation: Birth elevation in meters (default: 0).
- house_system: "placidus" (default), "equal", or "whole_sign".
- orb_limits: Per-aspect orb overrides.
- RENDERING OPTIONS:
- style: {_RENDER_STYLE_HELP}
- color_mode: {_RENDER_COLOR_HELP}
- size: {_RENDER_SIZE_HELP}
- title: {_RENDER_TITLE_HELP}
- format: Output format — "svg" (default), "png", or "jpg".
- Returns:
- Dict with "content", "format", "content_type", "width", "height", "included".
- """
- from .chart_renderer import render_transit_wheel
- chart_data = await calculate_transit_chart(
- birth_datetime=birth_datetime,
- transit_datetime=transit_datetime,
- latitude=latitude,
- longitude=longitude,
- transit_latitude=transit_latitude,
- transit_longitude=transit_longitude,
- elevation=elevation,
- house_system=house_system,
- orb_limits=orb_limits,
- )
- if "error" in chart_data:
- return chart_data
- result = render_transit_wheel(
- chart_data,
- style=style,
- color_mode=color_mode,
- size=size,
- title=title,
- format=format,
- )
- result["included"] = ["wheel"]
- return result
- # ── render_transit_chart_by_id ────────────────────────────────────────
- @mcp.tool()
- async def render_transit_chart_by_id(
- # ── Person lookup + transit date ────────────────────────────────
- person_id: str,
- transit_datetime: str,
- transit_latitude: float | None = None,
- transit_longitude: float | None = None,
- house_system: str = "placidus",
- orb_limits: dict[str, float] | None = None,
- # ── Rendering options ───────────────────────────────────────────
- style: str = "modern",
- color_mode: str = "color",
- size: int = 600,
- title: str | None = None,
- format: str = "svg",
- ) -> dict[str, Any]:
- """Render a transit bi-wheel for a person from the database.
- Looks up birth data by person_id, calculates transits for the given
- date, and renders a bi-wheel chart. Output as SVG or raster image (PNG/JPG).
- PERSON LOOKUP (required):
- person_id: ID or nickname of a person in the persons database.
- transit_datetime: ISO 8601 transit datetime.
- TRANSIT LOCATION (optional):
- transit_latitude: Location latitude. Defaults to birth latitude.
- transit_longitude: Location longitude. Defaults to birth longitude.
- CHART OPTIONS:
- house_system: "placidus" (default), "equal", or "whole_sign".
- orb_limits: Per-aspect orb overrides.
- RENDERING OPTIONS:
- style: {_RENDER_STYLE_HELP}
- color_mode: {_RENDER_COLOR_HELP}
- size: {_RENDER_SIZE_HELP}
- title: {_RENDER_TITLE_HELP}
- Returns:
- Dict with "svg", "format", "width", "height", "included".
- """
- from .chart_renderer import render_transit_wheel
- chart_data = await calculate_transit_chart_by_id(
- person_id=person_id,
- transit_datetime=transit_datetime,
- transit_latitude=transit_latitude,
- transit_longitude=transit_longitude,
- house_system=house_system,
- orb_limits=orb_limits,
- )
- if "error" in chart_data:
- return chart_data
- result = render_transit_wheel(
- chart_data,
- style=style,
- color_mode=color_mode,
- size=size,
- title=title,
- format=format,
- )
- result["included"] = ["wheel"]
- return result
- # ── render_synastry_chart ─────────────────────────────────────────────
- @mcp.tool()
- async def render_synastry_chart(
- # ── Two people's birth data (same as calculate_synastry_chart) ──
- person1_datetime: str,
- person1_latitude: float,
- person1_longitude: float,
- person2_datetime: str,
- person2_latitude: float,
- person2_longitude: float,
- elevation: float = 0.0,
- house_system: str = "placidus",
- orb_limits: dict[str, float] | None = None,
- top_n_aspects: int | None = None,
- # ── Rendering options ───────────────────────────────────────────
- style: str = "modern",
- color_mode: str = "color",
- size: int = 800,
- title: str | None = None,
- format: str = "svg",
- ) -> dict[str, Any]:
- """Render a synastry (relationship) chart with two side-by-side wheels.
- Calculates both natal charts and renders them side by side with
- interaspect lines between the two charts. Output as SVG or raster image (PNG/JPG).
- PERSON 1 (required):
- person1_datetime: ISO 8601 birth datetime with timezone.
- person1_latitude: Birth latitude in decimal degrees.
- person1_longitude: Birth longitude in decimal degrees.
- PERSON 2 (required):
- person2_datetime: ISO 8601 birth datetime with timezone.
- person2_latitude: Birth latitude in decimal degrees.
- person2_longitude: Birth longitude in decimal degrees.
- CHART OPTIONS:
- elevation: Birth elevation in meters (default: 0).
- house_system: "placidus" (default), "equal", or "whole_sign".
- orb_limits: Per-aspect orb overrides.
- top_n_aspects: Limit interaspects to the N tightest by orb.
- RENDERING OPTIONS:
- style: {_RENDER_STYLE_HELP}
- color_mode: {_RENDER_COLOR_HELP}
- size: {_RENDER_SIZE_HELP}
- title: {_RENDER_TITLE_HELP}
- Returns:
- Dict with "svg", "format", "width", "height", "included".
- """
- from .chart_renderer import render_synastry_wheel
- chart_data = await calculate_synastry_chart(
- person1_datetime=person1_datetime,
- person1_latitude=person1_latitude,
- person1_longitude=person1_longitude,
- person2_datetime=person2_datetime,
- person2_latitude=person2_latitude,
- person2_longitude=person2_longitude,
- elevation=elevation,
- house_system=house_system,
- orb_limits=orb_limits,
- top_n_aspects=top_n_aspects,
- )
- if "error" in chart_data:
- return chart_data
- result = render_synastry_wheel(
- chart_data,
- style=style,
- color_mode=color_mode,
- size=size,
- title=title,
- format=format,
- )
- result["included"] = ["wheel"]
- return result
- # ── render_synastry_chart_by_id ───────────────────────────────────────
- @mcp.tool()
- async def render_synastry_chart_by_id(
- # ── Two person IDs ──────────────────────────────────────────────
- person1_id: str,
- person2_id: str,
- house_system: str = "placidus",
- orb_limits: dict[str, float] | None = None,
- top_n_aspects: int | None = None,
- # ── Rendering options ───────────────────────────────────────────
- style: str = "modern",
- color_mode: str = "color",
- size: int = 800,
- title: str | None = None,
- format: str = "svg",
- ) -> dict[str, Any]:
- """Render a synastry chart for two people from the database.
- Looks up both persons by ID or nickname, calculates their synastry,
- and renders side-by-side natal wheels with interaspect lines.
- Output as SVG or raster image (PNG/JPG).
- PERSON LOOKUP (required):
- person1_id: ID or nickname of person 1 in the persons database.
- person2_id: ID or nickname of person 2 in the persons database.
- CHART OPTIONS:
- house_system: "placidus" (default), "equal", or "whole_sign".
- orb_limits: Per-aspect orb overrides.
- top_n_aspects: Limit interaspects to the N tightest by orb.
- RENDERING OPTIONS:
- style: {_RENDER_STYLE_HELP}
- color_mode: {_RENDER_COLOR_HELP}
- size: {_RENDER_SIZE_HELP}
- title: {_RENDER_TITLE_HELP}
- Returns:
- Dict with "svg", "format", "width", "height", "included".
- """
- from .chart_renderer import render_synastry_wheel
- chart_data = await calculate_synastry_chart_by_id(
- person1_id=person1_id,
- person2_id=person2_id,
- house_system=house_system,
- orb_limits=orb_limits,
- top_n_aspects=top_n_aspects,
- )
- if "error" in chart_data:
- return chart_data
- result = render_synastry_wheel(
- chart_data,
- style=style,
- color_mode=color_mode,
- size=size,
- title=title,
- format=format,
- )
- result["included"] = ["wheel"]
- return result
- # ── render_composite_chart ────────────────────────────────────────────
- @mcp.tool()
- async def render_composite_chart(
- # ── Two people's birth data (same as calculate_composite_chart) ─
- person1_datetime: str,
- person1_latitude: float,
- person1_longitude: float,
- person2_datetime: str,
- person2_latitude: float,
- person2_longitude: float,
- elevation: float = 0.0,
- house_system: str = "placidus",
- orb_limits: dict[str, float] | None = None,
- # ── Rendering options ───────────────────────────────────────────
- style: str = "modern",
- color_mode: str = "color",
- size: int = 600,
- table_position: str = "none",
- include_planets: bool = False,
- include_houses: bool = False,
- title: str | None = None,
- format: str = "svg",
- ) -> dict[str, Any]:
- """Render a composite chart (midpoint method) as a single wheel.
- Calculates the composite chart from two people's birth data and renders
- it as a standard natal-style wheel representing the relationship.
- Output as SVG or raster image (PNG/JPG).
- PERSON 1 (required):
- person1_datetime: ISO 8601 birth datetime with timezone.
- person1_latitude: Birth latitude in decimal degrees.
- person1_longitude: Birth longitude in decimal degrees.
- PERSON 2 (required):
- person2_datetime: ISO 8601 birth datetime with timezone.
- person2_latitude: Birth latitude in decimal degrees.
- person2_longitude: Birth longitude in decimal degrees.
- CHART OPTIONS:
- elevation: Birth elevation in meters (default: 0).
- house_system: "placidus" (default), "equal", or "whole_sign".
- orb_limits: Per-aspect orb overrides.
- RENDERING OPTIONS:
- style: {_RENDER_STYLE_HELP}
- color_mode: {_RENDER_COLOR_HELP}
- size: {_RENDER_SIZE_HELP}
- table_position: "none" (wheel only), "below" (portrait), or "right" (landscape).
- include_planets: {_RENDER_PLANETS_HELP}
- include_houses: {_RENDER_HOUSES_HELP}
- title: {_RENDER_TITLE_HELP}
- Returns:
- Dict with "svg", "format", "width", "height", "included".
- """
- from .chart_renderer import render_natal_wheel
- chart_data = await calculate_composite_chart(
- person1_datetime=person1_datetime,
- person1_latitude=person1_latitude,
- person1_longitude=person1_longitude,
- person2_datetime=person2_datetime,
- person2_latitude=person2_latitude,
- person2_longitude=person2_longitude,
- elevation=elevation,
- house_system=house_system,
- orb_limits=orb_limits,
- )
- if "error" in chart_data:
- return chart_data
- result = render_natal_wheel(
- chart_data,
- style=style,
- color_mode=color_mode,
- size=size,
- table_position=table_position,
- include_planets=include_planets,
- include_houses=include_houses,
- title=title,
- format=format,
- )
- result["included"] = _included_list(table_position, include_planets, include_houses)
- return result
- # ── render_composite_chart_by_id ──────────────────────────────────────
- @mcp.tool()
- async def render_composite_chart_by_id(
- # ── Two person IDs ──────────────────────────────────────────────
- person1_id: str,
- person2_id: str,
- house_system: str = "placidus",
- orb_limits: dict[str, float] | None = None,
- # ── Rendering options ───────────────────────────────────────────
- style: str = "modern",
- color_mode: str = "color",
- size: int = 600,
- table_position: str = "none",
- include_planets: bool = False,
- include_houses: bool = False,
- title: str | None = None,
- format: str = "svg",
- ) -> dict[str, Any]:
- """Render a composite chart for two people from the database.
- Looks up both persons by ID, calculates the composite chart, and
- renders it as a single natal-style wheel. Output as SVG or raster image (PNG/JPG).
- PERSON LOOKUP (required):
- person1_id: ID or nickname of person 1 in the persons database.
- person2_id: ID or nickname of person 2 in the persons database.
- CHART OPTIONS:
- house_system: "placidus" (default), "equal", or "whole_sign".
- orb_limits: Per-aspect orb overrides.
- RENDERING OPTIONS:
- style: {_RENDER_STYLE_HELP}
- color_mode: {_RENDER_COLOR_HELP}
- size: {_RENDER_SIZE_HELP}
- table_position: "none" (wheel only), "below" (portrait), or "right" (landscape).
- include_planets: {_RENDER_PLANETS_HELP}
- include_houses: {_RENDER_HOUSES_HELP}
- title: {_RENDER_TITLE_HELP}
- format: Output format — "svg" (default), "png", or "jpg".
- Returns:
- Dict with "content", "format", "content_type", "width", "height", "included".
- """
- from .chart_renderer import render_natal_wheel
- chart_data = await calculate_composite_chart_by_id(
- person1_id=person1_id,
- person2_id=person2_id,
- house_system=house_system,
- orb_limits=orb_limits,
- )
- if "error" in chart_data:
- return chart_data
- result = render_natal_wheel(
- chart_data,
- style=style,
- color_mode=color_mode,
- size=size,
- table_position=table_position,
- include_planets=include_planets,
- include_houses=include_houses,
- title=title,
- format=format,
- )
- result["included"] = _included_list(table_position, include_planets, include_houses)
- return result
- # ── render_davison_chart ──────────────────────────────────────────────
- @mcp.tool()
- async def render_davison_chart(
- # ── Two people's birth data (same as calculate_davison_chart) ───
- person1_datetime: str,
- person1_latitude: float,
- person1_longitude: float,
- person2_datetime: str,
- person2_latitude: float,
- person2_longitude: float,
- elevation: float = 0.0,
- house_system: str = "placidus",
- orb_limits: dict[str, float] | None = None,
- # ── Rendering options ───────────────────────────────────────────
- style: str = "modern",
- color_mode: str = "color",
- size: int = 600,
- table_position: str = "none",
- include_planets: bool = False,
- include_houses: bool = False,
- title: str | None = None,
- format: str = "svg",
- ) -> dict[str, Any]:
- """Render a Davison chart (midpoint in time and space) as a single wheel.
- Calculates the Davison chart from two people's birth data and renders
- it as a standard natal-style wheel. Output as SVG or raster image (PNG/JPG).
- PERSON 1 (required):
- person1_datetime: ISO 8601 birth datetime with timezone.
- person1_latitude: Birth latitude in decimal degrees.
- person1_longitude: Birth longitude in decimal degrees.
- PERSON 2 (required):
- person2_datetime: ISO 8601 birth datetime with timezone.
- person2_latitude: Birth latitude in decimal degrees.
- person2_longitude: Birth longitude in decimal degrees.
- CHART OPTIONS:
- elevation: Birth elevation in meters (default: 0).
- house_system: "placidus" (default), "equal", or "whole_sign".
- orb_limits: Per-aspect orb overrides.
- RENDERING OPTIONS:
- style: {_RENDER_STYLE_HELP}
- color_mode: {_RENDER_COLOR_HELP}
- size: {_RENDER_SIZE_HELP}
- table_position: "none" (wheel only), "below" (portrait), or "right" (landscape).
- include_planets: {_RENDER_PLANETS_HELP}
- include_houses: {_RENDER_HOUSES_HELP}
- title: {_RENDER_TITLE_HELP}
- Returns:
- Dict with "svg", "format", "width", "height", "included".
- """
- from .chart_renderer import render_natal_wheel
- chart_data = await calculate_davison_chart(
- person1_datetime=person1_datetime,
- person1_latitude=person1_latitude,
- person1_longitude=person1_longitude,
- person2_datetime=person2_datetime,
- person2_latitude=person2_latitude,
- person2_longitude=person2_longitude,
- elevation=elevation,
- house_system=house_system,
- orb_limits=orb_limits,
- )
- if "error" in chart_data:
- return chart_data
- result = render_natal_wheel(
- chart_data,
- style=style,
- color_mode=color_mode,
- size=size,
- table_position=table_position,
- include_planets=include_planets,
- include_houses=include_houses,
- title=title,
- format=format,
- )
- result["included"] = _included_list(table_position, include_planets, include_houses)
- return result
- # ── render_davison_chart_by_id ────────────────────────────────────────
- @mcp.tool()
- async def render_davison_chart_by_id(
- # ── Two person IDs ──────────────────────────────────────────────
- person1_id: str,
- person2_id: str,
- house_system: str = "placidus",
- orb_limits: dict[str, float] | None = None,
- # ── Rendering options ───────────────────────────────────────────
- style: str = "modern",
- color_mode: str = "color",
- size: int = 600,
- table_position: str = "none",
- include_planets: bool = False,
- include_houses: bool = False,
- title: str | None = None,
- format: str = "svg",
- ) -> dict[str, Any]:
- """Render a Davison chart for two people from the database.
- Looks up both persons by ID, calculates the Davison chart, and
- renders it as a single natal-style wheel. Output as SVG or raster image.
- PERSON LOOKUP (required):
- person1_id: ID or nickname of person 1 in the persons database.
- person2_id: ID or nickname of person 2 in the persons database.
- CHART OPTIONS:
- house_system: "placidus" (default), "equal", or "whole_sign".
- orb_limits: Per-aspect orb overrides.
- RENDERING OPTIONS:
- style: {_RENDER_STYLE_HELP}
- color_mode: {_RENDER_COLOR_HELP}
- size: {_RENDER_SIZE_HELP}
- table_position: "none" (wheel only), "below" (portrait), or "right" (landscape).
- include_planets: {_RENDER_PLANETS_HELP}
- include_houses: {_RENDER_HOUSES_HELP}
- title: {_RENDER_TITLE_HELP}
- Returns:
- Dict with "svg", "format", "width", "height", "included".
- """
- from .chart_renderer import render_natal_wheel
- chart_data = await calculate_davison_chart_by_id(
- person1_id=person1_id,
- person2_id=person2_id,
- house_system=house_system,
- orb_limits=orb_limits,
- )
- if "error" in chart_data:
- return chart_data
- result = render_natal_wheel(
- chart_data,
- style=style,
- color_mode=color_mode,
- size=size,
- table_position=table_position,
- include_planets=include_planets,
- include_houses=include_houses,
- title=title,
- format=format,
- )
- result["included"] = _included_list(table_position, include_planets, include_houses)
- return result
- # ── Helper ────────────────────────────────────────────────────────────
- def _included_list(table_position: str, planets: bool, houses: bool) -> list[str]:
- result = ["wheel"]
- if table_position in ("below", "right"):
- if planets:
- result.append("planet_table")
- if houses:
- result.append("house_table")
- return result
|