kerykeion 4.0.3__py3-none-any.whl → 4.8.1__py3-none-any.whl

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

Potentially problematic release.


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

@@ -1,30 +1,39 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  """
3
- This is part of Kerykeion (C) 2023 Giacomo Battaglia
3
+ This is part of Kerykeion (C) 2024 Giacomo Battaglia
4
4
  """
5
5
 
6
6
 
7
- import pytz
7
+ import logging
8
8
 
9
- from datetime import datetime
10
- from kerykeion.settings.kerykeion_settings import get_settings_dict
9
+ from kerykeion.settings.kerykeion_settings import get_settings
11
10
  from kerykeion.aspects.synastry_aspects import SynastryAspects
12
11
  from kerykeion.aspects.natal_aspects import NatalAspects
13
12
  from kerykeion.astrological_subject import AstrologicalSubject
14
13
  from kerykeion.kr_types import KerykeionException, ChartType
15
- from kerykeion.kr_types.chart_types import ChartTemplateModel
16
- from kerykeion.charts.charts_utils import decHourJoin, degreeDiff, offsetToTz, sliceToX, sliceToY
17
- from logging import getLogger, basicConfig
14
+ from kerykeion.kr_types import ChartTemplateDictionary
15
+ from kerykeion.kr_types.settings_models import KerykeionSettingsCelestialPointModel
16
+ from kerykeion.charts.charts_utils import (
17
+ degreeDiff,
18
+ sliceToX,
19
+ sliceToY,
20
+ draw_zodiac_slice,
21
+ convert_latitude_coordinate_to_string,
22
+ convert_longitude_coordinate_to_string,
23
+ draw_aspect_line,
24
+ draw_elements_percentages,
25
+ convert_decimal_to_degree_string,
26
+ draw_transit_ring_degree_steps,
27
+ draw_degree_ring,
28
+ draw_transit_ring,
29
+ draw_first_circle,
30
+ draw_second_circle
31
+ )
18
32
  from pathlib import Path
33
+ from scour.scour import scourString
19
34
  from string import Template
20
- from typing import Union
21
-
35
+ from typing import Union, List
22
36
 
23
- logger = getLogger(__name__)
24
- basicConfig(
25
- format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
26
- level="INFO"
27
- )
28
37
 
29
38
 
30
39
  class KerykeionChartSVG:
@@ -40,7 +49,13 @@ class KerykeionChartSVG:
40
49
  - lang: language settings (default: "EN")
41
50
  - new_settings_file: Set the settings file (default: kr.config.json)
42
51
  """
52
+
53
+ # Constants
54
+ _DEFAULT_HEIGHT = 546.0
55
+ _DEFAULT_FULL_WIDTH = 1200
56
+ _DEFAULT_NATAL_WIDTH = 772.2
43
57
 
58
+ # Set at init
44
59
  first_obj: AstrologicalSubject
45
60
  second_obj: Union[AstrologicalSubject, None]
46
61
  chart_type: ChartType
@@ -48,6 +63,44 @@ class KerykeionChartSVG:
48
63
  new_settings_file: Union[Path, None]
49
64
  output_directory: Path
50
65
 
66
+ # Internal properties
67
+ fire: float
68
+ earth: float
69
+ air: float
70
+ water: float
71
+ c1: float
72
+ c2: float
73
+ c3: float
74
+ homedir: Path
75
+ xml_svg: Path
76
+ width: Union[float, int]
77
+ language_settings: dict
78
+ chart_colors_settings: dict
79
+ planets_settings: dict
80
+ aspects_settings: dict
81
+ planet_in_zodiac_extra_points: int
82
+ chart_settings: dict
83
+ user: AstrologicalSubject
84
+ available_planets_setting: List[KerykeionSettingsCelestialPointModel]
85
+ transit_ring_exclude_points_names: List[str]
86
+ points_deg_ut: list
87
+ points_deg: list
88
+ points_sign: list
89
+ points_retrograde: list
90
+ houses_sign_graph: list
91
+ t_points_deg_ut: list
92
+ t_points_deg: list
93
+ t_points_sign: list
94
+ t_points_retrograde: list
95
+ t_houses_sign_graph: list
96
+ height: float
97
+ location: str
98
+ geolat: float
99
+ geolon: float
100
+ zoom: int
101
+ zodiac: tuple
102
+ template: str
103
+
51
104
  def __init__(
52
105
  self,
53
106
  first_obj: AstrologicalSubject,
@@ -68,56 +121,59 @@ class KerykeionChartSVG:
68
121
 
69
122
  self.xml_svg = DATA_DIR / "templates/chart.xml"
70
123
 
71
- # SVG Width
72
- self.natal_width = 772.2
73
- self.full_width = 1200
74
-
75
124
  self.parse_json_settings(new_settings_file)
76
125
  self.chart_type = chart_type
77
126
 
78
127
  # Kerykeion instance
79
128
  self.user = first_obj
80
129
 
81
- # Make a list for the absolute degrees of the points of the graphic.
82
- self.points_deg_ut = self.user.planets_degrees_ut + [
83
- self.user.houses_degree_ut[0],
84
- self.user.houses_degree_ut[9],
85
- self.user.houses_degree_ut[6],
86
- self.user.houses_degree_ut[3],
130
+ self.available_planets_setting = []
131
+ for body in self.planets_settings:
132
+ if body['is_active'] == False:
133
+ continue
134
+
135
+ self.available_planets_setting.append(body)
136
+
137
+ # House cusp points are excluded from the transit ring.
138
+ self.transit_ring_exclude_points_names = [
139
+ "First_House",
140
+ "Second_House",
141
+ "Third_House",
142
+ "Fourth_House",
143
+ "Fifth_House",
144
+ "Sixth_House",
145
+ "Seventh_House",
146
+ "Eighth_House",
147
+ "Ninth_House",
148
+ "Tenth_House",
149
+ "Eleventh_House",
150
+ "Twelfth_House"
87
151
  ]
88
152
 
153
+ # Available bodies
154
+ available_celestial_points = []
155
+ for body in self.available_planets_setting:
156
+ available_celestial_points.append(body["name"].lower())
157
+
158
+ # Make a list for the absolute degrees of the points of the graphic.
159
+ self.points_deg_ut = []
160
+ for planet in available_celestial_points:
161
+ self.points_deg_ut.append(self.user.get(planet).abs_pos)
162
+
89
163
  # Make a list of the relative degrees of the points in the graphic.
90
164
  self.points_deg = []
91
- for planet in self.user.planets_list:
92
- self.points_deg.append(planet["position"])
93
-
94
- self.points_deg = self.points_deg + [
95
- self.user.houses_list[0]["position"],
96
- self.user.houses_list[9]["position"],
97
- self.user.houses_list[6]["position"],
98
- self.user.houses_list[3]["position"],
99
- ]
165
+ for planet in available_celestial_points:
166
+ self.points_deg.append(self.user.get(planet).position)
100
167
 
101
168
  # Make list of the points sign
102
169
  self.points_sign = []
103
-
104
- for planet in self.user.planets_list:
105
- self.points_sign.append(planet["sign_num"])
106
-
107
- self.points_sign = self.points_sign + [
108
- self.user.houses_list[0]["sign_num"],
109
- self.user.houses_list[9]["sign_num"],
110
- self.user.houses_list[6]["sign_num"],
111
- self.user.houses_list[3]["sign_num"],
112
- ]
170
+ for planet in available_celestial_points:
171
+ self.points_sign.append(self.user.get(planet).sign_num)
113
172
 
114
173
  # Make a list of points if they are retrograde or not.
115
174
  self.points_retrograde = []
116
-
117
- for planet in self.user.planets_list:
118
- self.points_retrograde.append(planet["retrograde"])
119
-
120
- self.points_retrograde = self.points_retrograde + [False, False, False, False]
175
+ for planet in available_celestial_points:
176
+ self.points_retrograde.append(self.user.get(planet).retrograde)
121
177
 
122
178
  # Makes the sign number list.
123
179
 
@@ -127,7 +183,7 @@ class KerykeionChartSVG:
127
183
 
128
184
  if self.chart_type == "Natal" or self.chart_type == "ExternalNatal":
129
185
  natal_aspects_instance = NatalAspects(self.user, new_settings_file=self.new_settings_file)
130
- self.aspects_list = natal_aspects_instance.get_relevant_aspects()
186
+ self.aspects_list = natal_aspects_instance.relevant_aspects
131
187
 
132
188
  # TODO: If not second should exit
133
189
  if self.chart_type == "Transit" or self.chart_type == "Synastry":
@@ -138,112 +194,46 @@ class KerykeionChartSVG:
138
194
  self.t_user = second_obj
139
195
 
140
196
  # Make a list for the absolute degrees of the points of the graphic.
141
-
142
- self.t_points_deg_ut = self.t_user.planets_degrees_ut + [
143
- self.t_user.houses_degree_ut[0],
144
- self.t_user.houses_degree_ut[9],
145
- self.t_user.houses_degree_ut[6],
146
- self.t_user.houses_degree_ut[3],
147
- ]
197
+ self.t_points_deg_ut = []
198
+ for planet in available_celestial_points:
199
+ self.t_points_deg_ut.append(self.t_user.get(planet).abs_pos)
148
200
 
149
201
  # Make a list of the relative degrees of the points in the graphic.
150
-
151
202
  self.t_points_deg = []
152
- for planet in self.t_user.planets_list:
153
- self.t_points_deg.append(planet["position"])
154
-
155
- self.t_points_deg = self.t_points_deg + [
156
- self.t_user.houses_list[0]["position"],
157
- self.t_user.houses_list[9]["position"],
158
- self.t_user.houses_list[6]["position"],
159
- self.t_user.houses_list[3]["position"],
160
- ]
203
+ for planet in available_celestial_points:
204
+ self.t_points_deg.append(self.t_user.get(planet).position)
161
205
 
162
206
  # Make list of the poits sign.
163
-
164
207
  self.t_points_sign = []
165
-
166
- for planet in self.t_user.planets_list:
167
- self.t_points_sign.append(planet["sign_num"])
168
-
169
- self.t_points_sign = self.t_points_sign + [
170
- self.t_user.houses_list[0]["sign_num"],
171
- self.t_user.houses_list[9]["sign_num"],
172
- self.t_user.houses_list[6]["sign_num"],
173
- self.t_user.houses_list[3]["sign_num"],
174
- ]
208
+ for planet in available_celestial_points:
209
+ self.t_points_sign.append(self.t_user.get(planet).sign_num)
175
210
 
176
211
  # Make a list of poits if they are retrograde or not.
177
-
178
212
  self.t_points_retrograde = []
179
-
180
- for planet in self.t_user.planets_list:
181
- self.t_points_retrograde.append(planet["retrograde"])
182
-
183
- self.t_points_retrograde = self.t_points_retrograde + [False, False, False, False]
213
+ for planet in available_celestial_points:
214
+ self.t_points_retrograde.append(self.t_user.get(planet).retrograde)
184
215
 
185
216
  self.t_houses_sign_graph = []
186
217
  for h in self.t_user.houses_list:
187
218
  self.t_houses_sign_graph.append(h["sign_num"])
188
219
 
189
220
  # screen size
190
- if self.chart_type == "Natal":
191
- self.screen_width = 772.2
221
+
222
+ self.height = self._DEFAULT_HEIGHT
223
+ if self.chart_type == "Synastry" or self.chart_type == "Transit":
224
+ self.width = self._DEFAULT_FULL_WIDTH
192
225
  else:
193
- self.screen_width = 1200
194
- self.screen_height = 772.2
195
-
196
- # check for home
197
- self.home_location = self.user.city
198
- self.home_geolat = self.user.lat
199
- self.home_geolon = self.user.lng
200
- self.home_countrycode = self.user.nation
201
- self.home_timezonestr = self.user.tz_str
202
-
203
- print(f"{self.user.name} birth location: {self.home_location}, {self.home_geolat}, {self.home_geolon}")
226
+ self.width = self._DEFAULT_NATAL_WIDTH
204
227
 
205
228
  # default location
206
- self.location = self.home_location
207
- self.geolat = float(self.home_geolat)
208
- self.geolon = float(self.home_geolon)
209
- self.countrycode = self.home_countrycode
210
- self.timezonestr = self.home_timezonestr
211
-
212
- # current datetime
213
- now = datetime.now()
214
-
215
- # aware datetime object
216
- dt_input = datetime(now.year, now.month, now.day, now.hour, now.minute, now.second)
217
- dt = pytz.timezone(self.timezonestr).localize(dt_input)
218
-
219
- # naive utc datetime object
220
- dt_utc = dt.replace(tzinfo=None) - dt.utcoffset() # type: ignore
221
-
222
- # Default
223
- self.name = self.user.name
224
- self.charttype = self.chart_type
225
- self.year = self.user.utc.year
226
- self.month = self.user.utc.month
227
- self.day = self.user.utc.day
228
- self.hour = self.user.utc.hour + self.user.utc.minute / 100
229
- self.timezone = offsetToTz(dt.utcoffset())
230
- self.altitude = 25
231
- self.geonameid = None
232
-
233
- # Transit
229
+ self.location = self.user.city
230
+ self.geolat = self.user.lat
231
+ self.geolon = self.user.lng
232
+
233
+ logging.info(f"{self.user.name} birth location: {self.location}, {self.geolat}, {self.geolon}")
234
234
 
235
235
  if self.chart_type == "Transit":
236
- self.t_geolon = self.geolon
237
- self.t_geolat = self.geolat
238
- self.t_altitude = self.altitude
239
236
  self.t_name = self.language_settings["transit_name"]
240
- self.t_year = dt_utc.year
241
- self.t_month = dt_utc.month
242
- self.t_day = dt_utc.day
243
- self.t_hour = decHourJoin(dt_utc.hour, dt_utc.minute, dt_utc.second)
244
- self.t_timezone = offsetToTz(dt.utcoffset())
245
- self.t_altitude = 25
246
- self.t_geonameid = None
247
237
 
248
238
  # configuration
249
239
  # ZOOM 1 = 100%
@@ -264,22 +254,20 @@ class KerykeionChartSVG:
264
254
  {"name": "pisces", "element": "water"},
265
255
  )
266
256
 
267
- # Immediately generate template.
268
- self.template = self.makeTemplate()
257
+ self.template = None
269
258
 
270
259
  def set_output_directory(self, dir_path: Path) -> None:
271
260
  """
272
261
  Sets the output direcotry and returns it's path.
273
262
  """
274
263
  self.output_directory = dir_path
275
- dir_string = f"Output direcotry set to: {self.output_directory}"
276
- return print(dir_string)
264
+ logging.info(f"Output direcotry set to: {self.output_directory}")
277
265
 
278
266
  def parse_json_settings(self, settings_file):
279
267
  """
280
268
  Parse the settings file.
281
269
  """
282
- settings = get_settings_dict(settings_file)
270
+ settings = get_settings(settings_file)
283
271
 
284
272
  language = settings["general_settings"]["language"]
285
273
  self.language_settings = settings["language_settings"].get(language, "EN")
@@ -287,164 +275,32 @@ class KerykeionChartSVG:
287
275
  self.planets_settings = settings["celestial_points"]
288
276
  self.aspects_settings = settings["aspects"]
289
277
  self.planet_in_zodiac_extra_points = settings["general_settings"]["planet_in_zodiac_extra_points"]
278
+ self.chart_settings = settings["chart_settings"]
290
279
 
291
- def _transitRing(self, r) -> str:
280
+ def _draw_zodiac_circle_slices(self, r):
292
281
  """
293
- Draws the transit ring.
294
- """
295
- radius_offset = 18
296
-
297
- out = f'<circle cx="{r}" cy="{r}" r="{r - radius_offset}" style="fill: none; stroke: {self.chart_colors_settings["paper_1"]}; stroke-width: 36px; stroke-opacity: .4;"/>'
298
- out += f'<circle cx="{r}" cy="{r}" r="{r}" style="fill: none; stroke: {self.chart_colors_settings["zodiac_transit_ring_3"]}; stroke-width: 1px; stroke-opacity: .6;"/>'
299
-
300
- return out
301
-
302
- def _degreeRing(self, r) -> str:
303
- """
304
- Draws the degree ring.
305
- """
306
- out = ""
307
- for i in range(72):
308
- offset = float(i * 5) - self.user.houses_degree_ut[6]
309
- if offset < 0:
310
- offset = offset + 360.0
311
- elif offset > 360:
312
- offset = offset - 360.0
313
- x1 = sliceToX(0, r - self.c1, offset) + self.c1
314
- y1 = sliceToY(0, r - self.c1, offset) + self.c1
315
- x2 = sliceToX(0, r + 2 - self.c1, offset) - 2 + self.c1
316
- y2 = sliceToY(0, r + 2 - self.c1, offset) - 2 + self.c1
317
-
318
- out += f'<line x1="{x1}" y1="{y1}" x2="{x2}" y2="{y2}" style="stroke: {self.chart_colors_settings["paper_0"]}; stroke-width: 1px; stroke-opacity:.9;"/>'
319
-
320
- return out
321
-
322
- def _degreeTransitRing(self, r):
323
- out = ""
324
- for i in range(72):
325
- offset = float(i * 5) - self.user.houses_degree_ut[6]
326
- if offset < 0:
327
- offset = offset + 360.0
328
- elif offset > 360:
329
- offset = offset - 360.0
330
- x1 = sliceToX(0, r, offset)
331
- y1 = sliceToY(0, r, offset)
332
- x2 = sliceToX(0, r + 2, offset) - 2
333
- y2 = sliceToY(0, r + 2, offset) - 2
334
- out += f'<line x1="{x1}" y1="{y1}" x2="{x2}" y2="{y2}" style="stroke: #F00; stroke-width: 1px; stroke-opacity:.9;"/>'
335
-
336
- return out
337
-
338
- def _lat2str(self, coord):
339
- """Converts a floating point latitude to string with
340
- degree, minutes and seconds and the appropriate sign
341
- (north or south). Eg. 52.1234567 -> 52°7'25" N
282
+ Generate the SVG string representing the zodiac circle
283
+ with the 12 slices for each zodiac sign.
342
284
 
343
285
  Args:
344
- coord (float): latitude in floating point format
345
- Returns:
346
- str: latitude in string format with degree, minutes,
347
- seconds and sign (N/S)
348
- """
286
+ r (float): The radius of the zodiac slices.
349
287
 
350
- sign = self.language_settings["north"]
351
- if coord < 0.0:
352
- sign = self.language_settings["south"]
353
- coord = abs(coord)
354
- deg = int(coord)
355
- min = int((float(coord) - deg) * 60)
356
- sec = int(round(float(((float(coord) - deg) * 60) - min) * 60.0))
357
- return f"{deg}°{min}'{sec}\" {sign}"
358
-
359
- def _lon2str(self, coord):
360
- """Converts a floating point longitude to string with
361
- degree, minutes and seconds and the appropriate sign
362
- (east or west). Eg. 52.1234567 -> 52°7'25" E
363
-
364
- Args:
365
- coord (float): longitude in floating point format
366
288
  Returns:
367
- str: longitude in string format with degree, minutes,
368
- seconds and sign (E/W)
369
- """
370
-
371
- sign = self.language_settings["east"]
372
- if coord < 0.0:
373
- sign = self.language_settings["west"]
374
- coord = abs(coord)
375
- deg = int(coord)
376
- min = int((float(coord) - deg) * 60)
377
- sec = int(round(float(((float(coord) - deg) * 60) - min) * 60.0))
378
- return f"{deg}°{min}'{sec}\" {sign}"
379
-
380
- def _dec2deg(self, dec, type="3"):
381
- """Coverts decimal float to degrees in format
382
- a°b'c".
383
- """
384
-
385
- dec = float(dec)
386
- a = int(dec)
387
- a_new = (dec - float(a)) * 60.0
388
- b_rounded = int(round(a_new))
389
- b = int(a_new)
390
- c = int(round((a_new - float(b)) * 60.0))
391
- if type == "3":
392
- out = f"{a:02d}&#176;{b:02d}&#39;{c:02d}&#34;"
393
- elif type == "2":
394
- out = f"{a:02d}&#176;{b_rounded:02d}&#39;"
395
- elif type == "1":
396
- out = f"{a:02d}&#176;"
397
- else:
398
- raise KerykeionException(f"Wrong type: {type}, it must be 1, 2 or 3.")
399
- return str(out)
400
-
401
- def _drawAspect(self, r, ar, degA, degB, color):
402
- """
403
- Draws svg aspects: ring, aspect ring, degreeA degreeB
289
+ str: The SVG string representing the zodiac circle.
404
290
  """
405
- offset = (int(self.user.houses_degree_ut[6]) / -1) + int(degA)
406
- x1 = sliceToX(0, ar, offset) + (r - ar)
407
- y1 = sliceToY(0, ar, offset) + (r - ar)
408
- offset = (int(self.user.houses_degree_ut[6]) / -1) + int(degB)
409
- x2 = sliceToX(0, ar, offset) + (r - ar)
410
- y2 = sliceToY(0, ar, offset) + (r - ar)
411
- out = f' <line x1="{x1}" y1="{y1}" x2="{x2}" y2="{y2}" style="stroke: {color}; stroke-width: 1; stroke-opacity: .9;"/>'
412
291
 
413
- return out
414
-
415
- def _zodiacSlice(self, num, r, style, type):
416
- # pie slices
417
- offset = 360 - self.user.houses_degree_ut[6]
418
- # check transit
419
- if self.chart_type == "Transit" or self.chart_type == "Synastry":
420
- dropin = 0
421
- else:
422
- dropin = self.c1
423
- slice = f'<path d="M{str(r)},{str(r)} L{str(dropin + sliceToX(num, r - dropin, offset))},{str(dropin + sliceToY(num, r - dropin, offset))} A{str(r - dropin)},{str(r - dropin)} 0 0,0 {str(dropin + sliceToX(num + 1, r - dropin, offset))},{str(dropin + sliceToY(num + 1, r - dropin, offset))} z" style="{style}"/>'
424
-
425
- # symbols
426
- offset = offset + 15
427
- # check transit
428
- if self.chart_type == "Transit" or self.chart_type == "Synastry":
429
- dropin = 54
430
- else:
431
- dropin = 18 + self.c1
432
- sign = f'<g transform="translate(-16,-16)"><use x="{str(dropin + sliceToX(num, r - dropin, offset))}" y="{str(dropin + sliceToY(num, r - dropin, offset))}" xlink:href="#{type}" /></g>'
433
-
434
- return slice + "" + sign
435
-
436
- def _makeZodiac(self, r):
437
292
  output = ""
438
- for i in range(len(self.zodiac)):
439
- output = (
440
- output
441
- + self._zodiacSlice(
442
- i,
443
- r,
444
- f'fill:{self.chart_colors_settings[f"zodiac_bg_{i}"]}; fill-opacity: 0.5;',
445
- self.zodiac[i]["name"],
446
- )
293
+ for i, zodiac_element in enumerate(self.zodiac):
294
+ output += draw_zodiac_slice(
295
+ c1=self.c1,
296
+ chart_type=self.chart_type,
297
+ seventh_house_degree_ut=self.user.houses_degree_ut[6],
298
+ num=i,
299
+ r=r,
300
+ style=f'fill:{self.chart_colors_settings[f"zodiac_bg_{i}"]}; fill-opacity: 0.5;',
301
+ type=zodiac_element["name"],
447
302
  )
303
+
448
304
  return output
449
305
 
450
306
  def _makeHouses(self, r):
@@ -534,44 +390,50 @@ class KerykeionChartSVG:
534
390
 
535
391
  return path
536
392
 
537
- def _value_element_from_planet(self, i):
393
+ def _calculate_elements_points_from_planets(self):
538
394
  """
539
395
  Calculate chart element points from a planet.
540
396
  """
541
-
542
- # element: get extra points if planet is in own zodiac sign.
543
- related_zodiac_signs = self.planets_settings[i]["related_zodiac_signs"]
544
- cz = self.points_sign[i]
545
- extra_points = 0
546
- if related_zodiac_signs != []:
547
- for e in range(len(related_zodiac_signs)):
548
- if int(related_zodiac_signs[e]) == int(cz):
549
- extra_points = self.planet_in_zodiac_extra_points
550
-
551
- ele = self.zodiac[self.points_sign[i]]["element"]
552
- if ele == "fire":
553
- self.fire = self.fire + self.planets_settings[i]["element_points"] + extra_points
554
-
555
- elif ele == "earth":
556
- self.earth = self.earth + self.planets_settings[i]["element_points"] + extra_points
557
-
558
- elif ele == "air":
559
- self.air = self.air + self.planets_settings[i]["element_points"] + extra_points
560
-
561
- elif ele == "water":
562
- self.water = self.water + self.planets_settings[i]["element_points"] + extra_points
397
+
398
+ for i in range(len(self.available_planets_setting)):
399
+ # element: get extra points if planet is in own zodiac sign.
400
+ related_zodiac_signs = self.available_planets_setting[i]["related_zodiac_signs"]
401
+ cz = self.points_sign[i]
402
+ extra_points = 0
403
+ if related_zodiac_signs != []:
404
+ for e in range(len(related_zodiac_signs)):
405
+ if int(related_zodiac_signs[e]) == int(cz):
406
+ extra_points = self.planet_in_zodiac_extra_points
407
+
408
+ ele = self.zodiac[self.points_sign[i]]["element"]
409
+ if ele == "fire":
410
+ self.fire = self.fire + self.available_planets_setting[i]["element_points"] + extra_points
411
+
412
+ elif ele == "earth":
413
+ self.earth = self.earth + self.available_planets_setting[i]["element_points"] + extra_points
414
+
415
+ elif ele == "air":
416
+ self.air = self.air + self.available_planets_setting[i]["element_points"] + extra_points
417
+
418
+ elif ele == "water":
419
+ self.water = self.water + self.available_planets_setting[i]["element_points"] + extra_points
563
420
 
564
421
  def _make_planets(self, r):
565
422
  planets_degut = {}
566
- diff = range(len(self.planets_settings))
423
+ diff = range(len(self.available_planets_setting))
567
424
 
568
- for i in range(len(self.planets_settings)):
569
- if self.planets_settings[i]["is_active"] == 1:
570
- # list of planets sorted by degree
571
- logger.debug(f"planet: {i}, degree: {self.points_deg_ut[i]}")
572
- planets_degut[self.points_deg_ut[i]] = i
425
+ for i in range(len(self.available_planets_setting)):
426
+ # list of planets sorted by degree
427
+ logging.debug(f"planet: {i}, degree: {self.points_deg_ut[i]}")
428
+ planets_degut[self.points_deg_ut[i]] = i
573
429
 
574
- self._value_element_from_planet(i)
430
+ """
431
+ FIXME: The planets_degut is a dictionary like:
432
+ {planet_degree: planet_index}
433
+ It should be replaced bu points_deg_ut
434
+ print(self.points_deg_ut)
435
+ print(planets_degut)
436
+ """
575
437
 
576
438
  output = ""
577
439
  keys = list(planets_degut.keys())
@@ -600,24 +462,24 @@ class KerykeionChartSVG:
600
462
  diffb = degreeDiff(next, self.points_deg_ut[i])
601
463
  planets_by_pos[e] = [i, diffa, diffb]
602
464
 
603
- logger.debug(f'{self.planets_settings[i]["label"]}, {diffa}, {diffb}')
465
+ logging.debug(f'{self.available_planets_setting[i]["label"]}, {diffa}, {diffb}')
604
466
 
605
467
  if diffb < planet_drange:
606
468
  if group_open:
607
- groups[-1].append([e, diffa, diffb, self.planets_settings[planets_degut[keys[e]]]["label"]])
469
+ groups[-1].append([e, diffa, diffb, self.available_planets_setting[planets_degut[keys[e]]]["label"]])
608
470
  else:
609
471
  group_open = True
610
472
  groups.append([])
611
- groups[-1].append([e, diffa, diffb, self.planets_settings[planets_degut[keys[e]]]["label"]])
473
+ groups[-1].append([e, diffa, diffb, self.available_planets_setting[planets_degut[keys[e]]]["label"]])
612
474
  else:
613
475
  if group_open:
614
- groups[-1].append([e, diffa, diffb, self.planets_settings[planets_degut[keys[e]]]["label"]])
476
+ groups[-1].append([e, diffa, diffb, self.available_planets_setting[planets_degut[keys[e]]]["label"]])
615
477
  group_open = False
616
478
 
617
479
  def zero(x):
618
480
  return 0
619
481
 
620
- planets_delta = list(map(zero, range(len(self.planets_settings))))
482
+ planets_delta = list(map(zero, range(len(self.available_planets_setting))))
621
483
 
622
484
  # print groups
623
485
  # print planets_by_pos
@@ -729,7 +591,7 @@ class KerykeionChartSVG:
729
591
  y1 = sliceToY(0, (r - self.c3), trueoffset) + self.c3
730
592
  x2 = sliceToX(0, (r - rplanet - 30), trueoffset) + rplanet + 30
731
593
  y2 = sliceToY(0, (r - rplanet - 30), trueoffset) + rplanet + 30
732
- color = self.planets_settings[i]["color"]
594
+ color = self.available_planets_setting[i]["color"]
733
595
  output += (
734
596
  '<line x1="%s" y1="%s" x2="%s" y2="%s" style="stroke-width:1px;stroke:%s;stroke-opacity:.3;"/>\n'
735
597
  % (x1, y1, x2, y2, color)
@@ -747,20 +609,21 @@ class KerykeionChartSVG:
747
609
  else:
748
610
  scale = 1
749
611
  # output planet
750
- output += f'<g transform="translate(-{12 * scale},-{12 * scale})"><g transform="scale({scale})"><use x="{planet_x * (1/scale)}" y="{planet_y * (1/scale)}" xlink:href="#{self.planets_settings[i]["name"]}" /></g></g>'
612
+ output += f'<g transform="translate(-{12 * scale},-{12 * scale})"><g transform="scale({scale})"><use x="{planet_x * (1/scale)}" y="{planet_y * (1/scale)}" xlink:href="#{self.available_planets_setting[i]["name"]}" /></g></g>'
751
613
 
752
614
  # make transit degut and display planets
753
615
  if self.chart_type == "Transit" or self.chart_type == "Synastry":
754
616
  group_offset = {}
755
617
  t_planets_degut = {}
756
- if self.chart_type == "Transit":
757
- list_range = len(self.planets_settings) - 4
758
- else:
759
- list_range = len(self.planets_settings)
618
+ list_range = len(self.available_planets_setting)
619
+
760
620
  for i in range(list_range):
621
+ if self.chart_type == "Transit" and self.available_planets_setting[i]['name'] in self.transit_ring_exclude_points_names:
622
+ continue
623
+
761
624
  group_offset[i] = 0
762
- if self.planets_settings[i]["is_active"] == 1:
763
- t_planets_degut[self.t_points_deg_ut[i]] = i
625
+ t_planets_degut[self.t_points_deg_ut[i]] = i
626
+
764
627
  t_keys = list(t_planets_degut.keys())
765
628
  t_keys.sort()
766
629
 
@@ -802,7 +665,12 @@ class KerykeionChartSVG:
802
665
  group_offset[groups[i][3]] = 2.0
803
666
 
804
667
  switch = 0
668
+
669
+ # Transit planets loop
805
670
  for e in range(len(t_keys)):
671
+ if self.chart_type == "Transit" and self.available_planets_setting[e]["name"] in self.transit_ring_exclude_points_names:
672
+ continue
673
+
806
674
  i = t_planets_degut[t_keys[e]]
807
675
 
808
676
  if 22 < i < 27:
@@ -814,20 +682,21 @@ class KerykeionChartSVG:
814
682
  rplanet = 26
815
683
  switch = 1
816
684
 
685
+ # Transit planet name
817
686
  zeropoint = 360 - self.user.houses_degree_ut[6]
818
687
  t_offset = zeropoint + self.t_points_deg_ut[i]
819
688
  if t_offset > 360:
820
689
  t_offset = t_offset - 360
821
690
  planet_x = sliceToX(0, (r - rplanet), t_offset) + rplanet
822
691
  planet_y = sliceToY(0, (r - rplanet), t_offset) + rplanet
823
- output += f'<g transform="translate(-6,-6)"><g transform="scale(0.5)"><use x="{planet_x*2}" y="{planet_y*2}" xlink:href="#{self.planets_settings[i]["name"]}" /></g></g>'
692
+ 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>'
824
693
 
825
- # transit planet line
694
+ # Transit planet line
826
695
  x1 = sliceToX(0, r + 3, t_offset) - 3
827
696
  y1 = sliceToY(0, r + 3, t_offset) - 3
828
697
  x2 = sliceToX(0, r - 3, t_offset) + 3
829
698
  y2 = sliceToY(0, r - 3, t_offset) + 3
830
- output += f'<line x1="{str(x1)}" y1="{str(y1)}" x2="{str(x2)}" y2="{str(y2)}" style="stroke: {self.planets_settings[i]["color"]}; stroke-width: 1px; stroke-opacity:.8;"/>'
699
+ 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;"/>'
831
700
 
832
701
  # transit planet degree text
833
702
  rotate = self.user.houses_degree_ut[0] - self.t_points_deg_ut[i]
@@ -851,7 +720,7 @@ class KerykeionChartSVG:
851
720
  degree = int(t_offset)
852
721
  output += f'<g transform="translate({deg_x},{deg_y})">'
853
722
  output += f'<text transform="rotate({rotate})" text-anchor="{textanchor}'
854
- output += f'" style="fill: {self.planets_settings[i]["color"]}; font-size: 10px;">{self._dec2deg(self.t_points_deg[i], type="1")}'
723
+ 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")}'
855
724
  output += "</text></g>"
856
725
 
857
726
  # check transit
@@ -866,7 +735,7 @@ class KerykeionChartSVG:
866
735
  x2 = sliceToX(0, (r - (dropin - 3)), offset) + (dropin - 3)
867
736
  y2 = sliceToY(0, (r - (dropin - 3)), offset) + (dropin - 3)
868
737
 
869
- output += f'<line x1="{x1}" y1="{y1}" x2="{x2}" y2="{y2}" style="stroke: {self.planets_settings[i]["color"]}; stroke-width: 2px; stroke-opacity:.6;"/>'
738
+ 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;"/>'
870
739
 
871
740
  # check transit
872
741
  if self.chart_type == "Transit" or self.chart_type == "Synastry":
@@ -878,7 +747,7 @@ class KerykeionChartSVG:
878
747
  y1 = sliceToY(0, r - dropin, offset) + dropin
879
748
  x2 = sliceToX(0, (r - (dropin - 3)), offset) + (dropin - 3)
880
749
  y2 = sliceToY(0, (r - (dropin - 3)), offset) + (dropin - 3)
881
- output += f'<line x1="{x1}" y1="{y1}" x2="{x2}" y2="{y2}" style="stroke: {self.planets_settings[i]["color"]}; stroke-width: 2px; stroke-opacity:.6;"/>'
750
+ 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;"/>'
882
751
 
883
752
  return output
884
753
 
@@ -896,7 +765,7 @@ class KerykeionChartSVG:
896
765
  tr = {} # 6
897
766
  qc = {} # 9
898
767
  sext = {} # 3
899
- for i in range(len(self.planets_settings)):
768
+ for i in range(len(self.available_planets_setting)):
900
769
  a = self.points_deg_ut[i]
901
770
  qc[i] = {}
902
771
  sext[i] = {}
@@ -905,14 +774,14 @@ class KerykeionChartSVG:
905
774
  tr[i] = {}
906
775
  conj[i] = {}
907
776
  # skip some points
908
- n = self.planets_settings[i]["name"]
777
+ n = self.available_planets_setting[i]["name"]
909
778
  if n == "earth" or n == "True_Node" or n == "osc. apogee" or n == "intp. apogee" or n == "intp. perigee":
910
779
  continue
911
780
  if n == "Dsc" or n == "Ic":
912
781
  continue
913
- for j in range(len(self.planets_settings)):
782
+ for j in range(len(self.available_planets_setting)):
914
783
  # skip some points
915
- n = self.planets_settings[j]["name"]
784
+ n = self.available_planets_setting[j]["name"]
916
785
  if n == "earth" or n == "True_Node" or n == "osc. apogee" or n == "intp. apogee" or n == "intp. perigee":
917
786
  continue
918
787
  if n == "Dsc" or n == "Ic":
@@ -965,12 +834,12 @@ class KerykeionChartSVG:
965
834
  for l, w in opp[k].items():
966
835
  for a, b in sq.items():
967
836
  if k in sq[a] and l in sq[a]:
968
- logger.debug(f"Got tsquare {a} {k} {l}")
837
+ logging.debug(f"Got tsquare {a} {k} {l}")
969
838
  if k > l:
970
- tsquare[f"{a},{l},{k}"] = f"{self.planets_settings[a]['label']} => {self.planets_settings[l]['label']}, {self.planets_settings[k]['label']}"
839
+ tsquare[f"{a},{l},{k}"] = f"{self.available_planets_setting[a]['label']} => {self.available_planets_setting[l]['label']}, {self.available_planets_setting[k]['label']}"
971
840
 
972
841
  else:
973
- tsquare[f"{a},{k},{l}"] = f"{self.planets_settings[a]['label']} => {self.planets_settings[k]['label']}, {self.planets_settings[l]['label']}"
842
+ tsquare[f"{a},{k},{l}"] = f"{self.available_planets_setting[a]['label']} => {self.available_planets_setting[k]['label']}, {self.available_planets_setting[l]['label']}"
974
843
 
975
844
  stellium = {}
976
845
  # check for 4 continuous conjunctions
@@ -999,10 +868,10 @@ class KerykeionChartSVG:
999
868
  l = [k, n, p, r]
1000
869
  l.sort()
1001
870
  stellium["%s %s %s %s" % (l[0], l[1], l[2], l[3])] = "%s %s %s %s" % (
1002
- self.planets_settings[l[0]]["label"],
1003
- self.planets_settings[l[1]]["label"],
1004
- self.planets_settings[l[2]]["label"],
1005
- self.planets_settings[l[3]]["label"],
871
+ self.available_planets_setting[l[0]]["label"],
872
+ self.available_planets_setting[l[1]]["label"],
873
+ self.available_planets_setting[l[2]]["label"],
874
+ self.available_planets_setting[l[3]]["label"],
1006
875
  )
1007
876
  # print yots
1008
877
  out = '<g transform="translate(-30,380)">'
@@ -1013,15 +882,15 @@ class KerykeionChartSVG:
1013
882
 
1014
883
  # first planet symbol
1015
884
  out += f'<g transform="translate(20,{y})">'
1016
- out += f'<use transform="scale(0.4)" x="0" y="-20" xlink:href="#{self.planets_settings[yot[k][0]]["name"]}" /></g>'
885
+ out += f'<use transform="scale(0.4)" x="0" y="-20" xlink:href="#{self.available_planets_setting[yot[k][0]]["name"]}" /></g>'
1017
886
 
1018
887
  # second planet symbol
1019
888
  out += f'<g transform="translate(30,{y})">'
1020
- out += f'<use transform="scale(0.4)" x="0" y="-20" xlink:href="#{self.planets_settings[yot[k][1]]["name"]}" /></g>'
889
+ out += f'<use transform="scale(0.4)" x="0" y="-20" xlink:href="#{self.available_planets_setting[yot[k][1]]["name"]}" /></g>'
1021
890
 
1022
891
  # third planet symbol
1023
892
  out += f'<g transform="translate(40,{y})">'
1024
- out += f'<use transform="scale(0.4)" x="0" y="-20" xlink:href="#{self.planets_settings[yot[k][2]]["name"]}" /></g>'
893
+ out += f'<use transform="scale(0.4)" x="0" y="-20" xlink:href="#{self.available_planets_setting[yot[k][2]]["name"]}" /></g>'
1025
894
 
1026
895
  y = y + 14
1027
896
  # finalize
@@ -1033,12 +902,13 @@ class KerykeionChartSVG:
1033
902
  def _makeAspects(self, r, ar):
1034
903
  out = ""
1035
904
  for element in self.aspects_list:
1036
- out += self._drawAspect(
1037
- r,
1038
- ar,
1039
- element["p1_abs_pos"],
1040
- element["p2_abs_pos"],
1041
- self.aspects_settings[element["aid"]]["color"],
905
+ out += draw_aspect_line(
906
+ r=r,
907
+ ar=ar,
908
+ degA=element["p1_abs_pos"],
909
+ degB=element["p2_abs_pos"],
910
+ color=self.aspects_settings[element["aid"]]["color"],
911
+ seventh_house_degree_ut=self.user.seventh_house.abs_pos
1042
912
  )
1043
913
 
1044
914
  return out
@@ -1049,47 +919,44 @@ class KerykeionChartSVG:
1049
919
  xindent = 380
1050
920
  yindent = 468
1051
921
  box = 14
1052
- revr = list(range(len(self.planets_settings)))
922
+ revr = list(range(len(self.available_planets_setting)))
1053
923
  revr.reverse()
1054
924
  counter = 0
1055
925
  for a in revr:
1056
926
  counter += 1
1057
- if self.planets_settings[a]["is_active"] == 1:
1058
- out += f'<rect x="{xindent}" y="{yindent}" width="{box}" height="{box}" style="{style}"/>'
1059
- out += f'<use transform="scale(0.4)" x="{(xindent+2)*2.5}" y="{(yindent+1)*2.5}" xlink:href="#{self.planets_settings[a]["name"]}" />'
1060
-
1061
- xindent = xindent + box
1062
- yindent = yindent - box
1063
- revr2 = list(range(a))
1064
- revr2.reverse()
1065
- xorb = xindent
1066
- yorb = yindent + box
1067
- for b in revr2:
1068
- if self.planets_settings[b]["is_active"] == 1:
1069
- out += f'<rect x="{xorb}" y="{yorb}" width="{box}" height="{box}" style="{style}"/>'
1070
-
1071
- xorb = xorb + box
1072
- for element in self.aspects_list:
1073
- if (element["p1"] == a and element["p2"] == b) or (element["p1"] == b and element["p2"] == a):
1074
- out += f'<use x="{xorb-box+1}" y="{yorb+1}" xlink:href="#orb{element["aspect_degrees"]}" />'
927
+ out += f'<rect x="{xindent}" y="{yindent}" width="{box}" height="{box}" style="{style}"/>'
928
+ out += f'<use transform="scale(0.4)" x="{(xindent+2)*2.5}" y="{(yindent+1)*2.5}" xlink:href="#{self.available_planets_setting[a]["name"]}" />'
929
+
930
+ xindent = xindent + box
931
+ yindent = yindent - box
932
+ revr2 = list(range(a))
933
+ revr2.reverse()
934
+ xorb = xindent
935
+ yorb = yindent + box
936
+ for b in revr2:
937
+ out += f'<rect x="{xorb}" y="{yorb}" width="{box}" height="{box}" style="{style}"/>'
938
+
939
+ xorb = xorb + box
940
+ for element in self.aspects_list:
941
+ if (element["p1"] == a and element["p2"] == b) or (element["p1"] == b and element["p2"] == a):
942
+ out += f'<use x="{xorb-box+1}" y="{yorb+1}" xlink:href="#orb{element["aspect_degrees"]}" />'
1075
943
 
1076
944
  return out
1077
945
 
1078
- # Aspect and aspect grid functions for transit type charts.
1079
-
946
+ # Aspect and aspect grid functions for transit type charts
1080
947
  def _makeAspectsTransit(self, r, ar):
1081
948
  out = ""
1082
949
 
1083
- self.aspects_list = SynastryAspects(self.user, self.t_user, new_settings_file=self.new_settings_file).get_relevant_aspects()
950
+ self.aspects_list = SynastryAspects(self.user, self.t_user, new_settings_file=self.new_settings_file).relevant_aspects
1084
951
 
1085
952
  for element in self.aspects_list:
1086
- print(element)
1087
- out += self._drawAspect(
1088
- r,
1089
- ar,
1090
- element["p1_abs_pos"],
1091
- element["p2_abs_pos"],
1092
- self.aspects_settings[element["aid"]]["color"],
953
+ out += draw_aspect_line(
954
+ r=r,
955
+ ar=ar,
956
+ degA=element["p1_abs_pos"],
957
+ degB=element["p2_abs_pos"],
958
+ color=self.aspects_settings[element["aid"]]["color"],
959
+ seventh_house_degree_ut=self.user.seventh_house.abs_pos
1093
960
  )
1094
961
 
1095
962
  return out
@@ -1104,78 +971,60 @@ class KerykeionChartSVG:
1104
971
  for i in range(len(self.aspects_list)):
1105
972
  if i == 12:
1106
973
  nl = 100
1107
- # if len(self.aspects_list) > 24:
1108
- # line = -1 * ( len(self.aspects_list) - 24) * 14
1109
- # else:
1110
- # line = 0
1111
-
1112
- # temporary:
974
+
1113
975
  line = 0
1114
976
 
1115
- if i == 24:
977
+ elif i == 24:
1116
978
  nl = 200
1117
- # if len(self.aspects_list) > 36:
1118
- # line = -1 * ( len(self.aspects_list) - 36) * 14
1119
- # else:
1120
- # line = 0
979
+
1121
980
  line = 0
1122
981
 
1123
- if i == 36:
982
+ elif i == 36:
1124
983
  nl = 300
1125
- if len(self.aspects_list) > 48:
1126
- line = -1 * (len(self.aspects_list) - 48) * 14
984
+
985
+ line = 0
986
+
987
+ elif i == 48:
988
+ nl = 400
989
+
990
+ # When there are more than 60 aspects, the text is moved up
991
+ if len(self.aspects_list) > 60:
992
+ line = -1 * (len(self.aspects_list) - 60) * 14
1127
993
  else:
1128
994
  line = 0
995
+
1129
996
  out += f'<g transform="translate({nl},{line})">'
997
+
1130
998
  # first planet symbol
1131
-
1132
- # TODO: (next((item for item in self.planets_settings if item["id"] == self.aspects_list[i]["p1"]))) It preventes the use ot numeric ID, but it is not working.
1133
999
  out += f'<use transform="scale(0.4)" x="0" y="3" xlink:href="#{self.planets_settings[self.aspects_list[i]["p1"]]["name"]}" />'
1134
1000
 
1135
1001
  # aspect symbol
1136
1002
  out += f'<use x="15" y="0" xlink:href="#orb{self.aspects_settings[self.aspects_list[i]["aid"]]["degree"]}" />'
1003
+
1137
1004
  # second planet symbol
1138
1005
  out += '<g transform="translate(30,0)">'
1139
-
1140
- # TODO: (next((item for item in self.planets_settings if item["id"] == self.aspects_list[i]["p3"])))
1141
1006
  out += '<use transform="scale(0.4)" x="0" y="3" xlink:href="#%s" />' % (self.planets_settings[self.aspects_list[i]["p2"]]["name"])
1142
1007
 
1143
1008
  out += "</g>"
1144
1009
  # difference in degrees
1145
- out += f'<text y="8" x="45" style="fill:{self.chart_colors_settings["paper_0"]}; font-size: 10px;">{self._dec2deg(self.aspects_list[i]["orbit"])}</text>'
1010
+ out += f'<text y="8" x="45" style="fill:{self.chart_colors_settings["paper_0"]}; font-size: 10px;">{convert_decimal_to_degree_string(self.aspects_list[i]["orbit"])}</text>'
1146
1011
  # line
1147
1012
  out += "</g>"
1148
1013
  line = line + 14
1149
1014
  out += "</g>"
1150
1015
  return out
1151
1016
 
1152
- def _makeElements(self, r):
1153
- total = self.fire + self.earth + self.air + self.water
1154
- pf = int(round(100 * self.fire / total))
1155
- pe = int(round(100 * self.earth / total))
1156
- pa = int(round(100 * self.air / total))
1157
- pw = int(round(100 * self.water / total))
1158
-
1159
- out = '<g transform="translate(-30,79)">'
1160
- out += f'<text y="0" style="fill:#ff6600; font-size: 10px;">{self.language_settings["fire"]} {str(pf)}%</text>'
1161
- out += f'<text y="12" style="fill:#6a2d04; font-size: 10px;">{self.language_settings["earth"]} {str(pe)}%</text>'
1162
- out += f'<text y="24" style="fill:#6f76d1; font-size: 10px;">{self.language_settings["air"]} {str(pa)}%</text>'
1163
- out += f'<text y="36" style="fill:#630e73; font-size: 10px;">{self.language_settings["water"]} {str(pw)}%</text>'
1164
- out += "</g>"
1165
-
1166
- return out
1167
-
1168
1017
  def _makePlanetGrid(self):
1169
1018
  li = 10
1170
1019
  offset = 0
1171
1020
 
1172
1021
  out = '<g transform="translate(500,-20)">'
1173
1022
  out += '<g transform="translate(140, -15)">'
1174
- out += f'<text text-anchor="end" style="fill:{self.chart_colors_settings["paper_0"]}; font-size: 14px;">{self.language_settings["planets_and_house"]} {self.name}:</text>'
1023
+ out += f'<text text-anchor="end" style="fill:{self.chart_colors_settings["paper_0"]}; font-size: 14px;">{self.language_settings["planets_and_house"]} {self.user.name}:</text>'
1175
1024
  out += "</g>"
1176
1025
 
1177
1026
  end_of_line = None
1178
- for i in range(len(self.planets_settings)):
1027
+ for i in range(len(self.available_planets_setting)):
1179
1028
  offset_between_lines = 14
1180
1029
  end_of_line = "</g>"
1181
1030
 
@@ -1184,30 +1033,29 @@ class KerykeionChartSVG:
1184
1033
  li = 10
1185
1034
  offset = -120
1186
1035
 
1187
- if self.planets_settings[i]["is_active"] == 1:
1188
- # start of line
1189
- out += f'<g transform="translate({offset},{li})">'
1036
+ # start of line
1037
+ out += f'<g transform="translate({offset},{li})">'
1190
1038
 
1191
- # planet text
1192
- out += f'<text text-anchor="end" style="fill:{self.chart_colors_settings["paper_0"]}; font-size: 10px;">{self.language_settings["celestial_points"][self.planets_settings[i]["label"]]}</text>'
1039
+ # planet text
1040
+ 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>'
1193
1041
 
1194
- # planet symbol
1195
- out += f'<g transform="translate(5,-8)"><use transform="scale(0.4)" xlink:href="#{self.planets_settings[i]["name"]}" /></g>'
1042
+ # planet symbol
1043
+ out += f'<g transform="translate(5,-8)"><use transform="scale(0.4)" xlink:href="#{self.available_planets_setting[i]["name"]}" /></g>'
1196
1044
 
1197
- # planet degree
1198
- out += f'<text text-anchor="start" x="19" style="fill:{self.chart_colors_settings["paper_0"]}; font-size: 10px;">{self._dec2deg(self.points_deg[i])}</text>'
1045
+ # planet degree
1046
+ 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>'
1199
1047
 
1200
- # zodiac
1201
- out += f'<g transform="translate(60,-8)"><use transform="scale(0.3)" xlink:href="#{self.zodiac[self.points_sign[i]]["name"]}" /></g>'
1048
+ # zodiac
1049
+ out += f'<g transform="translate(60,-8)"><use transform="scale(0.3)" xlink:href="#{self.zodiac[self.points_sign[i]]["name"]}" /></g>'
1202
1050
 
1203
- # planet retrograde
1204
- if self.points_retrograde[i]:
1205
- out += '<g transform="translate(74,-6)"><use transform="scale(.5)" xlink:href="#retrograde" /></g>'
1051
+ # planet retrograde
1052
+ if self.points_retrograde[i]:
1053
+ out += '<g transform="translate(74,-6)"><use transform="scale(.5)" xlink:href="#retrograde" /></g>'
1206
1054
 
1207
- # end of line
1208
- out += end_of_line
1055
+ # end of line
1056
+ out += end_of_line
1209
1057
 
1210
- li = li + offset_between_lines
1058
+ li = li + offset_between_lines
1211
1059
 
1212
1060
  if self.chart_type == "Transit" or self.chart_type == "Synastry":
1213
1061
  if self.chart_type == "Transit":
@@ -1222,32 +1070,31 @@ class KerykeionChartSVG:
1222
1070
  t_li = 10
1223
1071
  t_offset = 250
1224
1072
 
1225
- for i in range(len(self.planets_settings)):
1073
+ for i in range(len(self.available_planets_setting)):
1226
1074
  if i == 27:
1227
1075
  t_li = 10
1228
1076
  t_offset = -120
1229
1077
 
1230
- if self.planets_settings[i]["is_active"] == 1:
1231
- # start of line
1232
- out += f'<g transform="translate({t_offset},{t_li})">'
1078
+ # start of line
1079
+ out += f'<g transform="translate({t_offset},{t_li})">'
1233
1080
 
1234
- # planet text
1235
- out += f'<text text-anchor="end" style="fill:{self.chart_colors_settings["paper_0"]}; font-size: 10px;">{self.language_settings["celestial_points"][self.planets_settings[i]["label"]]}</text>'
1236
- # planet symbol
1237
- out += f'<g transform="translate(5,-8)"><use transform="scale(0.4)" xlink:href="#{self.planets_settings[i]["name"]}" /></g>'
1238
- # planet degree
1239
- out += f'<text text-anchor="start" x="19" style="fill:{self.chart_colors_settings["paper_0"]}; font-size: 10px;">{self._dec2deg(self.t_points_deg[i])}</text>'
1240
- # zodiac
1241
- out += f'<g transform="translate(60,-8)"><use transform="scale(0.3)" xlink:href="#{self.zodiac[self.t_points_sign[i]]["name"]}" /></g>'
1081
+ # planet text
1082
+ 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>'
1083
+ # planet symbol
1084
+ out += f'<g transform="translate(5,-8)"><use transform="scale(0.4)" xlink:href="#{self.available_planets_setting[i]["name"]}" /></g>'
1085
+ # planet degree
1086
+ 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>'
1087
+ # zodiac
1088
+ out += f'<g transform="translate(60,-8)"><use transform="scale(0.3)" xlink:href="#{self.zodiac[self.t_points_sign[i]]["name"]}" /></g>'
1242
1089
 
1243
- # planet retrograde
1244
- if self.t_points_retrograde[i]:
1245
- out += '<g transform="translate(74,-6)"><use transform="scale(.5)" xlink:href="#retrograde" /></g>'
1090
+ # planet retrograde
1091
+ if self.t_points_retrograde[i]:
1092
+ out += '<g transform="translate(74,-6)"><use transform="scale(.5)" xlink:href="#retrograde" /></g>'
1246
1093
 
1247
- # end of line
1248
- out += end_of_line
1094
+ # end of line
1095
+ out += end_of_line
1249
1096
 
1250
- t_li = t_li + offset_between_lines
1097
+ t_li = t_li + offset_between_lines
1251
1098
 
1252
1099
  if end_of_line is None:
1253
1100
  raise KerykeionException("End of line not found")
@@ -1255,7 +1102,13 @@ class KerykeionChartSVG:
1255
1102
  out += end_of_line
1256
1103
  return out
1257
1104
 
1258
- def _makeHousesGrid(self):
1105
+ def _draw_house_grid(self):
1106
+ """
1107
+ Generate SVG code for a grid of astrological houses.
1108
+
1109
+ Returns:
1110
+ str: The SVG code for the grid of houses.
1111
+ """
1259
1112
  out = '<g transform="translate(600,-20)">'
1260
1113
 
1261
1114
  li = 10
@@ -1267,7 +1120,7 @@ class KerykeionChartSVG:
1267
1120
  out += f'<g transform="translate(0,{li})">'
1268
1121
  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>'
1269
1122
  out += f'<g transform="translate(40,-8)"><use transform="scale(0.3)" xlink:href="#{self.zodiac[self.houses_sign_graph[i]]["name"]}" /></g>'
1270
- out += f'<text x="53" style="fill:{self.chart_colors_settings["paper_0"]}; font-size: 10px;"> {self._dec2deg(self.user.houses_list[i]["position"])}</text>'
1123
+ 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>'
1271
1124
  out += "</g>"
1272
1125
  li = li + 14
1273
1126
 
@@ -1284,14 +1137,14 @@ class KerykeionChartSVG:
1284
1137
  out += '<g transform="translate(0,' + str(li) + ')">'
1285
1138
  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>'
1286
1139
  out += f'<g transform="translate(40,-8)"><use transform="scale(0.3)" xlink:href="#{self.zodiac[self.t_houses_sign_graph[i]]["name"]}" /></g>'
1287
- out += f'<text x="53" style="fill:{self.chart_colors_settings["paper_0"]}; font-size: 10px;"> {self._dec2deg(self.t_user.houses_list[i]["position"])}</text>'
1140
+ 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>'
1288
1141
  out += "</g>"
1289
1142
  li = li + 14
1290
1143
  out += "</g>"
1291
1144
 
1292
1145
  return out
1293
1146
 
1294
- def _createTemplateDictionary(self):
1147
+ def _createTemplateDictionary(self) -> ChartTemplateDictionary:
1295
1148
  # self.chart_type = "Transit"
1296
1149
  # empty element points
1297
1150
  self.fire = 0.0
@@ -1299,30 +1152,23 @@ class KerykeionChartSVG:
1299
1152
  self.air = 0.0
1300
1153
  self.water = 0.0
1301
1154
 
1302
- # width and height from screen
1303
- ratio = float(self.screen_width) / float(self.screen_height)
1304
- if ratio < 1.3: # 1280x1024
1305
- wm_off = 130
1306
- else: # 1024x768, 800x600, 1280x800, 1680x1050
1307
- wm_off = 100
1155
+ # Calculate the elements points
1156
+ self._calculate_elements_points_from_planets()
1308
1157
 
1309
1158
  # Viewbox and sizing
1310
- svgHeight = "100%" # self.screen_height-wm_off
1311
- svgWidth = "100%" #  self.screen_width-5.0
1312
- # svgHeight=self.screen_height-wm_off
1313
- # svgWidth=(770.0*svgHeight)/540.0
1314
- # svgWidth=float(self.screen_width)-25.0
1159
+ svgHeight = "100%"
1160
+ svgWidth = "100%"
1315
1161
  rotate = "0"
1316
1162
  translate = "0"
1317
- # Defoult:
1318
- # viewbox = '0 0 772.2 546.0' #297mm * 2.6 + 210mm * 2.6
1319
- if self.chart_type == "Natal":
1320
- viewbox = "0 0 772.2 546.0" # 297mm * 2.6 + 210mm * 2.6
1163
+
1164
+ # To increase the size of the chart, change the viewbox
1165
+ if self.chart_type == "Natal" or self.chart_type == "ExternalNatal":
1166
+ viewbox = self.chart_settings["basic_chart_viewBox"]
1321
1167
  else:
1322
- viewbox = "0 0 1000 546.0"
1168
+ viewbox = self.chart_settings["wide_chart_viewBox"]
1323
1169
 
1324
1170
  # template dictionary
1325
- td: ChartTemplateModel = dict()
1171
+ td: ChartTemplateDictionary = dict() # type: ignore
1326
1172
  r = 240
1327
1173
 
1328
1174
  if self.chart_type == "ExternalNatal":
@@ -1336,14 +1182,12 @@ class KerykeionChartSVG:
1336
1182
 
1337
1183
  # transit
1338
1184
  if self.chart_type == "Transit" or self.chart_type == "Synastry":
1339
- td["transitRing"] = self._transitRing(r)
1340
- td["degreeRing"] = self._degreeTransitRing(r)
1185
+ td["transitRing"] = draw_transit_ring(r, self.chart_colors_settings["paper_1"], self.chart_colors_settings["zodiac_transit_ring_3"])
1186
+ td["degreeRing"] = draw_transit_ring_degree_steps(r, self.user.seventh_house.abs_pos)
1341
1187
 
1342
1188
  # circles
1343
- td["c1"] = f'cx="{r}" cy="{r}" r="{r - 36}"'
1344
- td["c1style"] = f'fill: none; stroke: {self.chart_colors_settings["zodiac_transit_ring_2"]}; stroke-width: 1px; stroke-opacity:.4;'
1345
- td["c2"] = 'cx="' + str(r) + '" cy="' + str(r) + '" r="' + str(r - 72) + '"'
1346
- td["c2style"] = f"fill: {self.chart_colors_settings['paper_1']}; fill-opacity:.4; stroke: {self.chart_colors_settings['zodiac_transit_ring_1']}; stroke-opacity:.4; stroke-width: 1px"
1189
+ td["first_circle"] = draw_first_circle(r, self.chart_colors_settings["zodiac_transit_ring_2"], self.chart_type)
1190
+ td["second_circle"] = draw_second_circle(r, self.chart_colors_settings['zodiac_transit_ring_1'], self.chart_colors_settings['paper_1'], self.chart_type)
1347
1191
 
1348
1192
  td["c3"] = 'cx="' + str(r) + '" cy="' + str(r) + '" r="' + str(r - 160) + '"'
1349
1193
  td["c3style"] = f"fill: {self.chart_colors_settings['paper_1']}; fill-opacity:.8; stroke: {self.chart_colors_settings['zodiac_transit_ring_0']}; stroke-width: 1px"
@@ -1351,23 +1195,23 @@ class KerykeionChartSVG:
1351
1195
  td["makeAspects"] = self._makeAspectsTransit(r, (r - 160))
1352
1196
  td["makeAspectGrid"] = self._makeAspectTransitGrid(r)
1353
1197
  td["makePatterns"] = ""
1354
- td["chart_width"] = self.full_width
1355
1198
  else:
1356
1199
  td["transitRing"] = ""
1357
- td["degreeRing"] = self._degreeRing(r)
1200
+ td["degreeRing"] = draw_degree_ring(r, self.c1, self.user.seventh_house.abs_pos, self.chart_colors_settings["paper_0"])
1358
1201
 
1359
- # circles
1360
- td["c1"] = f'cx="{r}" cy="{r}" r="{r - self.c1}"'
1361
- td["c1style"] = f'fill: none; stroke: {self.chart_colors_settings["zodiac_radix_ring_2"]}; stroke-width: 1px; '
1362
- td["c2"] = f'cx="{r}" cy="{r}" r="{r - self.c2}"'
1363
- td["c2style"] = f'fill: {self.chart_colors_settings["paper_1"]}; fill-opacity:.2; stroke: {self.chart_colors_settings["zodiac_radix_ring_1"]}; stroke-opacity:.4; stroke-width: 1px'
1202
+ td['first_circle'] = draw_first_circle(r, self.chart_colors_settings["zodiac_radix_ring_2"], self.chart_type, self.c1)
1203
+
1204
+ 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)
1205
+
1364
1206
  td["c3"] = f'cx="{r}" cy="{r}" r="{r - self.c3}"'
1365
1207
  td["c3style"] = f'fill: {self.chart_colors_settings["paper_1"]}; fill-opacity:.8; stroke: {self.chart_colors_settings["zodiac_radix_ring_0"]}; stroke-width: 1px'
1208
+
1366
1209
  td["makeAspects"] = self._makeAspects(r, (r - self.c3))
1367
1210
  td["makeAspectGrid"] = self._makeAspectGrid(r)
1368
1211
  td["makePatterns"] = self._makePatterns()
1369
- td["chart_width"] = self.natal_width
1370
-
1212
+
1213
+ td["chart_height"] = self.height
1214
+ td["chart_width"] = self.width
1371
1215
  td["circleX"] = str(0)
1372
1216
  td["circleY"] = str(0)
1373
1217
  td["svgWidth"] = str(svgWidth)
@@ -1375,17 +1219,17 @@ class KerykeionChartSVG:
1375
1219
  td["viewbox"] = viewbox
1376
1220
 
1377
1221
  if self.chart_type == "Synastry":
1378
- td["stringTitle"] = f"{self.name} {self.language_settings['and_word']} {self.t_user.name}"
1222
+ td["stringTitle"] = f"{self.user.name} {self.language_settings['and_word']} {self.t_user.name}"
1379
1223
 
1380
1224
  elif self.chart_type == "Transit":
1381
1225
  td["stringTitle"] = f"{self.language_settings['transits']} {self.t_user.day}/{self.t_user.month}/{self.t_user.year}"
1382
1226
 
1383
1227
  else:
1384
- td["stringTitle"] = self.name
1228
+ td["stringTitle"] = self.user.name
1385
1229
 
1386
1230
  # Tipo di carta
1387
- if self.chart_type == "Synastry" or self.name == "Transit":
1388
- td["stringName"] = f"{self.name}:"
1231
+ if self.chart_type == "Synastry" or self.chart_type == "Transit":
1232
+ td["stringName"] = f"{self.user.name}:"
1389
1233
  else:
1390
1234
  td["stringName"] = f'{self.language_settings["info"]}:'
1391
1235
 
@@ -1469,9 +1313,20 @@ class KerykeionChartSVG:
1469
1313
  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}"
1470
1314
 
1471
1315
  else:
1472
- td["stringLat"] = f"{self.language_settings['latitude']}: {self._lat2str(self.geolat)}"
1473
- td["stringLon"] = f"{self.language_settings['longitude']}: {self._lon2str(self.geolon)}"
1474
- td["stringPosition"] = f"{self.language_settings['type']}: {self.charttype}"
1316
+ latitude_string = convert_latitude_coordinate_to_string(
1317
+ self.geolat,
1318
+ self.language_settings['north'],
1319
+ self.language_settings['south']
1320
+ )
1321
+ longitude_string = convert_longitude_coordinate_to_string(
1322
+ self.geolon,
1323
+ self.language_settings['east'],
1324
+ self.language_settings['west']
1325
+ )
1326
+
1327
+ td["stringLat"] = f"{self.language_settings['latitude']}: {latitude_string}"
1328
+ td["stringLon"] = f"{self.language_settings['longitude']}: {longitude_string}"
1329
+ td["stringPosition"] = f"{self.language_settings['type']}: {self.chart_type}"
1475
1330
 
1476
1331
  # paper_color_X
1477
1332
  td["paper_color_0"] = self.chart_colors_settings["paper_0"]
@@ -1495,48 +1350,68 @@ class KerykeionChartSVG:
1495
1350
  td["cfgRotate"] = rotate
1496
1351
  td["cfgTranslate"] = translate
1497
1352
 
1498
- # functions
1499
- td["makeZodiac"] = self._makeZodiac(r)
1353
+ # ---
1354
+ # Drawing Functions
1355
+ #---
1356
+
1357
+ td["makeZodiac"] = self._draw_zodiac_circle_slices(r)
1358
+ td["makeHousesGrid"] = self._draw_house_grid()
1359
+ # TODO: Add the rest of the functions
1500
1360
  td["makeHouses"] = self._makeHouses(r)
1501
1361
  td["makePlanets"] = self._make_planets(r)
1502
- td["makeElements"] = self._makeElements(r)
1362
+ td["elements_percentages"] = draw_elements_percentages(
1363
+ self.language_settings['fire'],
1364
+ self.fire,
1365
+ self.language_settings['earth'],
1366
+ self.earth,
1367
+ self.language_settings['air'],
1368
+ self.air,
1369
+ self.language_settings['water'],
1370
+ self.water,
1371
+ )
1503
1372
  td["makePlanetGrid"] = self._makePlanetGrid()
1504
- td["makeHousesGrid"] = self._makeHousesGrid()
1505
1373
 
1506
1374
  return td
1507
1375
 
1508
- def makeTemplate(self):
1376
+ def makeTemplate(self, minify: bool = False) -> str:
1509
1377
  """Creates the template for the SVG file"""
1510
1378
  td = self._createTemplateDictionary()
1511
1379
 
1512
1380
  # read template
1513
- with open(self.xml_svg, "r", encoding="utf-8", errors="ignore") as output_file:
1514
- f = open(self.xml_svg)
1381
+ with open(self.xml_svg, "r", encoding="utf-8", errors="ignore") as f:
1515
1382
  template = Template(f.read()).substitute(td)
1516
1383
 
1517
1384
  # return filename
1518
1385
 
1519
- logger.debug(f"Template dictionary keys: {td.keys()}")
1386
+ logging.debug(f"Template dictionary keys: {td.keys()}")
1520
1387
 
1521
1388
  self._createTemplateDictionary()
1522
- return template.replace('"', "'")
1523
1389
 
1524
- def makeSVG(self):
1390
+ if minify:
1391
+ template = scourString(template).replace('"', "'").replace("\n", "").replace("\t","").replace(" ", "").replace(" ", "")
1392
+
1393
+ else:
1394
+ template = template.replace('"', "'")
1395
+
1396
+ return template
1397
+
1398
+ def makeSVG(self, minify: bool = False):
1525
1399
  """Prints out the SVG file in the specifide folder"""
1526
1400
 
1527
1401
  if not (self.template):
1528
- self.template = self.makeTemplate()
1402
+ self.template = self.makeTemplate(minify)
1529
1403
 
1530
- self.chartname = self.output_directory / f"{self.name}{self.chart_type}Chart.svg"
1404
+ self.chartname = self.output_directory / f"{self.user.name}{self.chart_type}Chart.svg"
1531
1405
 
1532
1406
  with open(self.chartname, "w", encoding="utf-8", errors="ignore") as output_file:
1533
1407
  output_file.write(self.template)
1534
1408
 
1535
- return print(f"SVG Generated Correctly in: {self.chartname}")
1409
+ logging.info(f"SVG Generated Correctly in: {self.chartname}")
1536
1410
 
1537
1411
 
1538
1412
  if __name__ == "__main__":
1539
- basicConfig(level="DEBUG")
1413
+ from kerykeion.utilities import setup_logging
1414
+ setup_logging(level="debug")
1540
1415
 
1541
1416
  first = AstrologicalSubject("John Lennon", 1940, 10, 9, 10, 30, "Liverpool", "GB")
1542
1417
  second = AstrologicalSubject("Paul McCartney", 1942, 6, 18, 15, 30, "Liverpool", "GB")
@@ -1551,8 +1426,9 @@ if __name__ == "__main__":
1551
1426
 
1552
1427
  # Synastry Chart
1553
1428
  synastry_chart = KerykeionChartSVG(first, "Synastry", second)
1554
- synastry_chart.makeSVG()
1429
+ synastry_chart.makeSVG(minify=True)
1555
1430
 
1556
1431
  # Transits Chart
1557
1432
  transits_chart = KerykeionChartSVG(first, "Transit", second)
1558
- transits_chart.makeSVG()
1433
+ transits_chart.makeSVG(minify=True)
1434
+