How to Make a D3 Chart in Astrology
An astrology wheel is a polar chart. D3 already has pie and arc. Here's the drawing half, with fake planet positions on purpose.
How to make a D3 chart in astrology is, as a programming problem, a labeled ring. Twelve signs, equal width, planets sitting at ecliptic longitudes. I don't cast charts. I do know how to draw a circle that other people insist on calling a wheel.
The preview uses fake planet positions so we can talk about the SVG. Plug in numbers from an ephemeris when you have them. If you wanted a normal dashboard chart instead, start from D3 graph examples or the D3.js page.
The drawing problem, not the sky
Astrology software has two halves. One half computes where the planets were. The other half paints a wheel. D3 is the second half. Mixing them in one file is how you get a 400-line script nobody can debug.
A natal chart as drawn in the West often puts the Ascendant on the left. This example puts 0° Aries at the top because the math is obvious: longitude 0 lives at 12 o'clock. Rotate the whole group when you want the house cusps to match a printed chart.
A D3 astrology wheel
Twelve slices from d3.pie with value: 1 so
they're equal. Planet marks are circles on a smaller radius. Abbreviations
around the rim are the first three letters of each sign, not glyphs.
Glyphs are a font problem, not a D3 problem.
Preview
The code
d3.pie already lives in the polar world. You don't need a
custom layout. Longitude to x/y is high-school trigonometry. The
- 90 is so 0° sits at the top of the SVG, not at 3 o'clock.
Code
const signs = ["Aries", "Taurus", "Gemini", "Cancer", "Leo", "Virgo",
"Libra", "Scorpio", "Sagittarius", "Capricorn", "Aquarius", "Pisces"];
const pie = d3.pie().value(() => 1).sort(null);
const arc = d3.arc().innerRadius(132).outerRadius(168);
svg.append("g")
.attr("transform", "translate(210,210)")
.selectAll("path")
.data(pie(signs.map((name) => ({ name }))))
.join("path")
.attr("d", arc);
function xy(longitude, r) {
const a = ((longitude - 90) * Math.PI) / 180;
return [210 + r * Math.cos(a), 210 + r * Math.sin(a)];
}
const [x, y] = xy(42, 96); // Sun at 42° ecliptic longitude
svg.append("circle").attr("cx", x).attr("cy", y).attr("r", 7);
Real planet positions
For actual longitudes you need an ephemeris — Swiss Ephemeris is the
standard, and there are JavaScript ports of it. You provide a birth
date, time, and location, and the library gives you ecliptic longitudes
for each planet. None of that is D3's job. Once you have the numbers,
just feed this wheel an array of { name, lon } objects
and it places the markers.
Aspect lines are line segments drawn between planet points — entirely straightforward once you have the coordinates. Houses are another concentric pie with a smaller inner radius. And for what it's worth, I would not compute Placidus house cusps inside a render function. Do that calculation once, cache the result, pass it in.
Polar charts that aren't zodiacs — skill wheels, wind roses — use the
same pie + arc setup. The
sankey and
map posts cover the
layouts that don't fit on a circle.
Questions I get
How do I make a D3 chart in astrology?
Treat the natal wheel as a polar chart. The twelve zodiac signs are just a pie chart where every slice has equal value — d3.pie with value: () => 1 handles that. Planet positions are ecliptic longitudes, which you convert to screen coordinates with sine and cosine. D3 draws the wheel; you get the actual planetary longitudes from a separate ephemeris library.
Does this calculate my natal chart?
No — this post is only about the drawing step. The planet positions in the example are hardcoded so we can talk about the SVG without getting tangled up in astronomical math. A real natal chart requires a birth date, time, and location, run through an ephemeris library like Swiss Ephemeris or one of its JavaScript ports.
Should astrology charts use D3 or a canvas library?
D3 is a natural fit because the wheel is made of SVG arcs, circles, and text — things D3 handles well. Canvas works fine too if you're drawing a lot of aspect lines (the lines connecting planets that form aspects), since SVG can get slow with many overlapping paths. I wouldn't reach for Chart.js here; its mental model is Cartesian charts and it doesn't think in degrees or polar coordinates.