kerykeion 4.24.6__py3-none-any.whl → 4.25.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of kerykeion might be problematic. Click here for more details.
- kerykeion/__init__.py +1 -0
- kerykeion/aspects/natal_aspects.py +2 -1
- kerykeion/astrological_subject.py +9 -47
- kerykeion/charts/charts_utils.py +43 -77
- kerykeion/charts/kerykeion_chart_svg.py +117 -57
- kerykeion/charts/templates/chart.xml +28 -14
- kerykeion/composite_subject_factory.py +200 -0
- kerykeion/kr_types/chart_types.py +20 -13
- kerykeion/kr_types/kr_literals.py +6 -1
- kerykeion/kr_types/kr_models.py +79 -2
- kerykeion/kr_types/settings_models.py +6 -0
- kerykeion/settings/kr.config.json +60 -0
- kerykeion/utilities.py +73 -1
- {kerykeion-4.24.6.dist-info → kerykeion-4.25.0.dist-info}/METADATA +1 -1
- {kerykeion-4.24.6.dist-info → kerykeion-4.25.0.dist-info}/RECORD +18 -17
- {kerykeion-4.24.6.dist-info → kerykeion-4.25.0.dist-info}/LICENSE +0 -0
- {kerykeion-4.24.6.dist-info → kerykeion-4.25.0.dist-info}/WHEEL +0 -0
- {kerykeion-4.24.6.dist-info → kerykeion-4.25.0.dist-info}/entry_points.txt +0 -0
|
@@ -26,22 +26,31 @@ OpenAstro.org -->
|
|
|
26
26
|
<rect class="background-rectangle" x="0" y="0" width="$chart_width"
|
|
27
27
|
height="$chart_height" style="fill: $paper_color_1" />
|
|
28
28
|
<text x="20" y="22" style="fill: $paper_color_0; font-size: 24px">$stringTitle</text>
|
|
29
|
-
<text x="20" y="50" style="fill: $paper_color_0; font-size:
|
|
30
|
-
<text x="20" y="62" style="fill: $paper_color_0; font-size:
|
|
31
|
-
<text x="20" y="74" style="fill: $paper_color_0; font-size:
|
|
32
|
-
<text x="20" y="86" style="fill: $paper_color_0; font-size:
|
|
33
|
-
<text x="20" y="98" style="fill: $paper_color_0; font-size:
|
|
34
|
-
<text x="20" y="110" style="fill: $paper_color_0; font-size:
|
|
35
|
-
<text x="20" y="452" style="fill: $paper_color_0; font-size: 10px">$
|
|
36
|
-
<text x="20" y="466" style="fill: $paper_color_0; font-size: 10px">$
|
|
37
|
-
<text x="20" y="480" style="fill: $paper_color_0; font-size: 10px">$
|
|
38
|
-
<text x="20" y="494" style="fill: $paper_color_0; font-size: 10px">$
|
|
39
|
-
<text x="20" y="508" style="fill: $paper_color_0; font-size: 10px">$
|
|
29
|
+
<text x="20" y="50" style="fill: $paper_color_0; font-size: 10px">$top_left_0</text>
|
|
30
|
+
<text x="20" y="62" style="fill: $paper_color_0; font-size: 10px">$top_left_1</text>
|
|
31
|
+
<text x="20" y="74" style="fill: $paper_color_0; font-size: 10px">$top_left_2</text>
|
|
32
|
+
<text x="20" y="86" style="fill: $paper_color_0; font-size: 10px">$top_left_3</text>
|
|
33
|
+
<text x="20" y="98" style="fill: $paper_color_0; font-size: 10px">$top_left_4</text>
|
|
34
|
+
<text x="20" y="110" style="fill: $paper_color_0; font-size: 10px">$top_left_5</text>
|
|
35
|
+
<text x="20" y="452" style="fill: $paper_color_0; font-size: 10px">$bottom_left_0</text>
|
|
36
|
+
<text x="20" y="466" style="fill: $paper_color_0; font-size: 10px">$bottom_left_1</text>
|
|
37
|
+
<text x="20" y="480" style="fill: $paper_color_0; font-size: 10px">$bottom_left_2</text>
|
|
38
|
+
<text x="20" y="494" style="fill: $paper_color_0; font-size: 10px">$bottom_left_3</text>
|
|
39
|
+
<text x="20" y="508" style="fill: $paper_color_0; font-size: 10px">$bottom_left_4</text>
|
|
40
40
|
</g>
|
|
41
41
|
|
|
42
42
|
<!-- Lunar Phase -->
|
|
43
43
|
<g kr:node="Lunar_Phase" transform="translate(20,518)">
|
|
44
|
-
$
|
|
44
|
+
<g transform="rotate($lunar_phase_rotate 20 10)">
|
|
45
|
+
<defs>
|
|
46
|
+
<clipPath id="moonPhaseCutOffCircle">
|
|
47
|
+
<circle cx="20" cy="10" r="10" />
|
|
48
|
+
</clipPath>
|
|
49
|
+
</defs>
|
|
50
|
+
<circle cx="20" cy="10" r="10" style="fill: var(--kerykeion-chart-color-lunar-phase-0)" />
|
|
51
|
+
<circle cx="$lunar_phase_circle_center_x" cy="10" r="$lunar_phase_circle_radius" style="fill: var(--kerykeion-chart-color-lunar-phase-1)" clip-path="url(#moonPhaseCutOffCircle)" />
|
|
52
|
+
<circle cx="20" cy="10" r="10" style="fill: none; stroke: var(--kerykeion-chart-color-lunar-phase-0); stroke-width: 0.5px; stroke-opacity: 0.5" />
|
|
53
|
+
</g>
|
|
45
54
|
</g>
|
|
46
55
|
|
|
47
56
|
<g kr:node="Main_Content" transform="translate(50,50)">
|
|
@@ -94,13 +103,18 @@ OpenAstro.org -->
|
|
|
94
103
|
</g>
|
|
95
104
|
|
|
96
105
|
<!-- AspectGrid -->
|
|
97
|
-
<g kr:node="Aspect_Grid"
|
|
106
|
+
<g kr:node="Aspect_Grid">
|
|
98
107
|
$makeAspectGrid
|
|
99
108
|
</g>
|
|
100
109
|
|
|
101
110
|
<!-- Elements -->
|
|
102
111
|
<g kr:node="Elements_Percentages">
|
|
103
|
-
|
|
112
|
+
<g transform="translate(-30,79)">
|
|
113
|
+
<text y="0" style="fill: var(--kerykeion-chart-color-fire-percentage); font-size: 10px;">$fire_string</text>
|
|
114
|
+
<text y="12" style="fill: var(--kerykeion-chart-color-earth-percentage); font-size: 10px;">$earth_string</text>
|
|
115
|
+
<text y="24" style="fill: var(--kerykeion-chart-color-air-percentage); font-size: 10px;">$air_string</text>
|
|
116
|
+
<text y="36" style="fill: var(--kerykeion-chart-color-water-percentage); font-size: 10px;">$water_string</text>
|
|
117
|
+
</g>"
|
|
104
118
|
</g>
|
|
105
119
|
|
|
106
120
|
<!-- Houses_And_Planets_Grid -->
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
from typing import Union
|
|
2
|
+
|
|
3
|
+
from kerykeion import AstrologicalSubject
|
|
4
|
+
from kerykeion import KerykeionException
|
|
5
|
+
from kerykeion.kr_types.kr_models import CompositeSubjectModel, AstrologicalSubjectModel
|
|
6
|
+
from kerykeion.kr_types.kr_literals import ZodiacType, PerspectiveType, HousesSystemIdentifier, SiderealMode, Planet, Houses, AxialCusps, CompositeChartType
|
|
7
|
+
from kerykeion.utilities import (
|
|
8
|
+
get_kerykeion_point_from_degree,
|
|
9
|
+
get_planet_house,
|
|
10
|
+
circular_mean,
|
|
11
|
+
calculate_moon_phase
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class CompositeSubjectFactory:
|
|
16
|
+
"""
|
|
17
|
+
Factory class to create a Composite Subject Model from two Astrological Subjects
|
|
18
|
+
Currently, the only available method for creating composite charts is the midpoint method.
|
|
19
|
+
The composite houses and planets are calculated based on the midpoint of the corresponding points of the two subjects.
|
|
20
|
+
The house are then reordered to match the original house system of the first subject.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
first_subject (AstrologicalSubject): First astrological subject
|
|
24
|
+
second_subject (AstrologicalSubject): Second astrological subject
|
|
25
|
+
chart_name (str): Name of the composite chart. If None, it will be automatically generated.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
model: Union[CompositeSubjectModel, None]
|
|
29
|
+
first_subject: AstrologicalSubjectModel
|
|
30
|
+
second_subject: AstrologicalSubjectModel
|
|
31
|
+
name: str
|
|
32
|
+
composite_chart_type: CompositeChartType
|
|
33
|
+
zodiac_type: ZodiacType
|
|
34
|
+
sidereal_mode: Union[SiderealMode, None]
|
|
35
|
+
houses_system_identifier: HousesSystemIdentifier
|
|
36
|
+
houses_system_name: str
|
|
37
|
+
perspective_type: PerspectiveType
|
|
38
|
+
planets_names_list: list[Planet]
|
|
39
|
+
houses_names_list: list[Houses]
|
|
40
|
+
axial_cusps_names_list: list[AxialCusps]
|
|
41
|
+
|
|
42
|
+
def __init__(
|
|
43
|
+
self,
|
|
44
|
+
first_subject: Union[AstrologicalSubject, AstrologicalSubjectModel],
|
|
45
|
+
second_subject: Union[AstrologicalSubject, AstrologicalSubjectModel],
|
|
46
|
+
chart_name: Union[str, None] = None
|
|
47
|
+
):
|
|
48
|
+
self.model: Union[CompositeSubjectModel, None] = None
|
|
49
|
+
self.composite_chart_type = "Midpoint"
|
|
50
|
+
|
|
51
|
+
# Subjects
|
|
52
|
+
if isinstance(first_subject, AstrologicalSubject) or isinstance(first_subject, AstrologicalSubjectModel):
|
|
53
|
+
self.first_subject = first_subject.model() # type: ignore
|
|
54
|
+
self.second_subject = second_subject.model() # type: ignore
|
|
55
|
+
else:
|
|
56
|
+
self.first_subject = first_subject
|
|
57
|
+
self.second_subject = second_subject
|
|
58
|
+
|
|
59
|
+
# Name
|
|
60
|
+
if chart_name is None:
|
|
61
|
+
self.name = f"{first_subject.name} and {second_subject.name} Composite Chart"
|
|
62
|
+
else:
|
|
63
|
+
self.name = chart_name
|
|
64
|
+
|
|
65
|
+
# Zodiac Type
|
|
66
|
+
if first_subject.zodiac_type != second_subject.zodiac_type:
|
|
67
|
+
raise KerykeionException("Both subjects must have the same zodiac type")
|
|
68
|
+
self.zodiac_type = first_subject.zodiac_type
|
|
69
|
+
|
|
70
|
+
# Sidereal Mode
|
|
71
|
+
if first_subject.sidereal_mode != second_subject.sidereal_mode:
|
|
72
|
+
raise KerykeionException("Both subjects must have the same sidereal mode")
|
|
73
|
+
|
|
74
|
+
if first_subject.sidereal_mode is not None:
|
|
75
|
+
self.sidereal_mode = first_subject.sidereal_mode
|
|
76
|
+
else:
|
|
77
|
+
self.sidereal_mode = None
|
|
78
|
+
|
|
79
|
+
# Houses System
|
|
80
|
+
if first_subject.houses_system_identifier != second_subject.houses_system_identifier:
|
|
81
|
+
raise KerykeionException("Both subjects must have the same houses system")
|
|
82
|
+
self.houses_system_identifier = first_subject.houses_system_identifier
|
|
83
|
+
|
|
84
|
+
# Houses System Name
|
|
85
|
+
if first_subject.houses_system_name != second_subject.houses_system_name:
|
|
86
|
+
raise KerykeionException("Both subjects must have the same houses system name")
|
|
87
|
+
self.houses_system_name = first_subject.houses_system_name
|
|
88
|
+
|
|
89
|
+
# Perspective Type
|
|
90
|
+
if first_subject.perspective_type != second_subject.perspective_type:
|
|
91
|
+
raise KerykeionException("Both subjects must have the same perspective type")
|
|
92
|
+
self.perspective_type = first_subject.perspective_type
|
|
93
|
+
|
|
94
|
+
# Planets Names List
|
|
95
|
+
self.planets_names_list = []
|
|
96
|
+
for planet in first_subject.planets_names_list:
|
|
97
|
+
if planet in second_subject.planets_names_list:
|
|
98
|
+
self.planets_names_list.append(planet)
|
|
99
|
+
|
|
100
|
+
# Houses Names List
|
|
101
|
+
self.houses_names_list = self.first_subject.houses_names_list
|
|
102
|
+
|
|
103
|
+
# Axial Cusps Names List
|
|
104
|
+
self.axial_cusps_names_list = self.first_subject.axial_cusps_names_list
|
|
105
|
+
|
|
106
|
+
def __str__(self):
|
|
107
|
+
return f"Composite Chart Data for {self.name}"
|
|
108
|
+
|
|
109
|
+
def __repr__(self):
|
|
110
|
+
return f"Composite Chart Data for {self.name}"
|
|
111
|
+
|
|
112
|
+
def __eq__(self, other):
|
|
113
|
+
return self.first_subject == other.first_subject and self.second_subject == other.second_subject and self.name == other.chart_name
|
|
114
|
+
|
|
115
|
+
def __ne__(self, other):
|
|
116
|
+
return not self.__eq__(other)
|
|
117
|
+
|
|
118
|
+
def __hash__(self):
|
|
119
|
+
return hash((self.first_subject, self.second_subject, self.name))
|
|
120
|
+
|
|
121
|
+
def __copy__(self):
|
|
122
|
+
return CompositeSubjectFactory(self.first_subject, self.second_subject, self.name)
|
|
123
|
+
|
|
124
|
+
def __setitem__(self, key, value):
|
|
125
|
+
setattr(self, key, value)
|
|
126
|
+
|
|
127
|
+
def __getitem__(self, key):
|
|
128
|
+
return getattr(self, key)
|
|
129
|
+
|
|
130
|
+
def _calculate_midpoint_composite_points_and_houses(self):
|
|
131
|
+
# Houses
|
|
132
|
+
house_degree_list_ut = []
|
|
133
|
+
for house in self.first_subject.houses_names_list:
|
|
134
|
+
house_lower = house.lower()
|
|
135
|
+
self[house_lower] = get_kerykeion_point_from_degree(
|
|
136
|
+
circular_mean(
|
|
137
|
+
self.first_subject[house_lower]["abs_pos"],
|
|
138
|
+
self.second_subject[house_lower]["abs_pos"]
|
|
139
|
+
),
|
|
140
|
+
house,
|
|
141
|
+
"House"
|
|
142
|
+
)
|
|
143
|
+
house_degree_list_ut.append(self[house_lower]["abs_pos"])
|
|
144
|
+
|
|
145
|
+
house_degree_list_ut = sorted(house_degree_list_ut)
|
|
146
|
+
|
|
147
|
+
# Planets
|
|
148
|
+
common_planets = []
|
|
149
|
+
for planet in self.first_subject.planets_names_list:
|
|
150
|
+
if planet in self.second_subject.planets_names_list:
|
|
151
|
+
common_planets.append(planet)
|
|
152
|
+
|
|
153
|
+
planets = {}
|
|
154
|
+
for planet in common_planets:
|
|
155
|
+
planet_lower = planet.lower()
|
|
156
|
+
planets[planet_lower] = {}
|
|
157
|
+
planets[planet_lower]["abs_pos"] = circular_mean(
|
|
158
|
+
self.first_subject[planet_lower]["abs_pos"],
|
|
159
|
+
self.second_subject[planet_lower]["abs_pos"]
|
|
160
|
+
)
|
|
161
|
+
self[planet_lower] = get_kerykeion_point_from_degree(planets[planet_lower]["abs_pos"], planet, "Planet")
|
|
162
|
+
self[planet_lower]["house"] = get_planet_house(self[planet_lower]['abs_pos'], house_degree_list_ut)
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
# Axial Cusps
|
|
166
|
+
for cusp in self.first_subject.axial_cusps_names_list:
|
|
167
|
+
cusp_lower = cusp.lower()
|
|
168
|
+
self[cusp_lower] = get_kerykeion_point_from_degree(
|
|
169
|
+
circular_mean(
|
|
170
|
+
self.first_subject[cusp_lower]["abs_pos"],
|
|
171
|
+
self.second_subject[cusp_lower]["abs_pos"]
|
|
172
|
+
),
|
|
173
|
+
cusp,
|
|
174
|
+
"AxialCusps"
|
|
175
|
+
)
|
|
176
|
+
self[cusp_lower]["house"] = get_planet_house(self[cusp_lower]['abs_pos'], house_degree_list_ut)
|
|
177
|
+
|
|
178
|
+
def _calculate_composite_lunar_phase(self):
|
|
179
|
+
self.lunar_phase = calculate_moon_phase(
|
|
180
|
+
self['moon'].abs_pos,
|
|
181
|
+
self['sun'].abs_pos
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
def get_midpoint_composite_subject_model(self):
|
|
185
|
+
self._calculate_midpoint_composite_points_and_houses()
|
|
186
|
+
self._calculate_composite_lunar_phase()
|
|
187
|
+
|
|
188
|
+
return CompositeSubjectModel(
|
|
189
|
+
**self.__dict__
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
if __name__ == "__main__":
|
|
194
|
+
from kerykeion.astrological_subject import AstrologicalSubject
|
|
195
|
+
|
|
196
|
+
first = AstrologicalSubject("John Lennon", 1940, 10, 9, 18, 30, "Liverpool", "GB")
|
|
197
|
+
second = AstrologicalSubject("Paul McCartney", 1942, 6, 18, 15, 30, "Liverpool", "GB")
|
|
198
|
+
|
|
199
|
+
composite_chart = CompositeSubjectFactory(first, second)
|
|
200
|
+
print(composite_chart.get_midpoint_composite_subject_model().model_dump_json(indent=4))
|
|
@@ -13,18 +13,17 @@ class ChartTemplateDictionary(TypedDict):
|
|
|
13
13
|
chart_width: float
|
|
14
14
|
viewbox: str
|
|
15
15
|
stringTitle: str
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
stringPosition: str
|
|
16
|
+
top_left_0: str
|
|
17
|
+
bottom_left_0: str
|
|
18
|
+
bottom_left_1: str
|
|
19
|
+
bottom_left_2: str
|
|
20
|
+
bottom_left_3: str
|
|
21
|
+
bottom_left_4: str
|
|
22
|
+
top_left_1: str
|
|
23
|
+
top_left_2: str
|
|
24
|
+
top_left_3: str
|
|
25
|
+
top_left_4: str
|
|
26
|
+
top_left_5: str
|
|
28
27
|
|
|
29
28
|
# Font color
|
|
30
29
|
paper_color_0: str
|
|
@@ -81,8 +80,16 @@ class ChartTemplateDictionary(TypedDict):
|
|
|
81
80
|
makeZodiac: str
|
|
82
81
|
makeHouses: str
|
|
83
82
|
makePlanets: str
|
|
84
|
-
elements_percentages: str
|
|
85
83
|
makePlanetGrid: str
|
|
86
84
|
makeHousesGrid: str
|
|
87
85
|
|
|
88
86
|
color_style_tag: str
|
|
87
|
+
|
|
88
|
+
fire_string: str
|
|
89
|
+
earth_string: str
|
|
90
|
+
air_string: str
|
|
91
|
+
water_string: str
|
|
92
|
+
|
|
93
|
+
lunar_phase_rotate: str
|
|
94
|
+
lunar_phase_circle_center_x: str
|
|
95
|
+
lunar_phase_circle_radius: str
|
|
@@ -40,7 +40,7 @@ Quality = Literal["Cardinal", "Fixed", "Mutable"]
|
|
|
40
40
|
"""Literal type for Qualities"""
|
|
41
41
|
|
|
42
42
|
|
|
43
|
-
ChartType = Literal["Natal", "ExternalNatal", "Synastry", "Transit"]
|
|
43
|
+
ChartType = Literal["Natal", "ExternalNatal", "Synastry", "Transit", "Composite"]
|
|
44
44
|
"""Literal type for Chart Types"""
|
|
45
45
|
|
|
46
46
|
|
|
@@ -114,9 +114,14 @@ KerykeionChartTheme = Literal["light", "dark", "dark-high-contrast", "classic"]
|
|
|
114
114
|
KerykeionChartLanguage = Literal["EN", "FR", "PT", "IT", "CN", "ES", "RU", "TR", "DE", "HI"]
|
|
115
115
|
"""Literal type for Kerykeion Chart Languages"""
|
|
116
116
|
|
|
117
|
+
|
|
117
118
|
RelationshipScoreDescription = Literal["Minimal", "Medium", "Important", "Very Important", "Exceptional", "Rare Exceptional"]
|
|
118
119
|
"""Literal type for Relationship Score Description"""
|
|
119
120
|
|
|
121
|
+
|
|
122
|
+
CompositeChartType = Literal["Midpoint"]
|
|
123
|
+
"""Literal type for Composite Chart Types"""
|
|
124
|
+
|
|
120
125
|
AspectName = Literal[
|
|
121
126
|
"conjunction",
|
|
122
127
|
"semi-sextile",
|
kerykeion/kr_types/kr_models.py
CHANGED
|
@@ -25,7 +25,8 @@ from kerykeion.kr_types import (
|
|
|
25
25
|
HousesSystemIdentifier,
|
|
26
26
|
Houses,
|
|
27
27
|
SignsEmoji,
|
|
28
|
-
RelationshipScoreDescription
|
|
28
|
+
RelationshipScoreDescription,
|
|
29
|
+
PerspectiveType
|
|
29
30
|
)
|
|
30
31
|
|
|
31
32
|
|
|
@@ -74,6 +75,10 @@ class KerykeionPointModel(SubscriptableBaseModel):
|
|
|
74
75
|
|
|
75
76
|
|
|
76
77
|
class AstrologicalSubjectModel(SubscriptableBaseModel):
|
|
78
|
+
"""
|
|
79
|
+
Pydantic Model for Astrological Subject
|
|
80
|
+
"""
|
|
81
|
+
|
|
77
82
|
# Data
|
|
78
83
|
name: str
|
|
79
84
|
year: int
|
|
@@ -90,7 +95,7 @@ class AstrologicalSubjectModel(SubscriptableBaseModel):
|
|
|
90
95
|
sidereal_mode: Union[SiderealMode, None]
|
|
91
96
|
houses_system_identifier: HousesSystemIdentifier
|
|
92
97
|
houses_system_name: str
|
|
93
|
-
perspective_type:
|
|
98
|
+
perspective_type: PerspectiveType
|
|
94
99
|
iso_formatted_local_datetime: str
|
|
95
100
|
iso_formatted_utc_datetime: str
|
|
96
101
|
julian_day: float
|
|
@@ -198,6 +203,78 @@ class RelationshipScoreModel(SubscriptableBaseModel):
|
|
|
198
203
|
subjects: list[AstrologicalSubjectModel]
|
|
199
204
|
|
|
200
205
|
|
|
206
|
+
class CompositeSubjectModel(SubscriptableBaseModel):
|
|
207
|
+
"""
|
|
208
|
+
Pydantic Model for Composite Subject
|
|
209
|
+
"""
|
|
210
|
+
|
|
211
|
+
# Data
|
|
212
|
+
name: str
|
|
213
|
+
first_subject: AstrologicalSubjectModel
|
|
214
|
+
second_subject: AstrologicalSubjectModel
|
|
215
|
+
composite_chart_type: str
|
|
216
|
+
|
|
217
|
+
zodiac_type: ZodiacType
|
|
218
|
+
sidereal_mode: Union[SiderealMode, None]
|
|
219
|
+
houses_system_identifier: HousesSystemIdentifier
|
|
220
|
+
houses_system_name: str
|
|
221
|
+
perspective_type: PerspectiveType
|
|
222
|
+
|
|
223
|
+
# Planets
|
|
224
|
+
sun: KerykeionPointModel
|
|
225
|
+
moon: KerykeionPointModel
|
|
226
|
+
mercury: KerykeionPointModel
|
|
227
|
+
venus: KerykeionPointModel
|
|
228
|
+
mars: KerykeionPointModel
|
|
229
|
+
jupiter: KerykeionPointModel
|
|
230
|
+
saturn: KerykeionPointModel
|
|
231
|
+
uranus: KerykeionPointModel
|
|
232
|
+
neptune: KerykeionPointModel
|
|
233
|
+
pluto: KerykeionPointModel
|
|
234
|
+
|
|
235
|
+
# Axes
|
|
236
|
+
ascendant: KerykeionPointModel
|
|
237
|
+
descendant: KerykeionPointModel
|
|
238
|
+
medium_coeli: KerykeionPointModel
|
|
239
|
+
imum_coeli: KerykeionPointModel
|
|
240
|
+
|
|
241
|
+
# Optional Planets:
|
|
242
|
+
chiron: Union[KerykeionPointModel, None]
|
|
243
|
+
mean_lilith: Union[KerykeionPointModel, None]
|
|
244
|
+
|
|
245
|
+
# Houses
|
|
246
|
+
first_house: KerykeionPointModel
|
|
247
|
+
second_house: KerykeionPointModel
|
|
248
|
+
third_house: KerykeionPointModel
|
|
249
|
+
fourth_house: KerykeionPointModel
|
|
250
|
+
fifth_house: KerykeionPointModel
|
|
251
|
+
sixth_house: KerykeionPointModel
|
|
252
|
+
seventh_house: KerykeionPointModel
|
|
253
|
+
eighth_house: KerykeionPointModel
|
|
254
|
+
ninth_house: KerykeionPointModel
|
|
255
|
+
tenth_house: KerykeionPointModel
|
|
256
|
+
eleventh_house: KerykeionPointModel
|
|
257
|
+
twelfth_house: KerykeionPointModel
|
|
258
|
+
|
|
259
|
+
# Nodes
|
|
260
|
+
mean_node: KerykeionPointModel
|
|
261
|
+
true_node: KerykeionPointModel
|
|
262
|
+
mean_south_node: KerykeionPointModel
|
|
263
|
+
true_south_node: KerykeionPointModel
|
|
264
|
+
|
|
265
|
+
planets_names_list: list[Planet]
|
|
266
|
+
"""Ordered list of available planets names"""
|
|
267
|
+
|
|
268
|
+
axial_cusps_names_list: list[AxialCusps]
|
|
269
|
+
"""Ordered list of available axes names"""
|
|
270
|
+
|
|
271
|
+
houses_names_list: list[Houses]
|
|
272
|
+
"""Ordered list of houses names"""
|
|
273
|
+
|
|
274
|
+
lunar_phase: LunarPhaseModel
|
|
275
|
+
"""Lunar phase model"""
|
|
276
|
+
|
|
277
|
+
|
|
201
278
|
class ActiveAspect(TypedDict):
|
|
202
279
|
name: AspectName
|
|
203
280
|
orb: int
|
|
@@ -137,6 +137,12 @@ class KerykeionLanguageModel(SubscriptableBaseModel):
|
|
|
137
137
|
lunar_phase: str = Field(title="Lunar Phase", description="The name of the Lunar Phase label in the chart, in the language")
|
|
138
138
|
day: str = Field(title="Day", description="The name of the Day label in the chart, in the language")
|
|
139
139
|
celestial_points: KerykeionLanguageCelestialPointModel
|
|
140
|
+
composite_chart: str = Field(title="Composite Chart", description="The name of the Composite Chart label in the chart, in the language")
|
|
141
|
+
midpoints: str = Field(title="Midpoints", description="The name of the Midpoints label in the chart, in the language")
|
|
142
|
+
north_letter: str = Field(title="North Letter", description="The name of the North Letter label in the chart, in the language")
|
|
143
|
+
east_letter: str = Field(title="East Letter", description="The name of the East Letter label in the chart, in the language")
|
|
144
|
+
south_letter: str = Field(title="South Letter", description="The name of the South Letter label in the chart, in the language")
|
|
145
|
+
west_letter: str = Field(title="West Letter", description="The name of the West Letter label in the chart, in the language")
|
|
140
146
|
|
|
141
147
|
|
|
142
148
|
class KerykeionGeneralSettingsModel(SubscriptableBaseModel):
|
|
@@ -21,6 +21,12 @@
|
|
|
21
21
|
"transit_name": "At the time of the transit",
|
|
22
22
|
"lunar_phase": "Lunar phase",
|
|
23
23
|
"day": "Day",
|
|
24
|
+
"composite_chart": "Composite Chart",
|
|
25
|
+
"midpoints": "Midpoints",
|
|
26
|
+
"north_letter": "N",
|
|
27
|
+
"east_letter": "E",
|
|
28
|
+
"south_letter": "S",
|
|
29
|
+
"west_letter": "W",
|
|
24
30
|
"celestial_points": {
|
|
25
31
|
"Sun": "Sun",
|
|
26
32
|
"Moon": "Moon",
|
|
@@ -65,6 +71,12 @@
|
|
|
65
71
|
"transit_name": "Au moment de la transition",
|
|
66
72
|
"lunar_phase": "Phase Lunaire",
|
|
67
73
|
"day": "Jour",
|
|
74
|
+
"composite_chart": "Carte Composite",
|
|
75
|
+
"midpoints": "Milieux",
|
|
76
|
+
"north_letter": "N",
|
|
77
|
+
"east_letter": "E",
|
|
78
|
+
"south_letter": "S",
|
|
79
|
+
"west_letter": "W",
|
|
68
80
|
"celestial_points": {
|
|
69
81
|
"Sun": "Soleil",
|
|
70
82
|
"Moon": "Lune",
|
|
@@ -109,6 +121,12 @@
|
|
|
109
121
|
"transit_name": "No momento do trânsito",
|
|
110
122
|
"lunar_phase": "Fase lunar",
|
|
111
123
|
"day": "Dia",
|
|
124
|
+
"composite_chart": "Carta Composta",
|
|
125
|
+
"midpoints": "Meios",
|
|
126
|
+
"north_letter": "N",
|
|
127
|
+
"east_letter": "E",
|
|
128
|
+
"south_letter": "S",
|
|
129
|
+
"west_letter": "W",
|
|
112
130
|
"celestial_points": {
|
|
113
131
|
"Sun": "Sol",
|
|
114
132
|
"Moon": "Lua",
|
|
@@ -153,6 +171,12 @@
|
|
|
153
171
|
"transit_name": "Al momento del transito",
|
|
154
172
|
"lunar_phase": "Fase lunare",
|
|
155
173
|
"day": "Giorno",
|
|
174
|
+
"composite_chart": "Tema Composito",
|
|
175
|
+
"midpoints": "Punti Medi",
|
|
176
|
+
"north_letter": "N",
|
|
177
|
+
"east_letter": "E",
|
|
178
|
+
"south_letter": "S",
|
|
179
|
+
"west_letter": "W",
|
|
156
180
|
"celestial_points": {
|
|
157
181
|
"Sun": "Sole",
|
|
158
182
|
"Moon": "Luna",
|
|
@@ -197,6 +221,12 @@
|
|
|
197
221
|
"transit_name": "流年名稱",
|
|
198
222
|
"lunar_phase": "月相",
|
|
199
223
|
"day": "日",
|
|
224
|
+
"composite_chart": "合盤",
|
|
225
|
+
"midpoints": "中點",
|
|
226
|
+
"north_letter": "北",
|
|
227
|
+
"east_letter": "東",
|
|
228
|
+
"south_letter": "南",
|
|
229
|
+
"west_letter": "西",
|
|
200
230
|
"celestial_points": {
|
|
201
231
|
"Sun": "太陽",
|
|
202
232
|
"Moon": "月亮",
|
|
@@ -241,6 +271,12 @@
|
|
|
241
271
|
"transit_name": "En el momento del tránsito",
|
|
242
272
|
"lunar_phase": "Fase lunar",
|
|
243
273
|
"day": "Día",
|
|
274
|
+
"composite_chart": "Carta Compuesta",
|
|
275
|
+
"midpoints": "Puntos Medios",
|
|
276
|
+
"north_letter": "N",
|
|
277
|
+
"east_letter": "E",
|
|
278
|
+
"south_letter": "S",
|
|
279
|
+
"west_letter": "W",
|
|
244
280
|
"celestial_points": {
|
|
245
281
|
"Sun": "Sol",
|
|
246
282
|
"Moon": "Luna",
|
|
@@ -285,6 +321,12 @@
|
|
|
285
321
|
"transit_name": "В момент транзита",
|
|
286
322
|
"lunar_phase": "Лунная фаза",
|
|
287
323
|
"day": "День",
|
|
324
|
+
"composite_chart": "Композитная карта",
|
|
325
|
+
"midpoints": "Средние точки",
|
|
326
|
+
"north_letter": "С",
|
|
327
|
+
"east_letter": "В",
|
|
328
|
+
"south_letter": "Ю",
|
|
329
|
+
"west_letter": "З",
|
|
288
330
|
"celestial_points": {
|
|
289
331
|
"Sun": "Солнце",
|
|
290
332
|
"Moon": "Луна",
|
|
@@ -329,6 +371,12 @@
|
|
|
329
371
|
"transit_name": "Geçiş anında",
|
|
330
372
|
"lunar_phase": "Ay Aşaması",
|
|
331
373
|
"day": "Gün",
|
|
374
|
+
"composite_chart": "Kompozit Harita",
|
|
375
|
+
"midpoints": "Orta Noktalar",
|
|
376
|
+
"north_letter": "K",
|
|
377
|
+
"east_letter": "D",
|
|
378
|
+
"south_letter": "G",
|
|
379
|
+
"west_letter": "B",
|
|
332
380
|
"celestial_points": {
|
|
333
381
|
"Sun": "Güneş",
|
|
334
382
|
"Moon": "Ay",
|
|
@@ -373,6 +421,12 @@
|
|
|
373
421
|
"transit_name": "Zum Zeitpunkt des Transits",
|
|
374
422
|
"lunar_phase": "Mondphase",
|
|
375
423
|
"day": "Tag",
|
|
424
|
+
"composite_chart": "Komposit-Chart",
|
|
425
|
+
"midpoints": "Mittelpunkte",
|
|
426
|
+
"north_letter": "N",
|
|
427
|
+
"east_letter": "E",
|
|
428
|
+
"south_letter": "S",
|
|
429
|
+
"west_letter": "W",
|
|
376
430
|
"celestial_points": {
|
|
377
431
|
"Sun": "Sonne",
|
|
378
432
|
"Moon": "Mond",
|
|
@@ -417,6 +471,12 @@
|
|
|
417
471
|
"transit_name": "गोचर के समय",
|
|
418
472
|
"lunar_phase": "चंद्र चरण",
|
|
419
473
|
"day": "दिन",
|
|
474
|
+
"composite_chart": "संयुक्त चार्ट",
|
|
475
|
+
"midpoints": "मध्य बिंदु",
|
|
476
|
+
"north_letter": "उ",
|
|
477
|
+
"east_letter": "पू",
|
|
478
|
+
"south_letter": "द",
|
|
479
|
+
"west_letter": "प",
|
|
420
480
|
"celestial_points": {
|
|
421
481
|
"Sun": "सूर्य",
|
|
422
482
|
"Moon": "चंद्रमा",
|
kerykeion/utilities.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from kerykeion.kr_types import KerykeionPointModel, KerykeionException, ZodiacSignModel, AstrologicalSubjectModel
|
|
1
|
+
from kerykeion.kr_types import KerykeionPointModel, KerykeionException, ZodiacSignModel, AstrologicalSubjectModel, LunarPhaseModel
|
|
2
2
|
from kerykeion.kr_types.kr_literals import LunarPhaseEmoji, LunarPhaseName, PointType, Planet, Houses, AxialCusps
|
|
3
3
|
from typing import Union, get_args, TYPE_CHECKING
|
|
4
4
|
import logging
|
|
@@ -318,3 +318,75 @@ def get_available_astrological_points_list(subject: Union["AstrologicalSubject",
|
|
|
318
318
|
planets_absolute_position_list.append(subject[axis.lower()])
|
|
319
319
|
|
|
320
320
|
return planets_absolute_position_list
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
def circular_mean(first_position: Union[int, float], second_position: Union[int, float]) -> float:
|
|
324
|
+
"""
|
|
325
|
+
Computes the circular mean of two astrological positions (e.g., house cusps, planets).
|
|
326
|
+
|
|
327
|
+
This function ensures that positions crossing 0° Aries (360°) are correctly averaged,
|
|
328
|
+
avoiding errors that occur with simple linear means.
|
|
329
|
+
|
|
330
|
+
Args:
|
|
331
|
+
position1 (Union[int, float]): First position in degrees (0-360).
|
|
332
|
+
position2 (Union[int, float]): Second position in degrees (0-360).
|
|
333
|
+
|
|
334
|
+
Returns:
|
|
335
|
+
float: The circular mean position in degrees (0-360).
|
|
336
|
+
"""
|
|
337
|
+
x = (math.cos(math.radians(first_position)) + math.cos(math.radians(second_position))) / 2
|
|
338
|
+
y = (math.sin(math.radians(first_position)) + math.sin(math.radians(second_position))) / 2
|
|
339
|
+
mean_position = math.degrees(math.atan2(y, x))
|
|
340
|
+
|
|
341
|
+
# Ensure the result is within 0-360°
|
|
342
|
+
if mean_position < 0:
|
|
343
|
+
mean_position += 360
|
|
344
|
+
|
|
345
|
+
return mean_position
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
def calculate_moon_phase(moon_abs_pos: float, sun_abs_pos: float) -> LunarPhaseModel:
|
|
349
|
+
"""
|
|
350
|
+
Calculate the lunar phase based on the positions of the moon and sun.
|
|
351
|
+
|
|
352
|
+
Args:
|
|
353
|
+
- moon_abs_pos (float): The absolute position of the moon.
|
|
354
|
+
- sun_abs_pos (float): The absolute position of the sun.
|
|
355
|
+
|
|
356
|
+
Returns:
|
|
357
|
+
- dict: A dictionary containing the lunar phase information.
|
|
358
|
+
"""
|
|
359
|
+
# Initialize moon_phase and sun_phase to None in case of an error
|
|
360
|
+
moon_phase, sun_phase = None, None
|
|
361
|
+
|
|
362
|
+
# Calculate the anti-clockwise degrees between the sun and moon
|
|
363
|
+
degrees_between = (moon_abs_pos - sun_abs_pos) % 360
|
|
364
|
+
|
|
365
|
+
# Calculate the moon phase (1-28) based on the degrees between the sun and moon
|
|
366
|
+
step = 360.0 / 28.0
|
|
367
|
+
moon_phase = int(degrees_between // step) + 1
|
|
368
|
+
|
|
369
|
+
# Define the sun phase steps
|
|
370
|
+
sunstep = [
|
|
371
|
+
0, 30, 40, 50, 60, 70, 80, 90, 120, 130, 140, 150, 160, 170, 180,
|
|
372
|
+
210, 220, 230, 240, 250, 260, 270, 300, 310, 320, 330, 340, 350
|
|
373
|
+
]
|
|
374
|
+
|
|
375
|
+
# Calculate the sun phase (1-28) based on the degrees between the sun and moon
|
|
376
|
+
for x in range(len(sunstep)):
|
|
377
|
+
low = sunstep[x]
|
|
378
|
+
high = sunstep[x + 1] if x < len(sunstep) - 1 else 360
|
|
379
|
+
if low <= degrees_between < high:
|
|
380
|
+
sun_phase = x + 1
|
|
381
|
+
break
|
|
382
|
+
|
|
383
|
+
# Create a dictionary with the lunar phase information
|
|
384
|
+
lunar_phase_dictionary = {
|
|
385
|
+
"degrees_between_s_m": degrees_between,
|
|
386
|
+
"moon_phase": moon_phase,
|
|
387
|
+
"sun_phase": sun_phase,
|
|
388
|
+
"moon_emoji": get_moon_emoji_from_phase_int(moon_phase),
|
|
389
|
+
"moon_phase_name": get_moon_phase_name_from_phase_int(moon_phase)
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
return LunarPhaseModel(**lunar_phase_dictionary)
|