kerykeion 4.14.2__py3-none-any.whl → 4.18.0__py3-none-any.whl

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

Potentially problematic release.


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

Files changed (34) hide show
  1. kerykeion/__init__.py +2 -1
  2. kerykeion/aspects/aspects_utils.py +33 -117
  3. kerykeion/aspects/natal_aspects.py +26 -25
  4. kerykeion/aspects/synastry_aspects.py +25 -27
  5. kerykeion/astrological_subject.py +145 -189
  6. kerykeion/charts/charts_utils.py +400 -126
  7. kerykeion/charts/draw_planets.py +407 -0
  8. kerykeion/charts/kerykeion_chart_svg.py +502 -770
  9. kerykeion/charts/templates/aspect_grid_only.xml +452 -0
  10. kerykeion/charts/templates/chart.xml +39 -39
  11. kerykeion/charts/templates/wheel_only.xml +499 -0
  12. kerykeion/charts/themes/classic.css +82 -0
  13. kerykeion/charts/themes/dark-high-contrast.css +121 -0
  14. kerykeion/charts/themes/dark.css +121 -0
  15. kerykeion/charts/themes/light.css +117 -0
  16. kerykeion/ephemeris_data.py +22 -18
  17. kerykeion/kr_types/chart_types.py +3 -7
  18. kerykeion/kr_types/kr_literals.py +10 -1
  19. kerykeion/kr_types/kr_models.py +33 -8
  20. kerykeion/kr_types/settings_models.py +1 -10
  21. kerykeion/relationship_score/__init__.py +2 -0
  22. kerykeion/relationship_score/relationship_score.py +175 -0
  23. kerykeion/relationship_score/relationship_score_factory.py +275 -0
  24. kerykeion/report.py +6 -3
  25. kerykeion/settings/kerykeion_settings.py +6 -1
  26. kerykeion/settings/kr.config.json +238 -98
  27. kerykeion/utilities.py +116 -215
  28. {kerykeion-4.14.2.dist-info → kerykeion-4.18.0.dist-info}/METADATA +40 -10
  29. kerykeion-4.18.0.dist-info/RECORD +42 -0
  30. kerykeion/relationship_score.py +0 -205
  31. kerykeion-4.14.2.dist-info/RECORD +0 -33
  32. {kerykeion-4.14.2.dist-info → kerykeion-4.18.0.dist-info}/LICENSE +0 -0
  33. {kerykeion-4.14.2.dist-info → kerykeion-4.18.0.dist-info}/WHEEL +0 -0
  34. {kerykeion-4.14.2.dist-info → kerykeion-4.18.0.dist-info}/entry_points.txt +0 -0
@@ -5,24 +5,23 @@
5
5
 
6
6
 
7
7
  import logging
8
+ from typing import get_args
8
9
 
9
10
  from kerykeion.settings.kerykeion_settings import get_settings
10
11
  from kerykeion.aspects.synastry_aspects import SynastryAspects
11
12
  from kerykeion.aspects.natal_aspects import NatalAspects
12
13
  from kerykeion.astrological_subject import AstrologicalSubject
13
- from kerykeion.kr_types import KerykeionException, ChartType
14
+ from kerykeion.kr_types import KerykeionException, ChartType, KerykeionPointModel, Sign
14
15
  from kerykeion.kr_types import ChartTemplateDictionary
15
- from kerykeion.kr_types.settings_models import KerykeionSettingsCelestialPointModel
16
+ from kerykeion.kr_types.kr_models import AstrologicalSubjectModel
17
+ from kerykeion.kr_types.settings_models import KerykeionSettingsCelestialPointModel, KerykeionSettingsModel
18
+ from kerykeion.kr_types.kr_literals import KerykeionChartTheme
16
19
  from kerykeion.charts.charts_utils import (
17
- degreeDiff,
18
- sliceToX,
19
- sliceToY,
20
20
  draw_zodiac_slice,
21
21
  convert_latitude_coordinate_to_string,
22
22
  convert_longitude_coordinate_to_string,
23
23
  draw_aspect_line,
24
24
  draw_elements_percentages,
25
- convert_decimal_to_degree_string,
26
25
  draw_transit_ring_degree_steps,
27
26
  draw_degree_ring,
28
27
  draw_transit_ring,
@@ -31,17 +30,21 @@ from kerykeion.charts.charts_utils import (
31
30
  draw_third_circle,
32
31
  draw_aspect_grid,
33
32
  draw_houses_cusps_and_text_number,
34
- draw_aspect_transit_grid,
35
- draw_moon_phase
33
+ draw_transit_aspect_list,
34
+ draw_transit_aspect_grid,
35
+ draw_moon_phase,
36
+ draw_house_grid,
37
+ draw_planet_grid,
36
38
  )
39
+ from kerykeion.charts.draw_planets import draw_planets # type: ignore
40
+ from kerykeion.utilities import get_houses_list
37
41
  from pathlib import Path
38
42
  from scour.scour import scourString
39
43
  from string import Template
40
- from typing import Union, List
44
+ from typing import Union, List, Literal
41
45
  from datetime import datetime
42
46
 
43
47
 
44
-
45
48
  class KerykeionChartSVG:
46
49
  """
47
50
  Creates the instance that can generate the chart with the
@@ -54,19 +57,26 @@ class KerykeionChartSVG:
54
57
  - new_output_directory: Set the output directory (default: home directory).
55
58
  - new_settings_file: Set the settings file (default: kr.config.json).
56
59
  In the settings file you can set the language, colors, planets, aspects, etc.
60
+ - theme: Set the theme for the chart (default: classic). If None the <style> tag will be empty.
61
+ That's useful if you want to use your own CSS file customizing the value of the default theme variables.
62
+ - double_chart_aspect_grid_type: Set the type of the aspect grid for the double chart (transit or synastry). (Default: list.)
63
+ - chart_language: Set the language for the chart (default: EN).
57
64
  """
58
65
 
59
66
  # Constants
67
+ _BASIC_CHART_VIEWBOX = "0 0 772.2 546.0"
68
+ _WIDE_CHART_VIEWBOX = "0 0 1060 546.0"
60
69
  _DEFAULT_HEIGHT = 546.0
61
70
  _DEFAULT_FULL_WIDTH = 1200
62
71
  _DEFAULT_NATAL_WIDTH = 772.2
72
+ _PLANET_IN_ZODIAC_EXTRA_POINTS = 10
63
73
 
64
74
  # Set at init
65
- first_obj: AstrologicalSubject
66
- second_obj: Union[AstrologicalSubject, None]
75
+ first_obj: Union[AstrologicalSubject, AstrologicalSubjectModel]
76
+ second_obj: Union[AstrologicalSubject, AstrologicalSubjectModel, None]
67
77
  chart_type: ChartType
68
78
  new_output_directory: Union[Path, None]
69
- new_settings_file: Union[Path, None]
79
+ new_settings_file: Union[Path, None, KerykeionSettingsModel, dict]
70
80
  output_directory: Path
71
81
 
72
82
  # Internal properties
@@ -74,57 +84,43 @@ class KerykeionChartSVG:
74
84
  earth: float
75
85
  air: float
76
86
  water: float
77
- c1: float
78
- c2: float
79
- c3: float
80
- homedir: Path
81
- xml_svg: Path
87
+ main_radius: float
88
+ first_circle_radius: float
89
+ second_circle_radius: float
90
+ third_circle_radius: float
82
91
  width: Union[float, int]
83
92
  language_settings: dict
84
93
  chart_colors_settings: dict
85
94
  planets_settings: dict
86
95
  aspects_settings: dict
87
- planet_in_zodiac_extra_points: int
88
- chart_settings: dict
89
- user: AstrologicalSubject
96
+ user: Union[AstrologicalSubject, AstrologicalSubjectModel]
90
97
  available_planets_setting: List[KerykeionSettingsCelestialPointModel]
91
- transit_ring_exclude_points_names: List[str]
92
- points_deg_ut: list
93
- points_deg: list
94
- points_sign: list
95
- points_retrograde: list
96
- houses_sign_graph: list
97
- t_points_deg_ut: list
98
- t_points_deg: list
99
- t_points_sign: list
100
- t_points_retrograde: list
101
- t_houses_sign_graph: list
102
98
  height: float
103
99
  location: str
104
100
  geolat: float
105
101
  geolon: float
106
- zodiac: tuple
107
102
  template: str
108
103
 
109
104
  def __init__(
110
105
  self,
111
- first_obj: AstrologicalSubject,
106
+ first_obj: Union[AstrologicalSubject, AstrologicalSubjectModel],
112
107
  chart_type: ChartType = "Natal",
113
- second_obj: Union[AstrologicalSubject, None] = None,
108
+ second_obj: Union[AstrologicalSubject, AstrologicalSubjectModel, None] = None,
114
109
  new_output_directory: Union[str, None] = None,
115
- new_settings_file: Union[Path, None] = None,
110
+ new_settings_file: Union[Path, None, KerykeionSettingsModel, dict] = None,
111
+ theme: Union[KerykeionChartTheme, None] = "classic",
112
+ double_chart_aspect_grid_type: Literal["list", "table"] = "list",
113
+ chart_language: str = "EN",
116
114
  ):
117
115
  # Directories:
118
- DATA_DIR = Path(__file__).parent
119
- self.homedir = Path.home()
116
+ home_directory = Path.home()
120
117
  self.new_settings_file = new_settings_file
118
+ self.chart_language = chart_language
121
119
 
122
120
  if new_output_directory:
123
121
  self.output_directory = Path(new_output_directory)
124
122
  else:
125
- self.output_directory = self.homedir
126
-
127
- self.xml_svg = DATA_DIR / "templates/chart.xml"
123
+ self.output_directory = home_directory
128
124
 
129
125
  self.parse_json_settings(new_settings_file)
130
126
  self.chart_type = chart_type
@@ -139,58 +135,20 @@ class KerykeionChartSVG:
139
135
 
140
136
  self.available_planets_setting.append(body)
141
137
 
142
- # House cusp points are excluded from the transit ring.
143
- self.transit_ring_exclude_points_names = [
144
- "First_House",
145
- "Second_House",
146
- "Third_House",
147
- "Fourth_House",
148
- "Fifth_House",
149
- "Sixth_House",
150
- "Seventh_House",
151
- "Eighth_House",
152
- "Ninth_House",
153
- "Tenth_House",
154
- "Eleventh_House",
155
- "Twelfth_House"
156
- ]
157
-
158
138
  # Available bodies
159
- available_celestial_points = []
139
+ available_celestial_points_names = []
160
140
  for body in self.available_planets_setting:
161
- available_celestial_points.append(body["name"].lower())
162
-
163
- # Make a list for the absolute degrees of the points of the graphic.
164
- self.points_deg_ut = []
165
- for planet in available_celestial_points:
166
- self.points_deg_ut.append(self.user.get(planet).abs_pos)
167
-
168
- # Make a list of the relative degrees of the points in the graphic.
169
- self.points_deg = []
170
- for planet in available_celestial_points:
171
- self.points_deg.append(self.user.get(planet).position)
141
+ available_celestial_points_names.append(body["name"].lower())
172
142
 
173
- # Make list of the points sign
174
- self.points_sign = []
175
- for planet in available_celestial_points:
176
- self.points_sign.append(self.user.get(planet).sign_num)
177
-
178
- # Make a list of points if they are retrograde or not.
179
- self.points_retrograde = []
180
- for planet in available_celestial_points:
181
- self.points_retrograde.append(self.user.get(planet).retrograde)
143
+ self.available_kerykeion_celestial_points: list[KerykeionPointModel] = []
144
+ for body in available_celestial_points_names:
145
+ self.available_kerykeion_celestial_points.append(self.user.get(body))
182
146
 
183
147
  # Makes the sign number list.
184
-
185
- self.houses_sign_graph = []
186
- for h in self.user.houses_list:
187
- self.houses_sign_graph.append(h["sign_num"])
188
-
189
148
  if self.chart_type == "Natal" or self.chart_type == "ExternalNatal":
190
149
  natal_aspects_instance = NatalAspects(self.user, new_settings_file=self.new_settings_file)
191
150
  self.aspects_list = natal_aspects_instance.relevant_aspects
192
151
 
193
- # TODO: If not second should exit
194
152
  if self.chart_type == "Transit" or self.chart_type == "Synastry":
195
153
  if not second_obj:
196
154
  raise KerykeionException("Second object is required for Transit or Synastry charts.")
@@ -198,29 +156,15 @@ class KerykeionChartSVG:
198
156
  # Kerykeion instance
199
157
  self.t_user = second_obj
200
158
 
201
- # Make a list for the absolute degrees of the points of the graphic.
202
- self.t_points_deg_ut = []
203
- for planet in available_celestial_points:
204
- self.t_points_deg_ut.append(self.t_user.get(planet).abs_pos)
159
+ # Aspects
160
+ self.aspects_list = SynastryAspects(self.user, self.t_user, new_settings_file=self.new_settings_file).relevant_aspects
205
161
 
206
- # Make a list of the relative degrees of the points in the graphic.
207
- self.t_points_deg = []
208
- for planet in available_celestial_points:
209
- self.t_points_deg.append(self.t_user.get(planet).position)
162
+ self.t_available_kerykeion_celestial_points = []
163
+ for body in available_celestial_points_names:
164
+ self.t_available_kerykeion_celestial_points.append(self.t_user.get(body))
210
165
 
211
- # Make list of the poits sign.
212
- self.t_points_sign = []
213
- for planet in available_celestial_points:
214
- self.t_points_sign.append(self.t_user.get(planet).sign_num)
215
-
216
- # Make a list of poits if they are retrograde or not.
217
- self.t_points_retrograde = []
218
- for planet in available_celestial_points:
219
- self.t_points_retrograde.append(self.t_user.get(planet).retrograde)
220
-
221
- self.t_houses_sign_graph = []
222
- for h in self.t_user.houses_list:
223
- self.t_houses_sign_graph.append(h["sign_num"])
166
+ # Double chart aspect grid type
167
+ self.double_chart_aspect_grid_type = double_chart_aspect_grid_type
224
168
 
225
169
  # screen size
226
170
  self.height = self._DEFAULT_HEIGHT
@@ -234,31 +178,45 @@ class KerykeionChartSVG:
234
178
  self.geolat = self.user.lat
235
179
  self.geolon = self.user.lng
236
180
 
237
- logging.info(f"{self.user.name} birth location: {self.location}, {self.geolat}, {self.geolon}")
238
-
239
181
  if self.chart_type == "Transit":
240
182
  self.t_name = self.language_settings["transit_name"]
241
183
 
242
- # configuration
243
- # ZOOM 1 = 100%
244
- self.zoom = 1
245
-
246
- self.zodiac = (
247
- {"name": "aries", "element": "fire"},
248
- {"name": "taurus", "element": "earth"},
249
- {"name": "gemini", "element": "air"},
250
- {"name": "cancer", "element": "water"},
251
- {"name": "leo", "element": "fire"},
252
- {"name": "virgo", "element": "earth"},
253
- {"name": "libra", "element": "air"},
254
- {"name": "scorpio", "element": "water"},
255
- {"name": "sagittarius", "element": "fire"},
256
- {"name": "capricorn", "element": "earth"},
257
- {"name": "aquarius", "element": "air"},
258
- {"name": "pisces", "element": "water"},
259
- )
184
+ # Default radius for the chart
185
+ self.main_radius = 240
186
+
187
+ # Set circle radii based on chart type
188
+ if self.chart_type == "ExternalNatal":
189
+ self.first_circle_radius, self.second_circle_radius, self.third_circle_radius = 56, 92, 112
190
+ else:
191
+ self.first_circle_radius, self.second_circle_radius, self.third_circle_radius = 0, 36, 120
192
+
193
+ # Initialize element points
194
+ self.fire = 0.0
195
+ self.earth = 0.0
196
+ self.air = 0.0
197
+ self.water = 0.0
198
+
199
+ # Calculate element points from planets
200
+ self._calculate_elements_points_from_planets()
201
+
202
+ # Set up theme
203
+ if theme not in get_args(KerykeionChartTheme) and theme is not None:
204
+ raise KerykeionException(f"Theme {theme} is not available. Set None for default theme.")
260
205
 
261
- self.template = None
206
+ self.set_up_theme(theme)
207
+
208
+ def set_up_theme(self, theme: Union[KerykeionChartTheme, None] = None) -> None:
209
+ """
210
+ Set the theme for the chart.
211
+ """
212
+ if theme is None:
213
+ self.color_style_tag = ""
214
+ return
215
+
216
+ theme_dir = Path(__file__).parent / "themes"
217
+
218
+ with open(theme_dir / f"{theme}.css", "r") as f:
219
+ self.color_style_tag = f.read()
262
220
 
263
221
  def set_output_directory(self, dir_path: Path) -> None:
264
222
  """
@@ -267,19 +225,16 @@ class KerykeionChartSVG:
267
225
  self.output_directory = dir_path
268
226
  logging.info(f"Output direcotry set to: {self.output_directory}")
269
227
 
270
- def parse_json_settings(self, settings_file):
228
+ def parse_json_settings(self, settings_file_or_dict: Union[Path, dict, KerykeionSettingsModel, None]) -> None:
271
229
  """
272
230
  Parse the settings file.
273
231
  """
274
- settings = get_settings(settings_file)
232
+ settings = get_settings(settings_file_or_dict)
275
233
 
276
- language = settings["general_settings"]["language"]
277
- self.language_settings = settings["language_settings"].get(language, "EN")
234
+ self.language_settings = settings["language_settings"][self.chart_language]
278
235
  self.chart_colors_settings = settings["chart_colors"]
279
236
  self.planets_settings = settings["celestial_points"]
280
237
  self.aspects_settings = settings["aspects"]
281
- self.planet_in_zodiac_extra_points = settings["general_settings"]["planet_in_zodiac_extra_points"]
282
- self.chart_settings = settings["chart_settings"]
283
238
 
284
239
  def _draw_zodiac_circle_slices(self, r):
285
240
  """
@@ -292,17 +247,17 @@ class KerykeionChartSVG:
292
247
  Returns:
293
248
  str: The SVG string representing the zodiac circle.
294
249
  """
295
-
250
+ sings = get_args(Sign)
296
251
  output = ""
297
- for i, zodiac_element in enumerate(self.zodiac):
252
+ for i, sing in enumerate(sings):
298
253
  output += draw_zodiac_slice(
299
- c1=self.c1,
254
+ c1=self.first_circle_radius,
300
255
  chart_type=self.chart_type,
301
- seventh_house_degree_ut=self.user.houses_degree_ut[6],
256
+ seventh_house_degree_ut=self.user.seventh_house.abs_pos,
302
257
  num=i,
303
258
  r=r,
304
259
  style=f'fill:{self.chart_colors_settings[f"zodiac_bg_{i}"]}; fill-opacity: 0.5;',
305
- type=zodiac_element["name"],
260
+ type=sing,
306
261
  )
307
262
 
308
263
  return output
@@ -310,19 +265,47 @@ class KerykeionChartSVG:
310
265
  def _calculate_elements_points_from_planets(self):
311
266
  """
312
267
  Calculate chart element points from a planet.
268
+ TODO: Refactor this method.
269
+ Should be completely rewritten. Maybe even part of the AstrologicalSubject class.
270
+ The points should include just the standard way of calculating the elements points.
313
271
  """
272
+
273
+ ZODIAC = (
274
+ {"name": "Ari", "element": "fire"},
275
+ {"name": "Tau", "element": "earth"},
276
+ {"name": "Gem", "element": "air"},
277
+ {"name": "Can", "element": "water"},
278
+ {"name": "Leo", "element": "fire"},
279
+ {"name": "Vir", "element": "earth"},
280
+ {"name": "Lib", "element": "air"},
281
+ {"name": "Sco", "element": "water"},
282
+ {"name": "Sag", "element": "fire"},
283
+ {"name": "Cap", "element": "earth"},
284
+ {"name": "Aqu", "element": "air"},
285
+ {"name": "Pis", "element": "water"},
286
+ )
314
287
 
288
+ # Available bodies
289
+ available_celestial_points_names = []
290
+ for body in self.available_planets_setting:
291
+ available_celestial_points_names.append(body["name"].lower())
292
+
293
+ # Make list of the points sign
294
+ points_sign = []
295
+ for planet in available_celestial_points_names:
296
+ points_sign.append(self.user.get(planet).sign_num)
297
+
315
298
  for i in range(len(self.available_planets_setting)):
316
299
  # element: get extra points if planet is in own zodiac sign.
317
300
  related_zodiac_signs = self.available_planets_setting[i]["related_zodiac_signs"]
318
- cz = self.points_sign[i]
301
+ cz = points_sign[i]
319
302
  extra_points = 0
320
303
  if related_zodiac_signs != []:
321
304
  for e in range(len(related_zodiac_signs)):
322
305
  if int(related_zodiac_signs[e]) == int(cz):
323
- extra_points = self.planet_in_zodiac_extra_points
306
+ extra_points = self._PLANET_IN_ZODIAC_EXTRA_POINTS
324
307
 
325
- ele = self.zodiac[self.points_sign[i]]["element"]
308
+ ele = ZODIAC[points_sign[i]]["element"]
326
309
  if ele == "fire":
327
310
  self.fire = self.fire + self.available_planets_setting[i]["element_points"] + extra_points
328
311
 
@@ -335,344 +318,6 @@ class KerykeionChartSVG:
335
318
  elif ele == "water":
336
319
  self.water = self.water + self.available_planets_setting[i]["element_points"] + extra_points
337
320
 
338
- def _make_planets(self, r):
339
- planets_degut = {}
340
- diff = range(len(self.available_planets_setting))
341
-
342
- for i in range(len(self.available_planets_setting)):
343
- # list of planets sorted by degree
344
- logging.debug(f"planet: {i}, degree: {self.points_deg_ut[i]}")
345
- planets_degut[self.points_deg_ut[i]] = i
346
-
347
- """
348
- FIXME: The planets_degut is a dictionary like:
349
- {planet_degree: planet_index}
350
- It should be replaced bu points_deg_ut
351
- print(self.points_deg_ut)
352
- print(planets_degut)
353
- """
354
-
355
- output = ""
356
- keys = list(planets_degut.keys())
357
- keys.sort()
358
- switch = 0
359
-
360
- planets_degrouped = {}
361
- groups = []
362
- planets_by_pos = list(range(len(planets_degut)))
363
- planet_drange = 3.4
364
- # get groups closely together
365
- group_open = False
366
- for e in range(len(keys)):
367
- i = planets_degut[keys[e]]
368
- # get distances between planets
369
- if e == 0:
370
- prev = self.points_deg_ut[planets_degut[keys[-1]]]
371
- next = self.points_deg_ut[planets_degut[keys[1]]]
372
- elif e == (len(keys) - 1):
373
- prev = self.points_deg_ut[planets_degut[keys[e - 1]]]
374
- next = self.points_deg_ut[planets_degut[keys[0]]]
375
- else:
376
- prev = self.points_deg_ut[planets_degut[keys[e - 1]]]
377
- next = self.points_deg_ut[planets_degut[keys[e + 1]]]
378
- diffa = degreeDiff(prev, self.points_deg_ut[i])
379
- diffb = degreeDiff(next, self.points_deg_ut[i])
380
- planets_by_pos[e] = [i, diffa, diffb]
381
-
382
- logging.debug(f'{self.available_planets_setting[i]["label"]}, {diffa}, {diffb}')
383
-
384
- if diffb < planet_drange:
385
- if group_open:
386
- groups[-1].append([e, diffa, diffb, self.available_planets_setting[planets_degut[keys[e]]]["label"]])
387
- else:
388
- group_open = True
389
- groups.append([])
390
- groups[-1].append([e, diffa, diffb, self.available_planets_setting[planets_degut[keys[e]]]["label"]])
391
- else:
392
- if group_open:
393
- groups[-1].append([e, diffa, diffb, self.available_planets_setting[planets_degut[keys[e]]]["label"]])
394
- group_open = False
395
-
396
- def zero(x):
397
- return 0
398
-
399
- planets_delta = list(map(zero, range(len(self.available_planets_setting))))
400
-
401
- # print groups
402
- # print planets_by_pos
403
- for a in range(len(groups)):
404
- # Two grouped planets
405
- if len(groups[a]) == 2:
406
- next_to_a = groups[a][0][0] - 1
407
- if groups[a][1][0] == (len(planets_by_pos) - 1):
408
- next_to_b = 0
409
- else:
410
- next_to_b = groups[a][1][0] + 1
411
- # if both planets have room
412
- if (groups[a][0][1] > (2 * planet_drange)) & (groups[a][1][2] > (2 * planet_drange)):
413
- planets_delta[groups[a][0][0]] = -(planet_drange - groups[a][0][2]) / 2
414
- planets_delta[groups[a][1][0]] = +(planet_drange - groups[a][0][2]) / 2
415
- # if planet a has room
416
- elif groups[a][0][1] > (2 * planet_drange):
417
- planets_delta[groups[a][0][0]] = -planet_drange
418
- # if planet b has room
419
- elif groups[a][1][2] > (2 * planet_drange):
420
- planets_delta[groups[a][1][0]] = +planet_drange
421
-
422
- # if planets next to a and b have room move them
423
- elif (planets_by_pos[next_to_a][1] > (2.4 * planet_drange)) & (planets_by_pos[next_to_b][2] > (2.4 * planet_drange)):
424
- planets_delta[(next_to_a)] = groups[a][0][1] - planet_drange * 2
425
- planets_delta[groups[a][0][0]] = -planet_drange * 0.5
426
- planets_delta[next_to_b] = -(groups[a][1][2] - planet_drange * 2)
427
- planets_delta[groups[a][1][0]] = +planet_drange * 0.5
428
-
429
- # if planet next to a has room move them
430
- elif planets_by_pos[next_to_a][1] > (2 * planet_drange):
431
- planets_delta[(next_to_a)] = groups[a][0][1] - planet_drange * 2.5
432
- planets_delta[groups[a][0][0]] = -planet_drange * 1.2
433
-
434
- # if planet next to b has room move them
435
- elif planets_by_pos[next_to_b][2] > (2 * planet_drange):
436
- planets_delta[next_to_b] = -(groups[a][1][2] - planet_drange * 2.5)
437
- planets_delta[groups[a][1][0]] = +planet_drange * 1.2
438
-
439
- # Three grouped planets or more
440
- xl = len(groups[a])
441
- if xl >= 3:
442
- available = groups[a][0][1]
443
- for f in range(xl):
444
- available += groups[a][f][2]
445
- need = (3 * planet_drange) + (1.2 * (xl - 1) * planet_drange)
446
- leftover = available - need
447
- xa = groups[a][0][1]
448
- xb = groups[a][(xl - 1)][2]
449
-
450
- # center
451
- if (xa > (need * 0.5)) & (xb > (need * 0.5)):
452
- startA = xa - (need * 0.5)
453
- # position relative to next planets
454
- else:
455
- startA = (leftover / (xa + xb)) * xa
456
- startB = (leftover / (xa + xb)) * xb
457
-
458
- if available > need:
459
- planets_delta[groups[a][0][0]] = startA - groups[a][0][1] + (1.5 * planet_drange)
460
- for f in range(xl - 1):
461
- planets_delta[groups[a][(f + 1)][0]] = 1.2 * planet_drange + planets_delta[groups[a][f][0]] - groups[a][f][2]
462
-
463
- for e in range(len(keys)):
464
- i = planets_degut[keys[e]]
465
-
466
- # coordinates
467
- if self.chart_type == "Transit" or self.chart_type == "Synastry":
468
- if 22 < i < 27:
469
- rplanet = 76
470
- elif switch == 1:
471
- rplanet = 110
472
- switch = 0
473
- else:
474
- rplanet = 130
475
- switch = 1
476
- else:
477
- # if 22 < i < 27 it is asc,mc,dsc,ic (angles of chart)
478
- # put on special line (rplanet is range from outer ring)
479
- amin, bmin, cmin = 0, 0, 0
480
- if self.chart_type == "ExternalNatal":
481
- amin = 74 - 10
482
- bmin = 94 - 10
483
- cmin = 40 - 10
484
-
485
- if 22 < i < 27:
486
- rplanet = 40 - cmin
487
- elif switch == 1:
488
- rplanet = 74 - amin
489
- switch = 0
490
- else:
491
- rplanet = 94 - bmin
492
- switch = 1
493
-
494
- rtext = 45
495
-
496
- offset = (int(self.user.houses_degree_ut[6]) / -1) + int(self.points_deg_ut[i] + planets_delta[e])
497
- trueoffset = (int(self.user.houses_degree_ut[6]) / -1) + int(self.points_deg_ut[i])
498
-
499
- planet_x = sliceToX(0, (r - rplanet), offset) + rplanet
500
- planet_y = sliceToY(0, (r - rplanet), offset) + rplanet
501
- if self.chart_type == "Transit" or self.chart_type == "Synastry":
502
- scale = 0.8
503
-
504
- elif self.chart_type == "ExternalNatal":
505
- scale = 0.8
506
- # line1
507
- x1 = sliceToX(0, (r - self.c3), trueoffset) + self.c3
508
- y1 = sliceToY(0, (r - self.c3), trueoffset) + self.c3
509
- x2 = sliceToX(0, (r - rplanet - 30), trueoffset) + rplanet + 30
510
- y2 = sliceToY(0, (r - rplanet - 30), trueoffset) + rplanet + 30
511
- color = self.available_planets_setting[i]["color"]
512
- output += (
513
- '<line x1="%s" y1="%s" x2="%s" y2="%s" style="stroke-width:1px;stroke:%s;stroke-opacity:.3;"/>\n'
514
- % (x1, y1, x2, y2, color)
515
- )
516
- # line2
517
- x1 = sliceToX(0, (r - rplanet - 30), trueoffset) + rplanet + 30
518
- y1 = sliceToY(0, (r - rplanet - 30), trueoffset) + rplanet + 30
519
- x2 = sliceToX(0, (r - rplanet - 10), offset) + rplanet + 10
520
- y2 = sliceToY(0, (r - rplanet - 10), offset) + rplanet + 10
521
- output += (
522
- '<line x1="%s" y1="%s" x2="%s" y2="%s" style="stroke-width:1px;stroke:%s;stroke-opacity:.5;"/>\n'
523
- % (x1, y1, x2, y2, color)
524
- )
525
-
526
- else:
527
- scale = 1
528
-
529
- planet_details = self.user[self.available_planets_setting[i]["name"].lower()]
530
-
531
- output += f'<g kr:node="ChartPoint" kr:house="{planet_details['house']}" kr:sign="{planet_details['sign']}" kr:slug="{planet_details['name']}" transform="translate(-{12 * scale},-{12 * scale}) scale({scale})">'
532
- output += f'<use x="{planet_x * (1/scale)}" y="{planet_y * (1/scale)}" xlink:href="#{self.available_planets_setting[i]["name"]}" />'
533
- output += f'</g>'
534
-
535
- # make transit degut and display planets
536
- if self.chart_type == "Transit" or self.chart_type == "Synastry":
537
- group_offset = {}
538
- t_planets_degut = {}
539
- list_range = len(self.available_planets_setting)
540
-
541
- for i in range(list_range):
542
- if self.chart_type == "Transit" and self.available_planets_setting[i]['name'] in self.transit_ring_exclude_points_names:
543
- continue
544
-
545
- group_offset[i] = 0
546
- t_planets_degut[self.t_points_deg_ut[i]] = i
547
-
548
- t_keys = list(t_planets_degut.keys())
549
- t_keys.sort()
550
-
551
- # grab closely grouped planets
552
- groups = []
553
- in_group = False
554
- for e in range(len(t_keys)):
555
- i_a = t_planets_degut[t_keys[e]]
556
- if e == (len(t_keys) - 1):
557
- i_b = t_planets_degut[t_keys[0]]
558
- else:
559
- i_b = t_planets_degut[t_keys[e + 1]]
560
-
561
- a = self.t_points_deg_ut[i_a]
562
- b = self.t_points_deg_ut[i_b]
563
- diff = degreeDiff(a, b)
564
- if diff <= 2.5:
565
- if in_group:
566
- groups[-1].append(i_b)
567
- else:
568
- groups.append([i_a])
569
- groups[-1].append(i_b)
570
- in_group = True
571
- else:
572
- in_group = False
573
- # loop groups and set degrees display adjustment
574
- for i in range(len(groups)):
575
- if len(groups[i]) == 2:
576
- group_offset[groups[i][0]] = -1.0
577
- group_offset[groups[i][1]] = 1.0
578
- elif len(groups[i]) == 3:
579
- group_offset[groups[i][0]] = -1.5
580
- group_offset[groups[i][1]] = 0
581
- group_offset[groups[i][2]] = 1.5
582
- elif len(groups[i]) == 4:
583
- group_offset[groups[i][0]] = -2.0
584
- group_offset[groups[i][1]] = -1.0
585
- group_offset[groups[i][2]] = 1.0
586
- group_offset[groups[i][3]] = 2.0
587
-
588
- switch = 0
589
-
590
- # Transit planets loop
591
- for e in range(len(t_keys)):
592
- if self.chart_type == "Transit" and self.available_planets_setting[e]["name"] in self.transit_ring_exclude_points_names:
593
- continue
594
-
595
- i = t_planets_degut[t_keys[e]]
596
-
597
- if 22 < i < 27:
598
- rplanet = 9
599
- elif switch == 1:
600
- rplanet = 18
601
- switch = 0
602
- else:
603
- rplanet = 26
604
- switch = 1
605
-
606
- # Transit planet name
607
- zeropoint = 360 - self.user.houses_degree_ut[6]
608
- t_offset = zeropoint + self.t_points_deg_ut[i]
609
- if t_offset > 360:
610
- t_offset = t_offset - 360
611
- planet_x = sliceToX(0, (r - rplanet), t_offset) + rplanet
612
- planet_y = sliceToY(0, (r - rplanet), t_offset) + rplanet
613
- output += f'<g class="transit-planet-name" transform="translate(-6,-6)"><g transform="scale(0.5)"><use x="{planet_x*2}" y="{planet_y*2}" xlink:href="#{self.available_planets_setting[i]["name"]}" /></g></g>'
614
-
615
- # Transit planet line
616
- x1 = sliceToX(0, r + 3, t_offset) - 3
617
- y1 = sliceToY(0, r + 3, t_offset) - 3
618
- x2 = sliceToX(0, r - 3, t_offset) + 3
619
- y2 = sliceToY(0, r - 3, t_offset) + 3
620
- output += f'<line class="transit-planet-line" x1="{str(x1)}" y1="{str(y1)}" x2="{str(x2)}" y2="{str(y2)}" style="stroke: {self.available_planets_setting[i]["color"]}; stroke-width: 1px; stroke-opacity:.8;"/>'
621
-
622
- # transit planet degree text
623
- rotate = self.user.houses_degree_ut[0] - self.t_points_deg_ut[i]
624
- textanchor = "end"
625
- t_offset += group_offset[i]
626
- rtext = -3.0
627
-
628
- if -90 > rotate > -270:
629
- rotate = rotate + 180.0
630
- textanchor = "start"
631
- if 270 > rotate > 90:
632
- rotate = rotate - 180.0
633
- textanchor = "start"
634
-
635
- if textanchor == "end":
636
- xo = 1
637
- else:
638
- xo = -1
639
- deg_x = sliceToX(0, (r - rtext), t_offset + xo) + rtext
640
- deg_y = sliceToY(0, (r - rtext), t_offset + xo) + rtext
641
- degree = int(t_offset)
642
- output += f'<g transform="translate({deg_x},{deg_y})">'
643
- output += f'<text transform="rotate({rotate})" text-anchor="{textanchor}'
644
- output += f'" style="fill: {self.available_planets_setting[i]["color"]}; font-size: 10px;">{convert_decimal_to_degree_string(self.t_points_deg[i], type="1")}'
645
- output += "</text></g>"
646
-
647
- # check transit
648
- if self.chart_type == "Transit" or self.chart_type == "Synastry":
649
- dropin = 36
650
- else:
651
- dropin = 0
652
-
653
- # planet line
654
- x1 = sliceToX(0, r - (dropin + 3), offset) + (dropin + 3)
655
- y1 = sliceToY(0, r - (dropin + 3), offset) + (dropin + 3)
656
- x2 = sliceToX(0, (r - (dropin - 3)), offset) + (dropin - 3)
657
- y2 = sliceToY(0, (r - (dropin - 3)), offset) + (dropin - 3)
658
-
659
- output += f'<line x1="{x1}" y1="{y1}" x2="{x2}" y2="{y2}" style="stroke: {self.available_planets_setting[i]["color"]}; stroke-width: 2px; stroke-opacity:.6;"/>'
660
-
661
- # check transit
662
- if self.chart_type == "Transit" or self.chart_type == "Synastry":
663
- dropin = 160
664
- else:
665
- dropin = 120
666
-
667
- x1 = sliceToX(0, r - dropin, offset) + dropin
668
- y1 = sliceToY(0, r - dropin, offset) + dropin
669
- x2 = sliceToX(0, (r - (dropin - 3)), offset) + (dropin - 3)
670
- y2 = sliceToY(0, (r - (dropin - 3)), offset) + (dropin - 3)
671
- output += f'<line x1="{x1}" y1="{y1}" x2="{x2}" y2="{y2}" style="stroke: {self.available_planets_setting[i]["color"]}; stroke-width: 2px; stroke-opacity:.6;"/>'
672
-
673
- return output
674
-
675
- # Aspect and aspect grid functions for natal type charts.
676
321
  def _draw_all_aspects_lines(self, r, ar):
677
322
  out = ""
678
323
  for aspect in self.aspects_list:
@@ -686,12 +331,8 @@ class KerykeionChartSVG:
686
331
 
687
332
  return out
688
333
 
689
- # Aspect and aspect grid functions for transit type charts
690
334
  def _draw_all_transit_aspects_lines(self, r, ar):
691
335
  out = ""
692
-
693
- self.aspects_list = SynastryAspects(self.user, self.t_user, new_settings_file=self.new_settings_file).relevant_aspects
694
-
695
336
  for aspect in self.aspects_list:
696
337
  out += draw_aspect_line(
697
338
  r=r,
@@ -700,335 +341,200 @@ class KerykeionChartSVG:
700
341
  color=self.aspects_settings[aspect["aid"]]["color"],
701
342
  seventh_house_degree_ut=self.user.seventh_house.abs_pos
702
343
  )
703
-
704
- return out
705
-
706
- def _makePlanetGrid(self):
707
- li = 10
708
- offset = 0
709
-
710
- out = '<g transform="translate(510,-20)">'
711
- out += '<g transform="translate(140, -15)">'
712
- 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>'
713
- out += "</g>"
714
-
715
- end_of_line = None
716
- for i in range(len(self.available_planets_setting)):
717
- offset_between_lines = 14
718
- end_of_line = "</g>"
719
-
720
- # Guarda qui !!
721
- if i == 27:
722
- li = 10
723
- offset = -120
724
-
725
- # start of line
726
- out += f'<g transform="translate({offset},{li})">'
727
-
728
- # planet text
729
- out += f'<text text-anchor="end" style="fill:{self.chart_colors_settings["paper_0"]}; font-size: 10px;">{self.language_settings["celestial_points"][self.available_planets_setting[i]["label"]]}</text>'
730
-
731
- # planet symbol
732
- out += f'<g transform="translate(5,-8)"><use transform="scale(0.4)" xlink:href="#{self.available_planets_setting[i]["name"]}" /></g>'
733
-
734
- # planet degree
735
- out += f'<text text-anchor="start" x="19" style="fill:{self.chart_colors_settings["paper_0"]}; font-size: 10px;">{convert_decimal_to_degree_string(self.points_deg[i])}</text>'
736
-
737
- # zodiac
738
- out += f'<g transform="translate(60,-8)"><use transform="scale(0.3)" xlink:href="#{self.zodiac[self.points_sign[i]]["name"]}" /></g>'
739
-
740
- # planet retrograde
741
- if self.points_retrograde[i]:
742
- out += '<g transform="translate(74,-6)"><use transform="scale(.5)" xlink:href="#retrograde" /></g>'
743
-
744
- # end of line
745
- out += end_of_line
746
-
747
- li = li + offset_between_lines
748
-
749
- if self.chart_type == "Transit" or self.chart_type == "Synastry":
750
- if self.chart_type == "Transit":
751
- out += '<g transform="translate(320, -15)">'
752
- out += f'<text text-anchor="end" style="fill:{self.chart_colors_settings["paper_0"]}; font-size: 14px;">{self.t_name}:</text>'
753
- else:
754
- out += '<g transform="translate(380, -15)">'
755
- out += f'<text text-anchor="end" style="fill:{self.chart_colors_settings["paper_0"]}; font-size: 14px;">{self.language_settings["planets_and_house"]} {self.t_user.name}:</text>'
756
-
757
- out += end_of_line
758
-
759
- t_li = 10
760
- t_offset = 250
761
-
762
- for i in range(len(self.available_planets_setting)):
763
- if i == 27:
764
- t_li = 10
765
- t_offset = -120
766
-
767
- # start of line
768
- out += f'<g transform="translate({t_offset},{t_li})">'
769
-
770
- # planet text
771
- out += f'<text text-anchor="end" style="fill:{self.chart_colors_settings["paper_0"]}; font-size: 10px;">{self.language_settings["celestial_points"][self.available_planets_setting[i]["label"]]}</text>'
772
- # planet symbol
773
- out += f'<g transform="translate(5,-8)"><use transform="scale(0.4)" xlink:href="#{self.available_planets_setting[i]["name"]}" /></g>'
774
- # planet degree
775
- out += f'<text text-anchor="start" x="19" style="fill:{self.chart_colors_settings["paper_0"]}; font-size: 10px;">{convert_decimal_to_degree_string(self.t_points_deg[i])}</text>'
776
- # zodiac
777
- out += f'<g transform="translate(60,-8)"><use transform="scale(0.3)" xlink:href="#{self.zodiac[self.t_points_sign[i]]["name"]}" /></g>'
778
-
779
- # planet retrograde
780
- if self.t_points_retrograde[i]:
781
- out += '<g transform="translate(74,-6)"><use transform="scale(.5)" xlink:href="#retrograde" /></g>'
782
-
783
- # end of line
784
- out += end_of_line
785
-
786
- t_li = t_li + offset_between_lines
787
-
788
- if end_of_line is None:
789
- raise KerykeionException("End of line not found")
790
-
791
- out += end_of_line
792
344
  return out
793
345
 
794
- def _makeHouseGrid(self):
346
+ def _create_template_dictionary(self) -> ChartTemplateDictionary:
795
347
  """
796
- Generate SVG code for a grid of astrological houses.
348
+ Create a dictionary containing the template data for generating an astrological chart.
797
349
 
798
350
  Returns:
799
- str: The SVG code for the grid of houses.
351
+ ChartTemplateDictionary: A dictionary with template data for the chart.
800
352
  """
801
- out = '<g transform="translate(610,-20)">'
353
+ # Initialize template dictionary
354
+ template_dict: ChartTemplateDictionary = dict() # type: ignore
802
355
 
803
- li = 10
804
- for i in range(12):
805
- if i < 9:
806
- cusp = "&#160;&#160;" + str(i + 1)
807
- else:
808
- cusp = str(i + 1)
809
- out += f'<g transform="translate(0,{li})">'
810
- out += f'<text text-anchor="end" x="40" style="fill:{self.chart_colors_settings["paper_0"]}; font-size: 10px;">{self.language_settings["cusp"]} {cusp}:</text>'
811
- out += f'<g transform="translate(40,-8)"><use transform="scale(0.3)" xlink:href="#{self.zodiac[self.houses_sign_graph[i]]["name"]}" /></g>'
812
- out += f'<text x="53" style="fill:{self.chart_colors_settings["paper_0"]}; font-size: 10px;"> {convert_decimal_to_degree_string(self.user.houses_list[i]["position"])}</text>'
813
- out += "</g>"
814
- li = li + 14
356
+ # Set the color style tag
357
+ template_dict["color_style_tag"] = self.color_style_tag
815
358
 
816
- out += "</g>"
359
+ # Set chart dimensions
360
+ template_dict["chart_height"] = self.height
361
+ template_dict["chart_width"] = self.width
817
362
 
818
- if self.chart_type == "Synastry":
819
- out += '<!-- Synastry Houses -->'
820
- out += '<g transform="translate(850, -20)">'
821
- li = 10
822
-
823
- for i in range(12):
824
- if i < 9:
825
- cusp = "&#160;&#160;" + str(i + 1)
826
- else:
827
- cusp = str(i + 1)
828
- out += '<g transform="translate(0,' + str(li) + ')">'
829
- out += f'<text text-anchor="end" x="40" style="fill:{self.chart_colors_settings["paper_0"]}; font-size: 10px;">{self.language_settings["cusp"]} {cusp}:</text>'
830
- out += f'<g transform="translate(40,-8)"><use transform="scale(0.3)" xlink:href="#{self.zodiac[self.t_houses_sign_graph[i]]["name"]}" /></g>'
831
- out += f'<text x="53" style="fill:{self.chart_colors_settings["paper_0"]}; font-size: 10px;"> {convert_decimal_to_degree_string(self.t_user.houses_list[i]["position"])}</text>'
832
- out += "</g>"
833
- li = li + 14
834
- out += "</g>"
363
+ # Set chart name
364
+ template_dict["stringName"] = f"{self.user.name}:" if self.chart_type in ["Synastry", "Transit"] else f'{self.language_settings["info"]}:'
835
365
 
836
- return out
366
+ # Set viewbox based on chart type
367
+ template_dict['viewbox'] = self._BASIC_CHART_VIEWBOX if self.chart_type in ["Natal", "ExternalNatal"] else self._WIDE_CHART_VIEWBOX
837
368
 
838
- def _createTemplateDictionary(self) -> ChartTemplateDictionary:
839
- # self.chart_type = "Transit"
840
- # empty element points
841
- self.fire = 0.0
842
- self.earth = 0.0
843
- self.air = 0.0
844
- self.water = 0.0
845
-
846
- # Calculate the elements points
847
- self._calculate_elements_points_from_planets()
848
-
849
- rotate = "0"
850
-
851
- # template dictionary
852
- td: ChartTemplateDictionary = dict() # type: ignore
853
- r = 240
854
-
855
- # To increase the size of the chart, change the viewbox
856
- if self.chart_type == "Natal" or self.chart_type == "ExternalNatal":
857
- td['viewbox'] = self.chart_settings["basic_chart_viewBox"]
858
- else:
859
- td['viewbox'] = self.chart_settings["wide_chart_viewBox"]
860
-
861
- if self.chart_type == "ExternalNatal":
862
- self.c1 = 56
863
- self.c2 = 92
864
- self.c3 = 112
865
- else:
866
- self.c1 = 0
867
- self.c2 = 36
868
- self.c3 = 120
369
+ # Generate rings and circles based on chart type
370
+ if self.chart_type in ["Transit", "Synastry"]:
371
+ template_dict["transitRing"] = draw_transit_ring(self.main_radius, self.chart_colors_settings["paper_1"], self.chart_colors_settings["zodiac_transit_ring_3"])
372
+ template_dict["degreeRing"] = draw_transit_ring_degree_steps(self.main_radius, self.user.seventh_house.abs_pos)
373
+ template_dict["first_circle"] = draw_first_circle(self.main_radius, self.chart_colors_settings["zodiac_transit_ring_2"], self.chart_type)
374
+ template_dict["second_circle"] = draw_second_circle(self.main_radius, self.chart_colors_settings['zodiac_transit_ring_1'], self.chart_colors_settings['paper_1'], self.chart_type)
375
+ template_dict['third_circle'] = draw_third_circle(self.main_radius, self.chart_colors_settings['zodiac_transit_ring_0'], self.chart_colors_settings['paper_1'], self.chart_type, self.third_circle_radius)
869
376
 
870
- # transit
871
- if self.chart_type == "Transit" or self.chart_type == "Synastry":
872
- td["transitRing"] = draw_transit_ring(r, self.chart_colors_settings["paper_1"], self.chart_colors_settings["zodiac_transit_ring_3"])
873
- td["degreeRing"] = draw_transit_ring_degree_steps(r, self.user.seventh_house.abs_pos)
874
-
875
- # circles
876
- td["first_circle"] = draw_first_circle(r, self.chart_colors_settings["zodiac_transit_ring_2"], self.chart_type)
877
- td["second_circle"] = draw_second_circle(r, self.chart_colors_settings['zodiac_transit_ring_1'], self.chart_colors_settings['paper_1'], self.chart_type)
878
- td['third_circle'] = draw_third_circle(r, self.chart_colors_settings['zodiac_transit_ring_0'], self.chart_colors_settings['paper_1'], self.chart_type)
879
-
880
- td["makeAspects"] = self._draw_all_transit_aspects_lines(r, (r - 160))
881
-
882
- td["makeAspectGrid"] = draw_aspect_transit_grid(
883
- self.language_settings["aspects"],
884
- self.aspects_list,
885
- self.planets_settings,
886
- self.aspects_settings
887
- )
377
+ if self.double_chart_aspect_grid_type == "list":
378
+ template_dict["makeAspectGrid"] = draw_transit_aspect_list(self.language_settings["aspects"], self.aspects_list, self.planets_settings, self.aspects_settings)
379
+ else:
380
+ template_dict["makeAspectGrid"] = draw_transit_aspect_grid(self.chart_colors_settings['paper_0'], self.available_planets_setting, self.aspects_list, 550, 450)
888
381
 
889
- # Natal, External Natal
382
+ template_dict["makeAspects"] = self._draw_all_transit_aspects_lines(self.main_radius, self.main_radius - 160)
890
383
  else:
891
- td["transitRing"] = ""
892
- td["degreeRing"] = draw_degree_ring(r, self.c1, self.user.seventh_house.abs_pos, self.chart_colors_settings["paper_0"])
384
+ template_dict["transitRing"] = ""
385
+ template_dict["degreeRing"] = draw_degree_ring(self.main_radius, self.first_circle_radius, self.user.seventh_house.abs_pos, self.chart_colors_settings["paper_0"])
386
+ template_dict['first_circle'] = draw_first_circle(self.main_radius, self.chart_colors_settings["zodiac_radix_ring_2"], self.chart_type, self.first_circle_radius)
387
+ template_dict["second_circle"] = draw_second_circle(self.main_radius, self.chart_colors_settings["zodiac_radix_ring_1"], self.chart_colors_settings["paper_1"], self.chart_type, self.second_circle_radius)
388
+ template_dict['third_circle'] = draw_third_circle(self.main_radius, self.chart_colors_settings["zodiac_radix_ring_0"], self.chart_colors_settings["paper_1"], self.chart_type, self.third_circle_radius)
389
+ template_dict["makeAspectGrid"] = draw_aspect_grid(self.chart_colors_settings['paper_0'], self.available_planets_setting, self.aspects_list)
893
390
 
894
- td['first_circle'] = draw_first_circle(r, self.chart_colors_settings["zodiac_radix_ring_2"], self.chart_type, self.c1)
895
- td["second_circle"] = draw_second_circle(r, self.chart_colors_settings["zodiac_radix_ring_1"], self.chart_colors_settings["paper_1"], self.chart_type, self.c2)
896
- td['third_circle'] = draw_third_circle(r, self.chart_colors_settings["zodiac_radix_ring_0"], self.chart_colors_settings["paper_1"], self.chart_type, self.c3)
897
-
898
- td["makeAspects"] = self._draw_all_aspects_lines(r, (r - self.c3))
899
- td["makeAspectGrid"] = draw_aspect_grid(self.chart_colors_settings['paper_0'], self.available_planets_setting, self.aspects_list)
900
-
901
- td["chart_height"] = self.height
902
- td["chart_width"] = self.width
391
+ template_dict["makeAspects"] = self._draw_all_aspects_lines(self.main_radius, self.main_radius - self.third_circle_radius)
903
392
 
904
- # Chart Title
393
+ # Set chart title
905
394
  if self.chart_type == "Synastry":
906
- td["stringTitle"] = f"{self.user.name} {self.language_settings['and_word']} {self.t_user.name}"
907
-
395
+ template_dict["stringTitle"] = f"{self.user.name} {self.language_settings['and_word']} {self.t_user.name}"
908
396
  elif self.chart_type == "Transit":
909
- td["stringTitle"] = f"{self.language_settings['transits']} {self.t_user.day}/{self.t_user.month}/{self.t_user.year}"
910
-
397
+ template_dict["stringTitle"] = f"{self.language_settings['transits']} {self.t_user.day}/{self.t_user.month}/{self.t_user.year}"
911
398
  else:
912
- td["stringTitle"] = self.user.name
913
-
914
- # Chart Name
915
- if self.chart_type == "Synastry" or self.chart_type == "Transit":
916
- td["stringName"] = f"{self.user.name}:"
399
+ template_dict["stringTitle"] = self.user.name
400
+
401
+ # Set bottom left corner information
402
+ template_dict["bottomLeft0"] = f"{self.user.zodiac_type if self.user.zodiac_type == 'Tropic' else str(self.user.zodiac_type) + ' ' + str(self.user.sidereal_mode)}"
403
+ template_dict["bottomLeft1"] = f"{self.user.houses_system_name}"
404
+ if self.chart_type in ["Natal", "ExternalNatal", "Synastry"]:
405
+ template_dict["bottomLeft2"] = f'{self.language_settings.get("lunar_phase", "Lunar Phase")}: {self.language_settings.get("day", "Day")} {self.user.lunar_phase.get("moon_phase", "")}'
406
+ template_dict["bottomLeft3"] = f'{self.language_settings.get("lunar_phase", "Lunar Phase")}: {self.user.lunar_phase.moon_phase_name}'
407
+ template_dict["bottomLeft4"] = f'{self.user.perspective_type}'
917
408
  else:
918
- td["stringName"] = f'{self.language_settings["info"]}:'
409
+ template_dict["bottomLeft2"] = f'{self.language_settings.get("lunar_phase", "Lunar Phase")}: {self.language_settings.get("day", "Day")} {self.t_user.lunar_phase.get("moon_phase", "")}'
410
+ template_dict["bottomLeft3"] = f'{self.language_settings.get("lunar_phase", "Lunar Phase")}: {self.t_user.lunar_phase.moon_phase_name}'
411
+ template_dict["bottomLeft4"] = f'{self.t_user.perspective_type}'
919
412
 
920
- # Bottom Left Corner
921
- if self.chart_type == "Natal" or self.chart_type == "ExternalNatal" or self.chart_type == "Synastry":
922
- td["bottomLeft0"] = f"{self.user.zodiac_type if self.user.zodiac_type == 'Tropic' else self.user.zodiac_type + ' ' + self.user.sidereal_mode}"
923
- td["bottomLeft1"] = f"{self.user.houses_system_name}"
924
- td["bottomLeft2"] = f'{self.language_settings.get("lunar_phase", "Lunar Phase")}: {self.language_settings.get("day", "Day")} {self.user.lunar_phase.get("moon_phase", "")}'
925
- td["bottomLeft3"] = f'{self.language_settings.get("lunar_phase", "Lunar Phase")}: {self.user.lunar_phase.moon_phase_name}'
926
- td["bottomLeft4"] = f'{self.user.perspective_type}'
927
-
928
- else:
929
- td["bottomLeft0"] = f"{self.user.zodiac_type if self.user.zodiac_type == 'Tropic' else self.user.zodiac_type + ' ' + self.user.sidereal_mode}"
930
- td["bottomLeft1"] = f"{self.user.houses_system_name}"
931
- 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", "")}'
932
- td["bottomLeft3"] = f'{self.language_settings.get("lunar_phase", "Lunar Phase")}: {self.t_user.lunar_phase.moon_phase_name}'
933
- td["bottomLeft4"] = f'{self.t_user.perspective_type}'
934
-
935
- td['moon_phase'] = draw_moon_phase(
936
- self.user.lunar_phase["degrees_between_s_m"],
413
+ # Draw moon phase
414
+ template_dict['moon_phase'] = draw_moon_phase(
415
+ self.user.lunar_phase["degrees_between_s_m"],
937
416
  self.geolat
938
417
  )
939
-
940
- # stringlocation
418
+
419
+ # Set location string
941
420
  if len(self.location) > 35:
942
- split = self.location.split(",")
943
- if len(split) > 1:
944
- td["stringLocation"] = split[0] + ", " + split[-1]
945
- if len(td["stringLocation"]) > 35:
946
- td["stringLocation"] = td["stringLocation"][:35] + "..."
421
+ split_location = self.location.split(",")
422
+ if len(split_location) > 1:
423
+ template_dict["stringLocation"] = split_location[0] + ", " + split_location[-1]
424
+ if len(template_dict["stringLocation"]) > 35:
425
+ template_dict["stringLocation"] = template_dict["stringLocation"][:35] + "..."
947
426
  else:
948
- td["stringLocation"] = self.location[:35] + "..."
427
+ template_dict["stringLocation"] = self.location[:35] + "..."
949
428
  else:
950
- td["stringLocation"] = self.location
429
+ template_dict["stringLocation"] = self.location
951
430
 
431
+ # Set additional information for Synastry chart type
952
432
  if self.chart_type == "Synastry":
953
- td["stringLat"] = f"{self.t_user.name}: "
954
- td["stringLon"] = self.t_user.city
955
- td["stringPosition"] = f"{self.t_user.year}-{self.t_user.month}-{self.t_user.day} {self.t_user.hour:02d}:{self.t_user.minute:02d}"
956
-
433
+ template_dict["stringLat"] = f"{self.t_user.name}: "
434
+ template_dict["stringLon"] = self.t_user.city
435
+ template_dict["stringPosition"] = f"{self.t_user.year}-{self.t_user.month}-{self.t_user.day} {self.t_user.hour:02d}:{self.t_user.minute:02d}"
957
436
  else:
958
- latitude_string = convert_latitude_coordinate_to_string(
959
- self.geolat,
960
- self.language_settings['north'],
961
- self.language_settings['south']
962
- )
963
- longitude_string = convert_longitude_coordinate_to_string(
964
- self.geolon,
965
- self.language_settings['east'],
966
- self.language_settings['west']
967
- )
968
-
969
- td["stringLat"] = f"{self.language_settings['latitude']}: {latitude_string}"
970
- td["stringLon"] = f"{self.language_settings['longitude']}: {longitude_string}"
971
- td["stringPosition"] = f"{self.language_settings['type']}: {self.chart_type}"
972
-
973
- # paper_color_X
974
- td["paper_color_0"] = self.chart_colors_settings["paper_0"]
975
- td["paper_color_1"] = self.chart_colors_settings["paper_1"]
437
+ latitude_string = convert_latitude_coordinate_to_string(self.geolat, self.language_settings['north'], self.language_settings['south'])
438
+ longitude_string = convert_longitude_coordinate_to_string(self.geolon, self.language_settings['east'], self.language_settings['west'])
439
+ template_dict["stringLat"] = f"{self.language_settings['latitude']}: {latitude_string}"
440
+ template_dict["stringLon"] = f"{self.language_settings['longitude']}: {longitude_string}"
441
+ template_dict["stringPosition"] = f"{self.language_settings['type']}: {self.chart_type}"
442
+
443
+ # Set paper colors
444
+ template_dict["paper_color_0"] = self.chart_colors_settings["paper_0"]
445
+ template_dict["paper_color_1"] = self.chart_colors_settings["paper_1"]
446
+
447
+ # Set planet colors
448
+ for planet in self.planets_settings:
449
+ planet_id = planet["id"]
450
+ template_dict[f"planets_color_{planet_id}"] = planet["color"] # type: ignore
451
+
452
+ # Set zodiac colors
453
+ for i in range(12):
454
+ template_dict[f"zodiac_color_{i}"] = self.chart_colors_settings[f"zodiac_icon_{i}"] # type: ignore
976
455
 
977
- # planets_color_X
978
- for i in range(len(self.planets_settings)):
979
- planet_id = self.planets_settings[i]["id"]
980
- td[f"planets_color_{planet_id}"] = self.planets_settings[i]["color"]
456
+ # Set orb colors
457
+ for aspect in self.aspects_settings:
458
+ template_dict[f"orb_color_{aspect['degree']}"] = aspect['color'] # type: ignore
981
459
 
982
- # zodiac_color_X
983
- for i in range(12):
984
- td[f"zodiac_color_{i}"] = self.chart_colors_settings[f"zodiac_icon_{i}"]
460
+ # Drawing functions
461
+ template_dict["makeZodiac"] = self._draw_zodiac_circle_slices(self.main_radius)
985
462
 
986
- # orb_color_X
987
- for i in range(len(self.aspects_settings)):
988
- td[f"orb_color_{self.aspects_settings[i]['degree']}"] = self.aspects_settings[i]['color']
463
+ first_subject_houses_list = get_houses_list(self.user)
989
464
 
990
- # config
991
- td["cfgRotate"] = rotate
465
+ # Draw houses grid and cusps
466
+ if self.chart_type in ["Transit", "Synastry"]:
467
+ second_subject_houses_list = get_houses_list(self.t_user)
992
468
 
993
- # ---
994
- # Drawing Functions
995
- #---
469
+ template_dict["makeHousesGrid"] = draw_house_grid(
470
+ main_subject_houses_list=first_subject_houses_list,
471
+ secondary_subject_houses_list=second_subject_houses_list,
472
+ chart_type=self.chart_type,
473
+ text_color=self.chart_colors_settings["paper_0"],
474
+ house_cusp_generale_name_label=self.language_settings["cusp"]
475
+ )
996
476
 
997
- td["makeZodiac"] = self._draw_zodiac_circle_slices(r)
998
- td["makeHousesGrid"] = self._makeHouseGrid()
999
-
1000
- # Houses Cusps and Number
1001
- if self.chart_type == "Transit" or self.chart_type == "Synastry":
1002
- td["makeHouses"] = draw_houses_cusps_and_text_number(
1003
- r=r,
1004
- first_subject_houses_list_ut=self.user.houses_degree_ut,
477
+ template_dict["makeHouses"] = draw_houses_cusps_and_text_number(
478
+ r=self.main_radius,
479
+ first_subject_houses_list=first_subject_houses_list,
1005
480
  standard_house_cusp_color=self.chart_colors_settings["houses_radix_line"],
1006
481
  first_house_color=self.planets_settings[12]["color"],
1007
482
  tenth_house_color=self.planets_settings[13]["color"],
1008
483
  seventh_house_color=self.planets_settings[14]["color"],
1009
484
  fourth_house_color=self.planets_settings[15]["color"],
1010
- c1=self.c1,
1011
- c3=self.c3,
485
+ c1=self.first_circle_radius,
486
+ c3=self.third_circle_radius,
1012
487
  chart_type=self.chart_type,
1013
- second_subject_houses_list_ut=self.t_user.houses_degree_ut,
488
+ second_subject_houses_list=second_subject_houses_list,
1014
489
  transit_house_cusp_color=self.chart_colors_settings["houses_transit_line"],
1015
490
  )
491
+
1016
492
  else:
1017
- td["makeHouses"] = draw_houses_cusps_and_text_number(
1018
- r=r,
1019
- first_subject_houses_list_ut=self.user.houses_degree_ut,
493
+ template_dict["makeHousesGrid"] = draw_house_grid(
494
+ main_subject_houses_list=first_subject_houses_list,
495
+ chart_type=self.chart_type,
496
+ text_color=self.chart_colors_settings["paper_0"],
497
+ house_cusp_generale_name_label=self.language_settings["cusp"]
498
+ )
499
+
500
+ template_dict["makeHouses"] = draw_houses_cusps_and_text_number(
501
+ r=self.main_radius,
502
+ first_subject_houses_list=first_subject_houses_list,
1020
503
  standard_house_cusp_color=self.chart_colors_settings["houses_radix_line"],
1021
504
  first_house_color=self.planets_settings[12]["color"],
1022
505
  tenth_house_color=self.planets_settings[13]["color"],
1023
506
  seventh_house_color=self.planets_settings[14]["color"],
1024
507
  fourth_house_color=self.planets_settings[15]["color"],
1025
- c1=self.c1,
1026
- c3=self.c3,
508
+ c1=self.first_circle_radius,
509
+ c3=self.third_circle_radius,
1027
510
  chart_type=self.chart_type,
1028
511
  )
1029
512
 
1030
- td["makePlanets"] = self._make_planets(r)
1031
- td["elements_percentages"] = draw_elements_percentages(
513
+ # Draw planets
514
+ if self.chart_type in ["Transit", "Synastry"]:
515
+ template_dict["makePlanets"] = draw_planets(
516
+ available_kerykeion_celestial_points=self.available_kerykeion_celestial_points,
517
+ available_planets_setting=self.available_planets_setting,
518
+ second_subject_available_kerykeion_celestial_points=self.t_available_kerykeion_celestial_points,
519
+ radius=self.main_radius,
520
+ main_subject_first_house_degree_ut=self.user.first_house.abs_pos,
521
+ main_subject_seventh_house_degree_ut=self.user.seventh_house.abs_pos,
522
+ chart_type=self.chart_type,
523
+ third_circle_radius=self.third_circle_radius,
524
+ )
525
+ else:
526
+ template_dict["makePlanets"] = draw_planets(
527
+ available_planets_setting=self.available_planets_setting,
528
+ chart_type=self.chart_type,
529
+ radius=self.main_radius,
530
+ available_kerykeion_celestial_points=self.available_kerykeion_celestial_points,
531
+ third_circle_radius=self.third_circle_radius,
532
+ main_subject_first_house_degree_ut=self.user.first_house.abs_pos,
533
+ main_subject_seventh_house_degree_ut=self.user.seventh_house.abs_pos
534
+ )
535
+
536
+ # Draw elements percentages
537
+ template_dict["elements_percentages"] = draw_elements_percentages(
1032
538
  self.language_settings['fire'],
1033
539
  self.fire,
1034
540
  self.language_settings['earth'],
@@ -1039,29 +545,56 @@ class KerykeionChartSVG:
1039
545
  self.water,
1040
546
  )
1041
547
 
1042
- td["makePlanetGrid"] = self._makePlanetGrid()
548
+ # Draw planet grid
549
+ if self.chart_type in ["Transit", "Synastry"]:
550
+ if self.chart_type == "Transit":
551
+ second_subject_table_name = self.language_settings["transit_name"]
552
+ else:
553
+ second_subject_table_name = self.t_user.name
554
+ template_dict["makePlanetGrid"] = draw_planet_grid(
555
+ planets_and_houses_grid_title=self.language_settings["planets_and_house"],
556
+ subject_name=self.user.name,
557
+ available_kerykeion_celestial_points=self.available_kerykeion_celestial_points,
558
+ chart_type=self.chart_type,
559
+ text_color=self.chart_colors_settings["paper_0"],
560
+ celestial_point_language=self.language_settings["celestial_points"],
561
+ second_subject_name=second_subject_table_name,
562
+ second_subject_available_kerykeion_celestial_points=self.t_available_kerykeion_celestial_points,
563
+ )
564
+ else:
565
+ template_dict["makePlanetGrid"] = draw_planet_grid(
566
+ planets_and_houses_grid_title=self.language_settings["planets_and_house"],
567
+ subject_name=self.user.name,
568
+ available_kerykeion_celestial_points=self.available_kerykeion_celestial_points,
569
+ chart_type=self.chart_type,
570
+ text_color=self.chart_colors_settings["paper_0"],
571
+ celestial_point_language=self.language_settings["celestial_points"],
572
+ )
1043
573
 
1044
- # Date time String
574
+ # Set date time string
1045
575
  dt = datetime.fromisoformat(self.user.iso_formatted_local_datetime)
1046
- custom_format = dt.strftime('%Y-%-m-%-d %H:%M [%z]') # Note the use of '-' to remove leading zeros
576
+ custom_format = dt.strftime('%Y-%m-%d %H:%M [%z]')
1047
577
  custom_format = custom_format[:-3] + ':' + custom_format[-3:]
1048
- td["stringDateTime"] = f"{custom_format}"
578
+ template_dict["stringDateTime"] = f"{custom_format}"
1049
579
 
1050
- return td
580
+ return template_dict
1051
581
 
1052
582
  def makeTemplate(self, minify: bool = False) -> str:
1053
583
  """Creates the template for the SVG file"""
1054
- td = self._createTemplateDictionary()
584
+ td = self._create_template_dictionary()
1055
585
 
586
+ DATA_DIR = Path(__file__).parent
587
+ xml_svg = DATA_DIR / "templates" / "chart.xml"
588
+
1056
589
  # read template
1057
- with open(self.xml_svg, "r", encoding="utf-8", errors="ignore") as f:
590
+ with open(xml_svg, "r", encoding="utf-8", errors="ignore") as f:
1058
591
  template = Template(f.read()).substitute(td)
1059
592
 
1060
593
  # return filename
1061
594
 
1062
595
  logging.debug(f"Template dictionary keys: {td.keys()}")
1063
596
 
1064
- self._createTemplateDictionary()
597
+ self._create_template_dictionary()
1065
598
 
1066
599
  if minify:
1067
600
  template = scourString(template).replace('"', "'").replace("\n", "").replace("\t","").replace(" ", "").replace(" ", "")
@@ -1072,9 +605,9 @@ class KerykeionChartSVG:
1072
605
  return template
1073
606
 
1074
607
  def makeSVG(self, minify: bool = False):
1075
- """Prints out the SVG file in the specifide folder"""
608
+ """Prints out the SVG file in the specified folder"""
1076
609
 
1077
- if not (self.template):
610
+ if not hasattr(self, "template"):
1078
611
  self.template = self.makeTemplate(minify)
1079
612
 
1080
613
  self.chartname = self.output_directory / f"{self.user.name} - {self.chart_type} Chart.svg"
@@ -1084,6 +617,70 @@ class KerykeionChartSVG:
1084
617
 
1085
618
  logging.info(f"SVG Generated Correctly in: {self.chartname}")
1086
619
 
620
+ def makeWheelOnlyTemplate(self, minify: bool = False):
621
+ """Creates the template for the SVG file with only the wheel"""
622
+
623
+ with open(Path(__file__).parent / "templates" / "wheel_only.xml", "r", encoding="utf-8", errors="ignore") as f:
624
+ template = f.read()
625
+
626
+ template_dict = self._create_template_dictionary()
627
+ template = Template(template).substitute(template_dict)
628
+
629
+ if minify:
630
+ template = scourString(template).replace('"', "'").replace("\n", "").replace("\t","").replace(" ", "").replace(" ", "")
631
+
632
+ else:
633
+ template = template.replace('"', "'")
634
+
635
+ return template
636
+
637
+ def makeWheelOnlySVG(self, minify: bool = False):
638
+ """Prints out the SVG file in the specified folder with only the wheel"""
639
+
640
+ template = self.makeWheelOnlyTemplate(minify)
641
+
642
+ self.chartname = self.output_directory / f"{self.user.name} - {self.chart_type} Chart - Wheel Only.svg"
643
+
644
+ with open(self.chartname, "w", encoding="utf-8", errors="ignore") as output_file:
645
+ output_file.write(template)
646
+
647
+ logging.info(f"SVG Generated Correctly in: {self.chartname}")
648
+
649
+ def makeAspectGridOnlyTemplate(self, minify: bool = False):
650
+ """Creates the template for the SVG file with only the aspect grid"""
651
+
652
+ with open(Path(__file__).parent / "templates" / "aspect_grid_only.xml", "r", encoding="utf-8", errors="ignore") as f:
653
+ template = f.read()
654
+
655
+ template_dict = self._create_template_dictionary()
656
+
657
+ if self.chart_type in ["Transit", "Synastry"]:
658
+ aspects_grid = draw_transit_aspect_grid(self.chart_colors_settings['paper_0'], self.available_planets_setting, self.aspects_list)
659
+ else:
660
+ aspects_grid = draw_aspect_grid(self.chart_colors_settings['paper_0'], self.available_planets_setting, self.aspects_list, x_start=50, y_start=250)
661
+
662
+ template = Template(template).substitute({**template_dict, "makeAspectGrid": aspects_grid})
663
+
664
+ if minify:
665
+ template = scourString(template).replace('"', "'").replace("\n", "").replace("\t","").replace(" ", "").replace(" ", "")
666
+
667
+ else:
668
+ template = template.replace('"', "'")
669
+
670
+ return template
671
+
672
+ def makeAspectGridOnlySVG(self, minify: bool = False):
673
+ """Prints out the SVG file in the specified folder with only the aspect grid"""
674
+
675
+ template = self.makeAspectGridOnlyTemplate(minify)
676
+
677
+ self.chartname = self.output_directory / f"{self.user.name} - {self.chart_type} Chart - Aspect Grid Only.svg"
678
+
679
+ with open(self.chartname, "w", encoding="utf-8", errors="ignore") as output_file:
680
+ output_file.write(template)
681
+
682
+ logging.info(f"SVG Generated Correctly in: {self.chartname}")
683
+
1087
684
 
1088
685
  if __name__ == "__main__":
1089
686
  from kerykeion.utilities import setup_logging
@@ -1154,4 +751,139 @@ if __name__ == "__main__":
1154
751
  # With Topocentric Perspective
1155
752
  topocentric_subject = AstrologicalSubject("John Lennon - Topocentric", 1940, 10, 9, 18, 30, "Liverpool", "GB", perspective_type="Topocentric")
1156
753
  topocentric_chart = KerykeionChartSVG(topocentric_subject)
1157
- topocentric_chart.makeSVG()
754
+ topocentric_chart.makeSVG()
755
+
756
+ # Minified SVG
757
+ minified_subject = AstrologicalSubject("John Lennon - Minified", 1940, 10, 9, 18, 30, "Liverpool", "GB")
758
+ minified_chart = KerykeionChartSVG(minified_subject)
759
+ minified_chart.makeSVG(minify=True)
760
+
761
+ # Dark Theme Natal Chart
762
+ dark_theme_subject = AstrologicalSubject("John Lennon - Dark Theme", 1940, 10, 9, 18, 30, "Liverpool", "GB")
763
+ dark_theme_natal_chart = KerykeionChartSVG(dark_theme_subject, theme="dark")
764
+ dark_theme_natal_chart.makeSVG()
765
+
766
+ # Dark High Contrast Theme Natal Chart
767
+ dark_high_contrast_theme_subject = AstrologicalSubject("John Lennon - Dark High Contrast Theme", 1940, 10, 9, 18, 30, "Liverpool", "GB")
768
+ dark_high_contrast_theme_natal_chart = KerykeionChartSVG(dark_high_contrast_theme_subject, theme="dark-high-contrast")
769
+ dark_high_contrast_theme_natal_chart.makeSVG()
770
+
771
+ # Light Theme Natal Chart
772
+ light_theme_subject = AstrologicalSubject("John Lennon - Light Theme", 1940, 10, 9, 18, 30, "Liverpool", "GB")
773
+ light_theme_natal_chart = KerykeionChartSVG(light_theme_subject, theme="light")
774
+ light_theme_natal_chart.makeSVG()
775
+
776
+ # Dark Theme External Natal Chart
777
+ dark_theme_external_subject = AstrologicalSubject("John Lennon - Dark Theme External", 1940, 10, 9, 18, 30, "Liverpool", "GB")
778
+ dark_theme_external_chart = KerykeionChartSVG(dark_theme_external_subject, "ExternalNatal", second, theme="dark")
779
+ dark_theme_external_chart.makeSVG()
780
+
781
+ # Dark Theme Synastry Chart
782
+ dark_theme_synastry_subject = AstrologicalSubject("John Lennon - DTS", 1940, 10, 9, 18, 30, "Liverpool", "GB")
783
+ dark_theme_synastry_chart = KerykeionChartSVG(dark_theme_synastry_subject, "Synastry", second, theme="dark")
784
+ dark_theme_synastry_chart.makeSVG()
785
+
786
+ # Wheel Natal Only Chart
787
+ wheel_only_subject = AstrologicalSubject("John Lennon - Wheel Only", 1940, 10, 9, 18, 30, "Liverpool", "GB")
788
+ wheel_only_chart = KerykeionChartSVG(wheel_only_subject)
789
+ wheel_only_chart.makeWheelOnlySVG()
790
+
791
+ # Wheel External Natal Only Chart
792
+ wheel_external_subject = AstrologicalSubject("John Lennon - Wheel External Only", 1940, 10, 9, 18, 30, "Liverpool", "GB")
793
+ wheel_external_chart = KerykeionChartSVG(wheel_external_subject, "ExternalNatal", second)
794
+ wheel_external_chart.makeWheelOnlySVG()
795
+
796
+ # Wheel Synastry Only Chart
797
+ wheel_synastry_subject = AstrologicalSubject("John Lennon - Wheel Synastry Only", 1940, 10, 9, 18, 30, "Liverpool", "GB")
798
+ wheel_synastry_chart = KerykeionChartSVG(wheel_synastry_subject, "Synastry", second)
799
+ wheel_synastry_chart.makeWheelOnlySVG()
800
+
801
+ # Wheel Transit Only Chart
802
+ wheel_transit_subject = AstrologicalSubject("John Lennon - Wheel Transit Only", 1940, 10, 9, 18, 30, "Liverpool", "GB")
803
+ wheel_transit_chart = KerykeionChartSVG(wheel_transit_subject, "Transit", second)
804
+ wheel_transit_chart.makeWheelOnlySVG()
805
+
806
+ # Wheel Sidereal Birth Chart (Lahiri) Dark Theme
807
+ sidereal_dark_subject = AstrologicalSubject("John Lennon Lahiri - Dark Theme", 1940, 10, 9, 18, 30, "Liverpool", "GB", zodiac_type="Sidereal", sidereal_mode="LAHIRI")
808
+ sidereal_dark_chart = KerykeionChartSVG(sidereal_dark_subject, theme="dark")
809
+ sidereal_dark_chart.makeWheelOnlySVG()
810
+
811
+ # Wheel Sidereal Birth Chart (Fagan-Bradley) Light Theme
812
+ sidereal_light_subject = AstrologicalSubject("John Lennon Fagan-Bradley - Light Theme", 1940, 10, 9, 18, 30, "Liverpool", "GB", zodiac_type="Sidereal", sidereal_mode="FAGAN_BRADLEY")
813
+ sidereal_light_chart = KerykeionChartSVG(sidereal_light_subject, theme="light")
814
+ sidereal_light_chart.makeWheelOnlySVG()
815
+
816
+ # Aspect Grid Only Natal Chart
817
+ aspect_grid_only_subject = AstrologicalSubject("John Lennon - Aspect Grid Only", 1940, 10, 9, 18, 30, "Liverpool", "GB")
818
+ aspect_grid_only_chart = KerykeionChartSVG(aspect_grid_only_subject)
819
+ aspect_grid_only_chart.makeAspectGridOnlySVG()
820
+
821
+ # Aspect Grid Only Dark Theme Natal Chart
822
+ aspect_grid_dark_subject = AstrologicalSubject("John Lennon - Aspect Grid Dark Theme", 1940, 10, 9, 18, 30, "Liverpool", "GB")
823
+ aspect_grid_dark_chart = KerykeionChartSVG(aspect_grid_dark_subject, theme="dark")
824
+ aspect_grid_dark_chart.makeAspectGridOnlySVG()
825
+
826
+ # Aspect Grid Only Light Theme Natal Chart
827
+ aspect_grid_light_subject = AstrologicalSubject("John Lennon - Aspect Grid Light Theme", 1940, 10, 9, 18, 30, "Liverpool", "GB")
828
+ aspect_grid_light_chart = KerykeionChartSVG(aspect_grid_light_subject, theme="light")
829
+ aspect_grid_light_chart.makeAspectGridOnlySVG()
830
+
831
+ # Synastry Chart Aspect Grid Only
832
+ aspect_grid_synastry_subject = AstrologicalSubject("John Lennon - Aspect Grid Synastry", 1940, 10, 9, 18, 30, "Liverpool", "GB")
833
+ aspect_grid_synastry_chart = KerykeionChartSVG(aspect_grid_synastry_subject, "Synastry", second)
834
+ aspect_grid_synastry_chart.makeAspectGridOnlySVG()
835
+
836
+ # Transit Chart Aspect Grid Only
837
+ aspect_grid_transit_subject = AstrologicalSubject("John Lennon - Aspect Grid Transit", 1940, 10, 9, 18, 30, "Liverpool", "GB")
838
+ aspect_grid_transit_chart = KerykeionChartSVG(aspect_grid_transit_subject, "Transit", second)
839
+ aspect_grid_transit_chart.makeAspectGridOnlySVG()
840
+
841
+ # Synastry Chart Aspect Grid Only Dark Theme
842
+ aspect_grid_dark_synastry_subject = AstrologicalSubject("John Lennon - Aspect Grid Dark Synastry", 1940, 10, 9, 18, 30, "Liverpool", "GB")
843
+ aspect_grid_dark_synastry_chart = KerykeionChartSVG(aspect_grid_dark_synastry_subject, "Synastry", second, theme="dark")
844
+ aspect_grid_dark_synastry_chart.makeAspectGridOnlySVG()
845
+
846
+ # Transit Chart With draw_transit_aspect_grid table
847
+ transit_chart_with_table_grid_subject = AstrologicalSubject("John Lennon - TCWTG", 1940, 10, 9, 18, 30, "Liverpool", "GB")
848
+ transit_chart_with_table_grid = KerykeionChartSVG(transit_chart_with_table_grid_subject, "Transit", second, double_chart_aspect_grid_type="table", theme="dark")
849
+ transit_chart_with_table_grid.makeSVG()
850
+
851
+ # Chines Language Chart
852
+ chinese_subject = AstrologicalSubject("Hua Chenyu", 1990, 2, 7, 12, 0, "Hunan", "CN")
853
+ chinese_chart = KerykeionChartSVG(chinese_subject, chart_language="CN")
854
+ chinese_chart.makeSVG()
855
+
856
+ # French Language Chart
857
+ french_subject = AstrologicalSubject("Jeanne Moreau", 1928, 1, 23, 10, 0, "Paris", "FR")
858
+ french_chart = KerykeionChartSVG(french_subject, chart_language="FR")
859
+ french_chart.makeSVG()
860
+
861
+ # Spanish Language Chart
862
+ spanish_subject = AstrologicalSubject("Antonio Banderas", 1960, 8, 10, 12, 0, "Malaga", "ES")
863
+ spanish_chart = KerykeionChartSVG(spanish_subject, chart_language="ES")
864
+ spanish_chart.makeSVG()
865
+
866
+ # Portuguese Language Chart
867
+ portuguese_subject = AstrologicalSubject("Cristiano Ronaldo", 1985, 2, 5, 5, 25, "Funchal", "PT")
868
+ portuguese_chart = KerykeionChartSVG(portuguese_subject, chart_language="PT")
869
+ portuguese_chart.makeSVG()
870
+
871
+ # Italian Language Chart
872
+ italian_subject = AstrologicalSubject("Sophia Loren", 1934, 9, 20, 2, 0, "Rome", "IT")
873
+ italian_chart = KerykeionChartSVG(italian_subject, chart_language="IT")
874
+ italian_chart.makeSVG()
875
+
876
+ # Russian Language Chart
877
+ russian_subject = AstrologicalSubject("Mikhail Bulgakov", 1891, 5, 15, 12, 0, "Kiev", "UA")
878
+ russian_chart = KerykeionChartSVG(russian_subject, chart_language="RU")
879
+ russian_chart.makeSVG()
880
+
881
+ # Turkish Language Chart
882
+ turkish_subject = AstrologicalSubject("Mehmet Oz", 1960, 6, 11, 12, 0, "Istanbul", "TR")
883
+ turkish_chart = KerykeionChartSVG(turkish_subject, chart_language="TR")
884
+ turkish_chart.makeSVG()
885
+
886
+ # German Language Chart
887
+ german_subject = AstrologicalSubject("Albert Einstein", 1879, 3, 14, 11, 30, "Ulm", "DE")
888
+ german_chart = KerykeionChartSVG(german_subject, chart_language="DE")
889
+ german_chart.makeSVG()