kerykeion 5.0.1__py3-none-any.whl → 5.1.8__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.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kerykeion
3
- Version: 5.0.1
3
+ Version: 5.1.8
4
4
  Summary: A Python library for astrological calculations, including natal charts, houses, planetary aspects, and SVG chart generation.
5
5
  Project-URL: Homepage, https://www.kerykeion.net/
6
6
  Project-URL: Repository, https://github.com/g-battaglia/kerykeion
@@ -68,7 +68,7 @@ Here is an example of a birthchart:
68
68
 
69
69
  ## **Web API**
70
70
 
71
- If you want to use Kerykeion in a web application, you can try the dedicated web API:
71
+ If you want to use Kerykeion in a web application or for commercial or *closed-source* purposes, you can try the dedicated web API:
72
72
 
73
73
  **[AstrologerAPI](https://rapidapi.com/gbattaglia/api/astrologer/pricing)**
74
74
 
@@ -86,12 +86,17 @@ Maintaining this project requires substantial time and effort. The Astrologer AP
86
86
  - [**Donate**](#donate)
87
87
  - [Table of Contents](#table-of-contents)
88
88
  - [Installation](#installation)
89
+ - [Quick Start](#quick-start)
90
+ - [Documentation Map](#documentation-map)
89
91
  - [Basic Usage](#basic-usage)
90
92
  - [Generate a SVG Chart](#generate-a-svg-chart)
91
93
  - [Birth Chart](#birth-chart)
92
94
  - [External Birth Chart](#external-birth-chart)
93
95
  - [Synastry Chart](#synastry-chart)
94
96
  - [Transit Chart](#transit-chart)
97
+ - [Solar Return Chart (Dual Wheel)](#solar-return-chart-dual-wheel)
98
+ - [Solar Return Chart (Single Wheel)](#solar-return-chart-single-wheel)
99
+ - [Lunar Return Chart](#lunar-return-chart)
95
100
  - [Composite Chart](#composite-chart)
96
101
  - [Wheel Only Charts](#wheel-only-charts)
97
102
  - [Birth Chart](#birth-chart-1)
@@ -99,6 +104,7 @@ Maintaining this project requires substantial time and effort. The Astrologer AP
99
104
  - [Synastry Chart](#synastry-chart-1)
100
105
  - [Change the Output Directory](#change-the-output-directory)
101
106
  - [Change Language](#change-language)
107
+ - [Minified SVG](#minified-svg)
102
108
  - [SVG without CSS Variables](#svg-without-css-variables)
103
109
  - [Grid Only SVG](#grid-only-svg)
104
110
  - [Report Generator](#report-generator)
@@ -148,6 +154,48 @@ Kerykeion requires **Python 3.9** or higher.
148
154
  pip3 install kerykeion
149
155
  ```
150
156
 
157
+ ## Quick Start
158
+
159
+ ```python
160
+ from pathlib import Path
161
+ from kerykeion import AstrologicalSubjectFactory
162
+ from kerykeion.chart_data_factory import ChartDataFactory
163
+ from kerykeion.charts.chart_drawer import ChartDrawer
164
+
165
+ subject = AstrologicalSubjectFactory.from_birth_data(
166
+ name="Example Person",
167
+ year=1990, month=7, day=15,
168
+ hour=10, minute=30,
169
+ lng=12.4964,
170
+ lat=41.9028,
171
+ tz_str="Europe/Rome",
172
+ online=False,
173
+ )
174
+
175
+ chart_data = ChartDataFactory.create_natal_chart_data(subject)
176
+ chart_drawer = ChartDrawer(chart_data=chart_data)
177
+
178
+ output_dir = Path("charts_output")
179
+ output_dir.mkdir(exist_ok=True)
180
+
181
+ chart_drawer.save_svg(output_path=output_dir, filename="example-natal")
182
+ print("Chart saved to", (output_dir / "example-natal.svg").resolve())
183
+ ```
184
+
185
+ This script shows the recommended workflow:
186
+ 1. Create an `AstrologicalSubject` with explicit coordinates and timezone (offline mode).
187
+ 2. Build a `ChartDataModel` through `ChartDataFactory`.
188
+ 3. Render the SVG via `ChartDrawer`, saving it to a controlled folder (`charts_output`).
189
+
190
+ Use the same pattern for synastry, composite, transit, or return charts by swapping the factory method.
191
+
192
+ ## Documentation Map
193
+
194
+ - **README (this file):** Quick start, common recipes, and v5 migration notes.
195
+ - **`site-docs/` (offline Markdown guides):** Deep dives for each factory (`chart_data_factory.md`, `charts.md`, `planetary_return_factory.md`, etc.) with runnable snippets. Run `python scripts/test_markdown_snippets.py site-docs` to validate them locally.
196
+ - **[Auto-generated API Reference](https://www.kerykeion.net/pydocs/kerykeion.html):** Detailed model and function signatures straight from the codebase.
197
+ - **[Kerykeion website](https://www.kerykeion.net/docs/):** Rendered documentation with additional context, tutorials, and showcase material.
198
+
151
199
  ## Basic Usage
152
200
 
153
201
  Below is a simple example illustrating the creation of an astrological subject and retrieving astrological details:
@@ -157,7 +205,13 @@ from kerykeion import AstrologicalSubjectFactory
157
205
 
158
206
  # Create an instance of the AstrologicalSubjectFactory class.
159
207
  # Arguments: Name, year, month, day, hour, minutes, city, nation
160
- john = AstrologicalSubjectFactory.from_birth_data("John Lennon", 1940, 10, 9, 18, 30, "Liverpool", "GB")
208
+ john = AstrologicalSubjectFactory.from_birth_data(
209
+ "John Lennon", 1940, 10, 9, 18, 30,
210
+ lng=-2.9833,
211
+ lat=53.4,
212
+ tz_str="Europe/London",
213
+ online=False,
214
+ )
161
215
 
162
216
  # Retrieve information about the Sun:
163
217
  print(john.sun.model_dump_json())
@@ -172,6 +226,9 @@ print(john.moon.element)
172
226
  # > 'Air'
173
227
  ```
174
228
 
229
+ > **Working offline:** pass `online=False` and specify `lng`, `lat`, and `tz_str` as shown above.
230
+ > **Working online:** set `online=True` and provide `city`, `nation`, and a valid GeoNames username (see `AstrologicalSubjectFactory.from_birth_data()` for details).
231
+
175
232
  **To avoid using GeoNames online, specify longitude, latitude, and timezone instead of city and nation:**
176
233
 
177
234
  ```python
@@ -186,6 +243,8 @@ john = AstrologicalSubjectFactory.from_birth_data(
186
243
 
187
244
  ## Generate a SVG Chart
188
245
 
246
+ All chart-rendering examples below create a local `charts_output/` folder so the tests can write without touching your home directory. Feel free to change the path when integrating into your own projects.
247
+
189
248
  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
249
 
191
250
  **Tip:**
@@ -195,40 +254,60 @@ To improve compatibility across different applications, you can use the `remove_
195
254
  ### Birth Chart
196
255
 
197
256
  ```python
257
+ from pathlib import Path
198
258
  from kerykeion import AstrologicalSubjectFactory
199
259
  from kerykeion.chart_data_factory import ChartDataFactory
200
260
  from kerykeion.charts.chart_drawer import ChartDrawer
201
261
 
202
262
  # Step 1: Create subject
203
- john = AstrologicalSubjectFactory.from_birth_data("John Lennon", 1940, 10, 9, 18, 30, "Liverpool", "GB")
263
+ john = AstrologicalSubjectFactory.from_birth_data(
264
+ "John Lennon", 1940, 10, 9, 18, 30,
265
+ lng=-2.9833,
266
+ lat=53.4,
267
+ tz_str="Europe/London",
268
+ online=False,
269
+ )
204
270
 
205
271
  # Step 2: Pre-compute chart data
206
272
  chart_data = ChartDataFactory.create_natal_chart_data(john)
207
273
 
208
274
  # Step 3: Create visualization
209
275
  birth_chart_svg = ChartDrawer(chart_data=chart_data)
210
- birth_chart_svg.save_svg()
276
+
277
+ output_dir = Path("charts_output")
278
+ output_dir.mkdir(exist_ok=True)
279
+ birth_chart_svg.save_svg(output_path=output_dir, filename="john-lennon-natal")
211
280
  ```
212
281
 
213
- The SVG file will be saved in the home directory.
282
+ The SVG file is saved under `charts_output/john-lennon-natal.svg`.
214
283
  ![John Lennon Birth Chart](https://raw.githubusercontent.com/g-battaglia/kerykeion/refs/heads/main/tests/charts/svg/John%20Lennon%20-%20Natal%20Chart.svg)
215
284
 
216
285
  ### External Birth Chart
217
286
 
218
287
  ```python
288
+ from pathlib import Path
219
289
  from kerykeion import AstrologicalSubjectFactory
220
290
  from kerykeion.chart_data_factory import ChartDataFactory
221
291
  from kerykeion.charts.chart_drawer import ChartDrawer
222
292
 
223
293
  # Step 1: Create subject
224
- birth_chart = AstrologicalSubjectFactory.from_birth_data("John Lennon", 1940, 10, 9, 18, 30, "Liverpool", "GB")
294
+ birth_chart = AstrologicalSubjectFactory.from_birth_data(
295
+ "John Lennon", 1940, 10, 9, 18, 30,
296
+ lng=-2.9833,
297
+ lat=53.4,
298
+ tz_str="Europe/London",
299
+ online=False,
300
+ )
225
301
 
226
302
  # Step 2: Pre-compute chart data for external natal chart
227
- chart_data = ChartDataFactory.create_external_natal_chart_data(birth_chart)
303
+ chart_data = ChartDataFactory.create_natal_chart_data(birth_chart)
228
304
 
229
305
  # Step 3: Create visualization
230
306
  birth_chart_svg = ChartDrawer(chart_data=chart_data)
231
- birth_chart_svg.save_svg()
307
+
308
+ output_dir = Path("charts_output")
309
+ output_dir.mkdir(exist_ok=True)
310
+ birth_chart_svg.save_svg(output_path=output_dir, filename="john-lennon-natal-external")
232
311
  ```
233
312
 
234
313
  ![John Lennon External Birth Chart](https://raw.githubusercontent.com/g-battaglia/kerykeion/refs/heads/main/tests/charts/svg/John%20Lennon%20-%20ExternalNatal%20-%20Natal%20Chart.svg)
@@ -236,20 +315,36 @@ birth_chart_svg.save_svg()
236
315
  ### Synastry Chart
237
316
 
238
317
  ```python
318
+ from pathlib import Path
239
319
  from kerykeion import AstrologicalSubjectFactory
240
320
  from kerykeion.chart_data_factory import ChartDataFactory
241
321
  from kerykeion.charts.chart_drawer import ChartDrawer
242
322
 
243
323
  # 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")
324
+ first = AstrologicalSubjectFactory.from_birth_data(
325
+ "John Lennon", 1940, 10, 9, 18, 30,
326
+ lng=-2.9833,
327
+ lat=53.4,
328
+ tz_str="Europe/London",
329
+ online=False,
330
+ )
331
+ second = AstrologicalSubjectFactory.from_birth_data(
332
+ "Paul McCartney", 1942, 6, 18, 15, 30,
333
+ lng=-2.9833,
334
+ lat=53.4,
335
+ tz_str="Europe/London",
336
+ online=False,
337
+ )
246
338
 
247
339
  # Step 2: Pre-compute synastry chart data
248
340
  chart_data = ChartDataFactory.create_synastry_chart_data(first, second)
249
341
 
250
342
  # Step 3: Create visualization
251
343
  synastry_chart = ChartDrawer(chart_data=chart_data)
252
- synastry_chart.save_svg()
344
+
345
+ output_dir = Path("charts_output")
346
+ output_dir.mkdir(exist_ok=True)
347
+ synastry_chart.save_svg(output_path=output_dir, filename="lennon-mccartney-synastry")
253
348
  ```
254
349
 
255
350
  ![John Lennon and Paul McCartney Synastry](https://www.kerykeion.net/img/examples/synastry-chart.svg)
@@ -257,35 +352,192 @@ synastry_chart.save_svg()
257
352
  ### Transit Chart
258
353
 
259
354
  ```python
355
+ from pathlib import Path
260
356
  from kerykeion import AstrologicalSubjectFactory
261
357
  from kerykeion.chart_data_factory import ChartDataFactory
262
358
  from kerykeion.charts.chart_drawer import ChartDrawer
263
359
 
264
360
  # 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")
361
+ transit = AstrologicalSubjectFactory.from_birth_data(
362
+ "Transit", 2025, 6, 8, 8, 45,
363
+ lng=-84.3880,
364
+ lat=33.7490,
365
+ tz_str="America/New_York",
366
+ online=False,
367
+ )
368
+ subject = AstrologicalSubjectFactory.from_birth_data(
369
+ "John Lennon", 1940, 10, 9, 18, 30,
370
+ lng=-2.9833,
371
+ lat=53.4,
372
+ tz_str="Europe/London",
373
+ online=False,
374
+ )
267
375
 
268
376
  # Step 2: Pre-compute transit chart data
269
377
  chart_data = ChartDataFactory.create_transit_chart_data(subject, transit)
270
378
 
271
379
  # Step 3: Create visualization
272
380
  transit_chart = ChartDrawer(chart_data=chart_data)
273
- transit_chart.save_svg()
381
+
382
+ output_dir = Path("charts_output")
383
+ output_dir.mkdir(exist_ok=True)
384
+ transit_chart.save_svg(output_path=output_dir, filename="john-lennon-transit")
274
385
  ```
275
386
 
276
387
  ![John Lennon Transit Chart](https://raw.githubusercontent.com/g-battaglia/kerykeion/refs/heads/main/tests/charts/svg/John%20Lennon%20-%20Transit%20Chart.svg)
277
388
 
389
+ ### Solar Return Chart (Dual Wheel)
390
+
391
+ ```python
392
+ from pathlib import Path
393
+ from kerykeion import AstrologicalSubjectFactory
394
+ from kerykeion.planetary_return_factory import PlanetaryReturnFactory
395
+ from kerykeion.chart_data_factory import ChartDataFactory
396
+ from kerykeion.charts.chart_drawer import ChartDrawer
397
+
398
+ # Step 1: Create natal subject
399
+ john = AstrologicalSubjectFactory.from_birth_data(
400
+ "John Lennon", 1940, 10, 9, 18, 30,
401
+ lng=-2.9833,
402
+ lat=53.4,
403
+ tz_str="Europe/London",
404
+ online=False,
405
+ )
406
+
407
+ # Step 2: Calculate Solar Return subject (offline example with manual coordinates)
408
+ return_factory = PlanetaryReturnFactory(
409
+ john,
410
+ lng=-2.9833,
411
+ lat=53.4000,
412
+ tz_str="Europe/London",
413
+ online=False
414
+ )
415
+ solar_return_subject = return_factory.next_return_from_year(1964, "Solar")
416
+
417
+ # Step 3: Pre-compute return chart data (dual wheel: natal + solar return)
418
+ chart_data = ChartDataFactory.create_return_chart_data(john, solar_return_subject)
419
+
420
+ # Step 4: Create visualization
421
+ solar_return_chart = ChartDrawer(chart_data=chart_data)
422
+
423
+ output_dir = Path("charts_output")
424
+ output_dir.mkdir(exist_ok=True)
425
+ solar_return_chart.save_svg(output_path=output_dir, filename="john-lennon-solar-return-dual")
426
+ ```
427
+
428
+ ![John Lennon Solar Return Chart (Dual Wheel)](https://raw.githubusercontent.com/g-battaglia/kerykeion/refs/heads/main/tests/charts/svg/John%20Lennon%20-%20DualReturnChart%20Chart%20-%20Solar%20Return.svg)
429
+
430
+ ### Solar Return Chart (Single Wheel)
431
+
432
+ ```python
433
+ from pathlib import Path
434
+ from kerykeion import AstrologicalSubjectFactory
435
+ from kerykeion.planetary_return_factory import PlanetaryReturnFactory
436
+ from kerykeion.chart_data_factory import ChartDataFactory
437
+ from kerykeion.charts.chart_drawer import ChartDrawer
438
+
439
+ # Step 1: Create natal subject
440
+ john = AstrologicalSubjectFactory.from_birth_data(
441
+ "John Lennon", 1940, 10, 9, 18, 30,
442
+ lng=-2.9833,
443
+ lat=53.4,
444
+ tz_str="Europe/London",
445
+ online=False,
446
+ )
447
+
448
+ # Step 2: Calculate Solar Return subject (offline example with manual coordinates)
449
+ return_factory = PlanetaryReturnFactory(
450
+ john,
451
+ lng=-2.9833,
452
+ lat=53.4000,
453
+ tz_str="Europe/London",
454
+ online=False
455
+ )
456
+ solar_return_subject = return_factory.next_return_from_year(1964, "Solar")
457
+
458
+ # Step 3: Build a single-wheel return chart
459
+ chart_data = ChartDataFactory.create_single_wheel_return_chart_data(solar_return_subject)
460
+
461
+ # Step 4: Create visualization
462
+ single_wheel_chart = ChartDrawer(chart_data=chart_data)
463
+
464
+ output_dir = Path("charts_output")
465
+ output_dir.mkdir(exist_ok=True)
466
+ single_wheel_chart.save_svg(output_path=output_dir, filename="john-lennon-solar-return-single")
467
+ ```
468
+
469
+ ![John Lennon Solar Return Chart (Single Wheel)](https://raw.githubusercontent.com/g-battaglia/kerykeion/refs/heads/main/tests/charts/svg/John%20Lennon%20Solar%20Return%20-%20SingleReturnChart%20Chart.svg)
470
+
471
+ ### Lunar Return Chart
472
+
473
+ ```python
474
+ from pathlib import Path
475
+ from kerykeion import AstrologicalSubjectFactory
476
+ from kerykeion.planetary_return_factory import PlanetaryReturnFactory
477
+ from kerykeion.chart_data_factory import ChartDataFactory
478
+ from kerykeion.charts.chart_drawer import ChartDrawer
479
+
480
+ # Step 1: Create natal subject
481
+ john = AstrologicalSubjectFactory.from_birth_data(
482
+ "John Lennon", 1940, 10, 9, 18, 30,
483
+ lng=-2.9833,
484
+ lat=53.4,
485
+ tz_str="Europe/London",
486
+ online=False,
487
+ )
488
+
489
+ # Step 2: Calculate Lunar Return subject
490
+ return_factory = PlanetaryReturnFactory(
491
+ john,
492
+ lng=-2.9833,
493
+ lat=53.4000,
494
+ tz_str="Europe/London",
495
+ online=False
496
+ )
497
+ lunar_return_subject = return_factory.next_return_from_year(1964, "Lunar")
498
+
499
+ # Step 3: Build a dual wheel (natal + lunar return)
500
+ lunar_return_chart_data = ChartDataFactory.create_return_chart_data(john, lunar_return_subject)
501
+ dual_wheel_chart = ChartDrawer(chart_data=lunar_return_chart_data)
502
+
503
+ output_dir = Path("charts_output")
504
+ output_dir.mkdir(exist_ok=True)
505
+ dual_wheel_chart.save_svg(output_path=output_dir, filename="john-lennon-lunar-return-dual")
506
+
507
+ # Optional: create a single-wheel lunar return
508
+ single_wheel_data = ChartDataFactory.create_single_wheel_return_chart_data(lunar_return_subject)
509
+ single_wheel_chart = ChartDrawer(chart_data=single_wheel_data)
510
+ single_wheel_chart.save_svg(output_path=output_dir, filename="john-lennon-lunar-return-single")
511
+ ```
512
+
513
+ ![John Lennon Lunar Return Chart (Dual Wheel)](https://raw.githubusercontent.com/g-battaglia/kerykeion/refs/heads/main/tests/charts/svg/John%20Lennon%20-%20DualReturnChart%20Chart%20-%20Lunar%20Return.svg)
514
+
515
+ ![John Lennon Lunar Return Chart (Single Wheel)](https://raw.githubusercontent.com/g-battaglia/kerykeion/refs/heads/main/tests/charts/svg/John%20Lennon%20Lunar%20Return%20-%20SingleReturnChart%20Chart.svg)
516
+
278
517
  ### Composite Chart
279
518
 
280
519
  ```python
520
+ from pathlib import Path
281
521
  from kerykeion import CompositeSubjectFactory, AstrologicalSubjectFactory
282
522
  from kerykeion.chart_data_factory import ChartDataFactory
283
523
  from kerykeion.charts.chart_drawer import ChartDrawer
284
524
 
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")
525
+ # Step 1: Create subjects (offline configuration)
526
+ angelina = AstrologicalSubjectFactory.from_birth_data(
527
+ "Angelina Jolie", 1975, 6, 4, 9, 9,
528
+ lng=-118.2437,
529
+ lat=34.0522,
530
+ tz_str="America/Los_Angeles",
531
+ online=False,
532
+ )
287
533
 
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")
534
+ brad = AstrologicalSubjectFactory.from_birth_data(
535
+ "Brad Pitt", 1963, 12, 18, 6, 31,
536
+ lng=-96.7069,
537
+ lat=35.3273,
538
+ tz_str="America/Chicago",
539
+ online=False,
540
+ )
289
541
 
290
542
  # Step 2: Create composite subject
291
543
  factory = CompositeSubjectFactory(angelina, brad)
@@ -296,7 +548,10 @@ chart_data = ChartDataFactory.create_composite_chart_data(composite_model)
296
548
 
297
549
  # Step 4: Create visualization
298
550
  composite_chart = ChartDrawer(chart_data=chart_data)
299
- composite_chart.save_svg()
551
+
552
+ output_dir = Path("charts_output")
553
+ output_dir.mkdir(exist_ok=True)
554
+ composite_chart.save_svg(output_path=output_dir, filename="jolie-pitt-composite")
300
555
  ```
301
556
 
302
557
  ![Angelina Jolie and Brad Pitt Composite Chart](https://raw.githubusercontent.com/g-battaglia/kerykeion/refs/heads/main/tests/charts/svg/Angelina%20Jolie%20and%20Brad%20Pitt%20Composite%20Chart%20-%20Composite%20Chart.svg)
@@ -308,19 +563,29 @@ For _all_ the charts, you can generate a wheel-only chart by using the method `m
308
563
  ### Birth Chart
309
564
 
310
565
  ```python
566
+ from pathlib import Path
311
567
  from kerykeion import AstrologicalSubjectFactory
312
568
  from kerykeion.chart_data_factory import ChartDataFactory
313
569
  from kerykeion.charts.chart_drawer import ChartDrawer
314
570
 
315
571
  # Step 1: Create subject
316
- birth_chart = AstrologicalSubjectFactory.from_birth_data("John Lennon", 1940, 10, 9, 18, 30, "Liverpool", "GB")
572
+ birth_chart = AstrologicalSubjectFactory.from_birth_data(
573
+ "John Lennon", 1940, 10, 9, 18, 30,
574
+ lng=-2.9833,
575
+ lat=53.4,
576
+ tz_str="Europe/London",
577
+ online=False,
578
+ )
317
579
 
318
580
  # Step 2: Pre-compute chart data
319
581
  chart_data = ChartDataFactory.create_natal_chart_data(birth_chart)
320
582
 
321
583
  # Step 3: Create visualization
322
584
  birth_chart_svg = ChartDrawer(chart_data=chart_data)
323
- birth_chart_svg.save_wheel_only_svg_file()
585
+
586
+ output_dir = Path("charts_output")
587
+ output_dir.mkdir(exist_ok=True)
588
+ birth_chart_svg.save_wheel_only_svg_file(output_path=output_dir, filename="john-lennon-natal-wheel")
324
589
  ```
325
590
 
326
591
  ![John Lennon Birth Chart](https://raw.githubusercontent.com/g-battaglia/kerykeion/refs/heads/main/tests/charts/svg/John%20Lennon%20-%20Wheel%20Only%20-%20Natal%20Chart%20-%20Wheel%20Only.svg)
@@ -328,22 +593,29 @@ birth_chart_svg.save_wheel_only_svg_file()
328
593
  ### Wheel Only Birth Chart (External)
329
594
 
330
595
  ```python
596
+ from pathlib import Path
331
597
  from kerykeion import AstrologicalSubjectFactory
332
598
  from kerykeion.chart_data_factory import ChartDataFactory
333
599
  from kerykeion.charts.chart_drawer import ChartDrawer
334
600
 
335
601
  # Step 1: Create subject
336
- birth_chart = AstrologicalSubjectFactory.from_birth_data("John Lennon", 1940, 10, 9, 18, 30, "Liverpool", "GB")
602
+ birth_chart = AstrologicalSubjectFactory.from_birth_data(
603
+ "John Lennon", 1940, 10, 9, 18, 30,
604
+ lng=-2.9833,
605
+ lat=53.4,
606
+ tz_str="Europe/London",
607
+ online=False,
608
+ )
337
609
 
338
610
  # Step 2: Pre-compute external natal chart data
339
- chart_data = ChartDataFactory.create_external_natal_chart_data(birth_chart)
611
+ chart_data = ChartDataFactory.create_natal_chart_data(birth_chart)
340
612
 
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
- )
613
+ # Step 3: Create visualization (external wheel view)
614
+ birth_chart_svg = ChartDrawer(chart_data=chart_data, external_view=True)
615
+
616
+ output_dir = Path("charts_output")
617
+ output_dir.mkdir(exist_ok=True)
618
+ birth_chart_svg.save_wheel_only_svg_file(output_path=output_dir, filename="john-lennon-natal-wheel-external")
347
619
  ```
348
620
 
349
621
  ![John Lennon Birth Chart](https://raw.githubusercontent.com/g-battaglia/kerykeion/refs/heads/main/tests/charts/svg/John%20Lennon%20-%20Wheel%20External%20Only%20-%20ExternalNatal%20Chart%20-%20Wheel%20Only.svg)
@@ -351,20 +623,36 @@ birth_chart_svg.save_wheel_only_svg_file(
351
623
  ### Synastry Chart
352
624
 
353
625
  ```python
626
+ from pathlib import Path
354
627
  from kerykeion import AstrologicalSubjectFactory
355
628
  from kerykeion.chart_data_factory import ChartDataFactory
356
629
  from kerykeion.charts.chart_drawer import ChartDrawer
357
630
 
358
631
  # 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")
632
+ first = AstrologicalSubjectFactory.from_birth_data(
633
+ "John Lennon", 1940, 10, 9, 18, 30,
634
+ lng=-2.9833,
635
+ lat=53.4,
636
+ tz_str="Europe/London",
637
+ online=False,
638
+ )
639
+ second = AstrologicalSubjectFactory.from_birth_data(
640
+ "Paul McCartney", 1942, 6, 18, 15, 30,
641
+ lng=-2.9833,
642
+ lat=53.4,
643
+ tz_str="Europe/London",
644
+ online=False,
645
+ )
361
646
 
362
647
  # Step 2: Pre-compute synastry chart data
363
648
  chart_data = ChartDataFactory.create_synastry_chart_data(first, second)
364
649
 
365
650
  # Step 3: Create visualization
366
651
  synastry_chart = ChartDrawer(chart_data=chart_data)
367
- synastry_chart.save_wheel_only_svg_file()
652
+
653
+ output_dir = Path("charts_output")
654
+ output_dir.mkdir(exist_ok=True)
655
+ synastry_chart.save_wheel_only_svg_file(output_path=output_dir, filename="lennon-mccartney-synastry-wheel")
368
656
  ```
369
657
 
370
658
  ![John Lennon and Paul McCartney Synastry](https://raw.githubusercontent.com/g-battaglia/kerykeion/refs/heads/main/tests/charts/svg/John%20Lennon%20-%20Wheel%20Synastry%20Only%20-%20Synastry%20Chart%20-%20Wheel%20Only.svg)
@@ -374,20 +662,37 @@ synastry_chart.save_wheel_only_svg_file()
374
662
  To save the SVG file in a custom location, specify the `output_path` parameter in `save_svg()`:
375
663
 
376
664
  ```python
665
+ from pathlib import Path
377
666
  from kerykeion import AstrologicalSubjectFactory
378
667
  from kerykeion.chart_data_factory import ChartDataFactory
379
668
  from kerykeion.charts.chart_drawer import ChartDrawer
380
669
 
381
670
  # 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")
671
+ first = AstrologicalSubjectFactory.from_birth_data(
672
+ "John Lennon", 1940, 10, 9, 18, 30,
673
+ lng=-2.9833,
674
+ lat=53.4,
675
+ tz_str="Europe/London",
676
+ online=False,
677
+ )
678
+ second = AstrologicalSubjectFactory.from_birth_data(
679
+ "Paul McCartney", 1942, 6, 18, 15, 30,
680
+ lng=-2.9833,
681
+ lat=53.4,
682
+ tz_str="Europe/London",
683
+ online=False,
684
+ )
384
685
 
385
686
  # Step 2: Pre-compute synastry chart data
386
687
  chart_data = ChartDataFactory.create_synastry_chart_data(first, second)
387
688
 
388
689
  # Step 3: Create visualization with custom output directory
389
690
  synastry_chart = ChartDrawer(chart_data=chart_data)
390
- synastry_chart.save_svg(output_path=".")
691
+
692
+ output_dir = Path("my_charts")
693
+ output_dir.mkdir(exist_ok=True)
694
+ synastry_chart.save_svg(output_path=output_dir)
695
+ print("Saved to", (output_dir / f"{synastry_chart.first_obj.name} - Synastry Chart.svg").resolve())
391
696
  ```
392
697
 
393
698
  ### Change Language
@@ -395,12 +700,19 @@ synastry_chart.save_svg(output_path=".")
395
700
  You can switch chart language by passing `chart_language` to the `ChartDrawer` class:
396
701
 
397
702
  ```python
703
+ from pathlib import Path
398
704
  from kerykeion import AstrologicalSubjectFactory
399
705
  from kerykeion.chart_data_factory import ChartDataFactory
400
706
  from kerykeion.charts.chart_drawer import ChartDrawer
401
707
 
402
708
  # Step 1: Create subject
403
- birth_chart = AstrologicalSubjectFactory.from_birth_data("John Lennon", 1940, 10, 9, 18, 30, "Liverpool", "GB")
709
+ birth_chart = AstrologicalSubjectFactory.from_birth_data(
710
+ "John Lennon", 1940, 10, 9, 18, 30,
711
+ lng=-2.9833,
712
+ lat=53.4,
713
+ tz_str="Europe/London",
714
+ online=False,
715
+ )
404
716
 
405
717
  # Step 2: Pre-compute chart data
406
718
  chart_data = ChartDataFactory.create_natal_chart_data(birth_chart)
@@ -410,13 +722,31 @@ birth_chart_svg = ChartDrawer(
410
722
  chart_data=chart_data,
411
723
  chart_language="IT" # Change to Italian
412
724
  )
413
- birth_chart_svg.save_svg()
725
+
726
+ output_dir = Path("charts_output")
727
+ output_dir.mkdir(exist_ok=True)
728
+ birth_chart_svg.save_svg(output_path=output_dir, filename="john-lennon-natal-it")
729
+ ```
414
730
 
415
731
  You can also provide custom labels (or introduce a brand-new language) by passing
416
732
  a dictionary to `language_pack`. Only the keys you supply are merged on top of the
417
733
  built-in strings:
418
734
 
419
735
  ```python
736
+ from pathlib import Path
737
+ from kerykeion import AstrologicalSubjectFactory
738
+ from kerykeion.chart_data_factory import ChartDataFactory
739
+ from kerykeion.charts.chart_drawer import ChartDrawer
740
+
741
+ birth_chart = AstrologicalSubjectFactory.from_birth_data(
742
+ "John Lennon", 1940, 10, 9, 18, 30,
743
+ lng=-2.9833,
744
+ lat=53.4,
745
+ tz_str="Europe/London",
746
+ online=False,
747
+ )
748
+ chart_data = ChartDataFactory.create_natal_chart_data(birth_chart)
749
+
420
750
  custom_labels = {
421
751
  "PT": {
422
752
  "info": "Informações",
@@ -424,12 +754,15 @@ custom_labels = {
424
754
  }
425
755
  }
426
756
 
427
- birth_chart_svg = ChartDrawer(
757
+ custom_chart = ChartDrawer(
428
758
  chart_data=chart_data,
429
759
  chart_language="PT",
430
760
  language_pack=custom_labels["PT"],
431
761
  )
432
- ```
762
+
763
+ output_dir = Path("charts_output")
764
+ output_dir.mkdir(exist_ok=True)
765
+ custom_chart.save_svg(output_path=output_dir, filename="john-lennon-natal-pt")
433
766
  ```
434
767
 
435
768
  More details [here](https://www.kerykeion.net/docs/chart-language).
@@ -451,20 +784,32 @@ The available languages are:
451
784
  To generate a minified SVG, set `minify_svg=True` in the `makeSVG()` method:
452
785
 
453
786
  ```python
787
+ from pathlib import Path
454
788
  from kerykeion import AstrologicalSubjectFactory
455
789
  from kerykeion.chart_data_factory import ChartDataFactory
456
790
  from kerykeion.charts.chart_drawer import ChartDrawer
457
791
 
458
792
  # Step 1: Create subject
459
- birth_chart = AstrologicalSubjectFactory.from_birth_data("John Lennon", 1940, 10, 9, 18, 30, "Liverpool", "GB")
793
+ birth_chart = AstrologicalSubjectFactory.from_birth_data(
794
+ "John Lennon", 1940, 10, 9, 18, 30,
795
+ lng=-2.9833,
796
+ lat=53.4,
797
+ tz_str="Europe/London",
798
+ online=False,
799
+ )
460
800
 
461
801
  # Step 2: Pre-compute chart data
462
802
  chart_data = ChartDataFactory.create_natal_chart_data(birth_chart)
463
803
 
464
804
  # Step 3: Create visualization
465
805
  birth_chart_svg = ChartDrawer(chart_data=chart_data)
806
+
807
+ output_dir = Path("charts_output")
808
+ output_dir.mkdir(exist_ok=True)
466
809
  birth_chart_svg.save_svg(
467
- minify=True
810
+ output_path=output_dir,
811
+ filename="john-lennon-natal-minified",
812
+ minify=True,
468
813
  )
469
814
  ```
470
815
 
@@ -473,20 +818,32 @@ birth_chart_svg.save_svg(
473
818
  To generate an SVG without CSS variables, set `remove_css_variables=True` in the `makeSVG()` method:
474
819
 
475
820
  ```python
821
+ from pathlib import Path
476
822
  from kerykeion import AstrologicalSubjectFactory
477
823
  from kerykeion.chart_data_factory import ChartDataFactory
478
824
  from kerykeion.charts.chart_drawer import ChartDrawer
479
825
 
480
826
  # Step 1: Create subject
481
- birth_chart = AstrologicalSubjectFactory.from_birth_data("John Lennon", 1940, 10, 9, 18, 30, "Liverpool", "GB")
827
+ birth_chart = AstrologicalSubjectFactory.from_birth_data(
828
+ "John Lennon", 1940, 10, 9, 18, 30,
829
+ lng=-2.9833,
830
+ lat=53.4,
831
+ tz_str="Europe/London",
832
+ online=False,
833
+ )
482
834
 
483
835
  # Step 2: Pre-compute chart data
484
836
  chart_data = ChartDataFactory.create_natal_chart_data(birth_chart)
485
837
 
486
838
  # Step 3: Create visualization
487
839
  birth_chart_svg = ChartDrawer(chart_data=chart_data)
840
+
841
+ output_dir = Path("charts_output")
842
+ output_dir.mkdir(exist_ok=True)
488
843
  birth_chart_svg.save_svg(
489
- remove_css_variables=True
844
+ output_path=output_dir,
845
+ filename="john-lennon-natal-no-css-variables",
846
+ remove_css_variables=True,
490
847
  )
491
848
  ```
492
849
 
@@ -497,20 +854,36 @@ This will inline all styles and eliminate CSS variables, resulting in an SVG tha
497
854
  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
855
 
499
856
  ```python
857
+ from pathlib import Path
500
858
  from kerykeion import AstrologicalSubjectFactory
501
859
  from kerykeion.chart_data_factory import ChartDataFactory
502
860
  from kerykeion.charts.chart_drawer import ChartDrawer
503
861
 
504
862
  # 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")
863
+ birth_chart = AstrologicalSubjectFactory.from_birth_data(
864
+ "John Lennon", 1940, 10, 9, 18, 30,
865
+ lng=-2.9833,
866
+ lat=53.4,
867
+ tz_str="Europe/London",
868
+ online=False,
869
+ )
870
+ second = AstrologicalSubjectFactory.from_birth_data(
871
+ "Paul McCartney", 1942, 6, 18, 15, 30,
872
+ lng=-2.9833,
873
+ lat=53.4,
874
+ tz_str="Europe/London",
875
+ online=False,
876
+ )
507
877
 
508
878
  # Step 2: Pre-compute synastry chart data
509
879
  chart_data = ChartDataFactory.create_synastry_chart_data(birth_chart, second)
510
880
 
511
881
  # Step 3: Create visualization with dark theme
512
882
  aspect_grid_chart = ChartDrawer(chart_data=chart_data, theme="dark")
513
- aspect_grid_chart.save_aspect_grid_only_svg_file()
883
+
884
+ output_dir = Path("charts_output")
885
+ output_dir.mkdir(exist_ok=True)
886
+ aspect_grid_chart.save_aspect_grid_only_svg_file(output_path=output_dir, filename="lennon-mccartney-aspect-grid")
514
887
  ```
515
888
 
516
889
  ![John Lennon Birth Chart](https://raw.githubusercontent.com/g-battaglia/kerykeion/refs/heads/main/tests/charts/svg/John%20Lennon%20-%20Aspect%20Grid%20Only%20-%20Natal%20Chart%20-%20Aspect%20Grid%20Only.svg)
@@ -526,7 +899,11 @@ from kerykeion import ReportGenerator, AstrologicalSubjectFactory, ChartDataFact
526
899
 
527
900
  # Subject-only report
528
901
  subject = AstrologicalSubjectFactory.from_birth_data(
529
- "Sample Natal", 1990, 7, 21, 14, 45, "Rome", "IT"
902
+ "Sample Natal", 1990, 7, 21, 14, 45,
903
+ lng=12.4964,
904
+ lat=41.9028,
905
+ tz_str="Europe/Rome",
906
+ online=False,
530
907
  )
531
908
  ReportGenerator(subject).print_report(include_aspects=False)
532
909
 
@@ -536,7 +913,11 @@ ReportGenerator(natal_data).print_report(max_aspects=10)
536
913
 
537
914
  # Dual-chart data (synastry, transit, dual return, …)
538
915
  partner = AstrologicalSubjectFactory.from_birth_data(
539
- "Sample Partner", 1992, 11, 5, 9, 30, "Rome", "IT"
916
+ "Sample Partner", 1992, 11, 5, 9, 30,
917
+ lng=12.4964,
918
+ lat=41.9028,
919
+ tz_str="Europe/Rome",
920
+ online=False,
540
921
  )
541
922
  synastry_data = ChartDataFactory.create_synastry_chart_data(subject, partner)
542
923
  ReportGenerator(synastry_data).print_report(max_aspects=12)
@@ -558,11 +939,21 @@ Each report contains:
558
939
  All section helpers remain available for targeted output:
559
940
 
560
941
  ```python
942
+ from kerykeion import ReportGenerator, AstrologicalSubjectFactory, ChartDataFactory
943
+
944
+ subject = AstrologicalSubjectFactory.from_birth_data(
945
+ "Sample Natal", 1990, 7, 21, 14, 45,
946
+ lng=12.4964,
947
+ lat=41.9028,
948
+ tz_str="Europe/Rome",
949
+ online=False,
950
+ )
951
+ natal_data = ChartDataFactory.create_natal_chart_data(subject)
952
+
561
953
  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))
954
+ sections = report.generate_report(max_aspects=5).split("\n\n")
955
+ for section in sections[:3]:
956
+ print(section)
566
957
  ```
567
958
 
568
959
  Refer to the refreshed [Report Documentation](https://www.kerykeion.net/report/) for end-to-end examples covering every supported chart model.
@@ -575,22 +966,32 @@ Kerykeion provides a unified `AspectsFactory` class for calculating astrological
575
966
  from kerykeion import AspectsFactory, AstrologicalSubjectFactory
576
967
 
577
968
  # 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")
969
+ jack = AstrologicalSubjectFactory.from_birth_data(
970
+ "Jack", 1990, 6, 15, 15, 15,
971
+ lng=12.4964,
972
+ lat=41.9028,
973
+ tz_str="Europe/Rome",
974
+ online=False,
975
+ )
976
+ jane = AstrologicalSubjectFactory.from_birth_data(
977
+ "Jane", 1991, 10, 25, 21, 0,
978
+ lng=12.4964,
979
+ lat=41.9028,
980
+ tz_str="Europe/Rome",
981
+ online=False,
982
+ )
580
983
 
581
984
  # 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.
985
+ single_chart_result = AspectsFactory.single_chart_aspects(jack)
986
+ print(f"Found {len(single_chart_result.aspects)} aspects in Jack's chart")
987
+ print(single_chart_result.aspects[0])
586
988
 
587
989
  # 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
990
+ dual_chart_result = AspectsFactory.dual_chart_aspects(jack, jane)
991
+ print(f"Found {len(dual_chart_result.aspects)} aspects between Jack and Jane's charts")
992
+ print(dual_chart_result.aspects[0])
592
993
 
593
- # The factory returns structured AspectModel objects with properties like:
994
+ # Each AspectModel includes:
594
995
  # - p1_name, p2_name: Planet/point names
595
996
  # - aspect: Aspect type (conjunction, trine, square, etc.)
596
997
  # - orbit: Orb tolerance in degrees
@@ -622,7 +1023,11 @@ You can refine the weighting without rebuilding the dictionary: pass lowercase p
622
1023
  from kerykeion import AstrologicalSubjectFactory, ChartDataFactory
623
1024
 
624
1025
  subject = AstrologicalSubjectFactory.from_birth_data(
625
- "Sample", 1986, 4, 12, 8, 45, "Bologna", "IT"
1026
+ "Sample", 1986, 4, 12, 8, 45,
1027
+ lng=11.3426,
1028
+ lat=44.4949,
1029
+ tz_str="Europe/Rome",
1030
+ online=False,
626
1031
  )
627
1032
 
628
1033
  # Equal weighting: every active point counts once
@@ -656,7 +1061,10 @@ By default, the zodiac type is **Tropical**. To use **Sidereal**, specify the si
656
1061
  ```python
657
1062
  johnny = AstrologicalSubjectFactory.from_birth_data(
658
1063
  "Johnny Depp", 1963, 6, 9, 0, 0,
659
- "Owensboro", "US",
1064
+ lng=-87.1112,
1065
+ lat=37.7719,
1066
+ tz_str="America/Chicago",
1067
+ online=False,
660
1068
  zodiac_type="Sidereal",
661
1069
  sidereal_mode="LAHIRI"
662
1070
  )
@@ -673,8 +1081,11 @@ By default, houses are calculated using **Placidus**. Configure a different hous
673
1081
  ```python
674
1082
  johnny = AstrologicalSubjectFactory.from_birth_data(
675
1083
  "Johnny Depp", 1963, 6, 9, 0, 0,
676
- "Owensboro", "US",
677
- houses_system="M"
1084
+ lng=-87.1112,
1085
+ lat=37.7719,
1086
+ tz_str="America/Chicago",
1087
+ online=False,
1088
+ houses_system_identifier="M"
678
1089
  )
679
1090
  ```
680
1091
 
@@ -691,7 +1102,10 @@ By default, Kerykeion uses the **Apparent Geocentric** perspective (the most sta
691
1102
  ```python
692
1103
  johnny = AstrologicalSubjectFactory.from_birth_data(
693
1104
  "Johnny Depp", 1963, 6, 9, 0, 0,
694
- "Owensboro", "US",
1105
+ lng=-87.1112,
1106
+ lat=37.7719,
1107
+ tz_str="America/Chicago",
1108
+ online=False,
695
1109
  perspective_type="Heliocentric"
696
1110
  )
697
1111
  ```
@@ -718,43 +1132,56 @@ The Black & White theme renders glyphs, rings, and aspects in solid black on lig
718
1132
  Here's an example of how to set the theme:
719
1133
 
720
1134
  ```python
1135
+ from pathlib import Path
721
1136
  from kerykeion import AstrologicalSubjectFactory
722
1137
  from kerykeion.chart_data_factory import ChartDataFactory
723
1138
  from kerykeion.charts.chart_drawer import ChartDrawer
724
1139
 
725
1140
  # Step 1: Create subject
726
- dark_theme_subject = AstrologicalSubjectFactory.from_birth_data("John Lennon - Dark Theme", 1940, 10, 9, 18, 30, "Liverpool", "GB")
1141
+ dark_theme_subject = AstrologicalSubjectFactory.from_birth_data(
1142
+ "John Lennon - Dark Theme", 1940, 10, 9, 18, 30,
1143
+ lng=-2.9833,
1144
+ lat=53.4,
1145
+ tz_str="Europe/London",
1146
+ online=False,
1147
+ )
727
1148
 
728
1149
  # Step 2: Pre-compute chart data
729
1150
  chart_data = ChartDataFactory.create_natal_chart_data(dark_theme_subject)
730
1151
 
731
1152
  # Step 3: Create visualization with dark high contrast theme
732
1153
  dark_theme_natal_chart = ChartDrawer(chart_data=chart_data, theme="dark-high-contrast")
733
- dark_theme_natal_chart.save_svg()
1154
+
1155
+ output_dir = Path("charts_output")
1156
+ output_dir.mkdir(exist_ok=True)
1157
+ dark_theme_natal_chart.save_svg(output_path=output_dir, filename="john-lennon-natal-dark-high-contrast")
734
1158
  ```
735
1159
 
736
1160
  ![John Lennon](https://www.kerykeion.net/img/showcase/John%20Lennon%20-%20Dark%20-%20Natal%20Chart.svg)
737
1161
 
738
1162
  ## Alternative Initialization
739
1163
 
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:
1164
+ Create an `AstrologicalSubjectModel` from a UTC ISO 8601 string:
749
1165
 
750
1166
  ```python
751
- from kerykeion.astrological_subject import AstrologicalSubjectFactory
1167
+ from kerykeion import AstrologicalSubjectFactory
752
1168
 
753
- subject = AstrologicalSubject.get_from_iso_utc_time(
754
- "Johnny Depp", "1963-06-09T05:00:00Z", "Owensboro", "US", online=True
1169
+ subject = AstrologicalSubjectFactory.from_iso_utc_time(
1170
+ name="Johnny Depp",
1171
+ iso_utc_time="1963-06-09T05:00:00Z",
1172
+ city="Owensboro",
1173
+ nation="US",
1174
+ lng=-87.1112,
1175
+ lat=37.7719,
1176
+ tz_str="America/Chicago",
1177
+ online=False,
755
1178
  )
1179
+
1180
+ print(subject.iso_formatted_local_datetime)
756
1181
  ```
757
1182
 
1183
+ If you prefer automatic geocoding, set `online=True` and provide your GeoNames credentials via `geonames_username`.
1184
+
758
1185
  ## Lunar Nodes (Rahu & Ketu)
759
1186
 
760
1187
  Kerykeion supports both **True** and **Mean** Lunar Nodes:
@@ -769,12 +1196,19 @@ In instances of the classes used to generate aspects and SVG charts, only the me
769
1196
  Example:
770
1197
 
771
1198
  ```python
1199
+ from pathlib import Path
772
1200
  from kerykeion import AstrologicalSubjectFactory
773
1201
  from kerykeion.chart_data_factory import ChartDataFactory
774
1202
  from kerykeion.charts.chart_drawer import ChartDrawer
775
1203
 
776
1204
  # Step 1: Create subject
777
- subject = AstrologicalSubjectFactory.from_birth_data("John Lennon", 1940, 10, 9, 18, 30, "Liverpool", "GB")
1205
+ subject = AstrologicalSubjectFactory.from_birth_data(
1206
+ "John Lennon", 1940, 10, 9, 18, 30,
1207
+ lng=-2.9833,
1208
+ lat=53.4,
1209
+ tz_str="Europe/London",
1210
+ online=False,
1211
+ )
778
1212
 
779
1213
  # Step 2: Pre-compute chart data with custom active points including true nodes
780
1214
  chart_data = ChartDataFactory.create_natal_chart_data(
@@ -803,7 +1237,10 @@ chart_data = ChartDataFactory.create_natal_chart_data(
803
1237
 
804
1238
  # Step 3: Create visualization
805
1239
  chart = ChartDrawer(chart_data=chart_data)
806
- chart.save_svg()
1240
+
1241
+ output_dir = Path("charts_output")
1242
+ output_dir.mkdir(exist_ok=True)
1243
+ chart.save_svg(output_path=output_dir, filename="johnny-depp-custom-points")
807
1244
  ```
808
1245
 
809
1246
  ## JSON Support
@@ -813,9 +1250,15 @@ You can serialize the astrological subject (the base data used throughout the li
813
1250
  ```python
814
1251
  from kerykeion import AstrologicalSubjectFactory
815
1252
 
816
- johnny = AstrologicalSubjectFactory.from_birth_data("Johnny Depp", 1963, 6, 9, 0, 0, "Owensboro", "US")
1253
+ johnny = AstrologicalSubjectFactory.from_birth_data(
1254
+ "Johnny Depp", 1963, 6, 9, 0, 0,
1255
+ lng=-87.1112,
1256
+ lat=37.7719,
1257
+ tz_str="America/Chicago",
1258
+ online=False,
1259
+ )
817
1260
 
818
- print(johnny.json(dump=False, indent=2))
1261
+ print(johnny.model_dump_json(indent=2))
819
1262
  ```
820
1263
 
821
1264
  ## Auto Generated Documentation
@@ -847,24 +1290,44 @@ The old class-based approach has been replaced with a modern factory pattern:
847
1290
  **Old v4 API:**
848
1291
 
849
1292
  ```python
1293
+ from pathlib import Path
850
1294
  from kerykeion import AstrologicalSubject, KerykeionChartSVG
851
1295
 
852
1296
  # v4 - Class-based approach
853
- subject = AstrologicalSubject("John", 1990, 1, 1, 12, 0, "London", "GB")
854
- chart = KerykeionChartSVG(subject)
1297
+ output_dir = Path("charts_output")
1298
+ output_dir.mkdir(exist_ok=True)
1299
+
1300
+ subject = AstrologicalSubject(
1301
+ "John", 1990, 1, 1, 12, 0,
1302
+ lng=-0.1276,
1303
+ lat=51.5074,
1304
+ tz_str="Europe/London",
1305
+ online=False,
1306
+ )
1307
+ chart = KerykeionChartSVG(subject, new_output_directory=output_dir)
855
1308
  chart.makeSVG()
856
1309
  ```
857
1310
 
858
1311
  **New v5 API:**
859
1312
 
860
1313
  ```python
1314
+ from pathlib import Path
861
1315
  from kerykeion import AstrologicalSubjectFactory, ChartDataFactory, ChartDrawer
862
1316
 
863
1317
  # v5 - Factory-based approach with separation of concerns
864
- subject = AstrologicalSubjectFactory.from_birth_data("John", 1990, 1, 1, 12, 0, "London", "GB")
1318
+ subject = AstrologicalSubjectFactory.from_birth_data(
1319
+ "John", 1990, 1, 1, 12, 0,
1320
+ lng=-0.1276,
1321
+ lat=51.5074,
1322
+ tz_str="Europe/London",
1323
+ online=False,
1324
+ )
865
1325
  chart_data = ChartDataFactory.create_natal_chart_data(subject)
866
1326
  drawer = ChartDrawer(chart_data=chart_data)
867
- drawer.save_svg()
1327
+
1328
+ output_dir = Path("charts_output")
1329
+ output_dir.mkdir(exist_ok=True)
1330
+ drawer.save_svg(output_path=output_dir, filename="john-factory-demo")
868
1331
  ```
869
1332
 
870
1333
  #### Pydantic 2 Models & Type Safety
@@ -873,7 +1336,7 @@ All data structures are now strongly typed Pydantic models:
873
1336
 
874
1337
  - **`AstrologicalSubjectModel`**: Subject data with full validation
875
1338
  - **`ChartDataModel`**: Enriched chart data with elements, qualities, aspects
876
- - **`SingleChartAspectsModel` / `DualChartAspectsModel`**: Typed aspect collections
1339
+ - **`AspectModel` list**: Raw aspect entries directly on `ChartDataModel.aspects`
877
1340
  - **`PlanetReturnModel`**: Planetary return data
878
1341
  - **`ElementDistributionModel`**: Element statistics (fire, earth, air, water)
879
1342
  - **`QualityDistributionModel`**: Quality statistics (cardinal, fixed, mutable)
@@ -970,11 +1433,27 @@ All lunar node fields have been renamed for clarity:
970
1433
  **Migration example:**
971
1434
 
972
1435
  ```python
973
- # v4
974
- print(subject.mean_node)
975
-
976
- # v5
977
- print(subject.mean_north_lunar_node)
1436
+ from kerykeion import AstrologicalSubject, AstrologicalSubjectFactory
1437
+
1438
+ # v4 alias (still available, emits DeprecationWarning)
1439
+ legacy_subject = AstrologicalSubject(
1440
+ "John", 1990, 1, 1, 12, 0,
1441
+ lng=-0.1276,
1442
+ lat=51.5074,
1443
+ tz_str="Europe/London",
1444
+ online=False,
1445
+ )
1446
+ print(legacy_subject.mean_node)
1447
+
1448
+ # v5 canonical name
1449
+ modern_subject = AstrologicalSubjectFactory.from_birth_data(
1450
+ "John", 1990, 1, 1, 12, 0,
1451
+ lng=-0.1276,
1452
+ lat=51.5074,
1453
+ tz_str="Europe/London",
1454
+ online=False,
1455
+ )
1456
+ print(modern_subject.mean_north_lunar_node)
978
1457
  ```
979
1458
 
980
1459
  #### 5. Axis Orb Filtering
@@ -988,16 +1467,43 @@ The two-step process (data + rendering) is now required:
988
1467
  **Old v4:**
989
1468
 
990
1469
  ```python
991
- chart = KerykeionChartSVG(subject)
1470
+ from pathlib import Path
1471
+ from kerykeion import AstrologicalSubject, KerykeionChartSVG
1472
+
1473
+ output_dir = Path("charts_output")
1474
+ output_dir.mkdir(exist_ok=True)
1475
+
1476
+ subject = AstrologicalSubject(
1477
+ "John", 1990, 1, 1, 12, 0,
1478
+ lng=-0.1276,
1479
+ lat=51.5074,
1480
+ tz_str="Europe/London",
1481
+ online=False,
1482
+ )
1483
+ chart = KerykeionChartSVG(subject, new_output_directory=output_dir)
992
1484
  chart.makeSVG()
993
1485
  ```
994
1486
 
995
1487
  **New v5:**
996
1488
 
997
1489
  ```python
1490
+ from pathlib import Path
1491
+ from kerykeion import AstrologicalSubjectFactory, ChartDataFactory
1492
+ from kerykeion.charts.chart_drawer import ChartDrawer
1493
+
1494
+ subject = AstrologicalSubjectFactory.from_birth_data(
1495
+ "John", 1990, 1, 1, 12, 0,
1496
+ lng=-0.1276,
1497
+ lat=51.5074,
1498
+ tz_str="Europe/London",
1499
+ online=False,
1500
+ )
998
1501
  chart_data = ChartDataFactory.create_natal_chart_data(subject)
999
1502
  drawer = ChartDrawer(chart_data=chart_data)
1000
- drawer.save_svg()
1503
+
1504
+ output_dir = Path("charts_output")
1505
+ output_dir.mkdir(exist_ok=True)
1506
+ drawer.save_svg(output_path=output_dir, filename="john-v5-demo")
1001
1507
  ```
1002
1508
 
1003
1509
  #### 7. Aspects API Changes
@@ -1007,7 +1513,23 @@ Aspects are now calculated through the factory:
1007
1513
  **Old v4:**
1008
1514
 
1009
1515
  ```python
1010
- from kerykeion import NatalAspects, SynastryAspects
1516
+ from kerykeion import AstrologicalSubjectFactory, NatalAspects, SynastryAspects
1517
+
1518
+ subject = AstrologicalSubjectFactory.from_birth_data(
1519
+ "John", 1990, 1, 1, 12, 0,
1520
+ lng=-0.1276,
1521
+ lat=51.5074,
1522
+ tz_str="Europe/London",
1523
+ online=False,
1524
+ )
1525
+ subject1 = subject
1526
+ subject2 = AstrologicalSubjectFactory.from_birth_data(
1527
+ "Jane", 1990, 6, 5, 8, 30,
1528
+ lng=-0.1276,
1529
+ lat=51.5074,
1530
+ tz_str="Europe/London",
1531
+ online=False,
1532
+ )
1011
1533
 
1012
1534
  natal_aspects = NatalAspects(subject)
1013
1535
  synastry_aspects = SynastryAspects(subject1, subject2)
@@ -1016,12 +1538,30 @@ synastry_aspects = SynastryAspects(subject1, subject2)
1016
1538
  **New v5:**
1017
1539
 
1018
1540
  ```python
1019
- from kerykeion import AspectsFactory
1541
+ from kerykeion import AstrologicalSubjectFactory, AspectsFactory
1542
+
1543
+ subject = AstrologicalSubjectFactory.from_birth_data(
1544
+ "John", 1990, 1, 1, 12, 0,
1545
+ lng=-0.1276,
1546
+ lat=51.5074,
1547
+ tz_str="Europe/London",
1548
+ online=False,
1549
+ )
1550
+ subject1 = subject
1551
+ subject2 = AstrologicalSubjectFactory.from_birth_data(
1552
+ "Jane", 1990, 6, 5, 8, 30,
1553
+ lng=-0.1276,
1554
+ lat=51.5074,
1555
+ tz_str="Europe/London",
1556
+ online=False,
1557
+ )
1020
1558
 
1021
1559
  natal_aspects = AspectsFactory.single_chart_aspects(subject)
1022
1560
  synastry_aspects = AspectsFactory.dual_chart_aspects(subject1, subject2)
1023
1561
  ```
1024
1562
 
1563
+ Note (v5.1): The two lists `relevant_aspects` and `all_aspects` were unified into a single, cleaned list: `aspects`. If you previously used either property, switch to `aspects`. The legacy properties still work via the backward-compatibility layer but both return the same unified list.
1564
+
1025
1565
  ### 🔄 Migration Guide
1026
1566
 
1027
1567
  #### Using the Backward Compatibility Layer
@@ -1031,7 +1571,13 @@ For a gradual migration, use the `kerykeion.backword` module:
1031
1571
  ```python
1032
1572
  from kerykeion import AstrologicalSubject # Legacy wrapper
1033
1573
 
1034
- subject = AstrologicalSubject("John Doe", 1990, 1, 1, 12, 0, "London", "GB")
1574
+ subject = AstrologicalSubject(
1575
+ "John Doe", 1990, 1, 1, 12, 0,
1576
+ lng=-0.1276,
1577
+ lat=51.5074,
1578
+ tz_str="Europe/London",
1579
+ online=False,
1580
+ )
1035
1581
 
1036
1582
  # These still work but show DeprecationWarnings
1037
1583
  print(subject.mean_node) # Maps to mean_north_lunar_node
@@ -1044,58 +1590,127 @@ print(subject.true_node) # Maps to true_north_lunar_node
1044
1590
 
1045
1591
  1. **Update imports**
1046
1592
 
1047
- ```python
1048
- # Old
1049
- from kerykeion import AstrologicalSubject, KerykeionChartSVG
1593
+ ```python
1594
+ # Old (v4)
1595
+ from kerykeion import AstrologicalSubject, KerykeionChartSVG
1050
1596
 
1051
- # New
1052
- from kerykeion import AstrologicalSubjectFactory, ChartDataFactory, ChartDrawer
1053
- ```
1597
+ # New (v5)
1598
+ from kerykeion import AstrologicalSubjectFactory, ChartDataFactory, ChartDrawer
1599
+ ```
1054
1600
 
1055
1601
  2. **Update subject creation**
1056
1602
 
1057
- ```python
1058
- # Old
1059
- subject = AstrologicalSubject("John", 1990, 1, 1, 12, 0, "London", "GB")
1603
+ ```python
1604
+ from kerykeion import AstrologicalSubject, AstrologicalSubjectFactory
1605
+
1606
+ # Old (v4)
1607
+ subject = AstrologicalSubject(
1608
+ "John", 1990, 1, 1, 12, 0,
1609
+ lng=-0.1276,
1610
+ lat=51.5074,
1611
+ tz_str="Europe/London",
1612
+ online=False,
1613
+ )
1060
1614
 
1061
- # New
1062
- subject = AstrologicalSubjectFactory.from_birth_data("John", 1990, 1, 1, 12, 0, "London", "GB")
1063
- ```
1615
+ # New (v5)
1616
+ subject = AstrologicalSubjectFactory.from_birth_data(
1617
+ "John", 1990, 1, 1, 12, 0,
1618
+ lng=-0.1276,
1619
+ lat=51.5074,
1620
+ tz_str="Europe/London",
1621
+ online=False,
1622
+ )
1623
+ ```
1064
1624
 
1065
1625
  3. **Update chart generation**
1066
1626
 
1067
- ```python
1068
- # Old
1069
- chart = KerykeionChartSVG(subject)
1070
- chart.makeSVG()
1627
+ ```python
1628
+ from pathlib import Path
1629
+ from kerykeion import AstrologicalSubject, AstrologicalSubjectFactory, ChartDataFactory, KerykeionChartSVG
1630
+ from kerykeion.charts.chart_drawer import ChartDrawer
1071
1631
 
1072
- # New
1073
- chart_data = ChartDataFactory.create_natal_chart_data(subject)
1074
- drawer = ChartDrawer(chart_data=chart_data)
1075
- drawer.save_svg()
1076
- ```
1632
+ # Old (v4)
1633
+ legacy_subject = AstrologicalSubject(
1634
+ "John", 1990, 1, 1, 12, 0,
1635
+ lng=-0.1276,
1636
+ lat=51.5074,
1637
+ tz_str="Europe/London",
1638
+ online=False,
1639
+ )
1640
+ output_dir = Path("charts_output")
1641
+ output_dir.mkdir(exist_ok=True)
1077
1642
 
1078
- 4. **Update field access** (lunar nodes)
1643
+ chart = KerykeionChartSVG(legacy_subject, new_output_directory=output_dir)
1644
+ chart.makeSVG()
1079
1645
 
1080
- ```python
1081
- # Old
1082
- print(subject.mean_node.position)
1646
+ # New (v5)
1647
+ modern_subject = AstrologicalSubjectFactory.from_birth_data(
1648
+ "John", 1990, 1, 1, 12, 0,
1649
+ lng=-0.1276,
1650
+ lat=51.5074,
1651
+ tz_str="Europe/London",
1652
+ online=False,
1653
+ )
1654
+ chart_data = ChartDataFactory.create_natal_chart_data(modern_subject)
1655
+ drawer = ChartDrawer(chart_data=chart_data)
1656
+ drawer.save_svg(output_path=output_dir, filename="john-v5-migration")
1657
+ ```
1083
1658
 
1084
- # New
1085
- print(subject.mean_north_lunar_node.position)
1086
- ```
1659
+ 4. **Update field access** (lunar nodes)
1087
1660
 
1088
- 5. **Update aspects**
1661
+ ```python
1662
+ from kerykeion import AstrologicalSubject, AstrologicalSubjectFactory
1663
+
1664
+ # Old (v4)
1665
+ legacy_subject = AstrologicalSubject(
1666
+ "John", 1990, 1, 1, 12, 0,
1667
+ lng=-0.1276,
1668
+ lat=51.5074,
1669
+ tz_str="Europe/London",
1670
+ online=False,
1671
+ )
1672
+ legacy_mean_node = legacy_subject.mean_node
1673
+ print(getattr(legacy_mean_node, "position", "Legacy mean node not active"))
1674
+
1675
+ # New (v5)
1676
+ modern_subject = AstrologicalSubjectFactory.from_birth_data(
1677
+ "John", 1990, 1, 1, 12, 0,
1678
+ lng=-0.1276,
1679
+ lat=51.5074,
1680
+ tz_str="Europe/London",
1681
+ online=False,
1682
+ )
1683
+ modern_mean_node = modern_subject.mean_north_lunar_node
1684
+ print(getattr(modern_mean_node, "position", "Modern mean node not active"))
1685
+ ```
1089
1686
 
1090
- ```python
1091
- # Old
1092
- from kerykeion import NatalAspects
1093
- aspects = NatalAspects(subject)
1687
+ 5. **Update aspects**
1094
1688
 
1095
- # New
1096
- from kerykeion import AspectsFactory
1097
- aspects = AspectsFactory.single_chart_aspects(subject)
1098
- ```
1689
+ ```python
1690
+ from kerykeion import AstrologicalSubject, AstrologicalSubjectFactory, NatalAspects, AspectsFactory
1691
+
1692
+ # Old (v4)
1693
+ legacy_subject = AstrologicalSubject(
1694
+ "John", 1990, 1, 1, 12, 0,
1695
+ lng=-0.1276,
1696
+ lat=51.5074,
1697
+ tz_str="Europe/London",
1698
+ online=False,
1699
+ )
1700
+ legacy_aspects = NatalAspects(legacy_subject)
1701
+ print(f"Legacy aspects count: {len(legacy_aspects.relevant_aspects)}")
1702
+
1703
+ # New (v5)
1704
+ modern_subject = AstrologicalSubjectFactory.from_birth_data(
1705
+ "John", 1990, 1, 1, 12, 0,
1706
+ lng=-0.1276,
1707
+ lat=51.5074,
1708
+ tz_str="Europe/London",
1709
+ online=False,
1710
+ )
1711
+ modern_aspects = AspectsFactory.single_chart_aspects(modern_subject)
1712
+ print(f"Modern aspects count: {len(modern_aspects.aspects)}")
1713
+ ```
1099
1714
 
1100
1715
  #### Automated Migration Script
1101
1716
 
@@ -1166,6 +1781,8 @@ Since the AstrologerAPI is an external third-party service, using it does _not_
1166
1781
 
1167
1782
  Contributions are welcome! Feel free to submit pull requests or report issues.
1168
1783
 
1784
+ By submitting a contribution, you agree to assign the copyright of that contribution to the maintainer. The project stays openly available under the AGPL for everyone, while the re-licensing option helps sustain future development. Your authorship remains acknowledged in the commit history and release notes.
1785
+
1169
1786
  ## Citations
1170
1787
 
1171
1788
  If using Kerykeion in published or academic work, please cite as follows: