Skip to main content

ephemvis

CI PyPI Python License: MIT

Themeable SVG rendering for astrological chart data — the display layer that pairs with openephem (the calculation core). ephemvis turns a chart dict into a self-contained chart wheel and a triangular aspect grid.

The split is deliberate: openephem computes, ephemvis draws. The math core stays small and auditable; the visuals can be forked and restyled freely without touching (or destabilising) the calculations.

Install

pip install ephemvis            # pure renderer, zero runtime deps
pip install ephemvis[compute]   # also pulls openephem to compute charts

Use

from openephem import resolve, assemble          # needs ephemvis[compute]
from ephemvis import render_svg, render_aspect_grid_svg

chart = assemble(resolve(date=(1990, 5, 15), time=(14, 30),
                         place="New York, NY"))
open("wheel.svg", "w", encoding="utf-8").write(render_svg(chart, theme="prism"))
open("grid.svg",  "w", encoding="utf-8").write(render_aspect_grid_svg(chart, theme="prism"))

render_svg and render_aspect_grid_svg accept any dict with the openephem ChartResult shape (angles, cusps, bodies, aspects), so any engine that emits that shape can be rendered — ephemvis has no dependency on how the chart was computed.

Profections

Two ways to show profections, both from a chart dict carrying a profections block (openephem's assemble() adds one for a given age/date):

A dedicated wheel — render_profection_wheel_svg(chart, theme=…) draws the whole-sign profection wheel: twelve house wedges (ASC..12th) with the natal planets in their houses, the signs on the rim, and concentric age rings (each house lists the ages that profect there — 0,12,24… in the 1st, 1,13,25… in the 2nd, …). The profected house + sign are highlighted for the chart's age, and the age cells are a heatmap keyed to age along the theme's ramp (a thermal map of life in infrared, black-light in ultraviolet). Options:

from ephemvis import render_profection_wheel_svg
svg = render_profection_wheel_svg(chart, theme="infrared", max_age=83,
                                  title="Annual Profections", planets="classical")

max_age sets the final year (the outer ring is always completed: 83 → seven rings 0–83, 84 → eight rings 0–95). planets is "classical" (default), "all", or a list of body names. title sets the top-left heading. Each sign's outer-ring arc is tinted with its Lord of the Year (domicile-ruler) colour, with two stacked legends below (the lord colours, then the age gradient).

Pass layout="spiral" to unroll the age rings into one continuous expanding coil (birth at the centre, one 12-year turn per loop). Because profections are exactly 12-periodic, each sign holds the same angle on every turn, so the recurrence reads as aligned radial wedges. layout="annulus" (concentric rings) is the default.

An overlay on the natal wheel — render_svg also marks the profection on the ordinary chart in the theme accent: a filled band on the annual profected sign and a ring tagged TL on the Lord of the Year glyph, each with a hover tooltip. A bottom-left key names the annual lord and rising sign (Lord: Mars · Aries rising) and, when the chart carries an as-of date, tags each part of that date with the sign it profects to (June ♊ · 3rd ♐ · 2030 ♒ — month → Lord of the Month's sign, day → Lord of the Day's, year → the annual sign). Pass show_profection=False to suppress it. All whole-sign, counted from the Ascendant.

Firdaria

render_firdaria_svg(chart, theme=…) draws the Persian firdaria time-lords as a horizontal timeline (they're a temporal sequence, not a wheel): a top row of major planetary periods and a bottom row of their sub-periods, each segment coloured and glyphed by its ruling planet, with the current major/sub outlined and a marker at the current age. Needs a firdaria block (openephem's assemble(..., firdaria_as_of=)).

from ephemvis import render_firdaria_svg
svg = render_firdaria_svg(chart, theme="dark", max_age=84, title="Firdaria")

max_age is the right edge (years). A companion table is trivially built from the same firdaria block. Planet identity is carried by the glyph (nine categories can't all be maximally distinct); colour is a supporting cue.

Chart style — render_firdaria_svg(chart, style="chart") projects the sequence onto the profection wheel instead (band = major lord, glyph = sub lord; the two nodes carried through), sharing the natal core with every other chart. Add layout="spiral" for the coil. Needs a profections block alongside the firdaria one.

Zodiacal Releasing

render_zodiacal_releasing_svg(chart, theme=…) draws Valens' zodiacal releasing as a horizontal timeline of nested periods: a top row of level-1 (L1) periods and a bottom row of their level-2 (L2) sub-periods. Each band is coloured by the element of its sign (Fire/Earth/Air/Water — four categories separate cleanly for colour-vision deficiency) and carries the sign's glyph as the primary identifier. Peak periods (angular from the Lot of Fortune) get an ink accent bar; a Loosing-of-the-Bond jump is marked where it occurs; the current L1 period is outlined with a marker at the current age. Needs a zodiacal_releasing block (openephem's assemble(..., releasing_as_of=)).

from ephemvis import render_zodiacal_releasing_svg
svg = render_zodiacal_releasing_svg(chart, theme="dark", max_age=84,
                                    title="Zodiacal Releasing")

max_age is the right edge (years). The Lot released (Fortune by default, or any of the seven Hermetic Lots) and the active L1→L4 path are named in the subtitle; a companion table is trivially built from the same block.

Chart style — render_zodiacal_releasing_svg(chart, style="chart") projects releasing onto the profection wheel, each cell coloured by its L1 sign's element and glyphed by its L2 sign (the angularity / peak / loosing-of-the-bond markers stay on the timeline). Add layout="spiral" for the coil. Needs a profections block alongside the zodiacal_releasing one.

Decennials

render_decennials_svg(chart, theme=…) draws Valens' decennial time-lords as a horizontal timeline: a top row of the general decennial periods (each a fixed 10 years 9 months) and a bottom row of their planetary sub-periods (unequal — each planet's minor years as months), coloured and glyphed by ruling planet, with the current general/sub lord outlined and a marker at the current age. Needs a decennials block (openephem's assemble(..., decennials_as_of=)).

from ephemvis import render_decennials_svg
svg = render_decennials_svg(chart, theme="dark", max_age=76, title="Decennials")

max_age is the right edge (years; a full cycle is ~75¼). The starting planet is named in the subtitle; a companion table is trivially built from the same block. Planet identity is carried by the glyph; colour is a supporting cue.

Chart style — render_decennials_svg(chart, style="chart") rolls the decennial Gantt onto the profection wheel (band = major lord, glyph = sub lord, radial ticks at the real sub-period boundaries, or sub_style="gradient" for sub-lord colour slices). Add layout="spiral" for the coil. Needs a profections block alongside the decennials one.

Jyotiṣa (Vedic) charts

render_vedic_square_svg(chart, style=…) draws the classical rāśi square in three regional styles — "south" (South Indian fixed-sign grid), "north" (North Indian fixed-house diamond), and "east" (East Indian / Bengali fixed-house). Grahas are placed by their sidereal rāśi (Rāhu/Ketu included), the Lagna is marked, and each house scales its contents so a dense stellium stays inside its cell. Needs a sidereal chart (assemble(zodiac="sidereal")); the same function renders any vārga (divisional) chart when the chart carries a varga block (openephem's varga_chart()).

from ephemvis import render_vedic_square_svg
svg = render_vedic_square_svg(chart, style="south", theme="meadow", title="Rāśi")

render_vimshottari_svg(chart, style=…, layout=…) draws the Vimśottarī daśā — either a horizontal timeline (Mahādaśā over Antardaśā, the balance at birth, an as-of marker) or, with style="chart", projected onto the shared wheel core (band = Mahādaśā, glyph = Antardaśā) as concentric rings (layout="annulus") or an expanding coil (layout="spiral"). The seven classical lords share the firdaria/decennials theme colours; Rāhu/Ketu carry their own. Needs a vimshottari block (openephem ≥ 0.2.0's assemble(..., vimshottari_as_of=)).

from ephemvis import render_vimshottari_svg
svg = render_vimshottari_svg(chart, style="chart", layout="spiral", theme="meadow")

Bi-wheel & synastry

render_biwheel_svg(inner, outer, …) draws a double wheel — two charts on one wheel, for comparing any pair: natal + transit, two transits, synastry (compatibility), natal + solar/lunar return, natal + progressed. The inner chart (the radix) owns the zodiac ring, the house cusps and the orientation; the outer chart's planets are placed against that same ring on their own band. Between the two planet bands sits a shared divider ring — every planet's short true-position tick points to it — and the bands sit symmetric about it. Both rings carry the full readout (glyph · degree · sign · minute) in the same order. The outer chart may be an untimed transit (no houses of its own); only the inner chart needs a house framework.

Three aspect layers cross the hub, each switchable: cross-aspects (inner × outer, bold, on by default) plus each chart's own internal aspects (faint, off by default). Cross-aspects are computed upstream — openephem's cross_aspects() returns the list:

from openephem import resolve, assemble, cross_aspects   # needs ephemvis[compute]
from ephemvis import render_biwheel_svg, render_synastry_grid_svg

natal   = assemble(resolve(date=(1990, 5, 15), time=(14, 30), place="New York, NY"))
transit = assemble(resolve(date=(2026, 9, 15), time=(12, 0),  place="New York, NY"))
cross   = cross_aspects(natal, transit)                  # flat 5° orb by default, adjustable

wheel = render_biwheel_svg(natal, transit, cross_aspects=cross,
                           labels=("Natal", "Transit"), theme="prism")
grid  = render_synastry_grid_svg(natal, transit, cross, labels=("Natal", "Transit"))

labels names the two charts (hover text, and a small legend when key=True); toggle the intra-chart layers with show_inner_aspects / show_outer_aspects, or the cross layer with show_cross_aspects. The renderer only draws — pass any two chart dicts and a cross-aspect list, from any engine that emits the shape.

render_synastry_grid_svg(inner, outer, cross, …) is the companion synastry grid: a rectangular matrix with the inner chart's bodies down the left and the outer chart's across the top, each cell showing the cross-aspect between its row and column, coloured by nature — two folded aspectarians, its gradient falling inward from both corners.

Themes

light, dark, auto, and eight pastel "pretty" modes with a prism-halo ring: prism, twilight, aurora, opal, seafoam, meadow, dawn, blossom. See ephemvis.PALETTES.

Embedded glyphs

Every SVG embeds its astrology glyphs and numerals as @font-face data URIs, so a chart renders pixel-identical on any device — no dependence on whatever symbol font the viewer happens to have (which was the source of the classic "℞ looks like a serif here, a box there" and glyph-overlap problems). The glyphs are a curated subset of the OFL Noto fonts, packaged by the sibling astroglyphs_2K toolkit and vendored into ephemvis/_fontdata.py at build time — so ephemvis still has zero runtime dependencies. The font data is under the SIL Open Font License 1.1 (see NOTICE and LICENSES/OFL.txt); the code stays MIT.

The data contract

ephemvis reads the chart dict openephem's assemble() returns:

{
  "angles": {"asc": float, "mc": float, ...} | None,   # ecliptic longitude, degrees
  "cusps":  [float] (12) | None,                        # house cusp longitudes
  "bodies": {name: {"lon": float, "retro": bool}},      # ecliptic longitude, degrees
  "aspects": [{"a": name, "b": name, "aspect": str, "orb": float}],
  "warnings": [str],
}

MIT © 2026 Elizabeth Huston, Ph.D. and Noah Christian, Ph.D.
Contact: elpisastrology@gmail.com · elpisastrology.com and noahchristian@gmail.com

Metadata

Release files for ephemvis 0.5.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for ephemvis 0.5.1
File Size Uploaded Provenance
ephemvis-0.5.1.tar.gz 134.7 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for ephemvis 0.5.1
File Interpreter ABI Platform
ephemvis-0.5.1-py3-none-any.whl Python 3 none any Details

Total release size: 270.8 kB

Release files / ephemvis-0.5.1.tar.gz

Download URL ephemvis-0.5.1.tar.gz
Size 134.7 kB
Tags Source
SHA-256 checksum
How to use checksums
455d40affd120468aa07e7e48cee26a32d0ef348a62496da4e0eccbc045dd500
BLAKE2b-256 checksum
How to use checksums
16b5094f36c81724f0ced6c64d6cbaaabbc317e5da96186becf1dbd3929c5eb8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 16, 2026.

Transparency log

Release files / ephemvis-0.5.1-py3-none-any.whl

Download URL ephemvis-0.5.1-py3-none-any.whl
Size 136.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
9d4fea8a4cc21ee9473ca4229ae109013bacd66207f24001a255179f0319717a
BLAKE2b-256 checksum
How to use checksums
b7dffb0e707aca5433bc885a4409b942b873a0411b008145431e0bf4e28122e0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 16, 2026.

Transparency log

Security for ephemvis 0.5.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for ephemvis-0.5.1.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 16, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page