kerykeion 4.26.3__py3-none-any.whl → 5.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of kerykeion might be problematic. Click here for more details.

Files changed (76) hide show
  1. kerykeion/__init__.py +54 -11
  2. kerykeion/aspects/__init__.py +5 -2
  3. kerykeion/aspects/aspects_factory.py +569 -0
  4. kerykeion/aspects/aspects_utils.py +81 -8
  5. kerykeion/astrological_subject_factory.py +1897 -0
  6. kerykeion/backword.py +773 -0
  7. kerykeion/chart_data_factory.py +549 -0
  8. kerykeion/charts/chart_drawer.py +2601 -0
  9. kerykeion/charts/charts_utils.py +948 -177
  10. kerykeion/charts/draw_planets.py +602 -351
  11. kerykeion/charts/templates/aspect_grid_only.xml +328 -202
  12. kerykeion/charts/templates/chart.xml +432 -272
  13. kerykeion/charts/templates/wheel_only.xml +350 -214
  14. kerykeion/charts/themes/black-and-white.css +148 -0
  15. kerykeion/charts/themes/classic.css +107 -76
  16. kerykeion/charts/themes/dark-high-contrast.css +145 -107
  17. kerykeion/charts/themes/dark.css +146 -107
  18. kerykeion/charts/themes/light.css +146 -103
  19. kerykeion/charts/themes/strawberry.css +158 -0
  20. kerykeion/composite_subject_factory.py +253 -51
  21. kerykeion/ephemeris_data_factory.py +434 -0
  22. kerykeion/fetch_geonames.py +27 -8
  23. kerykeion/house_comparison/__init__.py +6 -0
  24. kerykeion/house_comparison/house_comparison_factory.py +103 -0
  25. kerykeion/house_comparison/house_comparison_utils.py +126 -0
  26. kerykeion/kr_types/__init__.py +66 -6
  27. kerykeion/kr_types/chart_template_model.py +20 -0
  28. kerykeion/kr_types/kerykeion_exception.py +15 -9
  29. kerykeion/kr_types/kr_literals.py +14 -132
  30. kerykeion/kr_types/kr_models.py +14 -318
  31. kerykeion/kr_types/settings_models.py +15 -203
  32. kerykeion/planetary_return_factory.py +805 -0
  33. kerykeion/relationship_score_factory.py +301 -0
  34. kerykeion/report.py +751 -64
  35. kerykeion/schemas/__init__.py +106 -0
  36. kerykeion/schemas/chart_template_model.py +367 -0
  37. kerykeion/schemas/kerykeion_exception.py +20 -0
  38. kerykeion/schemas/kr_literals.py +181 -0
  39. kerykeion/schemas/kr_models.py +605 -0
  40. kerykeion/schemas/settings_models.py +180 -0
  41. kerykeion/settings/__init__.py +20 -1
  42. kerykeion/settings/chart_defaults.py +444 -0
  43. kerykeion/settings/config_constants.py +117 -12
  44. kerykeion/settings/kerykeion_settings.py +31 -73
  45. kerykeion/settings/translation_strings.py +1479 -0
  46. kerykeion/settings/translations.py +74 -0
  47. kerykeion/sweph/ast136/s136108s.se1 +0 -0
  48. kerykeion/sweph/ast136/s136199s.se1 +0 -0
  49. kerykeion/sweph/ast136/s136472s.se1 +0 -0
  50. kerykeion/sweph/ast28/se28978s.se1 +0 -0
  51. kerykeion/sweph/ast50/se50000s.se1 +0 -0
  52. kerykeion/sweph/ast90/se90377s.se1 +0 -0
  53. kerykeion/sweph/ast90/se90482s.se1 +0 -0
  54. kerykeion/sweph/sefstars.txt +1602 -0
  55. kerykeion/transits_time_range_factory.py +302 -0
  56. kerykeion/utilities.py +393 -114
  57. kerykeion-5.0.0.dist-info/METADATA +1176 -0
  58. kerykeion-5.0.0.dist-info/RECORD +63 -0
  59. {kerykeion-4.26.3.dist-info → kerykeion-5.0.0.dist-info}/WHEEL +1 -1
  60. kerykeion/aspects/natal_aspects.py +0 -172
  61. kerykeion/aspects/synastry_aspects.py +0 -124
  62. kerykeion/aspects/transits_time_range.py +0 -41
  63. kerykeion/astrological_subject.py +0 -841
  64. kerykeion/charts/kerykeion_chart_svg.py +0 -1219
  65. kerykeion/enums.py +0 -57
  66. kerykeion/ephemeris_data.py +0 -242
  67. kerykeion/kr_types/chart_types.py +0 -95
  68. kerykeion/relationship_score/__init__.py +0 -2
  69. kerykeion/relationship_score/relationship_score.py +0 -175
  70. kerykeion/relationship_score/relationship_score_factory.py +0 -230
  71. kerykeion/settings/kr.config.json +0 -1258
  72. kerykeion/transits_time_range.py +0 -124
  73. kerykeion-4.26.3.dist-info/METADATA +0 -634
  74. kerykeion-4.26.3.dist-info/RECORD +0 -45
  75. kerykeion-4.26.3.dist-info/entry_points.txt +0 -3
  76. {kerykeion-4.26.3.dist-info → kerykeion-5.0.0.dist-info/licenses}/LICENSE +0 -0
@@ -0,0 +1,1176 @@
1
+ Metadata-Version: 2.4
2
+ Name: kerykeion
3
+ Version: 5.0.0
4
+ Summary: A Python library for astrological calculations, including natal charts, houses, planetary aspects, and SVG chart generation.
5
+ Project-URL: Homepage, https://www.kerykeion.net/
6
+ Project-URL: Repository, https://github.com/g-battaglia/kerykeion
7
+ Author-email: Giacomo Battaglia <kerykeion.astrology@gmail.com>
8
+ License: AGPL-3.0
9
+ License-File: LICENSE
10
+ Keywords: astrology,astrology calculations,astrology calculator,astrology library,astrology transits,astronomical algorithms,birth chart,ephemeris,houses of astrology,natal chart,planetary aspects,svg charts,synastry,zodiac,zodiac signs
11
+ Classifier: Development Status :: 5 - Production/Stable
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Intended Audience :: Information Technology
14
+ Classifier: Intended Audience :: Science/Research
15
+ Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3 :: Only
18
+ Classifier: Programming Language :: Python :: 3.9
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Topic :: Religion
24
+ Classifier: Topic :: Scientific/Engineering :: Astronomy
25
+ Classifier: Topic :: Scientific/Engineering :: Visualization
26
+ Classifier: Topic :: Software Development
27
+ Classifier: Topic :: Software Development :: Libraries
28
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
29
+ Classifier: Typing :: Typed
30
+ Requires-Python: >=3.9
31
+ Requires-Dist: pydantic>=2.5
32
+ Requires-Dist: pyswisseph>=2.10.3.1
33
+ Requires-Dist: pytz>=2024.2
34
+ Requires-Dist: requests-cache>=1.2.1
35
+ Requires-Dist: requests>=2.32.3
36
+ Requires-Dist: scour>=0.38.2
37
+ Requires-Dist: simple-ascii-tables>=1.0.0
38
+ Requires-Dist: typing-extensions>=4.12.2
39
+ Description-Content-Type: text/markdown
40
+
41
+ <h1 align="center">Kerykeion</h1>
42
+
43
+ <div align="center">
44
+ <img src="https://img.shields.io/github/stars/g-battaglia/kerykeion.svg?logo=github" alt="stars">
45
+ <img src="https://img.shields.io/github/forks/g-battaglia/kerykeion.svg?logo=github" alt="forks">
46
+ </div>
47
+ <div align="center">
48
+ <img src="https://static.pepy.tech/badge/kerykeion/month" alt="PyPI Downloads">
49
+ <img src="https://static.pepy.tech/badge/kerykeion/week" alt="PyPI Downloads">
50
+ <img src="https://static.pepy.tech/personalized-badge/kerykeion?period=total&units=INTERNATIONAL_SYSTEM&left_color=GREY&right_color=BLUE&left_text=downloads/total" alt="PyPI Downloads">
51
+ </div>
52
+ <div align="center">
53
+ <img src="https://img.shields.io/pypi/v/kerykeion?label=pypi%20package" alt="Package version">
54
+ <img src="https://img.shields.io/pypi/pyversions/kerykeion.svg" alt="Supported Python versions">
55
+ </div>
56
+ <p align="center">⭐ Like this project? Star it on GitHub and help it grow! ⭐</p>
57
+ &nbsp;
58
+
59
+ Kerykeion is a Python library for astrology. It computes planetary and house positions, detects aspects, and generates SVG charts—including birth, synastry, transit, and composite charts. You can also customize which planets to include in your calculations.
60
+
61
+ The main goal of this project is to offer a clean, data-driven approach to astrology, making it accessible and programmable.
62
+
63
+ Kerykeion also integrates seamlessly with LLM and AI applications.
64
+
65
+ Here is an example of a birthchart:
66
+
67
+ ![John Lenon Chart](https://raw.githubusercontent.com/g-battaglia/kerykeion/refs/heads/master/tests/charts/svg/John%20Lennon%20-%20Dark%20Theme%20-%20Natal%20Chart.svg)
68
+
69
+ ## **Web API**
70
+
71
+ If you want to use Kerykeion in a web application, you can try the dedicated web API:
72
+
73
+ **[AstrologerAPI](https://rapidapi.com/gbattaglia/api/astrologer/pricing)**
74
+
75
+ It is [open source](https://github.com/g-battaglia/Astrologer-API) and directly supports this project.
76
+
77
+ ## **Donate**
78
+
79
+ Maintaining this project requires substantial time and effort. The Astrologer API alone cannot cover the costs of full-time development. If you find Kerykeion valuable and would like to support further development, please consider donating:
80
+
81
+ [![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/kerykeion)
82
+
83
+ ## Table of Contents
84
+
85
+ - [**Web API**](#web-api)
86
+ - [**Donate**](#donate)
87
+ - [Table of Contents](#table-of-contents)
88
+ - [Installation](#installation)
89
+ - [Basic Usage](#basic-usage)
90
+ - [Generate a SVG Chart](#generate-a-svg-chart)
91
+ - [Birth Chart](#birth-chart)
92
+ - [External Birth Chart](#external-birth-chart)
93
+ - [Synastry Chart](#synastry-chart)
94
+ - [Transit Chart](#transit-chart)
95
+ - [Composite Chart](#composite-chart)
96
+ - [Wheel Only Charts](#wheel-only-charts)
97
+ - [Birth Chart](#birth-chart-1)
98
+ - [Wheel Only Birth Chart (External)](#wheel-only-birth-chart-external)
99
+ - [Synastry Chart](#synastry-chart-1)
100
+ - [Change the Output Directory](#change-the-output-directory)
101
+ - [Change Language](#change-language)
102
+ - [SVG without CSS Variables](#svg-without-css-variables)
103
+ - [Grid Only SVG](#grid-only-svg)
104
+ - [Report Generator](#report-generator)
105
+ - [Quick Examples](#quick-examples)
106
+ - [Section Access](#section-access)
107
+ - [Example: Retrieving Aspects](#example-retrieving-aspects)
108
+ - [Element \& Quality Distribution Strategies](#element--quality-distribution-strategies)
109
+ - [Ayanamsa (Sidereal Modes)](#ayanamsa-sidereal-modes)
110
+ - [House Systems](#house-systems)
111
+ - [Perspective Type](#perspective-type)
112
+ - [Themes](#themes)
113
+ - [Alternative Initialization](#alternative-initialization)
114
+ - [Lunar Nodes (Rahu \& Ketu)](#lunar-nodes-rahu--ketu)
115
+ - [JSON Support](#json-support)
116
+ - [Auto Generated Documentation](#auto-generated-documentation)
117
+ - [Development](#development)
118
+ - [Kerykeion v5.0 – What's New](#kerykeion-v50--whats-new)
119
+ - [🎯 Key Highlights](#-key-highlights)
120
+ - [Factory-Centered Architecture](#factory-centered-architecture)
121
+ - [Pydantic 2 Models \& Type Safety](#pydantic-2-models--type-safety)
122
+ - [Enhanced Features](#enhanced-features)
123
+ - [🚨 Breaking Changes](#-breaking-changes)
124
+ - [1. Removed Legacy Classes](#1-removed-legacy-classes)
125
+ - [2. Import Changes](#2-import-changes)
126
+ - [3. Type Aliases Unified](#3-type-aliases-unified)
127
+ - [4. Lunar Nodes Naming](#4-lunar-nodes-naming)
128
+ - [5. Axis Orb Filtering](#5-axis-orb-filtering)
129
+ - [6. Chart Generation Changes](#6-chart-generation-changes)
130
+ - [7. Aspects API Changes](#7-aspects-api-changes)
131
+ - [🔄 Migration Guide](#-migration-guide)
132
+ - [Using the Backward Compatibility Layer](#using-the-backward-compatibility-layer)
133
+ - [Step-by-Step Migration](#step-by-step-migration)
134
+ - [Automated Migration Script](#automated-migration-script)
135
+ - [📦 Other Notable Changes](#-other-notable-changes)
136
+ - [🎨 New Themes](#-new-themes)
137
+ - [📚 Resources](#-resources)
138
+ - [Integrating Kerykeion into Your Project](#integrating-kerykeion-into-your-project)
139
+ - [License](#license)
140
+ - [Contributing](#contributing)
141
+ - [Citations](#citations)
142
+
143
+ ## Installation
144
+
145
+ Kerykeion requires **Python 3.9** or higher.
146
+
147
+ ```bash
148
+ pip3 install kerykeion
149
+ ```
150
+
151
+ ## Basic Usage
152
+
153
+ Below is a simple example illustrating the creation of an astrological subject and retrieving astrological details:
154
+
155
+ ```python
156
+ from kerykeion import AstrologicalSubjectFactory
157
+
158
+ # Create an instance of the AstrologicalSubjectFactory class.
159
+ # Arguments: Name, year, month, day, hour, minutes, city, nation
160
+ john = AstrologicalSubjectFactory.from_birth_data("John Lennon", 1940, 10, 9, 18, 30, "Liverpool", "GB")
161
+
162
+ # Retrieve information about the Sun:
163
+ print(john.sun.model_dump_json())
164
+ # > {"name":"Sun","quality":"Cardinal","element":"Air","sign":"Lib","sign_num":6,"position":16.26789199474399,"abs_pos":196.267891994744,"emoji":"♎️","point_type":"AstrologicalPoint","house":"Sixth_House","retrograde":false}
165
+
166
+ # Retrieve information about the first house:
167
+ print(john.first_house.model_dump_json())
168
+ # > {"name":"First_House","quality":"Cardinal","element":"Fire","sign":"Ari","sign_num":0,"position":19.74676624176799,"abs_pos":19.74676624176799,"emoji":"♈️","point_type":"House","house":null,"retrograde":null}
169
+
170
+ # Retrieve the element of the Moon sign:
171
+ print(john.moon.element)
172
+ # > 'Air'
173
+ ```
174
+
175
+ **To avoid using GeoNames online, specify longitude, latitude, and timezone instead of city and nation:**
176
+
177
+ ```python
178
+ john = AstrologicalSubjectFactory.from_birth_data(
179
+ "John Lennon", 1940, 10, 9, 18, 30,
180
+ lng=-2.9833, # Longitude for Liverpool
181
+ lat=53.4000, # Latitude for Liverpool
182
+ tz_str="Europe/London", # Timezone for Liverpool
183
+ city="Liverpool",
184
+ )
185
+ ```
186
+
187
+ ## Generate a SVG Chart
188
+
189
+ To generate a chart, use the `ChartDataFactory` to pre-compute chart data, then `ChartDrawer` to create the visualization. This two-step process ensures clean separation between astrological calculations and chart rendering.
190
+
191
+ **Tip:**
192
+ The optimized way to open the generated SVG files is with a web browser (e.g., Chrome, Firefox).
193
+ To improve compatibility across different applications, you can use the `remove_css_variables` parameter when generating the SVG. This will inline all styles and eliminate CSS variables, resulting in an SVG that is more broadly supported.
194
+
195
+ ### Birth Chart
196
+
197
+ ```python
198
+ from kerykeion import AstrologicalSubjectFactory
199
+ from kerykeion.chart_data_factory import ChartDataFactory
200
+ from kerykeion.charts.chart_drawer import ChartDrawer
201
+
202
+ # Step 1: Create subject
203
+ john = AstrologicalSubjectFactory.from_birth_data("John Lennon", 1940, 10, 9, 18, 30, "Liverpool", "GB")
204
+
205
+ # Step 2: Pre-compute chart data
206
+ chart_data = ChartDataFactory.create_natal_chart_data(john)
207
+
208
+ # Step 3: Create visualization
209
+ birth_chart_svg = ChartDrawer(chart_data=chart_data)
210
+ birth_chart_svg.save_svg()
211
+ ```
212
+
213
+ The SVG file will be saved in the home directory.
214
+ ![John Lennon Birth Chart](https://raw.githubusercontent.com/g-battaglia/kerykeion/refs/heads/master/tests/charts/svg/John%20Lennon%20-%20Natal%20Chart.svg)
215
+
216
+ ### External Birth Chart
217
+
218
+ ```python
219
+ from kerykeion import AstrologicalSubjectFactory
220
+ from kerykeion.chart_data_factory import ChartDataFactory
221
+ from kerykeion.charts.chart_drawer import ChartDrawer
222
+
223
+ # Step 1: Create subject
224
+ birth_chart = AstrologicalSubjectFactory.from_birth_data("John Lennon", 1940, 10, 9, 18, 30, "Liverpool", "GB")
225
+
226
+ # Step 2: Pre-compute chart data for external natal chart
227
+ chart_data = ChartDataFactory.create_external_natal_chart_data(birth_chart)
228
+
229
+ # Step 3: Create visualization
230
+ birth_chart_svg = ChartDrawer(chart_data=chart_data)
231
+ birth_chart_svg.save_svg()
232
+ ```
233
+
234
+ ![John Lennon External Birth Chart](https://raw.githubusercontent.com/g-battaglia/kerykeion/refs/heads/master/tests/charts/svg/John%20Lennon%20-%20ExternalNatal%20Chart.svg)
235
+
236
+ ### Synastry Chart
237
+
238
+ ```python
239
+ from kerykeion import AstrologicalSubjectFactory
240
+ from kerykeion.chart_data_factory import ChartDataFactory
241
+ from kerykeion.charts.chart_drawer import ChartDrawer
242
+
243
+ # Step 1: Create subjects
244
+ first = AstrologicalSubjectFactory.from_birth_data("John Lennon", 1940, 10, 9, 18, 30, "Liverpool", "GB")
245
+ second = AstrologicalSubjectFactory.from_birth_data("Paul McCartney", 1942, 6, 18, 15, 30, "Liverpool", "GB")
246
+
247
+ # Step 2: Pre-compute synastry chart data
248
+ chart_data = ChartDataFactory.create_synastry_chart_data(first, second)
249
+
250
+ # Step 3: Create visualization
251
+ synastry_chart = ChartDrawer(chart_data=chart_data)
252
+ synastry_chart.save_svg()
253
+ ```
254
+
255
+ ![John Lennon and Paul McCartney Synastry](https://www.kerykeion.net/img/examples/synastry-chart.svg)
256
+
257
+ ### Transit Chart
258
+
259
+ ```python
260
+ from kerykeion import AstrologicalSubjectFactory
261
+ from kerykeion.chart_data_factory import ChartDataFactory
262
+ from kerykeion.charts.chart_drawer import ChartDrawer
263
+
264
+ # Step 1: Create subjects
265
+ transit = AstrologicalSubjectFactory.from_birth_data("Transit", 2025, 6, 8, 8, 45, "Atlanta", "US")
266
+ subject = AstrologicalSubjectFactory.from_birth_data("John Lennon", 1940, 10, 9, 18, 30, "Liverpool", "GB")
267
+
268
+ # Step 2: Pre-compute transit chart data
269
+ chart_data = ChartDataFactory.create_transit_chart_data(subject, transit)
270
+
271
+ # Step 3: Create visualization
272
+ transit_chart = ChartDrawer(chart_data=chart_data)
273
+ transit_chart.save_svg()
274
+ ```
275
+
276
+ ![John Lennon Transit Chart](https://raw.githubusercontent.com/g-battaglia/kerykeion/refs/heads/master/tests/charts/svg/John%20Lennon%20-%20Transit%20Chart.svg)
277
+
278
+ ### Composite Chart
279
+
280
+ ```python
281
+ from kerykeion import CompositeSubjectFactory, AstrologicalSubjectFactory
282
+ from kerykeion.chart_data_factory import ChartDataFactory
283
+ from kerykeion.charts.chart_drawer import ChartDrawer
284
+
285
+ # Step 1: Create subjects
286
+ angelina = AstrologicalSubjectFactory.from_birth_data("Angelina Jolie", 1975, 6, 4, 9, 9, "Los Angeles", "US", lng=-118.15, lat=34.03, tz_str="America/Los_Angeles")
287
+
288
+ brad = AstrologicalSubjectFactory.from_birth_data("Brad Pitt", 1963, 12, 18, 6, 31, "Shawnee", "US", lng=-96.56, lat=35.20, tz_str="America/Chicago")
289
+
290
+ # Step 2: Create composite subject
291
+ factory = CompositeSubjectFactory(angelina, brad)
292
+ composite_model = factory.get_midpoint_composite_subject_model()
293
+
294
+ # Step 3: Pre-compute composite chart data
295
+ chart_data = ChartDataFactory.create_composite_chart_data(composite_model)
296
+
297
+ # Step 4: Create visualization
298
+ composite_chart = ChartDrawer(chart_data=chart_data)
299
+ composite_chart.save_svg()
300
+ ```
301
+
302
+ ![Angelina Jolie and Brad Pitt Composite Chart](https://raw.githubusercontent.com/g-battaglia/kerykeion/refs/heads/master/tests/charts/svg/Angelina%20Jolie%20and%20Brad%20Pitt%20Composite%20Chart%20-%20Composite%20Chart.svg)
303
+
304
+ ## Wheel Only Charts
305
+
306
+ For _all_ the charts, you can generate a wheel-only chart by using the method `makeWheelOnlySVG()`:
307
+
308
+ ### Birth Chart
309
+
310
+ ```python
311
+ from kerykeion import AstrologicalSubjectFactory
312
+ from kerykeion.chart_data_factory import ChartDataFactory
313
+ from kerykeion.charts.chart_drawer import ChartDrawer
314
+
315
+ # Step 1: Create subject
316
+ birth_chart = AstrologicalSubjectFactory.from_birth_data("John Lennon", 1940, 10, 9, 18, 30, "Liverpool", "GB")
317
+
318
+ # Step 2: Pre-compute chart data
319
+ chart_data = ChartDataFactory.create_natal_chart_data(birth_chart)
320
+
321
+ # Step 3: Create visualization
322
+ birth_chart_svg = ChartDrawer(chart_data=chart_data)
323
+ birth_chart_svg.save_wheel_only_svg_file()
324
+ ```
325
+
326
+ ![John Lennon Birth Chart](https://raw.githubusercontent.com/g-battaglia/kerykeion/refs/heads/master/tests/charts/svg/John%20Lennon%20-%20Wheel%20Only%20-%20Natal%20Chart%20-%20Wheel%20Only.svg)
327
+
328
+ ### Wheel Only Birth Chart (External)
329
+
330
+ ```python
331
+ from kerykeion import AstrologicalSubjectFactory
332
+ from kerykeion.chart_data_factory import ChartDataFactory
333
+ from kerykeion.charts.chart_drawer import ChartDrawer
334
+
335
+ # Step 1: Create subject
336
+ birth_chart = AstrologicalSubjectFactory.from_birth_data("John Lennon", 1940, 10, 9, 18, 30, "Liverpool", "GB")
337
+
338
+ # Step 2: Pre-compute external natal chart data
339
+ chart_data = ChartDataFactory.create_external_natal_chart_data(birth_chart)
340
+
341
+ # Step 3: Create visualization
342
+ birth_chart_svg = ChartDrawer(chart_data=chart_data)
343
+ birth_chart_svg.save_wheel_only_svg_file(
344
+ wheel_only=True,
345
+ wheel_only_external=True
346
+ )
347
+ ```
348
+
349
+ ![John Lennon Birth Chart](https://raw.githubusercontent.com/g-battaglia/kerykeion/refs/heads/master/tests/charts/svg/John%20Lennon%20-%20Wheel%20External%20Only%20-%20ExternalNatal%20Chart%20-%20Wheel%20Only.svg)
350
+
351
+ ### Synastry Chart
352
+
353
+ ```python
354
+ from kerykeion import AstrologicalSubjectFactory
355
+ from kerykeion.chart_data_factory import ChartDataFactory
356
+ from kerykeion.charts.chart_drawer import ChartDrawer
357
+
358
+ # Step 1: Create subjects
359
+ first = AstrologicalSubjectFactory.from_birth_data("John Lennon", 1940, 10, 9, 18, 30, "Liverpool", "GB")
360
+ second = AstrologicalSubjectFactory.from_birth_data("Paul McCartney", 1942, 6, 18, 15, 30, "Liverpool", "GB")
361
+
362
+ # Step 2: Pre-compute synastry chart data
363
+ chart_data = ChartDataFactory.create_synastry_chart_data(first, second)
364
+
365
+ # Step 3: Create visualization
366
+ synastry_chart = ChartDrawer(chart_data=chart_data)
367
+ synastry_chart.save_wheel_only_svg_file()
368
+ ```
369
+
370
+ ![John Lennon and Paul McCartney Synastry](https://raw.githubusercontent.com/g-battaglia/kerykeion/refs/heads/master/tests/charts/svg/John%20Lennon%20-%20Wheel%20Synastry%20Only%20-%20Synastry%20Chart%20-%20Wheel%20Only.svg)
371
+
372
+ ### Change the Output Directory
373
+
374
+ To save the SVG file in a custom location, specify the `output_path` parameter in `save_svg()`:
375
+
376
+ ```python
377
+ from kerykeion import AstrologicalSubjectFactory
378
+ from kerykeion.chart_data_factory import ChartDataFactory
379
+ from kerykeion.charts.chart_drawer import ChartDrawer
380
+
381
+ # Step 1: Create subjects
382
+ first = AstrologicalSubjectFactory.from_birth_data("John Lennon", 1940, 10, 9, 18, 30, "Liverpool", "GB")
383
+ second = AstrologicalSubjectFactory.from_birth_data("Paul McCartney", 1942, 6, 18, 15, 30, "Liverpool", "GB")
384
+
385
+ # Step 2: Pre-compute synastry chart data
386
+ chart_data = ChartDataFactory.create_synastry_chart_data(first, second)
387
+
388
+ # Step 3: Create visualization with custom output directory
389
+ synastry_chart = ChartDrawer(chart_data=chart_data)
390
+ synastry_chart.save_svg(output_path=".")
391
+ ```
392
+
393
+ ### Change Language
394
+
395
+ You can switch chart language by passing `chart_language` to the `ChartDrawer` class:
396
+
397
+ ```python
398
+ from kerykeion import AstrologicalSubjectFactory
399
+ from kerykeion.chart_data_factory import ChartDataFactory
400
+ from kerykeion.charts.chart_drawer import ChartDrawer
401
+
402
+ # Step 1: Create subject
403
+ birth_chart = AstrologicalSubjectFactory.from_birth_data("John Lennon", 1940, 10, 9, 18, 30, "Liverpool", "GB")
404
+
405
+ # Step 2: Pre-compute chart data
406
+ chart_data = ChartDataFactory.create_natal_chart_data(birth_chart)
407
+
408
+ # Step 3: Create visualization with Italian language
409
+ birth_chart_svg = ChartDrawer(
410
+ chart_data=chart_data,
411
+ chart_language="IT" # Change to Italian
412
+ )
413
+ birth_chart_svg.save_svg()
414
+
415
+ You can also provide custom labels (or introduce a brand-new language) by passing
416
+ a dictionary to `language_pack`. Only the keys you supply are merged on top of the
417
+ built-in strings:
418
+
419
+ ```python
420
+ custom_labels = {
421
+ "PT": {
422
+ "info": "Informações",
423
+ "celestial_points": {"Sun": "Sol", "Moon": "Lua"},
424
+ }
425
+ }
426
+
427
+ birth_chart_svg = ChartDrawer(
428
+ chart_data=chart_data,
429
+ chart_language="PT",
430
+ language_pack=custom_labels["PT"],
431
+ )
432
+ ```
433
+ ```
434
+
435
+ More details [here](https://www.kerykeion.net/docs/chart-language).
436
+
437
+ The available languages are:
438
+
439
+ - EN (English)
440
+ - FR (French)
441
+ - PT (Portuguese)
442
+ - ES (Spanish)
443
+ - TR (Turkish)
444
+ - RU (Russian)
445
+ - IT (Italian)
446
+ - CN (Chinese)
447
+ - DE (German)
448
+
449
+ ### Minified SVG
450
+
451
+ To generate a minified SVG, set `minify_svg=True` in the `makeSVG()` method:
452
+
453
+ ```python
454
+ from kerykeion import AstrologicalSubjectFactory
455
+ from kerykeion.chart_data_factory import ChartDataFactory
456
+ from kerykeion.charts.chart_drawer import ChartDrawer
457
+
458
+ # Step 1: Create subject
459
+ birth_chart = AstrologicalSubjectFactory.from_birth_data("John Lennon", 1940, 10, 9, 18, 30, "Liverpool", "GB")
460
+
461
+ # Step 2: Pre-compute chart data
462
+ chart_data = ChartDataFactory.create_natal_chart_data(birth_chart)
463
+
464
+ # Step 3: Create visualization
465
+ birth_chart_svg = ChartDrawer(chart_data=chart_data)
466
+ birth_chart_svg.save_svg(
467
+ minify=True
468
+ )
469
+ ```
470
+
471
+ ### SVG without CSS Variables
472
+
473
+ To generate an SVG without CSS variables, set `remove_css_variables=True` in the `makeSVG()` method:
474
+
475
+ ```python
476
+ from kerykeion import AstrologicalSubjectFactory
477
+ from kerykeion.chart_data_factory import ChartDataFactory
478
+ from kerykeion.charts.chart_drawer import ChartDrawer
479
+
480
+ # Step 1: Create subject
481
+ birth_chart = AstrologicalSubjectFactory.from_birth_data("John Lennon", 1940, 10, 9, 18, 30, "Liverpool", "GB")
482
+
483
+ # Step 2: Pre-compute chart data
484
+ chart_data = ChartDataFactory.create_natal_chart_data(birth_chart)
485
+
486
+ # Step 3: Create visualization
487
+ birth_chart_svg = ChartDrawer(chart_data=chart_data)
488
+ birth_chart_svg.save_svg(
489
+ remove_css_variables=True
490
+ )
491
+ ```
492
+
493
+ This will inline all styles and eliminate CSS variables, resulting in an SVG that is more broadly supported.
494
+
495
+ ### Grid Only SVG
496
+
497
+ It's possible to generate a grid-only SVG, useful for creating a custom layout. To do this, use the `save_aspect_grid_only_svg_file()` method:
498
+
499
+ ```python
500
+ from kerykeion import AstrologicalSubjectFactory
501
+ from kerykeion.chart_data_factory import ChartDataFactory
502
+ from kerykeion.charts.chart_drawer import ChartDrawer
503
+
504
+ # Step 1: Create subjects
505
+ birth_chart = AstrologicalSubjectFactory.from_birth_data("John Lennon", 1940, 10, 9, 18, 30, "Liverpool", "GB")
506
+ second = AstrologicalSubjectFactory.from_birth_data("Paul McCartney", 1942, 6, 18, 15, 30, "Liverpool", "GB")
507
+
508
+ # Step 2: Pre-compute synastry chart data
509
+ chart_data = ChartDataFactory.create_synastry_chart_data(birth_chart, second)
510
+
511
+ # Step 3: Create visualization with dark theme
512
+ aspect_grid_chart = ChartDrawer(chart_data=chart_data, theme="dark")
513
+ aspect_grid_chart.save_aspect_grid_only_svg_file()
514
+ ```
515
+
516
+ ![John Lennon Birth Chart](https://raw.githubusercontent.com/g-battaglia/kerykeion/refs/heads/master/tests/charts/svg/John%20Lennon%20-%20Aspect%20Grid%20Only%20-%20Natal%20Chart%20-%20Aspect%20Grid%20Only.svg)
517
+
518
+ ## Report Generator
519
+
520
+ `ReportGenerator` mirrors the chart-type dispatch of `ChartDrawer`. It accepts raw `AstrologicalSubjectModel` instances as well as any `ChartDataModel` produced by `ChartDataFactory`—including natal, composite, synastry, transit, and planetary return charts—and renders the appropriate textual report automatically.
521
+
522
+ ### Quick Examples
523
+
524
+ ```python
525
+ from kerykeion import ReportGenerator, AstrologicalSubjectFactory, ChartDataFactory
526
+
527
+ # Subject-only report
528
+ subject = AstrologicalSubjectFactory.from_birth_data(
529
+ "Sample Natal", 1990, 7, 21, 14, 45, "Rome", "IT"
530
+ )
531
+ ReportGenerator(subject).print_report(include_aspects=False)
532
+
533
+ # Single-chart data (elements, qualities, aspects enabled)
534
+ natal_data = ChartDataFactory.create_natal_chart_data(subject)
535
+ ReportGenerator(natal_data).print_report(max_aspects=10)
536
+
537
+ # Dual-chart data (synastry, transit, dual return, …)
538
+ partner = AstrologicalSubjectFactory.from_birth_data(
539
+ "Sample Partner", 1992, 11, 5, 9, 30, "Rome", "IT"
540
+ )
541
+ synastry_data = ChartDataFactory.create_synastry_chart_data(subject, partner)
542
+ ReportGenerator(synastry_data).print_report(max_aspects=12)
543
+ ```
544
+
545
+ Each report contains:
546
+
547
+ - A chart-aware title summarising the subject(s) and chart type
548
+ - Birth/event metadata and configuration settings
549
+ - Celestial points with sign, position, **daily motion**, **declination**, retrograde flag, and house
550
+ - House cusp tables for every subject involved
551
+ - Lunar phase details when available
552
+ - Element/quality distributions and active configuration summaries (for chart data)
553
+ - Aspect listings tailored for single or dual charts, with symbols for type and movement
554
+ - Dual-chart extras such as house comparisons and relationship scores (when provided by the data)
555
+
556
+ ### Section Access
557
+
558
+ All section helpers remain available for targeted output:
559
+
560
+ ```python
561
+ report = ReportGenerator(natal_data)
562
+ print(report.get_subject_data_report())
563
+ print(report.get_celestial_points_report())
564
+ print(report.get_elements_report())
565
+ print(report.get_aspects_report(max_aspects=5))
566
+ ```
567
+
568
+ Refer to the refreshed [Report Documentation](https://www.kerykeion.net/report/) for end-to-end examples covering every supported chart model.
569
+
570
+ ## Example: Retrieving Aspects
571
+
572
+ Kerykeion provides a unified `AspectsFactory` class for calculating astrological aspects within single charts or between two charts:
573
+
574
+ ```python
575
+ from kerykeion import AspectsFactory, AstrologicalSubjectFactory
576
+
577
+ # Create astrological subjects
578
+ jack = AstrologicalSubjectFactory.from_birth_data("Jack", 1990, 6, 15, 15, 15, "Roma", "IT")
579
+ jane = AstrologicalSubjectFactory.from_birth_data("Jane", 1991, 10, 25, 21, 0, "Roma", "IT")
580
+
581
+ # For single chart aspects (natal, return, composite, etc.)
582
+ single_chart_aspects = AspectsFactory.single_chart_aspects(jack)
583
+ print(f"Found {len(single_chart_aspects)} aspects in Jack's chart")
584
+ print(single_chart_aspects[0])
585
+ # Output: AspectModel with details like aspect type, orb, planets involved, etc.
586
+
587
+ # For dual chart aspects (synastry, transits, comparisons, etc.)
588
+ dual_chart_aspects = AspectsFactory.dual_chart_aspects(jack, jane)
589
+ print(f"Found {len(dual_chart_aspects)} aspects between Jack and Jane's charts")
590
+ print(dual_chart_aspects[0])
591
+ # Output: AspectModel with cross-chart aspect details
592
+
593
+ # The factory returns structured AspectModel objects with properties like:
594
+ # - p1_name, p2_name: Planet/point names
595
+ # - aspect: Aspect type (conjunction, trine, square, etc.)
596
+ # - orbit: Orb tolerance in degrees
597
+ # - aspect_degrees: Exact degrees for the aspect (0, 60, 90, 120, 180, etc.)
598
+ # - color: Hex color code for visualization
599
+ ```
600
+
601
+ **Advanced Usage with Custom Settings:**
602
+
603
+ ```python
604
+ # You can also customize aspect calculations with custom orb settings
605
+ from kerykeion.settings.config_constants import DEFAULT_ACTIVE_ASPECTS
606
+
607
+ # Modify aspect settings if needed
608
+ custom_aspects = DEFAULT_ACTIVE_ASPECTS.copy()
609
+ # ... modify as needed
610
+
611
+ # The factory automatically uses the configured settings for orb calculations
612
+ # and filters aspects based on relevance and orb thresholds
613
+ ```
614
+
615
+ ## Element & Quality Distribution Strategies
616
+
617
+ `ChartDataFactory` now offers two strategies for calculating element and modality totals. The default `"weighted"` mode leans on a curated map that emphasises core factors (for example `sun`, `moon`, and `ascendant` weight 2.0, angles such as `medium_coeli` 1.5, personal planets 1.5, social planets 1.0, outers 0.5, and minor bodies 0.3–0.8). Provide `distribution_method="pure_count"` when you want every active point to contribute equally.
618
+
619
+ You can refine the weighting without rebuilding the dictionary: pass lowercase point names to `custom_distribution_weights` and use `"__default__"` to override the fallback value applied to entries that are not listed explicitly.
620
+
621
+ ```python
622
+ from kerykeion import AstrologicalSubjectFactory, ChartDataFactory
623
+
624
+ subject = AstrologicalSubjectFactory.from_birth_data(
625
+ "Sample", 1986, 4, 12, 8, 45, "Bologna", "IT"
626
+ )
627
+
628
+ # Equal weighting: every active point counts once
629
+ pure_data = ChartDataFactory.create_natal_chart_data(
630
+ subject,
631
+ distribution_method="pure_count",
632
+ )
633
+
634
+ # Custom emphasis: boost the Sun, soften everything else
635
+ weighted_data = ChartDataFactory.create_natal_chart_data(
636
+ subject,
637
+ distribution_method="weighted",
638
+ custom_distribution_weights={
639
+ "sun": 3.0,
640
+ "__default__": 0.75,
641
+ },
642
+ )
643
+
644
+ print(pure_data.element_distribution.fire)
645
+ print(weighted_data.element_distribution.fire)
646
+ ```
647
+
648
+ All convenience helpers (`create_synastry_chart_data`, `create_transit_chart_data`, returns, and composites) forward the same keyword-only parameters, so you can keep a consistent weighting scheme across every chart type.
649
+
650
+ For an extended walkthrough (including category breakdowns of the default map), see `site-docs/element_quality_distribution.md`.
651
+
652
+ ## Ayanamsa (Sidereal Modes)
653
+
654
+ By default, the zodiac type is **Tropical**. To use **Sidereal**, specify the sidereal mode:
655
+
656
+ ```python
657
+ johnny = AstrologicalSubjectFactory.from_birth_data(
658
+ "Johnny Depp", 1963, 6, 9, 0, 0,
659
+ "Owensboro", "US",
660
+ zodiac_type="Sidereal",
661
+ sidereal_mode="LAHIRI"
662
+ )
663
+ ```
664
+
665
+ More examples [here](https://www.kerykeion.net/docs//sidereal-modes/).
666
+
667
+ Full list of supported sidereal modes [here](https://www.kerykeion.net/pydocs/kerykeion/schemas/kr_literals.html#SiderealMode).
668
+
669
+ ## House Systems
670
+
671
+ By default, houses are calculated using **Placidus**. Configure a different house system as follows:
672
+
673
+ ```python
674
+ johnny = AstrologicalSubjectFactory.from_birth_data(
675
+ "Johnny Depp", 1963, 6, 9, 0, 0,
676
+ "Owensboro", "US",
677
+ houses_system="M"
678
+ )
679
+ ```
680
+
681
+ More examples [here](https://www.kerykeion.net/docs//houses-systems/).
682
+
683
+ Full list of supported house systems [here](https://www.kerykeion.net/pydocs/kerykeion/schemas/kr_literals.html#HousesSystem).
684
+
685
+ So far all the available houses system in the Swiss Ephemeris are supported but the Gauquelin Sectors.
686
+
687
+ ## Perspective Type
688
+
689
+ By default, Kerykeion uses the **Apparent Geocentric** perspective (the most standard in astrology). Other perspectives (e.g., **Heliocentric**) can be set this way:
690
+
691
+ ```python
692
+ johnny = AstrologicalSubjectFactory.from_birth_data(
693
+ "Johnny Depp", 1963, 6, 9, 0, 0,
694
+ "Owensboro", "US",
695
+ perspective_type="Heliocentric"
696
+ )
697
+ ```
698
+
699
+ More examples [here](https://www.kerykeion.net/docs//perspective-type/).
700
+
701
+ Full list of supported perspective types [here](https://www.kerykeion.net/pydocs/kerykeion/schemas/kr_literals.html#PerspectiveType).
702
+
703
+ ## Themes
704
+
705
+ Kerykeion provides several chart themes:
706
+
707
+ - **Classic** (default)
708
+ - **Dark**
709
+ - **Dark High Contrast**
710
+ - **Light**
711
+ - **Strawberry**
712
+ - **Black & White** (optimized for monochrome printing)
713
+
714
+ Each theme offers a distinct visual style, allowing you to choose the one that best suits your preferences or presentation needs. If you prefer more control over the appearance, you can opt not to set any theme, making it easier to customize the chart by overriding the default CSS variables. For more detailed instructions on how to apply themes, check the [documentation](https://www.kerykeion.net/docs/theming)
715
+
716
+ The Black & White theme renders glyphs, rings, and aspects in solid black on light backgrounds, designed for crisp B/W prints (PDF or paper) without sacrificing legibility.
717
+
718
+ Here's an example of how to set the theme:
719
+
720
+ ```python
721
+ from kerykeion import AstrologicalSubjectFactory
722
+ from kerykeion.chart_data_factory import ChartDataFactory
723
+ from kerykeion.charts.chart_drawer import ChartDrawer
724
+
725
+ # Step 1: Create subject
726
+ dark_theme_subject = AstrologicalSubjectFactory.from_birth_data("John Lennon - Dark Theme", 1940, 10, 9, 18, 30, "Liverpool", "GB")
727
+
728
+ # Step 2: Pre-compute chart data
729
+ chart_data = ChartDataFactory.create_natal_chart_data(dark_theme_subject)
730
+
731
+ # Step 3: Create visualization with dark high contrast theme
732
+ dark_theme_natal_chart = ChartDrawer(chart_data=chart_data, theme="dark-high-contrast")
733
+ dark_theme_natal_chart.save_svg()
734
+ ```
735
+
736
+ ![John Lennon](https://www.kerykeion.net/img/showcase/John%20Lennon%20-%20Dark%20-%20Natal%20Chart.svg)
737
+
738
+ ## Alternative Initialization
739
+
740
+ Create an `AstrologicalSubject` from a UTC ISO 8601 string:
741
+
742
+ ```python
743
+ subject = AstrologicalSubject.get_from_iso_utc_time(
744
+ "Johnny Depp", "1963-06-09T05:00:00Z", "Owensboro", "US"
745
+ )
746
+ ```
747
+
748
+ If you set `online=True`, provide a `geonames_username` to allow city-based geolocation:
749
+
750
+ ```python
751
+ from kerykeion.astrological_subject import AstrologicalSubjectFactory
752
+
753
+ subject = AstrologicalSubject.get_from_iso_utc_time(
754
+ "Johnny Depp", "1963-06-09T05:00:00Z", "Owensboro", "US", online=True
755
+ )
756
+ ```
757
+
758
+ ## Lunar Nodes (Rahu & Ketu)
759
+
760
+ Kerykeion supports both **True** and **Mean** Lunar Nodes:
761
+
762
+ - **True North Lunar Node**: `"true_node"` (name kept without "north" for backward compatibility).
763
+ - **True South Lunar Node**: `"true_south_node"`.
764
+ - **Mean North Lunar Node**: `"mean_node"` (name kept without "north" for backward compatibility).
765
+ - **Mean South Lunar Node**: `"mean_south_node"`.
766
+
767
+ In instances of the classes used to generate aspects and SVG charts, only the mean nodes are active. To activate the true nodes, you need to pass the `active_points` parameter to the `ChartDataFactory` methods.
768
+
769
+ Example:
770
+
771
+ ```python
772
+ from kerykeion import AstrologicalSubjectFactory
773
+ from kerykeion.chart_data_factory import ChartDataFactory
774
+ from kerykeion.charts.chart_drawer import ChartDrawer
775
+
776
+ # Step 1: Create subject
777
+ subject = AstrologicalSubjectFactory.from_birth_data("John Lennon", 1940, 10, 9, 18, 30, "Liverpool", "GB")
778
+
779
+ # Step 2: Pre-compute chart data with custom active points including true nodes
780
+ chart_data = ChartDataFactory.create_natal_chart_data(
781
+ subject,
782
+ active_points=[
783
+ "Sun",
784
+ "Moon",
785
+ "Mercury",
786
+ "Venus",
787
+ "Mars",
788
+ "Jupiter",
789
+ "Saturn",
790
+ "Uranus",
791
+ "Neptune",
792
+ "Pluto",
793
+ "Mean_Node",
794
+ "Mean_South_Node",
795
+ "True_Node", # Activates True North Node
796
+ "True_South_Node", # Activates True South Node
797
+ "Ascendant",
798
+ "Medium_Coeli",
799
+ "Descendant",
800
+ "Imum_Coeli"
801
+ ]
802
+ )
803
+
804
+ # Step 3: Create visualization
805
+ chart = ChartDrawer(chart_data=chart_data)
806
+ chart.save_svg()
807
+ ```
808
+
809
+ ## JSON Support
810
+
811
+ You can serialize the astrological subject (the base data used throughout the library) to JSON:
812
+
813
+ ```python
814
+ from kerykeion import AstrologicalSubjectFactory
815
+
816
+ johnny = AstrologicalSubjectFactory.from_birth_data("Johnny Depp", 1963, 6, 9, 0, 0, "Owensboro", "US")
817
+
818
+ print(johnny.json(dump=False, indent=2))
819
+ ```
820
+
821
+ ## Auto Generated Documentation
822
+
823
+ You can find auto-generated documentation [here](https://www.kerykeion.net/pydocs/kerykeion.html). Most classes and functions include docstrings.
824
+
825
+ ## Development
826
+
827
+ Clone the repository or download the ZIP via the GitHub interface.
828
+
829
+ ## Kerykeion v5.0 – What's New
830
+
831
+ Kerykeion v5 is a **complete redesign** that modernizes the library with a data-first approach, factory-based architecture, and Pydantic 2 models. This version brings significant improvements in API design, type safety, and extensibility.
832
+
833
+ ### 🎯 Key Highlights
834
+
835
+ #### Factory-Centered Architecture
836
+
837
+ The old class-based approach has been replaced with a modern factory pattern:
838
+
839
+ - **`AstrologicalSubjectFactory`**: Replaces the old `AstrologicalSubject` class
840
+ - **`ChartDataFactory`**: Pre-computes enriched chart data (elements, qualities, aspects)
841
+ - **`ChartDrawer`**: Pure SVG rendering separated from calculations
842
+ - **`AspectsFactory`**: Unified aspects calculation for natal and synastry charts
843
+ - **`PlanetaryReturnFactory`**: Solar and Lunar returns computation
844
+ - **`HouseComparisonFactory`**: House overlay analysis for synastry
845
+ - **`RelationshipScoreFactory`**: Compatibility scoring between charts
846
+
847
+ **Old v4 API:**
848
+
849
+ ```python
850
+ from kerykeion import AstrologicalSubject, KerykeionChartSVG
851
+
852
+ # v4 - Class-based approach
853
+ subject = AstrologicalSubject("John", 1990, 1, 1, 12, 0, "London", "GB")
854
+ chart = KerykeionChartSVG(subject)
855
+ chart.makeSVG()
856
+ ```
857
+
858
+ **New v5 API:**
859
+
860
+ ```python
861
+ from kerykeion import AstrologicalSubjectFactory, ChartDataFactory, ChartDrawer
862
+
863
+ # v5 - Factory-based approach with separation of concerns
864
+ subject = AstrologicalSubjectFactory.from_birth_data("John", 1990, 1, 1, 12, 0, "London", "GB")
865
+ chart_data = ChartDataFactory.create_natal_chart_data(subject)
866
+ drawer = ChartDrawer(chart_data=chart_data)
867
+ drawer.save_svg()
868
+ ```
869
+
870
+ #### Pydantic 2 Models & Type Safety
871
+
872
+ All data structures are now strongly typed Pydantic models:
873
+
874
+ - **`AstrologicalSubjectModel`**: Subject data with full validation
875
+ - **`ChartDataModel`**: Enriched chart data with elements, qualities, aspects
876
+ - **`SingleChartAspectsModel` / `DualChartAspectsModel`**: Typed aspect collections
877
+ - **`PlanetReturnModel`**: Planetary return data
878
+ - **`ElementDistributionModel`**: Element statistics (fire, earth, air, water)
879
+ - **`QualityDistributionModel`**: Quality statistics (cardinal, fixed, mutable)
880
+
881
+ All models support:
882
+
883
+ - JSON serialization/deserialization
884
+ - Dictionary export
885
+ - Subscript access
886
+ - Full IDE autocomplete and type checking
887
+
888
+ #### Enhanced Features
889
+
890
+ - **Speed & Declination**: All celestial points now include daily motion speed and declination
891
+ - **Element & Quality Analysis**: Automatic calculation of element/quality distributions
892
+ - **Relationship Scoring**: Built-in compatibility analysis for synastry
893
+ - **House Comparison**: Detailed house overlay analysis
894
+ - **Transit Time Ranges**: Advanced transit tracking over time periods
895
+ - **Report Module**: Comprehensive text reports with ASCII tables
896
+ - **Axis Orb Control**: Chart axes now share the same orb as planets by default; pass the keyword-only `axis_orb_limit` to return to a traditional, tighter axis filtering when you need it.
897
+ - **Element Weight Strategies**: Element and quality stats now default to a curated weighted balance; pass `distribution_method` or `custom_distribution_weights` when you need equal counts or bespoke weightings (including a `__default__` fallback) across any chart factory helper.
898
+
899
+ ### 🚨 Breaking Changes
900
+
901
+ #### 1. Removed Legacy Classes
902
+
903
+ The following classes have been **completely removed** and must be replaced:
904
+
905
+ | Removed (v4) | Replacement (v5) |
906
+ | ---------------------- | ---------------------------------------------- |
907
+ | `AstrologicalSubject` | `AstrologicalSubjectFactory.from_birth_data()` |
908
+ | `KerykeionChartSVG` | `ChartDrawer` + `ChartDataFactory` |
909
+ | `NatalAspects` | `AspectsFactory.single_chart_aspects()` |
910
+ | `SynastryAspects` | `AspectsFactory.dual_chart_aspects()` |
911
+ | `relationship_score()` | `RelationshipScoreFactory` |
912
+
913
+ **Note**: The `kerykeion.backword` module provides temporary wrappers for `AstrologicalSubject` and `KerykeionChartSVG` with deprecation warnings. These will be **removed in v6.0**.
914
+
915
+ #### 2. Import Changes
916
+
917
+ Module structure has been completely reorganized:
918
+
919
+ **Old imports (v4):**
920
+
921
+ ```python
922
+ from kerykeion import AstrologicalSubject, KerykeionChartSVG
923
+ from kerykeion.kr_types import KerykeionException
924
+ from kerykeion.kr_types.kr_literals import Planet, AxialCusps
925
+ ```
926
+
927
+ **New imports (v5):**
928
+
929
+ ```python
930
+ from kerykeion import AstrologicalSubjectFactory, ChartDataFactory, ChartDrawer
931
+ from kerykeion.schemas import KerykeionException
932
+ from kerykeion.schemas.kr_literals import AstrologicalPoint
933
+ ```
934
+
935
+ **Backward compatibility (v5 only, removed in v6.0):**
936
+
937
+ ```python
938
+ # Old kr_types imports still work with deprecation warnings
939
+ from kerykeion.kr_types import Planet, AxialCusps # Shows warning
940
+ from kerykeion.schemas import Planet, AxialCusps # Works, no warning
941
+ ```
942
+
943
+ #### 3. Type Aliases Unified
944
+
945
+ **Old (v4):** `Planet` and `AxialCusps` were separate types
946
+ **New (v5):** Unified as `AstrologicalPoint`
947
+
948
+ ```python
949
+ # v4
950
+ from kerykeion.kr_types.kr_literals import Planet, AxialCusps
951
+
952
+ # v5 (recommended)
953
+ from kerykeion.schemas.kr_literals import AstrologicalPoint
954
+
955
+ # v5 (transition, uses aliases)
956
+ from kerykeion.schemas import Planet, AxialCusps # Still available
957
+ ```
958
+
959
+ #### 4. Lunar Nodes Naming
960
+
961
+ All lunar node fields have been renamed for clarity:
962
+
963
+ | Old Name (v4) | New Name (v5) |
964
+ | ----------------- | ----------------------- |
965
+ | `Mean_Node` | `Mean_North_Lunar_Node` |
966
+ | `True_Node` | `True_North_Lunar_Node` |
967
+ | `Mean_South_Node` | `Mean_South_Lunar_Node` |
968
+ | `True_South_Node` | `True_South_Lunar_Node` |
969
+
970
+ **Migration example:**
971
+
972
+ ```python
973
+ # v4
974
+ print(subject.mean_node)
975
+
976
+ # v5
977
+ print(subject.mean_north_lunar_node)
978
+ ```
979
+
980
+ #### 5. Axis Orb Filtering
981
+
982
+ Modern default orbs now treat chart axes (ASC, MC, DSC, IC) exactly like planets. If you prefer a traditional, constrained approach, every public aspect factory exposes the keyword-only `axis_orb_limit` parameter so you can set a dedicated threshold when needed.
983
+
984
+ #### 6. Chart Generation Changes
985
+
986
+ The two-step process (data + rendering) is now required:
987
+
988
+ **Old v4:**
989
+
990
+ ```python
991
+ chart = KerykeionChartSVG(subject)
992
+ chart.makeSVG()
993
+ ```
994
+
995
+ **New v5:**
996
+
997
+ ```python
998
+ chart_data = ChartDataFactory.create_natal_chart_data(subject)
999
+ drawer = ChartDrawer(chart_data=chart_data)
1000
+ drawer.save_svg()
1001
+ ```
1002
+
1003
+ #### 7. Aspects API Changes
1004
+
1005
+ Aspects are now calculated through the factory:
1006
+
1007
+ **Old v4:**
1008
+
1009
+ ```python
1010
+ from kerykeion import NatalAspects, SynastryAspects
1011
+
1012
+ natal_aspects = NatalAspects(subject)
1013
+ synastry_aspects = SynastryAspects(subject1, subject2)
1014
+ ```
1015
+
1016
+ **New v5:**
1017
+
1018
+ ```python
1019
+ from kerykeion import AspectsFactory
1020
+
1021
+ natal_aspects = AspectsFactory.single_chart_aspects(subject)
1022
+ synastry_aspects = AspectsFactory.dual_chart_aspects(subject1, subject2)
1023
+ ```
1024
+
1025
+ ### 🔄 Migration Guide
1026
+
1027
+ #### Using the Backward Compatibility Layer
1028
+
1029
+ For a gradual migration, use the `kerykeion.backword` module:
1030
+
1031
+ ```python
1032
+ from kerykeion import AstrologicalSubject # Legacy wrapper
1033
+
1034
+ subject = AstrologicalSubject("John Doe", 1990, 1, 1, 12, 0, "London", "GB")
1035
+
1036
+ # These still work but show DeprecationWarnings
1037
+ print(subject.mean_node) # Maps to mean_north_lunar_node
1038
+ print(subject.true_node) # Maps to true_north_lunar_node
1039
+ ```
1040
+
1041
+ **⚠️ Warning**: This compatibility layer will be **removed in v6.0**.
1042
+
1043
+ #### Step-by-Step Migration
1044
+
1045
+ 1. **Update imports**
1046
+
1047
+ ```python
1048
+ # Old
1049
+ from kerykeion import AstrologicalSubject, KerykeionChartSVG
1050
+
1051
+ # New
1052
+ from kerykeion import AstrologicalSubjectFactory, ChartDataFactory, ChartDrawer
1053
+ ```
1054
+
1055
+ 2. **Update subject creation**
1056
+
1057
+ ```python
1058
+ # Old
1059
+ subject = AstrologicalSubject("John", 1990, 1, 1, 12, 0, "London", "GB")
1060
+
1061
+ # New
1062
+ subject = AstrologicalSubjectFactory.from_birth_data("John", 1990, 1, 1, 12, 0, "London", "GB")
1063
+ ```
1064
+
1065
+ 3. **Update chart generation**
1066
+
1067
+ ```python
1068
+ # Old
1069
+ chart = KerykeionChartSVG(subject)
1070
+ chart.makeSVG()
1071
+
1072
+ # New
1073
+ chart_data = ChartDataFactory.create_natal_chart_data(subject)
1074
+ drawer = ChartDrawer(chart_data=chart_data)
1075
+ drawer.save_svg()
1076
+ ```
1077
+
1078
+ 4. **Update field access** (lunar nodes)
1079
+
1080
+ ```python
1081
+ # Old
1082
+ print(subject.mean_node.position)
1083
+
1084
+ # New
1085
+ print(subject.mean_north_lunar_node.position)
1086
+ ```
1087
+
1088
+ 5. **Update aspects**
1089
+
1090
+ ```python
1091
+ # Old
1092
+ from kerykeion import NatalAspects
1093
+ aspects = NatalAspects(subject)
1094
+
1095
+ # New
1096
+ from kerykeion import AspectsFactory
1097
+ aspects = AspectsFactory.single_chart_aspects(subject)
1098
+ ```
1099
+
1100
+ #### Automated Migration Script
1101
+
1102
+ Use this sed script to update Python files automatically:
1103
+
1104
+ ```bash
1105
+ # Update lunar node references
1106
+ find . -name "*.py" -type f -exec sed -i.bak \
1107
+ -e 's/\.mean_node/.mean_north_lunar_node/g' \
1108
+ -e 's/\.true_node/.true_north_lunar_node/g' \
1109
+ -e 's/\.mean_south_node/.mean_south_lunar_node/g' \
1110
+ -e 's/\.true_south_node/.true_south_lunar_node/g' \
1111
+ -e 's/"Mean_Node"/"Mean_North_Lunar_Node"/g' \
1112
+ -e 's/"True_Node"/"True_North_Lunar_Node"/g' \
1113
+ -e 's/"Mean_South_Node"/"Mean_South_Lunar_Node"/g' \
1114
+ -e 's/"True_South_Node"/"True_South_Lunar_Node"/g' \
1115
+ {} \;
1116
+ ```
1117
+
1118
+ **Note**: Always review automated changes and test thoroughly before committing.
1119
+
1120
+ ### 📦 Other Notable Changes
1121
+
1122
+ - **Packaging**: Migrated from Poetry to PEP 621 + Hatchling with `uv.lock`
1123
+ - **Settings**: Centralized in `kerykeion.schemas` and `kerykeion.settings`
1124
+ - **Configuration**: Default chart presets consolidated in `kerykeion/settings/chart_defaults.py`
1125
+ - **Type System**: All literals consolidated in `kr_literals.py`
1126
+ - **Performance**: Caching improvements with `functools.lru_cache`
1127
+ - **Testing**: 376 tests with 87% coverage, regenerated fixtures for v5
1128
+
1129
+ ### 🎨 New Themes
1130
+
1131
+ Additional chart themes added:
1132
+
1133
+ - `classic` (default)
1134
+ - `dark`
1135
+ - `dark-high-contrast`
1136
+ - `light`
1137
+ - `strawberry`
1138
+ - `black-and-white`
1139
+
1140
+ ### 📚 Resources
1141
+
1142
+ - **Full Release Notes**: [v5.0.0.md](release_notes/v5.0.0b1.md)
1143
+ - **Documentation**: [kerykeion.readthedocs.io](https://kerykeion.readthedocs.io)
1144
+ - **API Reference**: [kerykeion.net/pydocs](https://www.kerykeion.net/pydocs/kerykeion.html)
1145
+ - **Examples**: See the `examples/` folder for runnable code
1146
+ - **Support**: [GitHub Discussions](https://github.com/g-battaglia/kerykeion/discussions)
1147
+
1148
+ **Migration Timeline:**
1149
+
1150
+ - **v5.0**: Current - Backward compatibility layer available
1151
+ - **v6.0**: Future - Compatibility layer will be removed
1152
+
1153
+ ## Integrating Kerykeion into Your Project
1154
+
1155
+ If you would like to incorporate Kerykeion's astrological features into your application, please reach out via [email](mailto:kerykeion.astrology@gmail.com?subject=Integration%20Request). Whether you need custom features, support, or specialized consulting, I am happy to discuss potential collaborations.
1156
+
1157
+ ## License
1158
+
1159
+ This project is covered under the AGPL-3.0 License. For detailed information, please see the [LICENSE](LICENSE) file. If you have questions, feel free to contact me at [kerykeion.astrology@gmail.com](mailto:kerykeion.astrology@gmail.com?subject=Kerykeion).
1160
+
1161
+ As a rule of thumb, if you use this library in a project, you should open-source that project under a compatible license. Alternatively, if you wish to keep your source closed, consider using the [AstrologerAPI](https://rapidapi.com/gbattaglia/api/astrologer/), which is AGPL-3.0 compliant and also helps support the project.
1162
+
1163
+ Since the AstrologerAPI is an external third-party service, using it does _not_ require your code to be open-source.
1164
+
1165
+ ## Contributing
1166
+
1167
+ Contributions are welcome! Feel free to submit pull requests or report issues.
1168
+
1169
+ ## Citations
1170
+
1171
+ If using Kerykeion in published or academic work, please cite as follows:
1172
+
1173
+ ```
1174
+ Battaglia, G. (2025). Kerykeion: A Python Library for Astrological Calculations and Chart Generation.
1175
+ https://github.com/g-battaglia/kerykeion
1176
+ ```