kerykeion 4.11.0__tar.gz → 4.12.0__tar.gz

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 (31) hide show
  1. {kerykeion-4.11.0 → kerykeion-4.12.0}/PKG-INFO +40 -16
  2. {kerykeion-4.11.0 → kerykeion-4.12.0}/README.md +38 -14
  3. kerykeion-4.12.0/kerykeion/__init__.py +16 -0
  4. {kerykeion-4.11.0 → kerykeion-4.12.0}/kerykeion/aspects/aspects_utils.py +0 -12
  5. {kerykeion-4.11.0 → kerykeion-4.12.0}/kerykeion/aspects/natal_aspects.py +1 -2
  6. {kerykeion-4.11.0 → kerykeion-4.12.0}/kerykeion/aspects/synastry_aspects.py +3 -4
  7. {kerykeion-4.11.0 → kerykeion-4.12.0}/kerykeion/astrological_subject.py +129 -110
  8. {kerykeion-4.11.0 → kerykeion-4.12.0}/kerykeion/charts/kerykeion_chart_svg.py +40 -18
  9. {kerykeion-4.11.0 → kerykeion-4.12.0}/kerykeion/charts/templates/chart.xml +6 -6
  10. {kerykeion-4.11.0 → kerykeion-4.12.0}/kerykeion/kr_types/kr_literals.py +14 -2
  11. {kerykeion-4.11.0 → kerykeion-4.12.0}/kerykeion/kr_types/kr_models.py +8 -2
  12. {kerykeion-4.11.0 → kerykeion-4.12.0}/kerykeion/utilities.py +14 -0
  13. {kerykeion-4.11.0 → kerykeion-4.12.0}/pyproject.toml +2 -2
  14. kerykeion-4.11.0/kerykeion/__init__.py +0 -257
  15. {kerykeion-4.11.0 → kerykeion-4.12.0}/LICENSE +0 -0
  16. {kerykeion-4.11.0 → kerykeion-4.12.0}/kerykeion/aspects/__init__.py +0 -0
  17. {kerykeion-4.11.0 → kerykeion-4.12.0}/kerykeion/charts/__init__.py +0 -0
  18. {kerykeion-4.11.0 → kerykeion-4.12.0}/kerykeion/charts/charts_utils.py +0 -0
  19. {kerykeion-4.11.0 → kerykeion-4.12.0}/kerykeion/enums.py +0 -0
  20. {kerykeion-4.11.0 → kerykeion-4.12.0}/kerykeion/fetch_geonames.py +0 -0
  21. {kerykeion-4.11.0 → kerykeion-4.12.0}/kerykeion/kr_types/__init__.py +0 -0
  22. {kerykeion-4.11.0 → kerykeion-4.12.0}/kerykeion/kr_types/chart_types.py +0 -0
  23. {kerykeion-4.11.0 → kerykeion-4.12.0}/kerykeion/kr_types/kerykeion_exception.py +0 -0
  24. {kerykeion-4.11.0 → kerykeion-4.12.0}/kerykeion/kr_types/settings_models.py +0 -0
  25. {kerykeion-4.11.0 → kerykeion-4.12.0}/kerykeion/relationship_score.py +0 -0
  26. {kerykeion-4.11.0 → kerykeion-4.12.0}/kerykeion/report.py +0 -0
  27. {kerykeion-4.11.0 → kerykeion-4.12.0}/kerykeion/settings/__init__.py +0 -0
  28. {kerykeion-4.11.0 → kerykeion-4.12.0}/kerykeion/settings/kerykeion_settings.py +0 -0
  29. {kerykeion-4.11.0 → kerykeion-4.12.0}/kerykeion/settings/kr.config.json +0 -0
  30. {kerykeion-4.11.0 → kerykeion-4.12.0}/kerykeion/sweph/README.md +0 -0
  31. {kerykeion-4.11.0 → kerykeion-4.12.0}/kerykeion/sweph/seas_18.se1 +0 -0
@@ -1,8 +1,8 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: kerykeion
3
- Version: 4.11.0
3
+ Version: 4.12.0
4
4
  Summary: A python library for astrology.
5
- Home-page: https://github.com/g-battaglia/kerykeion
5
+ Home-page: https://www.kerykeion.net/
6
6
  License: AGPL-3.0
7
7
  Keywords: astrology,ephemeris,astrology library,birtchart,svg,zodiac,zodiac-sing,astronomical-algorithms,synastry,astrology-calculator
8
8
  Author: Giacomo Battaglia
@@ -69,13 +69,13 @@ The core goal of this project is to provide a simple and easy approach to astrol
69
69
 
70
70
  Here's an example of a birthchart:
71
71
 
72
- ![Kanye Birth Chart](http://centuryboy.altervista.org/KanyeNatalChart.svg)
72
+ ![Kanye Birth Chart](https://www.kerykeion.net/assets/img/examples/birth-chart.svg)
73
73
 
74
74
  ## Web API
75
75
 
76
76
  If you want to use Kerykeion in a web application, I've created a web API for this purpose, you can find it here:
77
77
 
78
- **[AstrologerAPI](https://rapidapi.com/gbattaglia/api/astrologer/)**
78
+ **[AstrologerAPI](https://rapidapi.com/gbattaglia/api/astrologer/pricing)**
79
79
 
80
80
  It's [open source](https://github.com/g-battaglia/Astrologer-API), it's a way to support me and the project.
81
81
 
@@ -142,24 +142,35 @@ If you omit the nation, it will be set to "GB" by default, but the value is not
142
142
  ```python
143
143
  from kerykeion import AstrologicalSubject, KerykeionChartSVG
144
144
 
145
- first = AstrologicalSubject("Jack", 1990, 6, 15, 15, 15, "Roma")
146
- second = AstrologicalSubject("Jane", 1991, 10, 25, 21, 00, "Roma")
145
+ first = AstrologicalSubject("John Lennon", 1940, 10, 9, 18, 30, "Liverpool", "GB")
146
+ second = AstrologicalSubject("Paul McCartney", 1942, 6, 18, 15, 30, "Liverpool", "GB")
147
147
 
148
148
  # Set the type, it can be Natal, Synastry or Transit
149
+ synastry_chart = KerykeionChartSVG(first, "Synastry", second)
150
+ synastry_chart.makeSVG()
149
151
 
150
- name = KerykeionChartSVG(first, chart_type="Synastry", second_obj=second)
151
- name.makeSVG()
152
- print(len(name.aspects_list))
152
+ ```
153
153
 
154
- #> Generating kerykeion object for Jack...
155
- #> Generating kerykeion object for Jane...
156
- #> Jack birth location: Roma, 41.89193, 12.51133
157
- #> SVG Generated Correctly
158
- #> 38
154
+ ![John Lennon and Paul McCartney Synastry](https://www.kerykeion.net/assets/img/examples/synastry-chart.svg)
155
+
156
+ Note: By default, the generated SVG file will be in the home directory! To change the destination directory:
157
+
158
+ ```python
159
+ from kerykeion import AstrologicalSubject, KerykeionChartSVG
160
+
161
+ first = AstrologicalSubject("John Lennon", 1940, 10, 9, 18, 30, "Liverpool", "GB")
162
+ second = AstrologicalSubject("Paul McCartney", 1942, 6, 18, 15, 30, "Liverpool", "GB")
159
163
 
164
+ # Synastry Chart
165
+ synastry_chart = KerykeionChartSVG(first, "Synastry", second, new_output_directory=".")
166
+ synastry_chart.makeSVG()
160
167
  ```
161
168
 
162
- ![Synastry Chart](http://centuryboy.altervista.org/JackComposite_Chart.svg)
169
+ ### Change Language
170
+
171
+ To change the language of the chart you should create a new kr.config.js file and pass it to the BirthChartSVG class. So far the available languages are English, Portuguese, Italian, Spanish, French and Chinese.
172
+
173
+ Some examples [here](https://www.kerykeion.net/docs/examples/change-language).
163
174
 
164
175
  ## Report
165
176
 
@@ -264,12 +275,25 @@ You can set the houses system in the AstrologicalSubject class:
264
275
  johnny = AstrologicalSubject("Johnny Depp", 1963, 6, 9, 0, 0, "Owensboro", "US", houses_system="M")
265
276
  ```
266
277
 
267
- More examples [here](https://www.kerykeion.net/docs/examples/house-systems/).
278
+ More examples [here](https://www.kerykeion.net/docs/examples/houses-systems/).
268
279
 
269
280
  Full list of supported house systems [here](https://www.kerykeion.net/pydocs/kerykeion/kr_types/kr_literals.html#HousesSystem).
270
281
 
271
282
  So far all the available houses system in the Swiss Ephemeris are supported but the Gauquelin Sectors.
272
283
 
284
+ ## Perspective Type
285
+
286
+ The perspective indicates the point of view from which the chart is calculated (Es. Apparent Geocentric, Heliocentric, etc.).
287
+ You can set the perspective type in the AstrologicalSubject class:
288
+
289
+ ```python
290
+ johnny = AstrologicalSubject("Johnny Depp", 1963, 6, 9, 0, 0, "Owensboro", "US", perspective_type="Heliocentric")
291
+ ```
292
+
293
+ More examples [here](https://www.kerykeion.net/docs/examples/perspective-type/).
294
+
295
+ Full list of supported perspective types [here](https://www.kerykeion.net/pydocs/kerykeion/kr_types/kr_literals.html#PerspectiveType).
296
+
273
297
  ## Documentation
274
298
 
275
299
  Most of the functions and the classes are self documented by the types and have docstrings.
@@ -32,13 +32,13 @@ The core goal of this project is to provide a simple and easy approach to astrol
32
32
 
33
33
  Here's an example of a birthchart:
34
34
 
35
- ![Kanye Birth Chart](http://centuryboy.altervista.org/KanyeNatalChart.svg)
35
+ ![Kanye Birth Chart](https://www.kerykeion.net/assets/img/examples/birth-chart.svg)
36
36
 
37
37
  ## Web API
38
38
 
39
39
  If you want to use Kerykeion in a web application, I've created a web API for this purpose, you can find it here:
40
40
 
41
- **[AstrologerAPI](https://rapidapi.com/gbattaglia/api/astrologer/)**
41
+ **[AstrologerAPI](https://rapidapi.com/gbattaglia/api/astrologer/pricing)**
42
42
 
43
43
  It's [open source](https://github.com/g-battaglia/Astrologer-API), it's a way to support me and the project.
44
44
 
@@ -105,24 +105,35 @@ If you omit the nation, it will be set to "GB" by default, but the value is not
105
105
  ```python
106
106
  from kerykeion import AstrologicalSubject, KerykeionChartSVG
107
107
 
108
- first = AstrologicalSubject("Jack", 1990, 6, 15, 15, 15, "Roma")
109
- second = AstrologicalSubject("Jane", 1991, 10, 25, 21, 00, "Roma")
108
+ first = AstrologicalSubject("John Lennon", 1940, 10, 9, 18, 30, "Liverpool", "GB")
109
+ second = AstrologicalSubject("Paul McCartney", 1942, 6, 18, 15, 30, "Liverpool", "GB")
110
110
 
111
111
  # Set the type, it can be Natal, Synastry or Transit
112
+ synastry_chart = KerykeionChartSVG(first, "Synastry", second)
113
+ synastry_chart.makeSVG()
112
114
 
113
- name = KerykeionChartSVG(first, chart_type="Synastry", second_obj=second)
114
- name.makeSVG()
115
- print(len(name.aspects_list))
115
+ ```
116
116
 
117
- #> Generating kerykeion object for Jack...
118
- #> Generating kerykeion object for Jane...
119
- #> Jack birth location: Roma, 41.89193, 12.51133
120
- #> SVG Generated Correctly
121
- #> 38
117
+ ![John Lennon and Paul McCartney Synastry](https://www.kerykeion.net/assets/img/examples/synastry-chart.svg)
118
+
119
+ Note: By default, the generated SVG file will be in the home directory! To change the destination directory:
120
+
121
+ ```python
122
+ from kerykeion import AstrologicalSubject, KerykeionChartSVG
123
+
124
+ first = AstrologicalSubject("John Lennon", 1940, 10, 9, 18, 30, "Liverpool", "GB")
125
+ second = AstrologicalSubject("Paul McCartney", 1942, 6, 18, 15, 30, "Liverpool", "GB")
122
126
 
127
+ # Synastry Chart
128
+ synastry_chart = KerykeionChartSVG(first, "Synastry", second, new_output_directory=".")
129
+ synastry_chart.makeSVG()
123
130
  ```
124
131
 
125
- ![Synastry Chart](http://centuryboy.altervista.org/JackComposite_Chart.svg)
132
+ ### Change Language
133
+
134
+ To change the language of the chart you should create a new kr.config.js file and pass it to the BirthChartSVG class. So far the available languages are English, Portuguese, Italian, Spanish, French and Chinese.
135
+
136
+ Some examples [here](https://www.kerykeion.net/docs/examples/change-language).
126
137
 
127
138
  ## Report
128
139
 
@@ -227,12 +238,25 @@ You can set the houses system in the AstrologicalSubject class:
227
238
  johnny = AstrologicalSubject("Johnny Depp", 1963, 6, 9, 0, 0, "Owensboro", "US", houses_system="M")
228
239
  ```
229
240
 
230
- More examples [here](https://www.kerykeion.net/docs/examples/house-systems/).
241
+ More examples [here](https://www.kerykeion.net/docs/examples/houses-systems/).
231
242
 
232
243
  Full list of supported house systems [here](https://www.kerykeion.net/pydocs/kerykeion/kr_types/kr_literals.html#HousesSystem).
233
244
 
234
245
  So far all the available houses system in the Swiss Ephemeris are supported but the Gauquelin Sectors.
235
246
 
247
+ ## Perspective Type
248
+
249
+ The perspective indicates the point of view from which the chart is calculated (Es. Apparent Geocentric, Heliocentric, etc.).
250
+ You can set the perspective type in the AstrologicalSubject class:
251
+
252
+ ```python
253
+ johnny = AstrologicalSubject("Johnny Depp", 1963, 6, 9, 0, 0, "Owensboro", "US", perspective_type="Heliocentric")
254
+ ```
255
+
256
+ More examples [here](https://www.kerykeion.net/docs/examples/perspective-type/).
257
+
258
+ Full list of supported perspective types [here](https://www.kerykeion.net/pydocs/kerykeion/kr_types/kr_literals.html#PerspectiveType).
259
+
236
260
  ## Documentation
237
261
 
238
262
  Most of the functions and the classes are self documented by the types and have docstrings.
@@ -0,0 +1,16 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ This is part of Kerykeion (C) 2024 Giacomo Battaglia
4
+
5
+ .. include:: ../README.md
6
+ """
7
+
8
+ # Local
9
+ from .astrological_subject import AstrologicalSubject
10
+ from .charts.kerykeion_chart_svg import KerykeionChartSVG
11
+ from .kr_types import *
12
+ from .relationship_score import RelationshipScore
13
+ from .aspects import SynastryAspects, NatalAspects
14
+ from .report import Report
15
+ from .settings import KerykeionSettingsModel, get_settings
16
+ from .enums import Planets, Aspects, Signs
@@ -23,7 +23,6 @@ def get_aspect_from_two_points(aspects_settings: dict, point_one: Union[float, i
23
23
  if int(distance) <= aspects_settings[0]["orb"]:
24
24
  name = aspects_settings[0]["name"]
25
25
  aspect_degrees = aspects_settings[0]["degree"]
26
- color = aspects_settings[0]["color"]
27
26
  verdict = True
28
27
  aid = 0
29
28
 
@@ -34,7 +33,6 @@ def get_aspect_from_two_points(aspects_settings: dict, point_one: Union[float, i
34
33
  ):
35
34
  name = aspects_settings[1]["name"]
36
35
  aspect_degrees = aspects_settings[1]["degree"]
37
- color = aspects_settings[1]["color"]
38
36
  verdict = True
39
37
  aid = 1
40
38
 
@@ -45,7 +43,6 @@ def get_aspect_from_two_points(aspects_settings: dict, point_one: Union[float, i
45
43
  ):
46
44
  name = aspects_settings[2]["name"]
47
45
  aspect_degrees = aspects_settings[2]["degree"]
48
- color = aspects_settings[2]["color"]
49
46
  verdict = True
50
47
  aid = 2
51
48
 
@@ -56,7 +53,6 @@ def get_aspect_from_two_points(aspects_settings: dict, point_one: Union[float, i
56
53
  ):
57
54
  name = aspects_settings[3]["name"]
58
55
  aspect_degrees = aspects_settings[3]["degree"]
59
- color = aspects_settings[3]["color"]
60
56
  verdict = True
61
57
  aid = 3
62
58
 
@@ -67,7 +63,6 @@ def get_aspect_from_two_points(aspects_settings: dict, point_one: Union[float, i
67
63
  ):
68
64
  name = aspects_settings[4]["name"]
69
65
  aspect_degrees = aspects_settings[4]["degree"]
70
- color = aspects_settings[4]["color"]
71
66
  verdict = True
72
67
  aid = 4
73
68
 
@@ -78,7 +73,6 @@ def get_aspect_from_two_points(aspects_settings: dict, point_one: Union[float, i
78
73
  ):
79
74
  name = aspects_settings[5]["name"]
80
75
  aspect_degrees = aspects_settings[5]["degree"]
81
- color = aspects_settings[5]["color"]
82
76
  verdict = True
83
77
  aid = 5
84
78
 
@@ -89,7 +83,6 @@ def get_aspect_from_two_points(aspects_settings: dict, point_one: Union[float, i
89
83
  ):
90
84
  name = aspects_settings[6]["name"]
91
85
  aspect_degrees = aspects_settings[6]["degree"]
92
- color = aspects_settings[6]["color"]
93
86
  verdict = True
94
87
  aid = 6
95
88
 
@@ -100,7 +93,6 @@ def get_aspect_from_two_points(aspects_settings: dict, point_one: Union[float, i
100
93
  ):
101
94
  name = aspects_settings[7]["name"]
102
95
  aspect_degrees = aspects_settings[7]["degree"]
103
- color = aspects_settings[7]["color"]
104
96
  verdict = True
105
97
  aid = 7
106
98
 
@@ -111,7 +103,6 @@ def get_aspect_from_two_points(aspects_settings: dict, point_one: Union[float, i
111
103
  ):
112
104
  name = aspects_settings[8]["name"]
113
105
  aspect_degrees = aspects_settings[8]["degree"]
114
- color = aspects_settings[8]["color"]
115
106
  verdict = True
116
107
  aid = 8
117
108
 
@@ -122,7 +113,6 @@ def get_aspect_from_two_points(aspects_settings: dict, point_one: Union[float, i
122
113
  ):
123
114
  name = aspects_settings[9]["name"]
124
115
  aspect_degrees = aspects_settings[9]["degree"]
125
- color = aspects_settings[9]["color"]
126
116
  verdict = True
127
117
  aid = 9
128
118
 
@@ -133,7 +123,6 @@ def get_aspect_from_two_points(aspects_settings: dict, point_one: Union[float, i
133
123
  ):
134
124
  name = aspects_settings[10]["name"]
135
125
  aspect_degrees = aspects_settings[10]["degree"]
136
- color = aspects_settings[10]["color"]
137
126
  verdict = True
138
127
  aid = 10
139
128
 
@@ -150,7 +139,6 @@ def get_aspect_from_two_points(aspects_settings: dict, point_one: Union[float, i
150
139
  name,
151
140
  distance - aspect_degrees,
152
141
  aspect_degrees,
153
- color,
154
142
  aid,
155
143
  diff,
156
144
  )
@@ -52,7 +52,7 @@ class NatalAspects:
52
52
  for first in range(len(active_points_list)):
53
53
  # Generates the aspects list without repetitions
54
54
  for second in range(first + 1, len(active_points_list)):
55
- verdict, name, orbit, aspect_degrees, color, aid, diff = get_aspect_from_two_points(
55
+ verdict, name, orbit, aspect_degrees, aid, diff = get_aspect_from_two_points(
56
56
  self.aspects_settings, active_points_list[first]["abs_pos"], active_points_list[second]["abs_pos"]
57
57
  )
58
58
 
@@ -65,7 +65,6 @@ class NatalAspects:
65
65
  "aspect": name,
66
66
  "orbit": orbit,
67
67
  "aspect_degrees": aspect_degrees,
68
- "color": color,
69
68
  "aid": aid,
70
69
  "diff": diff,
71
70
  "p1": planet_id_decoder(self.celestial_points, active_points_list[first]["name"]),
@@ -60,7 +60,7 @@ class SynastryAspects(NatalAspects):
60
60
  for first in range(len(first_active_points_list)):
61
61
  # Generates the aspects list whitout repetitions
62
62
  for second in range(len(second_active_points_list)):
63
- verdict, name, orbit, aspect_degrees, color, aid, diff = get_aspect_from_two_points(
63
+ verdict, name, orbit, aspect_degrees, aid, diff = get_aspect_from_two_points(
64
64
  self.aspects_settings,
65
65
  first_active_points_list[first]["abs_pos"],
66
66
  second_active_points_list[second]["abs_pos"],
@@ -75,7 +75,6 @@ class SynastryAspects(NatalAspects):
75
75
  "aspect": name,
76
76
  "orbit": orbit,
77
77
  "aspect_degrees": aspect_degrees,
78
- "color": color,
79
78
  "aid": aid,
80
79
  "diff": diff,
81
80
  "p1": planet_id_decoder(
@@ -96,8 +95,8 @@ if __name__ == "__main__":
96
95
  from kerykeion.utilities import setup_logging
97
96
  setup_logging(level="debug")
98
97
 
99
- john = AstrologicalSubject("John", 1940, 10, 9, 10, 30, "Liverpool")
100
- yoko = AstrologicalSubject("Yoko", 1933, 2, 18, 10, 30, "Tokyo")
98
+ john = AstrologicalSubject("John", 1940, 10, 9, 18, 30, "Liverpool")
99
+ yoko = AstrologicalSubject("Yoko", 1933, 2, 18, 18, 30, "Tokyo")
101
100
 
102
101
  synastry_aspects = SynastryAspects(john, yoko)
103
102
 
@@ -17,7 +17,8 @@ from kerykeion.kr_types import (
17
17
  KerykeionPointModel,
18
18
  PointType,
19
19
  SiderealMode,
20
- HousesSystemIdentifier
20
+ HousesSystemIdentifier,
21
+ PerspectiveType
21
22
  )
22
23
  from kerykeion.utilities import (
23
24
  get_number_from_name,
@@ -25,6 +26,7 @@ from kerykeion.utilities import (
25
26
  get_planet_house,
26
27
  get_moon_emoji_from_phase_int,
27
28
  get_moon_phase_name_from_phase_int,
29
+ check_and_adjust_polar_latitude
28
30
  )
29
31
  from pathlib import Path
30
32
  from typing import Union, get_args
@@ -32,6 +34,8 @@ from typing import Union, get_args
32
34
  DEFAULT_GEONAMES_USERNAME = "century.boy"
33
35
  DEFAULT_SIDEREAL_MODE = "FAGAN_BRADLEY"
34
36
  DEFAULT_HOUSES_SYSTEM = "P"
37
+ PERSPECTIVE_TYPE = "Apparent Geocentric"
38
+ NOW = datetime.now()
35
39
 
36
40
 
37
41
  class AstrologicalSubject:
@@ -40,27 +44,25 @@ class AstrologicalSubject:
40
44
  it's utc and julian day and returns an object with all that data.
41
45
 
42
46
  Args:
43
- - name (str, optional): _ Defaults to "Now".
44
- - year (int, optional): _ Defaults to now.year.
45
- - month (int, optional): _ Defaults to now.month.
46
- - day (int, optional): _ Defaults to now.day.
47
- - hour (int, optional): _ Defaults to now.hour.
48
- - minute (int, optional): _ Defaults to now.minute.
47
+ - name (str, optional): The name of the subject. Defaults to "Now".
48
+ - year (int, optional): The year of birth. Defaults to the current year.
49
+ - month (int, optional): The month of birth. Defaults to the current month.
50
+ - day (int, optional): The day of birth. Defaults to the current day.
51
+ - hour (int, optional): The hour of birth. Defaults to the current hour.
52
+ - minute (int, optional): Defaults to the current minute.
49
53
  - city (str, optional): City or location of birth. Defaults to "London", which is GMT time.
50
54
  The city argument is used to get the coordinates and timezone from geonames just in case
51
55
  you don't insert them manually (see _get_tz).
52
56
  If you insert the coordinates and timezone manually, the city argument is not used for calculations
53
57
  but it's still used as a value for the city attribute.
54
58
  - nat (str, optional): _ Defaults to "".
55
- - lng (Union[int, float], optional): _ Defaults to False.
56
- - lat (Union[int, float], optional): _ Defaults to False.
57
- - tz_str (Union[str, bool], optional): _ Defaults to False.
58
- - geonames_username (str, optional): _ Defaults to 'century.boy'.
59
- - online (bool, optional): Sets if you want to use the online mode (using
60
- geonames) or not. Defaults to True.
61
- - utc_datetime (datetime, optional): An alternative way of constructing the object,
62
- if you know the UTC datetime but do not have easy access to e.g. timezone identifier
63
- _ Defaults to None.
59
+ - lng (Union[int, float], optional): Longitude of the birth location. Defaults to 0 (Greenwich, London).
60
+ - lat (Union[int, float], optional): Latitude of the birth location. Defaults to 51.5074 (Greenwich, London).
61
+ - tz_str (Union[str, bool], optional): Timezone of the birth location. Defaults to "GMT".
62
+ - geonames_username (str, optional): The username for the geonames API. Note: Change this to your own username to avoid rate limits!
63
+ You can get one for free here: https://www.geonames.org/login
64
+ - online (bool, optional): Sets if you want to use the online mode, which fetches the timezone and coordinates from geonames.
65
+ If you already have the coordinates and timezone, set this to False. Defaults to True.
64
66
  - disable_chiron (bool, optional): Disables the calculation of Chiron. Defaults to False.
65
67
  Chiron calculation can create some issues with the Swiss Ephemeris when the date is too far in the past.
66
68
  - sidereal_mode (SiderealMode, optional): Also known as Ayanamsa.
@@ -68,11 +70,15 @@ class AstrologicalSubject:
68
70
  Defaults to "FAGAN_BRADLEY".
69
71
  Available modes are visible in the SiderealMode Literal.
70
72
  - houses_system_identifier (HousesSystemIdentifier, optional): The system to use for the calculation of the houses.
73
+ Defaults to "P" (Placidus).
74
+ Available systems are visible in the HousesSystemIdentifier Literal.
75
+ - perspective_type (PerspectiveType, optional): The perspective to use for the calculation of the chart.
76
+ Defaults to "Apparent Geocentric".
77
+ Available perspectives are visible in the PerspectiveType Literal.
71
78
  """
72
79
 
73
80
  # Defined by the user
74
81
  name: str
75
- utc_datetime: Union[datetime, None]
76
82
  year: int
77
83
  month: int
78
84
  day: int
@@ -89,14 +95,14 @@ class AstrologicalSubject:
89
95
  sidereal_mode: SiderealMode
90
96
  houses_system_identifier: HousesSystemIdentifier
91
97
  houses_system_name: str
98
+ perspective_type: PerspectiveType
92
99
 
93
100
  # Generated internally
94
101
  city_data: dict[str, str]
95
102
  julian_day: Union[int, float]
96
- utc_time: float
97
- local_time: float
98
- utc: datetime
99
103
  json_dir: Path
104
+ iso_formatted_local_datetime: str
105
+ iso_formatted_utc_datetime: str
100
106
 
101
107
  # Planets
102
108
  sun: KerykeionPointModel
@@ -133,16 +139,14 @@ class AstrologicalSubject:
133
139
  planets_degrees_ut: list[float]
134
140
  houses_degree_ut: list[float]
135
141
 
136
- now = datetime.now()
137
-
138
142
  def __init__(
139
143
  self,
140
144
  name="Now",
141
- year: int = now.year,
142
- month: int = now.month,
143
- day: int = now.day,
144
- hour: int = now.hour,
145
- minute: int = now.minute,
145
+ year: int = NOW.year,
146
+ month: int = NOW.month,
147
+ day: int = NOW.day,
148
+ hour: int = NOW.hour,
149
+ minute: int = NOW.minute,
146
150
  city: Union[str, None] = None,
147
151
  nation: Union[str, None] = None,
148
152
  lng: Union[int, float, None] = None,
@@ -151,19 +155,13 @@ class AstrologicalSubject:
151
155
  geonames_username: Union[str, None] = None,
152
156
  zodiac_type: ZodiacType = "Tropic",
153
157
  online: bool = True,
154
- utc_datetime: Union[datetime, None] = None,
155
158
  disable_chiron: bool = False,
156
159
  sidereal_mode: Union[SiderealMode, None] = None,
157
- houses_system_identifier: HousesSystemIdentifier = DEFAULT_HOUSES_SYSTEM
160
+ houses_system_identifier: HousesSystemIdentifier = DEFAULT_HOUSES_SYSTEM,
161
+ perspective_type: PerspectiveType = PERSPECTIVE_TYPE
158
162
  ) -> None:
159
163
  logging.debug("Starting Kerykeion")
160
164
 
161
- # We set the swisseph path to the current directory
162
- swe.set_ephe_path(str(Path(__file__).parent.absolute() / "sweph"))
163
-
164
- # Flags for the Swiss Ephemeris
165
- self._iflag = swe.FLG_SWIEPH + swe.FLG_SPEED
166
-
167
165
  self.name = name
168
166
  self.year = year
169
167
  self.month = month
@@ -179,39 +177,14 @@ class AstrologicalSubject:
179
177
  self.online = online
180
178
  self.json_dir = Path.home()
181
179
  self.geonames_username = geonames_username
182
- self.utc_datetime = utc_datetime
183
180
  self.disable_chiron = disable_chiron
184
181
  self.sidereal_mode = sidereal_mode
185
182
  self.houses_system_identifier = houses_system_identifier
183
+ self.perspective_type = perspective_type
186
184
 
187
- # House System check and setup --->
188
- if self.houses_system_identifier not in get_args(HousesSystemIdentifier):
189
- raise KerykeionException(f"\n* ERROR: '{self.houses_system_identifier}' is NOT a valid house system! Available systems are: *" + "\n" + str(get_args(HousesSystemIdentifier)))
190
-
191
- self.houses_system_name = swe.house_name(self.houses_system_identifier.encode('ascii'))
192
- # <--- House System check and setup
193
-
194
- # Zodiac Type and Sidereal mode checks and setup --->
195
- if zodiac_type and not zodiac_type in get_args(ZodiacType):
196
- raise KerykeionException(f"\n* ERROR: '{zodiac_type}' is NOT a valid zodiac type! Available types are: *" + "\n" + str(get_args(ZodiacType)))
197
-
198
- if self.sidereal_mode and self.zodiac_type == "Tropic":
199
- raise KerykeionException("You can't set a sidereal mode with a Tropic zodiac type!")
200
-
201
- if self.zodiac_type == "Sidereal" and not self.sidereal_mode:
202
- self.sidereal_mode = DEFAULT_SIDEREAL_MODE
203
- logging.info("No sidereal mode set, using default FAGAN_BRADLEY")
204
-
205
- if self.zodiac_type == "Sidereal":
206
- # Check if the sidereal mode is valid
207
- if not self.sidereal_mode in get_args(SiderealMode):
208
- raise KerykeionException(f"\n* ERROR: '{self.sidereal_mode}' is NOT a valid sidereal mode! Available modes are: *" + "\n" + str(get_args(SiderealMode)))
209
-
210
- self._iflag += swe.FLG_SIDEREAL
211
- mode = "SIDM_" + self.sidereal_mode
212
- swe.set_sid_mode(getattr(swe, mode))
213
- logging.debug(f"Using sidereal mode: {mode}")
214
- # <--- Zodiac Type and Sidereal mode checks and setup
185
+ #---------------#
186
+ # General setup #
187
+ #---------------#
215
188
 
216
189
  # This message is set to encourage the user to set a custom geonames username
217
190
  if geonames_username is None and online:
@@ -253,23 +226,95 @@ class AstrologicalSubject:
253
226
  if (not self.online) and (not tz_str):
254
227
  raise KerykeionException("You need to set the coordinates and timezone if you want to use the offline mode!")
255
228
 
256
- self._check_if_poles()
229
+ #-----------------------#
230
+ # Swiss Ephemeris setup #
231
+ #-----------------------#
232
+
233
+ # We set the swisseph path to the current directory
234
+ swe.set_ephe_path(str(Path(__file__).parent.absolute() / "sweph"))
235
+
236
+ # Flags for the Swiss Ephemeris
237
+ self._iflag = swe.FLG_SWIEPH + swe.FLG_SPEED
238
+
239
+ # Chart Perspective check and setup --->
240
+ if self.perspective_type not in get_args(PerspectiveType):
241
+ raise KerykeionException(f"\n* ERROR: '{self.perspective_type}' is NOT a valid chart perspective! Available perspectives are: *" + "\n" + str(get_args(PerspectiveType)))
242
+
243
+ if self.perspective_type == "True Geocentric":
244
+ self._iflag += swe.FLG_TRUEPOS
245
+ elif self.perspective_type == "Heliocentric":
246
+ self._iflag += swe.FLG_HELCTR
247
+ elif self.perspective_type == "Topocentric":
248
+ self._iflag += swe.FLG_TOPOCTR
249
+ # geopos_is_set, for topocentric
250
+ swe.set_topo(self.lng, self.lat, 0)
251
+ # <--- Chart Perspective check and setup
252
+
253
+ # House System check and setup --->
254
+ if self.houses_system_identifier not in get_args(HousesSystemIdentifier):
255
+ raise KerykeionException(f"\n* ERROR: '{self.houses_system_identifier}' is NOT a valid house system! Available systems are: *" + "\n" + str(get_args(HousesSystemIdentifier)))
256
+
257
+ self.houses_system_name = swe.house_name(self.houses_system_identifier.encode('ascii'))
258
+ # <--- House System check and setup
259
+
260
+ # Zodiac Type and Sidereal mode checks and setup --->
261
+ if zodiac_type and not zodiac_type in get_args(ZodiacType):
262
+ raise KerykeionException(f"\n* ERROR: '{zodiac_type}' is NOT a valid zodiac type! Available types are: *" + "\n" + str(get_args(ZodiacType)))
263
+
264
+ if self.sidereal_mode and self.zodiac_type == "Tropic":
265
+ raise KerykeionException("You can't set a sidereal mode with a Tropic zodiac type!")
266
+
267
+ if self.zodiac_type == "Sidereal" and not self.sidereal_mode:
268
+ self.sidereal_mode = DEFAULT_SIDEREAL_MODE
269
+ logging.info("No sidereal mode set, using default FAGAN_BRADLEY")
270
+
271
+ if self.zodiac_type == "Sidereal":
272
+ # Check if the sidereal mode is valid
273
+ if not self.sidereal_mode in get_args(SiderealMode):
274
+ raise KerykeionException(f"\n* ERROR: '{self.sidereal_mode}' is NOT a valid sidereal mode! Available modes are: *" + "\n" + str(get_args(SiderealMode)))
275
+
276
+ self._iflag += swe.FLG_SIDEREAL
277
+ mode = "SIDM_" + self.sidereal_mode
278
+ swe.set_sid_mode(getattr(swe, mode))
279
+ logging.debug(f"Using sidereal mode: {mode}")
280
+ # <--- Zodiac Type and Sidereal mode checks and setup
281
+
282
+ #------------------------#
283
+ # Start the calculations #
284
+ #------------------------#
285
+
286
+ check_and_adjust_polar_latitude(self.lat, self.lng)
287
+
288
+ # UTC, julian day and local time setup --->
289
+ if (self.online) and (not self.tz_str):
290
+ self._fetch_tz_from_geonames()
291
+
292
+ # Local time to UTC
293
+ local_time = pytz.timezone(self.tz_str)
294
+ naive_datetime = datetime(self.year, self.month, self.day, self.hour, self.minute, 0)
295
+ local_datetime = local_time.localize(naive_datetime, is_dst=None)
296
+ utc_object = local_datetime.astimezone(pytz.utc)
297
+ self.iso_formatted_utc_datetime = utc_object.isoformat()
298
+
299
+ # ISO formatted local datetime
300
+ self.iso_formatted_local_datetime = local_datetime.isoformat()
301
+
302
+ # Julian day calculation
303
+ utc_float_hour_with_minutes = utc_object.hour + (utc_object.minute / 60)
304
+ self.julian_day = float(swe.julday(utc_object.year, utc_object.month, utc_object.day, utc_float_hour_with_minutes))
305
+ # <--- UTC, julian day and local time setup
257
306
 
258
- # Initialize everything
259
- self._get_utc()
260
- self._get_jd()
261
307
  self._planets_degrees_lister()
262
308
  self._planets()
263
309
  self._houses()
264
-
265
310
  self._planets_in_houses()
266
311
  self._lunar_phase_calc()
267
312
 
268
313
  def __str__(self) -> str:
269
- return f"Astrological data for: {self.name}, {self.utc} UTC\nBirth location: {self.city}, Lat {self.lat}, Lon {self.lng}"
314
+ return f"Astrological data for: {self.name}, {self.iso_formatted_utc_datetime} UTC\nBirth location: {self.city}, Lat {self.lat}, Lon {self.lng}"
270
315
 
271
316
  def __repr__(self) -> str:
272
- return f"Astrological data for: {self.name}, {self.utc} UTC\nBirth location: {self.city}, Lat {self.lat}, Lon {self.lng}"
317
+ return f"Astrological data for: {self.name}, {self.iso_formatted_utc_datetime} UTC\nBirth location: {self.city}, Lat {self.lat}, Lon {self.lng}"
273
318
 
274
319
  def __getitem__(self, item):
275
320
  return getattr(self, item)
@@ -301,32 +346,7 @@ class AstrologicalSubject:
301
346
  self.lat = float(self.city_data["lat"])
302
347
  self.tz_str = self.city_data["timezonestr"]
303
348
 
304
- self._check_if_poles()
305
-
306
- def _get_utc(self) -> None:
307
- """Converts local time to utc time."""
308
-
309
- # If the coordinates are not set, get them from geonames.
310
- if (self.online) and (not self.tz_str):
311
- self._fetch_tz_from_geonames()
312
-
313
- # If UTC datetime is provided, then use it directly
314
- if (self.utc_datetime):
315
- self.utc = self.utc_datetime
316
- return
317
-
318
- local_time = pytz.timezone(self.tz_str)
319
-
320
- naive_datetime = datetime(self.year, self.month, self.day, self.hour, self.minute, 0)
321
-
322
- local_datetime = local_time.localize(naive_datetime, is_dst=None)
323
- self.utc = local_datetime.astimezone(pytz.utc)
324
-
325
- def _get_jd(self) -> None:
326
- """Calculates julian day from the utc time."""
327
- self.utc_time = self.utc.hour + self.utc.minute / 60
328
- self.local_time = self.hour + self.minute / 60
329
- self.julian_day = float(swe.julday(self.utc.year, self.utc.month, self.utc.day, self.utc_time))
349
+ check_and_adjust_polar_latitude(self.lat, self.lng)
330
350
 
331
351
  def _houses(self) -> None:
332
352
  """
@@ -595,19 +615,6 @@ class AstrologicalSubject:
595
615
 
596
616
  self.lunar_phase = LunarPhaseModel(**lunar_phase_dictionary)
597
617
 
598
- def _check_if_poles(self):
599
- """
600
- Utility function to check if the location is in the polar circle.
601
- If it is, it sets the latitude to 66 or -66 degrees.
602
- """
603
- if self.lat > 66.0:
604
- self.lat = 66.0
605
- logging.info("Polar circle override for houses, using 66 degrees")
606
-
607
- elif self.lat < -66.0:
608
- self.lat = -66.0
609
- logging.info("Polar circle override for houses, using -66 degrees")
610
-
611
618
  def json(self, dump=False, destination_folder: Union[str, None] = None, indent: Union[int, None] = None) -> str:
612
619
  """
613
620
  Dumps the Kerykeion object to a json string foramt,
@@ -666,4 +673,16 @@ if __name__ == "__main__":
666
673
 
667
674
  # With Morinus Houses
668
675
  johnny = AstrologicalSubject("Johnny Depp", 1963, 6, 9, 0, 0, "Owensboro", "US", houses_system_identifier="M")
676
+ print(johnny.json(dump=True, indent=2))
677
+
678
+ # With True Geocentric Perspective
679
+ johnny = AstrologicalSubject("Johnny Depp", 1963, 6, 9, 0, 0, "Owensboro", "US", perspective_type="True Geocentric")
680
+ print(johnny.json(dump=True, indent=2))
681
+
682
+ # With Heliocentric Perspective
683
+ johnny = AstrologicalSubject("Johnny Depp", 1963, 6, 9, 0, 0, "Owensboro", "US", perspective_type="Heliocentric")
684
+ print(johnny.json(dump=True, indent=2))
685
+
686
+ # With Topocentric Perspective
687
+ johnny = AstrologicalSubject("Johnny Depp", 1963, 6, 9, 0, 0, "Owensboro", "US", perspective_type="Topocentric")
669
688
  print(johnny.json(dump=True, indent=2))
@@ -33,6 +33,7 @@ from pathlib import Path
33
33
  from scour.scour import scourString
34
34
  from string import Template
35
35
  from typing import Union, List
36
+ from datetime import datetime
36
37
 
37
38
 
38
39
 
@@ -1017,7 +1018,7 @@ class KerykeionChartSVG:
1017
1018
  li = 10
1018
1019
  offset = 0
1019
1020
 
1020
- out = '<g transform="translate(500,-20)">'
1021
+ out = '<g transform="translate(510,-20)">'
1021
1022
  out += '<g transform="translate(140, -15)">'
1022
1023
  out += f'<text text-anchor="end" style="fill:{self.chart_colors_settings["paper_0"]}; font-size: 14px;">{self.language_settings["planets_and_house"]} {self.user.name}:</text>'
1023
1024
  out += "</g>"
@@ -1108,7 +1109,7 @@ class KerykeionChartSVG:
1108
1109
  Returns:
1109
1110
  str: The SVG code for the grid of houses.
1110
1111
  """
1111
- out = '<g transform="translate(600,-20)">'
1112
+ out = '<g transform="translate(610,-20)">'
1112
1113
 
1113
1114
  li = 10
1114
1115
  for i in range(12):
@@ -1126,8 +1127,10 @@ class KerykeionChartSVG:
1126
1127
  out += "</g>"
1127
1128
 
1128
1129
  if self.chart_type == "Synastry":
1129
- out += '<g transform="translate(840, -20)">'
1130
+ out += '<!-- Synastry Houses -->'
1131
+ out += '<g transform="translate(850, -20)">'
1130
1132
  li = 10
1133
+
1131
1134
  for i in range(12):
1132
1135
  if i < 9:
1133
1136
  cusp = "&#160;&#160;" + str(i + 1)
@@ -1236,16 +1239,16 @@ class KerykeionChartSVG:
1236
1239
  if self.chart_type == "Natal" or self.chart_type == "ExternalNatal" or self.chart_type == "Synastry":
1237
1240
  td["bottomLeft0"] = f"{self.user.zodiac_type if self.user.zodiac_type == 'Tropic' else self.user.zodiac_type + ' ' + self.user.sidereal_mode}"
1238
1241
  td["bottomLeft1"] = f"{self.user.houses_system_name}"
1239
- td["bottomLeft2"] = f'{self.language_settings.get("lunar_phase", "Lunar Phase")}: {self.user.lunar_phase.moon_phase_name}'
1240
- td["bottomLeft3"] = f'{self.language_settings.get("lunar_phase", "Lunar Phase")}: {self.language_settings.get("day", "Day")} {self.user.lunar_phase.get("moon_phase", "")}'
1241
- td["bottomLeft4"] = ""
1242
+ td["bottomLeft2"] = f'{self.language_settings.get("lunar_phase", "Lunar Phase")}: {self.language_settings.get("day", "Day")} {self.user.lunar_phase.get("moon_phase", "")}'
1243
+ td["bottomLeft3"] = f'{self.language_settings.get("lunar_phase", "Lunar Phase")}: {self.user.lunar_phase.moon_phase_name}'
1244
+ td["bottomLeft4"] = f'{self.user.perspective_type}'
1242
1245
 
1243
1246
  else:
1244
1247
  td["bottomLeft0"] = f"{self.user.zodiac_type if self.user.zodiac_type == 'Tropic' else self.user.zodiac_type + ' ' + self.user.sidereal_mode}"
1245
1248
  td["bottomLeft1"] = f"{self.user.houses_system_name}"
1246
- td["bottomLeft2"] = f'{self.language_settings.get("lunar_phase", "Lunar Phase")}: {self.t_user.lunar_phase.moon_phase_name}'
1247
- td["bottomLeft3"] = f'{self.language_settings.get("lunar_phase", "Lunar Phase")}: {self.language_settings.get("day", "Day")} {self.t_user.lunar_phase.get("moon_phase", "")}'
1248
- td["bottomLeft4"] = ""
1249
+ td["bottomLeft2"] = f'{self.language_settings.get("lunar_phase", "Lunar Phase")}: {self.language_settings.get("day", "Day")} {self.t_user.lunar_phase.get("moon_phase", "")}'
1250
+ td["bottomLeft3"] = f'{self.language_settings.get("lunar_phase", "Lunar Phase")}: {self.t_user.lunar_phase.moon_phase_name}'
1251
+ td["bottomLeft4"] = f'{self.t_user.perspective_type}'
1249
1252
 
1250
1253
  # lunar phase
1251
1254
  deg = self.user.lunar_phase["degrees_between_s_m"]
@@ -1313,8 +1316,6 @@ class KerykeionChartSVG:
1313
1316
  else:
1314
1317
  td["stringLocation"] = self.location
1315
1318
 
1316
- td["stringDateTime"] = f"{self.user.year}-{self.user.month}-{self.user.day} {self.user.hour:02d}:{self.user.minute:02d}"
1317
-
1318
1319
  if self.chart_type == "Synastry":
1319
1320
  td["stringLat"] = f"{self.t_user.name}: "
1320
1321
  td["stringLon"] = self.t_user.city
@@ -1378,6 +1379,12 @@ class KerykeionChartSVG:
1378
1379
  )
1379
1380
  td["makePlanetGrid"] = self._makePlanetGrid()
1380
1381
 
1382
+ # Date time String
1383
+ dt = datetime.fromisoformat(self.user.iso_formatted_local_datetime)
1384
+ custom_format = dt.strftime('%Y-%-m-%-d %H:%M [%z]') # Note the use of '-' to remove leading zeros
1385
+ custom_format = custom_format[:-3] + ':' + custom_format[-3:]
1386
+ td["stringDateTime"] = f"{custom_format}"
1387
+
1381
1388
  return td
1382
1389
 
1383
1390
  def makeTemplate(self, minify: bool = False) -> str:
@@ -1420,7 +1427,7 @@ if __name__ == "__main__":
1420
1427
  from kerykeion.utilities import setup_logging
1421
1428
  setup_logging(level="debug")
1422
1429
 
1423
- first = AstrologicalSubject("John Lennon", 1940, 10, 9, 10, 30, "Liverpool", "GB")
1430
+ first = AstrologicalSubject("John Lennon", 1940, 10, 9, 18, 30, "Liverpool", "GB")
1424
1431
  second = AstrologicalSubject("Paul McCartney", 1942, 6, 18, 15, 30, "Liverpool", "GB")
1425
1432
 
1426
1433
  # Internal Natal Chart
@@ -1440,27 +1447,27 @@ if __name__ == "__main__":
1440
1447
  transits_chart.makeSVG()
1441
1448
 
1442
1449
  # Sidereal Birth Chart (Lahiri)
1443
- sidereal_subject = AstrologicalSubject("John Lennon Lahiri", 1940, 10, 9, 10, 30, "Liverpool", "GB", zodiac_type="Sidereal", sidereal_mode="LAHIRI")
1450
+ sidereal_subject = AstrologicalSubject("John Lennon Lahiri", 1940, 10, 9, 18, 30, "Liverpool", "GB", zodiac_type="Sidereal", sidereal_mode="LAHIRI")
1444
1451
  sidereal_chart = KerykeionChartSVG(sidereal_subject)
1445
1452
  sidereal_chart.makeSVG()
1446
1453
 
1447
1454
  # Sidereal Birth Chart (Fagan-Bradley)
1448
- sidereal_subject = AstrologicalSubject("John Lennon Fagan-Bradley", 1940, 10, 9, 10, 30, "Liverpool", "GB", zodiac_type="Sidereal", sidereal_mode="FAGAN_BRADLEY")
1455
+ sidereal_subject = AstrologicalSubject("John Lennon Fagan-Bradley", 1940, 10, 9, 18, 30, "Liverpool", "GB", zodiac_type="Sidereal", sidereal_mode="FAGAN_BRADLEY")
1449
1456
  sidereal_chart = KerykeionChartSVG(sidereal_subject)
1450
1457
  sidereal_chart.makeSVG()
1451
1458
 
1452
1459
  # Sidereal Birth Chart (DeLuce)
1453
- sidereal_subject = AstrologicalSubject("John Lennon DeLuce", 1940, 10, 9, 10, 30, "Liverpool", "GB", zodiac_type="Sidereal", sidereal_mode="DELUCE")
1460
+ sidereal_subject = AstrologicalSubject("John Lennon DeLuce", 1940, 10, 9, 18, 30, "Liverpool", "GB", zodiac_type="Sidereal", sidereal_mode="DELUCE")
1454
1461
  sidereal_chart = KerykeionChartSVG(sidereal_subject)
1455
1462
  sidereal_chart.makeSVG()
1456
1463
 
1457
1464
  # Sidereal Birth Chart (J2000)
1458
- sidereal_subject = AstrologicalSubject("John Lennon J2000", 1940, 10, 9, 10, 30, "Liverpool", "GB", zodiac_type="Sidereal", sidereal_mode="J2000")
1465
+ sidereal_subject = AstrologicalSubject("John Lennon J2000", 1940, 10, 9, 18, 30, "Liverpool", "GB", zodiac_type="Sidereal", sidereal_mode="J2000")
1459
1466
  sidereal_chart = KerykeionChartSVG(sidereal_subject)
1460
1467
  sidereal_chart.makeSVG()
1461
1468
 
1462
1469
  # House System Morinus
1463
- morinus_house_subject = AstrologicalSubject("John Lennon - House System Morinus", 1940, 10, 9, 10, 30, "Liverpool", "GB", houses_system_identifier="M")
1470
+ morinus_house_subject = AstrologicalSubject("John Lennon - House System Morinus", 1940, 10, 9, 18, 30, "Liverpool", "GB", houses_system_identifier="M")
1464
1471
  morinus_house_chart = KerykeionChartSVG(morinus_house_subject)
1465
1472
  morinus_house_chart.makeSVG()
1466
1473
 
@@ -1468,6 +1475,21 @@ if __name__ == "__main__":
1468
1475
  # from kerykeion.kr_types import HousesSystemIdentifier
1469
1476
  # from typing import get_args
1470
1477
  # for i in get_args(HousesSystemIdentifier):
1471
- # alternatives_house_subject = AstrologicalSubject(f"John Lennon - House System {i}", 1940, 10, 9, 10, 30, "Liverpool", "GB", houses_system=i)
1478
+ # alternatives_house_subject = AstrologicalSubject(f"John Lennon - House System {i}", 1940, 10, 9, 18, 30, "Liverpool", "GB", houses_system=i)
1472
1479
  # alternatives_house_chart = KerykeionChartSVG(alternatives_house_subject)
1473
1480
  # alternatives_house_chart.makeSVG()
1481
+
1482
+ # With True Geocentric Perspective
1483
+ true_geocentric_subject = AstrologicalSubject("John Lennon - True Geocentric", 1940, 10, 9, 18, 30, "Liverpool", "GB", perspective_type="True Geocentric")
1484
+ true_geocentric_chart = KerykeionChartSVG(true_geocentric_subject)
1485
+ true_geocentric_chart.makeSVG()
1486
+
1487
+ # With Heliocentric Perspective
1488
+ heliocentric_subject = AstrologicalSubject("John Lennon - Heliocentric", 1940, 10, 9, 18, 30, "Liverpool", "GB", perspective_type="Heliocentric")
1489
+ heliocentric_chart = KerykeionChartSVG(heliocentric_subject)
1490
+ heliocentric_chart.makeSVG()
1491
+
1492
+ # With Topocentric Perspective
1493
+ topocentric_subject = AstrologicalSubject("John Lennon - Topocentric", 1940, 10, 9, 18, 30, "Liverpool", "GB", perspective_type="Topocentric")
1494
+ topocentric_chart = KerykeionChartSVG(topocentric_subject)
1495
+ topocentric_chart.makeSVG()
@@ -14,18 +14,18 @@
14
14
  <g transform="scale($cfgZoom)">
15
15
  <rect class="background-rectangle" x="0" y="0" width="$chart_width"
16
16
  height="$chart_height" style="fill: $paper_color_1" />
17
- <text x="20" y="30" style="fill: $paper_color_0; font-size: 24px">$stringTitle</text>
17
+ <text x="20" y="22" style="fill: $paper_color_0; font-size: 24px">$stringTitle</text>
18
18
  <text x="20" y="50" style="fill: $paper_color_0; font-size: 11px">$stringName</text>
19
19
  <text x="20" y="62" style="fill: $paper_color_0; font-size: 11px">$stringLocation</text>
20
20
  <text x="20" y="74" style="fill: $paper_color_0; font-size: 11px">$stringDateTime</text>
21
21
  <text x="20" y="86" style="fill: $paper_color_0; font-size: 11px">$stringLat</text>
22
22
  <text x="20" y="98" style="fill: $paper_color_0; font-size: 11px">$stringLon</text>
23
23
  <text x="20" y="110" style="fill: $paper_color_0; font-size: 11px">$stringPosition</text>
24
- <text x="20" y="466" style="fill: $paper_color_0; font-size: 10px">$bottomLeft0</text>
25
- <text x="20" y="480" style="fill: $paper_color_0; font-size: 10px">$bottomLeft1</text>
26
- <text x="20" y="494" style="fill: $paper_color_0; font-size: 10px">$bottomLeft2</text>
27
- <text x="20" y="508" style="fill: $paper_color_0; font-size: 10px">$bottomLeft3</text>
28
- <text x="20" y="522" style="fill: $paper_color_0; font-size: 10px">$bottomLeft4</text>
24
+ <text x="20" y="452" style="fill: $paper_color_0; font-size: 10px">$bottomLeft0</text>
25
+ <text x="20" y="466" style="fill: $paper_color_0; font-size: 10px">$bottomLeft1</text>
26
+ <text x="20" y="480" style="fill: $paper_color_0; font-size: 10px">$bottomLeft2</text>
27
+ <text x="20" y="494" style="fill: $paper_color_0; font-size: 10px">$bottomLeft3</text>
28
+ <text x="20" y="508" style="fill: $paper_color_0; font-size: 10px">$bottomLeft4</text>
29
29
  <!-- Lunar Phase -->
30
30
  <g transform="translate(20,518)">
31
31
  <g transform="rotate($lunar_phase_rotate 20 10)">
@@ -14,7 +14,7 @@ Sign = Literal["Ari", "Tau", "Gem", "Can", "Leo", "Vir", "Lib", "Sco", "Sag", "C
14
14
 
15
15
 
16
16
  SignNumbers = Literal[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
17
- """Literal type for Zodiac Sign Numbers"""
17
+ """Literal type for Zodiac Sign Numbers, the signs are numbered in order starting from Aries (0) to Pisces (11)"""
18
18
 
19
19
 
20
20
  Houses = Literal["First_House", "Second_House", "Third_House", "Fourth_House", "Fifth_House", "Sixth_House", "Seventh_House", "Eighth_House", "Ninth_House", "Tenth_House", "Eleventh_House", "Twelfth_House"]
@@ -22,7 +22,7 @@ Houses = Literal["First_House", "Second_House", "Third_House", "Fourth_House", "
22
22
 
23
23
 
24
24
  HouseNumbers = Literal[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
25
- """Literal type for House Numbers"""
25
+ """Literal type for House Numbers, starting from the First House (1) to the Twelfth House (12)"""
26
26
 
27
27
 
28
28
  Planet = Literal["Sun", "Moon", "Mercury", "Venus", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune", "Pluto", "Mean_Node", "True_Node", "Chiron"]
@@ -87,3 +87,15 @@ Y = APC houses
87
87
 
88
88
  Usually the standard is Placidus (P)
89
89
  """
90
+
91
+
92
+ PerspectiveType = Literal["Apparent Geocentric", "Heliocentric", "Topocentric", "True Geocentric"]
93
+ """
94
+ Literal type for perspective types.
95
+ - "Apparent Geocentric": Earth-centered, apparent positions.
96
+ - "Heliocentric": Sun-centered.
97
+ - "Topocentric": Observer's location on Earth's surface.
98
+ - "True Geocentric": Earth-centered, true positions.
99
+
100
+ Usually the standard is "Apparent Geocentric"
101
+ """
@@ -68,8 +68,9 @@ class AstrologicalSubjectModel(SubscriptableBaseModel):
68
68
  sidereal_mode: Union[SiderealMode, None]
69
69
  houses_system_identifier: HousesSystemIdentifier
70
70
  houses_system_name: str
71
- local_time: float
72
- utc_time: float
71
+ perspective_type: str
72
+ iso_formatted_local_datetime: str
73
+ iso_formatted_utc_datetime: str
73
74
  julian_day: float
74
75
 
75
76
  # Planets
@@ -108,6 +109,11 @@ class AstrologicalSubjectModel(SubscriptableBaseModel):
108
109
  # Lunar Phase
109
110
  lunar_phase: LunarPhaseModel
110
111
 
112
+ # Lists
113
+ # houses_list: list[KerykeionPointModel]
114
+ # planets_list: list[KerykeionPointModel]
115
+ # planets_degrees_ut: list[float]
116
+ # houses_degree_ut: list[float]
111
117
 
112
118
  if __name__ == "__main__":
113
119
  from kerykeion.utilities import setup_logging
@@ -354,3 +354,17 @@ def get_moon_phase_name_from_phase_int(phase: int) -> LunarPhaseName:
354
354
  raise KerykeionException(f"Error in moon name calculation! Phase: {phase}")
355
355
 
356
356
  return result
357
+
358
+
359
+ def check_and_adjust_polar_latitude(latitude: float, longitude: float) -> bool:
360
+ """
361
+ Utility function to check if the location is in the polar circle.
362
+ If it is, it sets the latitude to 66 or -66 degrees.
363
+ """
364
+ if latitude > 66.0:
365
+ latitude = 66.0
366
+ logging.info("Polar circle override for houses, using 66 degrees")
367
+
368
+ elif latitude < -66.0:
369
+ latitude = -66.0
370
+ logging.info("Polar circle override for houses, using -66 degrees")
@@ -1,10 +1,10 @@
1
1
  [tool.poetry]
2
2
  name = "kerykeion"
3
- version = "4.11.0"
3
+ version = "4.12.0"
4
4
  authors = ["Giacomo Battaglia <battaglia.giacomo@yahoo.it>"]
5
5
  description = "A python library for astrology."
6
6
  license = "AGPL-3.0"
7
- homepage = "https://github.com/g-battaglia/kerykeion"
7
+ homepage = "https://www.kerykeion.net/"
8
8
  repository = "https://github.com/g-battaglia/kerykeion"
9
9
  keywords = [
10
10
  "astrology",
@@ -1,257 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- """
3
- <h1 align=center>Kerykeion</h1>
4
- <div align="center">
5
- <a href="#">
6
- <img src="https://img.shields.io/github/contributors/g-battaglia/kerykeion?color=blue&logo=github" alt="contributors">
7
- </a>
8
- <a href="#">
9
- <img src="https://img.shields.io/github/stars/g-battaglia/kerykeion.svg?logo=github" alt="stars">
10
- </a>
11
- <a href="#">
12
- <img src="https://img.shields.io/github/forks/g-battaglia/kerykeion.svg?logo=github" alt="forks">
13
- </a>
14
- <a href="https://pypi.org/project/kerykeion" target="_blank">
15
- <img src="https://visitor-badge.laobi.icu/badge?page_id=g-battaglia.kerykeion" alt="visitors"/>
16
- </a>
17
- <a href="https://pypi.org/project/kerykeion" target="_blank">
18
- <img src="https://img.shields.io/pypi/v/kerykeion?label=pypi%20package" alt="Package version">
19
- </a>
20
- <a href="https://pypi.org/project/kerykeion" target="_blank">
21
- <img src="https://img.shields.io/pypi/pyversions/kerykeion.svg" alt="Supported Python versions">
22
- </a>
23
- </div>
24
-
25
- &nbsp;
26
-
27
- Kerykeion is a python library for Astrology.
28
- It can calculate all the planet and house position,
29
- also it can calculate the aspects of a single persone or between two, you can set how many planets you
30
- need in the settings in the utility module.
31
- It also can generate an SVG of a birthchart, a synastry chart or a transit chart.
32
-
33
- The core goal of this project is to provide a simple and easy approach to astrology in a data driven way.
34
-
35
- Here's an example of a birthchart:
36
-
37
- ![Kanye Birth Chart](http://centuryboy.altervista.org/KanyeNatalChart.svg)
38
-
39
- ## Web API
40
-
41
- If you want to use Kerykeion in a web application, I've created a web API for this purpose, you can find it here:
42
-
43
- **[AstrologerAPI](https://rapidapi.com/gbattaglia/api/astrologer/)**
44
-
45
- It's [open source](https://github.com/g-battaglia/Astrologer-API), it's a way to support me and the project.
46
-
47
- ## Donate
48
-
49
- Maintaining this project is a lot of work, the Astrologer API doesn't nearly cover the costs of a software engineer working on this project full time. I do this because I love it, but until I can make this my full time job, I won't be able to spend as much time on it.
50
-
51
- If you want to support me, you can do it here:
52
-
53
- [![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/kerykeion)
54
-
55
- ## Installation
56
-
57
- Kerykeion is a _Python 3.9_ package, make sure you have _Python 3.9_ or above installed on your system.
58
-
59
- ```bash
60
- pip3 install kerykeion
61
- ```
62
-
63
- ## Usage
64
-
65
- Here some examples:
66
-
67
- ```python
68
-
69
- # Import the main class for creating a kerykeion instance:
70
- from kerykeion import AstrologicalSubject
71
-
72
- # Create a kerykeion instance:
73
- # Args: Name, year, month, day, hour, minuts, city, nation(optional)
74
- kanye = AstrologicalSubject("Kanye", 1977, 6, 8, 8, 45, "Atlanta")
75
-
76
- # Get the information about the sun in the chart:
77
- # (The position of the planets always starts at 0)
78
- kanye.sun
79
-
80
- #> {'name': 'Sun', 'quality': 'Mutable', 'element': 'Air', 'sign': 'Gem', 'sign_num': 2, 'pos': 17.598992059774275, 'abs_pos': 77.59899205977428, 'emoji': '♊️', 'house': '12th House', 'retrograde': False}
81
-
82
- # Get information about the first house:
83
- kanye.first_house
84
-
85
- #> {'name': 'First_House', 'quality': 'Cardinal', 'element': 'Water', 'sign': 'Can', 'sign_num': 3, 'pos': 17.995779673209114, 'abs_pos': 107.99577967320911, 'emoji': '♋️'}
86
-
87
- # Get element of the moon sign:
88
- kanye.moon.element
89
-
90
- #> 'Water'
91
-
92
- ```
93
-
94
- **To avoid connecting to GeoNames (eg. avoiding hourly limit or no internet connection) you should instance kerykeion like this:**
95
-
96
- ```python
97
- kanye = AstrologicalSubject(
98
- "Kanye", 1977, 6, 8, 8, 45, lng=50, lat=50, tz_str="Europe/Rome", city="Rome"
99
- )
100
- ```
101
-
102
- The difference is that you have to pass the longitude, latitude and the timezone string, instead of the city and nation.
103
- If you omit the nation, it will be set to "GB" by default, but the value is not used for calculations. It's better to set it to the correct value though.
104
-
105
- ## Generate a SVG Chart
106
-
107
- ```python
108
- from kerykeion import AstrologicalSubject, KerykeionChartSVG
109
-
110
- first = AstrologicalSubject("Jack", 1990, 6, 15, 15, 15, "Roma")
111
- second = AstrologicalSubject("Jane", 1991, 10, 25, 21, 00, "Roma")
112
-
113
- # Set the type, it can be Natal, Synastry or Transit
114
-
115
- name = KerykeionChartSVG(first, chart_type="Synastry", second_obj=second)
116
- name.makeSVG()
117
- print(len(name.aspects_list))
118
-
119
- #> Generating kerykeion object for Jack...
120
- #> Generating kerykeion object for Jane...
121
- #> Jack birth location: Roma, 41.89193, 12.51133
122
- #> SVG Generated Correctly
123
- #> 38
124
-
125
- ```
126
-
127
- ![Synastry Chart](http://centuryboy.altervista.org/JackComposite_Chart.svg)
128
-
129
- ## Report
130
-
131
- To print a report of all the data:
132
-
133
- ```python
134
- from kerykeion import Report, AstrologicalSubject
135
-
136
- kanye = AstrologicalSubject("Kanye", 1977, 6, 8, 8, 45, "Atlanta")
137
- report = Report(kanye)
138
- report.print_report()
139
-
140
- ```
141
-
142
- Returns:
143
-
144
- ```bash
145
- +- Kerykeion report for Kanye -+
146
- +----------+------+-------------+-----------+----------+
147
- | Date | Time | Location | Longitude | Latitude |
148
- +----------+------+-------------+-----------+----------+
149
- | 8/6/1977 | 8:45 | Atlanta, US | -84.38798 | 33.749 |
150
- +----------+------+-------------+-----------+----------+
151
- +-----------+------+-------+------+----------------+
152
- | Planet | Sign | Pos. | Ret. | House |
153
- +-----------+------+-------+------+----------------+
154
- | Sun | Gem | 17.6 | - | Twelfth_House |
155
- | Moon | Pis | 16.43 | - | Ninth_House |
156
- | Mercury | Tau | 26.29 | - | Eleventh_House |
157
- | Venus | Tau | 2.03 | - | Tenth_House |
158
- | Mars | Tau | 1.79 | - | Tenth_House |
159
- | Jupiter | Gem | 14.61 | - | Eleventh_House |
160
- | Saturn | Leo | 12.8 | - | Second_House |
161
- | Uranus | Sco | 8.27 | R | Fourth_House |
162
- | Neptune | Sag | 14.69 | R | Fifth_House |
163
- | Pluto | Lib | 11.45 | R | Fourth_House |
164
- | Mean_Node | Lib | 21.49 | R | Fourth_House |
165
- | True_Node | Lib | 22.82 | R | Fourth_House |
166
- | Chiron | Tau | 4.17 | - | Tenth_House |
167
- +-----------+------+-------+------+----------------+
168
- +----------------+------+----------+
169
- | House | Sign | Position |
170
- +----------------+------+----------+
171
- | First_House | Can | 18.0 |
172
- | Second_House | Leo | 9.51 |
173
- | Third_House | Vir | 4.02 |
174
- | Fourth_House | Lib | 3.98 |
175
- | Fifth_House | Sco | 9.39 |
176
- | Sixth_House | Sag | 15.68 |
177
- | Seventh_House | Cap | 18.0 |
178
- | Eighth_House | Aqu | 9.51 |
179
- | Ninth_House | Pis | 4.02 |
180
- | Tenth_House | Ari | 3.98 |
181
- | Eleventh_House | Tau | 9.39 |
182
- | Twelfth_House | Gem | 15.68 |
183
- +----------------+------+----------+
184
-
185
- ```
186
-
187
- And if you want to export it to a file:
188
-
189
- ```bash
190
- python3 your_script_name.py > file.txt
191
- ```
192
-
193
- ## Other exeples of possibles usecase
194
-
195
- ```python
196
- # Get all aspects between two persons:
197
-
198
- from kerykeion import SynastryAspects, AstrologicalSubject
199
- first = AstrologicalSubject("Jack", 1990, 6, 15, 15, 15, "Roma")
200
- second = AstrologicalSubject("Jane", 1991, 10, 25, 21, 00, "Roma")
201
-
202
- name = SynastryAspects(first, second)
203
- aspect_list = name.get_relevant_aspects()
204
- print(aspect_list[0])
205
-
206
- #> Generating kerykeion object for Jack...
207
- #> Generating kerykeion object for Jane...
208
- #> {'p1_name': 'Sun', 'p1_abs_pos': 84.17867971515636, 'p2_name': 'Sun', 'p2_abs_pos': 211.90472999502984, 'aspect': 'trine', 'orbit': 7.726050279873476, 'aspect_degrees': 120, 'color': '#36d100', 'aid': 6, 'diff': 127.72605027987348, 'p1': 0, 'p2': 0}
209
-
210
- ```
211
-
212
- ## Ayanamsa (Sidereal Modes)
213
-
214
- You can set the zodiac type and the sidereal mode in the AstrologicalSubject class:
215
-
216
- ```python
217
- johnny = AstrologicalSubject("Johnny Depp", 1963, 6, 9, 0, 0, "Owensboro", "US", zodiac_type="Sidereal", sidereal_mode="LAHIRI")
218
- ```
219
-
220
- More examples [here](https://www.kerykeion.net/docs/examples/sidereal-modes/).
221
-
222
- Full list of supported sidereal modes [here](https://www.kerykeion.net/pydocs/kerykeion/kr_types/kr_literals.html#SiderealMode).
223
-
224
- ## Documentation
225
-
226
- Most of the functions and the classes are self documented by the types and have docstrings.
227
- An auto-generated documentation [is available here](https://www.kerykeion.net/pydocs/kerykeion.html).
228
-
229
- Sooner or later I'll try to write an extensive documentation.
230
-
231
- ## Development
232
-
233
- You can clone this repository or download a zip file using the right side buttons.
234
-
235
- ## Contributing
236
-
237
- Feel free to contribute to the code!
238
-
239
- ## License
240
-
241
- This project is licensed under the AGPL-3.0 License.
242
- To understand how this impacts your use of the software, please see the [LICENSE](LICENSE) file for details.
243
- If you have questions, you can reach out to me at my [email](mailto:battaglia.giacomo@yahoo.it?subject=Kerykeion) address.
244
- As a rule of thumb, if you are using this library in a project, you should open source the code of the project with a compatible license.
245
-
246
- You can implement the logic of kerykeion in your project and also keep it closed source by using a third party API, like the [AstrologerAPI](https://rapidapi.com/gbattaglia/api/astrologer/). The AstrologerAPI is AGPL-3.0 compliant. Subscribing to the API is also, currently, the best way to support the project.
247
- """
248
-
249
- # Local
250
- from .astrological_subject import AstrologicalSubject
251
- from .charts.kerykeion_chart_svg import KerykeionChartSVG
252
- from .kr_types import *
253
- from .relationship_score import RelationshipScore
254
- from .aspects import SynastryAspects, NatalAspects
255
- from .report import Report
256
- from .settings import KerykeionSettingsModel, get_settings
257
- from .enums import Planets, Aspects, Signs
File without changes