kerykeion 5.0.0b1__py3-none-any.whl → 5.0.0b4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of kerykeion might be problematic. Click here for more details.
- kerykeion/__init__.py +3 -2
- kerykeion/aspects/aspects_factory.py +60 -21
- kerykeion/aspects/aspects_utils.py +1 -1
- kerykeion/backword.py +111 -18
- kerykeion/chart_data_factory.py +72 -7
- kerykeion/charts/chart_drawer.py +601 -206
- kerykeion/charts/charts_utils.py +440 -255
- kerykeion/charts/templates/aspect_grid_only.xml +269 -312
- kerykeion/charts/templates/chart.xml +302 -328
- kerykeion/charts/templates/wheel_only.xml +271 -312
- kerykeion/charts/themes/black-and-white.css +148 -0
- kerykeion/relationship_score_factory.py +12 -2
- kerykeion/schemas/chart_template_model.py +27 -0
- kerykeion/schemas/kr_literals.py +1 -1
- kerykeion/settings/__init__.py +16 -2
- kerykeion/settings/chart_defaults.py +444 -0
- kerykeion/settings/config_constants.py +0 -5
- kerykeion/settings/kerykeion_settings.py +31 -74
- kerykeion/settings/translation_strings.py +1479 -0
- kerykeion/settings/translations.py +74 -0
- kerykeion/transits_time_range_factory.py +10 -1
- {kerykeion-5.0.0b1.dist-info → kerykeion-5.0.0b4.dist-info}/METADATA +304 -204
- {kerykeion-5.0.0b1.dist-info → kerykeion-5.0.0b4.dist-info}/RECORD +25 -26
- kerykeion/settings/kr.config.json +0 -1474
- kerykeion/settings/legacy/__init__.py +0 -0
- kerykeion/settings/legacy/legacy_celestial_points_settings.py +0 -299
- kerykeion/settings/legacy/legacy_chart_aspects_settings.py +0 -71
- kerykeion/settings/legacy/legacy_color_settings.py +0 -42
- {kerykeion-5.0.0b1.dist-info → kerykeion-5.0.0b4.dist-info}/WHEEL +0 -0
- {kerykeion-5.0.0b1.dist-info → kerykeion-5.0.0b4.dist-info}/licenses/LICENSE +0 -0
kerykeion/charts/chart_drawer.py
CHANGED
|
@@ -5,19 +5,23 @@
|
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
import logging
|
|
8
|
-
|
|
9
|
-
from
|
|
8
|
+
from copy import deepcopy
|
|
9
|
+
from math import ceil
|
|
10
|
+
from datetime import datetime
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from string import Template
|
|
13
|
+
from typing import Any, Mapping, Optional, Union, get_args
|
|
10
14
|
|
|
15
|
+
import swisseph as swe
|
|
16
|
+
from scour.scour import scourString
|
|
11
17
|
|
|
12
|
-
from kerykeion.schemas.kr_models import ChartDataModel
|
|
13
|
-
from kerykeion.settings.config_constants import DEFAULT_ACTIVE_POINTS
|
|
14
|
-
from kerykeion.settings.kerykeion_settings import get_settings
|
|
15
18
|
from kerykeion.house_comparison.house_comparison_factory import HouseComparisonFactory
|
|
16
19
|
from kerykeion.schemas import (
|
|
17
20
|
KerykeionException,
|
|
18
21
|
ChartType,
|
|
19
22
|
Sign,
|
|
20
23
|
ActiveAspect,
|
|
24
|
+
KerykeionPointModel,
|
|
21
25
|
)
|
|
22
26
|
from kerykeion.schemas import ChartTemplateModel
|
|
23
27
|
from kerykeion.schemas.kr_models import (
|
|
@@ -27,13 +31,17 @@ from kerykeion.schemas.kr_models import (
|
|
|
27
31
|
)
|
|
28
32
|
from kerykeion.schemas.settings_models import (
|
|
29
33
|
KerykeionSettingsCelestialPointModel,
|
|
30
|
-
|
|
34
|
+
KerykeionLanguageModel,
|
|
31
35
|
)
|
|
32
36
|
from kerykeion.schemas.kr_literals import (
|
|
33
37
|
KerykeionChartTheme,
|
|
34
38
|
KerykeionChartLanguage,
|
|
35
39
|
AstrologicalPoint,
|
|
36
40
|
)
|
|
41
|
+
from kerykeion.schemas.kr_models import ChartDataModel
|
|
42
|
+
from kerykeion.settings import LANGUAGE_SETTINGS
|
|
43
|
+
from kerykeion.settings.config_constants import DEFAULT_ACTIVE_POINTS
|
|
44
|
+
from kerykeion.settings.translations import get_translations, load_language_settings
|
|
37
45
|
from kerykeion.charts.charts_utils import (
|
|
38
46
|
draw_zodiac_slice,
|
|
39
47
|
convert_latitude_coordinate_to_string,
|
|
@@ -62,14 +70,12 @@ from kerykeion.charts.charts_utils import (
|
|
|
62
70
|
)
|
|
63
71
|
from kerykeion.charts.draw_planets import draw_planets
|
|
64
72
|
from kerykeion.utilities import get_houses_list, inline_css_variables_in_svg, distribute_percentages_to_100
|
|
65
|
-
from kerykeion.settings.
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
from string import Template
|
|
73
|
+
from kerykeion.settings.chart_defaults import (
|
|
74
|
+
DEFAULT_CHART_COLORS,
|
|
75
|
+
DEFAULT_CELESTIAL_POINTS_SETTINGS,
|
|
76
|
+
DEFAULT_CHART_ASPECTS_SETTINGS,
|
|
77
|
+
)
|
|
71
78
|
from typing import List, Literal
|
|
72
|
-
from datetime import datetime
|
|
73
79
|
|
|
74
80
|
|
|
75
81
|
class ChartDrawer:
|
|
@@ -98,14 +104,16 @@ class ChartDrawer:
|
|
|
98
104
|
Pre-computed chart data from ChartDataFactory containing all subjects, aspects,
|
|
99
105
|
element/quality distributions, and other analytical data. This is the ONLY source
|
|
100
106
|
of chart information - no calculations are performed by ChartDrawer.
|
|
101
|
-
new_settings_file (Path | dict | KerykeionSettingsModel, optional):
|
|
102
|
-
Path or settings object to override default chart configuration (colors, fonts, aspects).
|
|
103
107
|
theme (KerykeionChartTheme, optional):
|
|
104
108
|
CSS theme for the chart. If None, no default styles are applied. Defaults to 'classic'.
|
|
105
109
|
double_chart_aspect_grid_type (Literal['list', 'table'], optional):
|
|
106
110
|
Specifies rendering style for double-chart aspect grids. Defaults to 'list'.
|
|
107
111
|
chart_language (KerykeionChartLanguage, optional):
|
|
108
112
|
Language code for chart labels. Defaults to 'EN'.
|
|
113
|
+
language_pack (dict | None, optional):
|
|
114
|
+
Additional translations merged over the bundled defaults for the
|
|
115
|
+
selected language. Useful to introduce new languages or override
|
|
116
|
+
existing labels.
|
|
109
117
|
transparent_background (bool, optional):
|
|
110
118
|
Whether to use a transparent background instead of the theme color. Defaults to False.
|
|
111
119
|
|
|
@@ -157,10 +165,29 @@ class ChartDrawer:
|
|
|
157
165
|
|
|
158
166
|
_DEFAULT_HEIGHT = 550
|
|
159
167
|
_DEFAULT_FULL_WIDTH = 1250
|
|
168
|
+
_DEFAULT_SYNASTRY_WIDTH = 1570
|
|
160
169
|
_DEFAULT_NATAL_WIDTH = 870
|
|
161
170
|
_DEFAULT_FULL_WIDTH_WITH_TABLE = 1250
|
|
162
171
|
_DEFAULT_ULTRA_WIDE_WIDTH = 1320
|
|
163
172
|
|
|
173
|
+
_ASPECT_LIST_ASPECTS_PER_COLUMN = 14
|
|
174
|
+
_ASPECT_LIST_COLUMN_WIDTH = 105
|
|
175
|
+
|
|
176
|
+
_BASE_VERTICAL_OFFSETS = {
|
|
177
|
+
"wheel": 50,
|
|
178
|
+
"grid": 0,
|
|
179
|
+
"aspect_grid": 50,
|
|
180
|
+
"aspect_list": 50,
|
|
181
|
+
"title": 0,
|
|
182
|
+
"elements": 0,
|
|
183
|
+
"qualities": 0,
|
|
184
|
+
"lunar_phase": 518,
|
|
185
|
+
"bottom_left": 0,
|
|
186
|
+
}
|
|
187
|
+
_MAX_TOP_SHIFT = 80
|
|
188
|
+
_TOP_SHIFT_FACTOR = 2
|
|
189
|
+
_ROW_HEIGHT = 8
|
|
190
|
+
|
|
164
191
|
_BASIC_CHART_VIEWBOX = f"0 0 {_DEFAULT_NATAL_WIDTH} {_DEFAULT_HEIGHT}"
|
|
165
192
|
_WIDE_CHART_VIEWBOX = f"0 0 {_DEFAULT_FULL_WIDTH} 546.0"
|
|
166
193
|
_ULTRA_WIDE_CHART_VIEWBOX = f"0 0 {_DEFAULT_ULTRA_WIDE_WIDTH} 546.0"
|
|
@@ -170,7 +197,6 @@ class ChartDrawer:
|
|
|
170
197
|
first_obj: Union[AstrologicalSubjectModel, CompositeSubjectModel, PlanetReturnModel]
|
|
171
198
|
second_obj: Union[AstrologicalSubjectModel, PlanetReturnModel, None]
|
|
172
199
|
chart_type: ChartType
|
|
173
|
-
new_settings_file: Union[Path, None, KerykeionSettingsModel, dict]
|
|
174
200
|
theme: Union[KerykeionChartTheme, None]
|
|
175
201
|
double_chart_aspect_grid_type: Literal["list", "table"]
|
|
176
202
|
chart_language: KerykeionChartLanguage
|
|
@@ -179,6 +205,8 @@ class ChartDrawer:
|
|
|
179
205
|
transparent_background: bool
|
|
180
206
|
external_view: bool
|
|
181
207
|
custom_title: Union[str, None]
|
|
208
|
+
_language_model: KerykeionLanguageModel
|
|
209
|
+
_fallback_language_model: KerykeionLanguageModel
|
|
182
210
|
|
|
183
211
|
# Internal properties
|
|
184
212
|
fire: float
|
|
@@ -204,10 +232,10 @@ class ChartDrawer:
|
|
|
204
232
|
self,
|
|
205
233
|
chart_data: "ChartDataModel",
|
|
206
234
|
*,
|
|
207
|
-
new_settings_file: Union[Path, None, KerykeionSettingsModel, dict] = None,
|
|
208
235
|
theme: Union[KerykeionChartTheme, None] = "classic",
|
|
209
236
|
double_chart_aspect_grid_type: Literal["list", "table"] = "list",
|
|
210
237
|
chart_language: KerykeionChartLanguage = "EN",
|
|
238
|
+
language_pack: Optional[Mapping[str, Any]] = None,
|
|
211
239
|
external_view: bool = False,
|
|
212
240
|
transparent_background: bool = False,
|
|
213
241
|
colors_settings: dict = DEFAULT_CHART_COLORS,
|
|
@@ -224,14 +252,16 @@ class ChartDrawer:
|
|
|
224
252
|
chart_data (ChartDataModel):
|
|
225
253
|
Pre-computed chart data from ChartDataFactory containing all subjects,
|
|
226
254
|
aspects, element/quality distributions, and other analytical data.
|
|
227
|
-
new_settings_file (Path, dict, or KerykeionSettingsModel, optional):
|
|
228
|
-
Custom settings source for chart colors, fonts, and aspects.
|
|
229
255
|
theme (KerykeionChartTheme or None, optional):
|
|
230
256
|
CSS theme to apply; None for default styling.
|
|
231
257
|
double_chart_aspect_grid_type (Literal['list','table'], optional):
|
|
232
258
|
Layout style for double-chart aspect grids ('list' or 'table').
|
|
233
259
|
chart_language (KerykeionChartLanguage, optional):
|
|
234
260
|
Language code for chart labels (e.g., 'EN', 'IT').
|
|
261
|
+
language_pack (dict | None, optional):
|
|
262
|
+
Additional translations merged over the bundled defaults for the
|
|
263
|
+
selected language. Useful to introduce new languages or override
|
|
264
|
+
existing labels.
|
|
235
265
|
external_view (bool, optional):
|
|
236
266
|
Whether to use external visualization (planets on outer ring) for single-subject charts. Defaults to False.
|
|
237
267
|
transparent_background (bool, optional):
|
|
@@ -242,17 +272,17 @@ class ChartDrawer:
|
|
|
242
272
|
# --------------------
|
|
243
273
|
# COMMON INITIALIZATION
|
|
244
274
|
# --------------------
|
|
245
|
-
self.new_settings_file = new_settings_file
|
|
246
275
|
self.chart_language = chart_language
|
|
247
276
|
self.double_chart_aspect_grid_type = double_chart_aspect_grid_type
|
|
248
277
|
self.transparent_background = transparent_background
|
|
249
278
|
self.external_view = external_view
|
|
250
|
-
self.chart_colors_settings = colors_settings
|
|
251
|
-
self.planets_settings = celestial_points_settings
|
|
252
|
-
self.aspects_settings = aspects_settings
|
|
279
|
+
self.chart_colors_settings = deepcopy(colors_settings)
|
|
280
|
+
self.planets_settings = [dict(body) for body in celestial_points_settings]
|
|
281
|
+
self.aspects_settings = [dict(aspect) for aspect in aspects_settings]
|
|
253
282
|
self.custom_title = custom_title
|
|
254
283
|
self.auto_size = auto_size
|
|
255
284
|
self._padding = padding
|
|
285
|
+
self._vertical_offsets: dict[str, int] = self._BASE_VERTICAL_OFFSETS.copy()
|
|
256
286
|
|
|
257
287
|
# Extract data from ChartDataModel
|
|
258
288
|
self.chart_data = chart_data
|
|
@@ -265,12 +295,13 @@ class ChartDrawer:
|
|
|
265
295
|
# SingleChartDataModel
|
|
266
296
|
self.first_obj = getattr(chart_data, 'subject')
|
|
267
297
|
self.second_obj = None
|
|
298
|
+
|
|
268
299
|
else: # DualChartDataModel for Transit, Synastry, DualReturnChart
|
|
269
300
|
self.first_obj = getattr(chart_data, 'first_subject')
|
|
270
301
|
self.second_obj = getattr(chart_data, 'second_subject')
|
|
271
302
|
|
|
272
303
|
# Load settings
|
|
273
|
-
self.
|
|
304
|
+
self._load_language_settings(language_pack)
|
|
274
305
|
|
|
275
306
|
# Default radius for all charts
|
|
276
307
|
self.main_radius = 240
|
|
@@ -282,12 +313,27 @@ class ChartDrawer:
|
|
|
282
313
|
body["is_active"] = True
|
|
283
314
|
self.available_planets_setting.append(body) # type: ignore[arg-type]
|
|
284
315
|
|
|
316
|
+
active_points_count = len(self.available_planets_setting)
|
|
317
|
+
if active_points_count > 24:
|
|
318
|
+
logging.warning(
|
|
319
|
+
"ChartDrawer detected %s active celestial points; rendering may look crowded beyond 24.",
|
|
320
|
+
active_points_count,
|
|
321
|
+
)
|
|
322
|
+
|
|
285
323
|
# Set available celestial points
|
|
286
324
|
available_celestial_points_names = [body["name"].lower() for body in self.available_planets_setting]
|
|
287
|
-
self.available_kerykeion_celestial_points =
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
325
|
+
self.available_kerykeion_celestial_points = self._collect_subject_points(
|
|
326
|
+
self.first_obj,
|
|
327
|
+
available_celestial_points_names,
|
|
328
|
+
)
|
|
329
|
+
|
|
330
|
+
# Collect secondary subject points for dual charts using the same active set
|
|
331
|
+
self.t_available_kerykeion_celestial_points: list[KerykeionPointModel] = []
|
|
332
|
+
if self.second_obj is not None:
|
|
333
|
+
self.t_available_kerykeion_celestial_points = self._collect_subject_points(
|
|
334
|
+
self.second_obj,
|
|
335
|
+
available_celestial_points_names,
|
|
336
|
+
)
|
|
291
337
|
|
|
292
338
|
# ------------------------
|
|
293
339
|
# CHART TYPE SPECIFIC SETUP FROM CHART DATA
|
|
@@ -340,9 +386,6 @@ class ChartDrawer:
|
|
|
340
386
|
# Extract aspects from pre-computed chart data
|
|
341
387
|
self.aspects_list = chart_data.aspects.relevant_aspects
|
|
342
388
|
|
|
343
|
-
# Secondary subject available points
|
|
344
|
-
self.t_available_kerykeion_celestial_points = self.available_kerykeion_celestial_points
|
|
345
|
-
|
|
346
389
|
# Screen size
|
|
347
390
|
self.height = self._DEFAULT_HEIGHT
|
|
348
391
|
if self.double_chart_aspect_grid_type == "table":
|
|
@@ -364,12 +407,9 @@ class ChartDrawer:
|
|
|
364
407
|
# Extract aspects from pre-computed chart data
|
|
365
408
|
self.aspects_list = chart_data.aspects.relevant_aspects
|
|
366
409
|
|
|
367
|
-
# Secondary subject available points
|
|
368
|
-
self.t_available_kerykeion_celestial_points = self.available_kerykeion_celestial_points
|
|
369
|
-
|
|
370
410
|
# Screen size
|
|
371
411
|
self.height = self._DEFAULT_HEIGHT
|
|
372
|
-
self.width = self.
|
|
412
|
+
self.width = self._DEFAULT_SYNASTRY_WIDTH
|
|
373
413
|
|
|
374
414
|
# Get location and coordinates
|
|
375
415
|
self.location, self.geolat, self.geolon = self._get_location_info()
|
|
@@ -385,9 +425,6 @@ class ChartDrawer:
|
|
|
385
425
|
# Extract aspects from pre-computed chart data
|
|
386
426
|
self.aspects_list = chart_data.aspects.relevant_aspects
|
|
387
427
|
|
|
388
|
-
# Secondary subject available points
|
|
389
|
-
self.t_available_kerykeion_celestial_points = self.available_kerykeion_celestial_points
|
|
390
|
-
|
|
391
428
|
# Screen size
|
|
392
429
|
self.height = self._DEFAULT_HEIGHT
|
|
393
430
|
self.width = self._DEFAULT_ULTRA_WIDE_WIDTH
|
|
@@ -438,20 +475,191 @@ class ChartDrawer:
|
|
|
438
475
|
|
|
439
476
|
self.set_up_theme(theme)
|
|
440
477
|
|
|
441
|
-
|
|
478
|
+
self._apply_dynamic_height_adjustment()
|
|
479
|
+
self._adjust_height_for_extended_aspect_columns()
|
|
480
|
+
# Reconcile width with the updated layout once height adjustments are known.
|
|
442
481
|
if self.auto_size:
|
|
443
|
-
|
|
444
|
-
required_width = self._estimate_required_width_full()
|
|
445
|
-
if required_width > self.width:
|
|
446
|
-
self.width = required_width
|
|
447
|
-
except Exception as e:
|
|
448
|
-
# Keep default on any unexpected issue; do not break rendering
|
|
449
|
-
logging.debug(f"Auto-size width calculation failed: {e}")
|
|
482
|
+
self._update_width_to_content()
|
|
450
483
|
|
|
451
484
|
def _count_active_planets(self) -> int:
|
|
452
485
|
"""Return number of active celestial points in the current chart."""
|
|
453
486
|
return len([p for p in self.available_planets_setting if p.get("is_active")])
|
|
454
487
|
|
|
488
|
+
def _apply_dynamic_height_adjustment(self) -> None:
|
|
489
|
+
"""Adjust chart height and vertical offsets based on active points."""
|
|
490
|
+
active_points_count = self._count_active_planets()
|
|
491
|
+
|
|
492
|
+
offsets = self._BASE_VERTICAL_OFFSETS.copy()
|
|
493
|
+
|
|
494
|
+
minimum_height = self._DEFAULT_HEIGHT
|
|
495
|
+
|
|
496
|
+
if self.chart_type == "Synastry":
|
|
497
|
+
self._apply_synastry_height_adjustment(
|
|
498
|
+
active_points_count=active_points_count,
|
|
499
|
+
offsets=offsets,
|
|
500
|
+
minimum_height=minimum_height,
|
|
501
|
+
)
|
|
502
|
+
return
|
|
503
|
+
|
|
504
|
+
if active_points_count <= 20:
|
|
505
|
+
self.height = max(self.height, minimum_height)
|
|
506
|
+
self._vertical_offsets = offsets
|
|
507
|
+
return
|
|
508
|
+
|
|
509
|
+
extra_points = active_points_count - 20
|
|
510
|
+
extra_height = extra_points * self._ROW_HEIGHT
|
|
511
|
+
|
|
512
|
+
self.height = max(self.height, minimum_height + extra_height)
|
|
513
|
+
|
|
514
|
+
delta_height = max(self.height - minimum_height, 0)
|
|
515
|
+
|
|
516
|
+
# Anchor wheel, aspect grid/list, and lunar phase to the bottom
|
|
517
|
+
offsets["wheel"] += delta_height
|
|
518
|
+
offsets["aspect_grid"] += delta_height
|
|
519
|
+
offsets["aspect_list"] += delta_height
|
|
520
|
+
offsets["lunar_phase"] += delta_height
|
|
521
|
+
offsets["bottom_left"] += delta_height
|
|
522
|
+
|
|
523
|
+
# Smooth top offsets to keep breathing room near the title and grids
|
|
524
|
+
shift = min(extra_points * self._TOP_SHIFT_FACTOR, self._MAX_TOP_SHIFT)
|
|
525
|
+
top_shift = shift // 2
|
|
526
|
+
|
|
527
|
+
offsets["grid"] += shift
|
|
528
|
+
offsets["title"] += top_shift
|
|
529
|
+
offsets["elements"] += top_shift
|
|
530
|
+
offsets["qualities"] += top_shift
|
|
531
|
+
|
|
532
|
+
self._vertical_offsets = offsets
|
|
533
|
+
|
|
534
|
+
def _adjust_height_for_extended_aspect_columns(self) -> None:
|
|
535
|
+
"""Ensure tall aspect columns fit within the SVG for double-chart lists."""
|
|
536
|
+
if self.double_chart_aspect_grid_type != "list":
|
|
537
|
+
return
|
|
538
|
+
|
|
539
|
+
if self.chart_type not in ("Synastry", "Transit", "DualReturnChart"):
|
|
540
|
+
return
|
|
541
|
+
|
|
542
|
+
total_aspects = len(self.aspects_list) if hasattr(self, "aspects_list") else 0
|
|
543
|
+
if total_aspects == 0:
|
|
544
|
+
return
|
|
545
|
+
|
|
546
|
+
aspects_per_column = 14
|
|
547
|
+
extended_column_start = 11 # Zero-based column index where tall columns begin
|
|
548
|
+
base_capacity = aspects_per_column * extended_column_start
|
|
549
|
+
|
|
550
|
+
if total_aspects <= base_capacity:
|
|
551
|
+
return
|
|
552
|
+
|
|
553
|
+
translate_y = 273
|
|
554
|
+
bottom_padding = 40
|
|
555
|
+
title_clearance = 18
|
|
556
|
+
line_height = 14
|
|
557
|
+
baseline_index = aspects_per_column - 1
|
|
558
|
+
top_limit_index = ceil((-translate_y + title_clearance) / line_height)
|
|
559
|
+
max_capacity_by_top = baseline_index - top_limit_index + 1
|
|
560
|
+
|
|
561
|
+
if max_capacity_by_top <= aspects_per_column:
|
|
562
|
+
return
|
|
563
|
+
|
|
564
|
+
target_capacity = max_capacity_by_top
|
|
565
|
+
required_available_height = target_capacity * line_height
|
|
566
|
+
required_height = translate_y + bottom_padding + required_available_height
|
|
567
|
+
|
|
568
|
+
if required_height <= self.height:
|
|
569
|
+
return
|
|
570
|
+
|
|
571
|
+
delta = required_height - self.height
|
|
572
|
+
self.height = required_height
|
|
573
|
+
|
|
574
|
+
offsets = self._vertical_offsets
|
|
575
|
+
# Keep bottom-anchored groups aligned after changing the overall height.
|
|
576
|
+
offsets["wheel"] += delta
|
|
577
|
+
offsets["aspect_grid"] += delta
|
|
578
|
+
offsets["aspect_list"] += delta
|
|
579
|
+
offsets["lunar_phase"] += delta
|
|
580
|
+
offsets["bottom_left"] += delta
|
|
581
|
+
self._vertical_offsets = offsets
|
|
582
|
+
|
|
583
|
+
def _apply_synastry_height_adjustment(
|
|
584
|
+
self,
|
|
585
|
+
*,
|
|
586
|
+
active_points_count: int,
|
|
587
|
+
offsets: dict[str, int],
|
|
588
|
+
minimum_height: int,
|
|
589
|
+
) -> None:
|
|
590
|
+
"""Specialised dynamic height handling for Synastry charts.
|
|
591
|
+
|
|
592
|
+
With the planet grids locked to a single column, every additional active
|
|
593
|
+
point extends multiple tables vertically (planets, houses, comparisons).
|
|
594
|
+
We therefore scale the height using the actual line spacing used by those
|
|
595
|
+
tables (≈14px) and keep the bottom anchored elements aligned.
|
|
596
|
+
"""
|
|
597
|
+
base_rows = 14 # Up to 16 active points fit without extra height
|
|
598
|
+
extra_rows = max(active_points_count - base_rows, 0)
|
|
599
|
+
|
|
600
|
+
synastry_row_height = 15
|
|
601
|
+
comparison_padding_per_row = 4 # Keeps house comparison grids within view.
|
|
602
|
+
extra_height = extra_rows * (synastry_row_height + comparison_padding_per_row)
|
|
603
|
+
|
|
604
|
+
self.height = max(self.height, minimum_height + extra_height)
|
|
605
|
+
|
|
606
|
+
delta_height = max(self.height - minimum_height, 0)
|
|
607
|
+
|
|
608
|
+
offsets["wheel"] += delta_height
|
|
609
|
+
offsets["aspect_grid"] += delta_height
|
|
610
|
+
offsets["aspect_list"] += delta_height
|
|
611
|
+
offsets["lunar_phase"] += delta_height
|
|
612
|
+
offsets["bottom_left"] += delta_height
|
|
613
|
+
|
|
614
|
+
row_height_ratio = synastry_row_height / max(self._ROW_HEIGHT, 1)
|
|
615
|
+
synastry_top_shift_factor = max(
|
|
616
|
+
self._TOP_SHIFT_FACTOR,
|
|
617
|
+
int(ceil(self._TOP_SHIFT_FACTOR * row_height_ratio)),
|
|
618
|
+
)
|
|
619
|
+
shift = min(extra_rows * synastry_top_shift_factor, self._MAX_TOP_SHIFT)
|
|
620
|
+
|
|
621
|
+
base_grid_padding = 36
|
|
622
|
+
grid_padding_per_row = 6
|
|
623
|
+
base_header_padding = 12
|
|
624
|
+
header_padding_per_row = 4
|
|
625
|
+
min_title_to_grid_gap = 36
|
|
626
|
+
|
|
627
|
+
grid_shift = shift + base_grid_padding + (extra_rows * grid_padding_per_row)
|
|
628
|
+
grid_shift = min(grid_shift, shift + self._MAX_TOP_SHIFT)
|
|
629
|
+
|
|
630
|
+
top_shift = (shift // 2) + base_header_padding + (extra_rows * header_padding_per_row)
|
|
631
|
+
|
|
632
|
+
max_allowed_shift = shift + self._MAX_TOP_SHIFT
|
|
633
|
+
missing_gap = min_title_to_grid_gap - (grid_shift - top_shift)
|
|
634
|
+
grid_shift = min(grid_shift + missing_gap, max_allowed_shift)
|
|
635
|
+
if grid_shift - top_shift < min_title_to_grid_gap:
|
|
636
|
+
top_shift = max(0, grid_shift - min_title_to_grid_gap)
|
|
637
|
+
|
|
638
|
+
offsets["grid"] += grid_shift
|
|
639
|
+
offsets["title"] += top_shift
|
|
640
|
+
offsets["elements"] += top_shift
|
|
641
|
+
offsets["qualities"] += top_shift
|
|
642
|
+
|
|
643
|
+
self._vertical_offsets = offsets
|
|
644
|
+
|
|
645
|
+
def _collect_subject_points(
|
|
646
|
+
self,
|
|
647
|
+
subject: Union[AstrologicalSubjectModel, CompositeSubjectModel, PlanetReturnModel],
|
|
648
|
+
point_attribute_names: list[str],
|
|
649
|
+
) -> list[KerykeionPointModel]:
|
|
650
|
+
"""Collect ordered active celestial points for a subject."""
|
|
651
|
+
|
|
652
|
+
collected: list[KerykeionPointModel] = []
|
|
653
|
+
|
|
654
|
+
for raw_name in point_attribute_names:
|
|
655
|
+
attr_name = raw_name if hasattr(subject, raw_name) else raw_name.lower()
|
|
656
|
+
point = getattr(subject, attr_name, None)
|
|
657
|
+
if point is None:
|
|
658
|
+
continue
|
|
659
|
+
collected.append(point)
|
|
660
|
+
|
|
661
|
+
return collected
|
|
662
|
+
|
|
455
663
|
def _dynamic_viewbox(self) -> str:
|
|
456
664
|
"""Return the viewBox string based on current width/height."""
|
|
457
665
|
return f"0 0 {int(self.width)} {int(self.height)}"
|
|
@@ -476,7 +684,7 @@ class ChartDrawer:
|
|
|
476
684
|
uses `x_indent=50`, `y_indent=250`, `box_size=14` and draws:
|
|
477
685
|
• a header row to the right of `x_indent`
|
|
478
686
|
• a left header column at `x_indent - box_size`
|
|
479
|
-
• an
|
|
687
|
+
• an NxN grid of cells above `y_indent`
|
|
480
688
|
|
|
481
689
|
- For Natal/Composite/SingleReturn charts, `draw_aspect_grid` uses
|
|
482
690
|
`x_start=50`, `y_start=250`, `box_size=14` and draws a triangular grid
|
|
@@ -534,21 +742,17 @@ class ChartDrawer:
|
|
|
534
742
|
extents.extend([main_planet_grid_right, main_houses_grid_right])
|
|
535
743
|
|
|
536
744
|
if self.chart_type in ("Natal", "Composite", "SingleReturnChart"):
|
|
537
|
-
# Triangular aspect grid at x_start=
|
|
538
|
-
aspect_grid_right =
|
|
745
|
+
# Triangular aspect grid at x_start=540, width ~ 14 * n_active
|
|
746
|
+
aspect_grid_right = 560 + 14 * n_active
|
|
539
747
|
extents.append(aspect_grid_right)
|
|
540
748
|
|
|
541
749
|
if self.chart_type in ("Transit", "Synastry", "DualReturnChart"):
|
|
542
750
|
# Double-chart aspects placement
|
|
543
751
|
if self.double_chart_aspect_grid_type == "list":
|
|
544
|
-
# Columnar list placed at translate(565,273), ~100-110px per column, 14 aspects per column
|
|
545
|
-
aspects_per_column = 14
|
|
546
752
|
total_aspects = len(self.aspects_list) if hasattr(self, "aspects_list") else 0
|
|
547
|
-
columns =
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
columns = min(columns, max_cols_cap)
|
|
551
|
-
aspect_list_right = 565 + (columns * 110)
|
|
753
|
+
columns = self._calculate_double_chart_aspect_columns(total_aspects, self.height)
|
|
754
|
+
columns = max(columns, 1)
|
|
755
|
+
aspect_list_right = 565 + (columns * self._ASPECT_LIST_COLUMN_WIDTH)
|
|
552
756
|
extents.append(aspect_list_right)
|
|
553
757
|
else:
|
|
554
758
|
# Grid table placed with x_indent ~550, width ~ 14px per cell across n_active+1
|
|
@@ -563,6 +767,9 @@ class ChartDrawer:
|
|
|
563
767
|
# Secondary houses grid default x ~ 1015
|
|
564
768
|
secondary_houses_grid_right = 1015 + 120
|
|
565
769
|
extents.append(secondary_houses_grid_right)
|
|
770
|
+
first_house_comparison_grid_right = 1090 + 180
|
|
771
|
+
second_house_comparison_grid_right = 1290 + 180
|
|
772
|
+
extents.extend([first_house_comparison_grid_right, second_house_comparison_grid_right])
|
|
566
773
|
|
|
567
774
|
if self.chart_type == "Transit":
|
|
568
775
|
# House comparison grid at x ~ 1030
|
|
@@ -577,6 +784,84 @@ class ChartDrawer:
|
|
|
577
784
|
# Conservative safety padding
|
|
578
785
|
return int(max(extents) + self._padding)
|
|
579
786
|
|
|
787
|
+
def _calculate_double_chart_aspect_columns(
|
|
788
|
+
self,
|
|
789
|
+
total_aspects: int,
|
|
790
|
+
chart_height: Optional[int],
|
|
791
|
+
) -> int:
|
|
792
|
+
"""Return how many columns the double-chart aspect list needs.
|
|
793
|
+
|
|
794
|
+
The first 11 columns follow the legacy 14-rows layout. Starting from the
|
|
795
|
+
12th column we can fit more rows thanks to the taller chart height that
|
|
796
|
+
gets computed earlier, so we re-use the same capacity as the SVG builder.
|
|
797
|
+
"""
|
|
798
|
+
if total_aspects <= 0:
|
|
799
|
+
return 0
|
|
800
|
+
|
|
801
|
+
per_column = self._ASPECT_LIST_ASPECTS_PER_COLUMN
|
|
802
|
+
extended_start = 10 # 0-based index where tall columns begin
|
|
803
|
+
base_capacity = per_column * extended_start
|
|
804
|
+
|
|
805
|
+
full_height_capacity = self._calculate_full_height_column_capacity(chart_height)
|
|
806
|
+
|
|
807
|
+
if total_aspects <= base_capacity:
|
|
808
|
+
return ceil(total_aspects / per_column)
|
|
809
|
+
|
|
810
|
+
remaining = max(total_aspects - base_capacity, 0)
|
|
811
|
+
extra_columns = ceil(remaining / full_height_capacity) if remaining > 0 else 0
|
|
812
|
+
return extended_start + extra_columns
|
|
813
|
+
|
|
814
|
+
def _calculate_full_height_column_capacity(
|
|
815
|
+
self,
|
|
816
|
+
chart_height: Optional[int],
|
|
817
|
+
) -> int:
|
|
818
|
+
"""Compute the row capacity for columns that use the tall layout."""
|
|
819
|
+
per_column = self._ASPECT_LIST_ASPECTS_PER_COLUMN
|
|
820
|
+
|
|
821
|
+
if chart_height is None:
|
|
822
|
+
return per_column
|
|
823
|
+
|
|
824
|
+
translate_y = 273
|
|
825
|
+
bottom_padding = 40
|
|
826
|
+
title_clearance = 18
|
|
827
|
+
line_height = 14
|
|
828
|
+
baseline_index = per_column - 1
|
|
829
|
+
top_limit_index = ceil((-translate_y + title_clearance) / line_height)
|
|
830
|
+
max_capacity_by_top = baseline_index - top_limit_index + 1
|
|
831
|
+
|
|
832
|
+
available_height = max(chart_height - translate_y - bottom_padding, line_height)
|
|
833
|
+
allowed_capacity = max(per_column, int(available_height // line_height))
|
|
834
|
+
|
|
835
|
+
# Respect both the physical height of the SVG and the visual limit
|
|
836
|
+
# imposed by the title area.
|
|
837
|
+
return max(per_column, min(allowed_capacity, max_capacity_by_top))
|
|
838
|
+
|
|
839
|
+
def _minimum_width_for_chart_type(self) -> int:
|
|
840
|
+
"""Baseline width to avoid compressing core groups too tightly."""
|
|
841
|
+
wheel_right = 100 + (2 * self.main_radius)
|
|
842
|
+
baseline = wheel_right + self._padding
|
|
843
|
+
|
|
844
|
+
if self.chart_type in ("Natal", "Composite", "SingleReturnChart"):
|
|
845
|
+
return max(int(baseline), self._DEFAULT_NATAL_WIDTH)
|
|
846
|
+
if self.chart_type == "Synastry":
|
|
847
|
+
return max(int(baseline), self._DEFAULT_SYNASTRY_WIDTH // 2)
|
|
848
|
+
if self.chart_type == "DualReturnChart":
|
|
849
|
+
return max(int(baseline), self._DEFAULT_ULTRA_WIDE_WIDTH // 2)
|
|
850
|
+
if self.chart_type == "Transit":
|
|
851
|
+
return max(int(baseline), self._DEFAULT_FULL_WIDTH // 2)
|
|
852
|
+
return max(int(baseline), self._DEFAULT_NATAL_WIDTH)
|
|
853
|
+
|
|
854
|
+
def _update_width_to_content(self) -> None:
|
|
855
|
+
"""Resize the chart width so the farthest element fits comfortably."""
|
|
856
|
+
try:
|
|
857
|
+
required_width = self._estimate_required_width_full()
|
|
858
|
+
except Exception as e:
|
|
859
|
+
logging.debug(f"Auto-size width calculation failed: {e}")
|
|
860
|
+
return
|
|
861
|
+
|
|
862
|
+
minimum_width = self._minimum_width_for_chart_type()
|
|
863
|
+
self.width = max(required_width, minimum_width)
|
|
864
|
+
|
|
580
865
|
def _get_location_info(self) -> tuple[str, float, float]:
|
|
581
866
|
"""
|
|
582
867
|
Determine location information based on chart type and subjects.
|
|
@@ -624,17 +909,31 @@ class ChartDrawer:
|
|
|
624
909
|
with open(theme_dir / f"{theme}.css", "r") as f:
|
|
625
910
|
self.color_style_tag = f.read()
|
|
626
911
|
|
|
627
|
-
def
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
912
|
+
def _load_language_settings(
|
|
913
|
+
self,
|
|
914
|
+
language_pack: Optional[Mapping[str, Any]],
|
|
915
|
+
) -> None:
|
|
916
|
+
"""Resolve language models for the requested chart language."""
|
|
917
|
+
overrides = {self.chart_language: dict(language_pack)} if language_pack else None
|
|
918
|
+
languages = load_language_settings(overrides)
|
|
919
|
+
|
|
920
|
+
fallback_data = languages.get("EN")
|
|
921
|
+
if fallback_data is None:
|
|
922
|
+
raise KerykeionException("English translations are missing from LANGUAGE_SETTINGS.")
|
|
923
|
+
|
|
924
|
+
base_data = languages.get(self.chart_language, fallback_data)
|
|
925
|
+
selected_model = KerykeionLanguageModel(**base_data)
|
|
926
|
+
fallback_model = KerykeionLanguageModel(**fallback_data)
|
|
927
|
+
|
|
928
|
+
self._fallback_language_model = fallback_model
|
|
929
|
+
self._language_model = selected_model
|
|
930
|
+
self._fallback_language_dict = fallback_model.model_dump()
|
|
931
|
+
self._language_dict = selected_model.model_dump()
|
|
932
|
+
self.language_settings = self._language_dict # Backward compatibility
|
|
933
|
+
|
|
934
|
+
def _translate(self, key: str, default: Any) -> Any:
|
|
935
|
+
fallback_value = get_translations(key, default, language_dict=self._fallback_language_dict)
|
|
936
|
+
return get_translations(key, fallback_value, language_dict=self._language_dict)
|
|
638
937
|
|
|
639
938
|
def _draw_zodiac_circle_slices(self, r):
|
|
640
939
|
"""
|
|
@@ -711,7 +1010,7 @@ class ChartDrawer:
|
|
|
711
1010
|
)
|
|
712
1011
|
return out
|
|
713
1012
|
|
|
714
|
-
def _truncate_name(self, name: str, max_length: int = 50) -> str:
|
|
1013
|
+
def _truncate_name(self, name: str, max_length: int = 50, ellipsis_symbol: str = "…", truncate_at_space: bool = False) -> str:
|
|
715
1014
|
"""
|
|
716
1015
|
Truncate a name if it's too long, preserving readability.
|
|
717
1016
|
|
|
@@ -722,9 +1021,13 @@ class ChartDrawer:
|
|
|
722
1021
|
Returns:
|
|
723
1022
|
str: Truncated name with ellipsis if needed
|
|
724
1023
|
"""
|
|
1024
|
+
if truncate_at_space:
|
|
1025
|
+
name = name.split(" ")[0]
|
|
1026
|
+
|
|
725
1027
|
if len(name) <= max_length:
|
|
726
1028
|
return name
|
|
727
|
-
|
|
1029
|
+
|
|
1030
|
+
return name[:max_length-1] + ellipsis_symbol
|
|
728
1031
|
|
|
729
1032
|
def _get_chart_title(self) -> str:
|
|
730
1033
|
"""
|
|
@@ -742,52 +1045,49 @@ class ChartDrawer:
|
|
|
742
1045
|
|
|
743
1046
|
# Generate default title based on chart type
|
|
744
1047
|
if self.chart_type == "Natal":
|
|
745
|
-
natal_label = self.
|
|
1048
|
+
natal_label = self._translate("birth_chart", "Natal")
|
|
746
1049
|
truncated_name = self._truncate_name(self.first_obj.name)
|
|
747
1050
|
return f'{truncated_name} - {natal_label}'
|
|
748
1051
|
|
|
749
1052
|
elif self.chart_type == "Composite":
|
|
750
|
-
composite_label = self.
|
|
751
|
-
and_word = self.
|
|
1053
|
+
composite_label = self._translate("composite_chart", "Composite")
|
|
1054
|
+
and_word = self._translate("and_word", "&")
|
|
752
1055
|
name1 = self._truncate_name(self.first_obj.first_subject.name) # type: ignore
|
|
753
1056
|
name2 = self._truncate_name(self.first_obj.second_subject.name) # type: ignore
|
|
754
1057
|
return f"{composite_label}: {name1} {and_word} {name2}"
|
|
755
1058
|
|
|
756
1059
|
elif self.chart_type == "Transit":
|
|
757
|
-
transit_label = self.
|
|
758
|
-
from datetime import datetime
|
|
1060
|
+
transit_label = self._translate("transits", "Transits")
|
|
759
1061
|
date_obj = datetime.fromisoformat(self.second_obj.iso_formatted_local_datetime) # type: ignore
|
|
760
1062
|
date_str = date_obj.strftime("%d/%m/%y")
|
|
761
1063
|
truncated_name = self._truncate_name(self.first_obj.name)
|
|
762
1064
|
return f"{truncated_name} - {transit_label} {date_str}"
|
|
763
1065
|
|
|
764
1066
|
elif self.chart_type == "Synastry":
|
|
765
|
-
synastry_label = self.
|
|
766
|
-
and_word = self.
|
|
1067
|
+
synastry_label = self._translate("synastry_chart", "Synastry")
|
|
1068
|
+
and_word = self._translate("and_word", "&")
|
|
767
1069
|
name1 = self._truncate_name(self.first_obj.name)
|
|
768
1070
|
name2 = self._truncate_name(self.second_obj.name) # type: ignore
|
|
769
1071
|
return f"{synastry_label}: {name1} {and_word} {name2}"
|
|
770
1072
|
|
|
771
1073
|
elif self.chart_type == "DualReturnChart":
|
|
772
|
-
from datetime import datetime
|
|
773
1074
|
year = datetime.fromisoformat(self.second_obj.iso_formatted_local_datetime).year # type: ignore
|
|
774
1075
|
truncated_name = self._truncate_name(self.first_obj.name)
|
|
775
1076
|
if self.second_obj is not None and isinstance(self.second_obj, PlanetReturnModel) and self.second_obj.return_type == "Solar":
|
|
776
|
-
solar_label = self.
|
|
1077
|
+
solar_label = self._translate("solar_return", "Solar")
|
|
777
1078
|
return f"{truncated_name} - {solar_label} {year}"
|
|
778
1079
|
else:
|
|
779
|
-
lunar_label = self.
|
|
1080
|
+
lunar_label = self._translate("lunar_return", "Lunar")
|
|
780
1081
|
return f"{truncated_name} - {lunar_label} {year}"
|
|
781
1082
|
|
|
782
1083
|
elif self.chart_type == "SingleReturnChart":
|
|
783
|
-
from datetime import datetime
|
|
784
1084
|
year = datetime.fromisoformat(self.first_obj.iso_formatted_local_datetime).year # type: ignore
|
|
785
1085
|
truncated_name = self._truncate_name(self.first_obj.name)
|
|
786
1086
|
if isinstance(self.first_obj, PlanetReturnModel) and self.first_obj.return_type == "Solar":
|
|
787
|
-
solar_label = self.
|
|
1087
|
+
solar_label = self._translate("solar_return", "Solar")
|
|
788
1088
|
return f"{truncated_name} - {solar_label} {year}"
|
|
789
1089
|
else:
|
|
790
|
-
lunar_label = self.
|
|
1090
|
+
lunar_label = self._translate("lunar_return", "Lunar")
|
|
791
1091
|
return f"{truncated_name} - {lunar_label} {year}"
|
|
792
1092
|
|
|
793
1093
|
# Fallback for unknown chart types
|
|
@@ -815,6 +1115,17 @@ class ChartDrawer:
|
|
|
815
1115
|
template_dict["chart_height"] = self.height
|
|
816
1116
|
template_dict["chart_width"] = self.width
|
|
817
1117
|
|
|
1118
|
+
offsets = self._vertical_offsets
|
|
1119
|
+
template_dict["full_wheel_translate_y"] = offsets["wheel"]
|
|
1120
|
+
template_dict["houses_and_planets_translate_y"] = offsets["grid"]
|
|
1121
|
+
template_dict["aspect_grid_translate_y"] = offsets["aspect_grid"]
|
|
1122
|
+
template_dict["aspect_list_translate_y"] = offsets["aspect_list"]
|
|
1123
|
+
template_dict["title_translate_y"] = offsets["title"]
|
|
1124
|
+
template_dict["elements_translate_y"] = offsets["elements"]
|
|
1125
|
+
template_dict["qualities_translate_y"] = offsets["qualities"]
|
|
1126
|
+
template_dict["lunar_phase_translate_y"] = offsets["lunar_phase"]
|
|
1127
|
+
template_dict["bottom_left_translate_y"] = offsets["bottom_left"]
|
|
1128
|
+
|
|
818
1129
|
# Set paper colors
|
|
819
1130
|
template_dict["paper_color_0"] = self.chart_colors_settings["paper_0"]
|
|
820
1131
|
|
|
@@ -855,11 +1166,11 @@ class ChartDrawer:
|
|
|
855
1166
|
water_percentage = element_percentages["water"]
|
|
856
1167
|
|
|
857
1168
|
# Element Percentages
|
|
858
|
-
template_dict["elements_string"] = f"{self.
|
|
859
|
-
template_dict["fire_string"] = f"{self.
|
|
860
|
-
template_dict["earth_string"] = f"{self.
|
|
861
|
-
template_dict["air_string"] = f"{self.
|
|
862
|
-
template_dict["water_string"] = f"{self.
|
|
1169
|
+
template_dict["elements_string"] = f"{self._translate('elements', 'Elements')}:"
|
|
1170
|
+
template_dict["fire_string"] = f"{self._translate('fire', 'Fire')} {fire_percentage}%"
|
|
1171
|
+
template_dict["earth_string"] = f"{self._translate('earth', 'Earth')} {earth_percentage}%"
|
|
1172
|
+
template_dict["air_string"] = f"{self._translate('air', 'Air')} {air_percentage}%"
|
|
1173
|
+
template_dict["water_string"] = f"{self._translate('water', 'Water')} {water_percentage}%"
|
|
863
1174
|
|
|
864
1175
|
|
|
865
1176
|
# Qualities Percentages
|
|
@@ -870,10 +1181,10 @@ class ChartDrawer:
|
|
|
870
1181
|
fixed_percentage = quality_percentages["fixed"]
|
|
871
1182
|
mutable_percentage = quality_percentages["mutable"]
|
|
872
1183
|
|
|
873
|
-
template_dict["qualities_string"] = f"{self.
|
|
874
|
-
template_dict["cardinal_string"] = f"{self.
|
|
875
|
-
template_dict["fixed_string"] = f"{self.
|
|
876
|
-
template_dict["mutable_string"] = f"{self.
|
|
1184
|
+
template_dict["qualities_string"] = f"{self._translate('qualities', 'Qualities')}:"
|
|
1185
|
+
template_dict["cardinal_string"] = f"{self._translate('cardinal', 'Cardinal')} {cardinal_percentage}%"
|
|
1186
|
+
template_dict["fixed_string"] = f"{self._translate('fixed', 'Fixed')} {fixed_percentage}%"
|
|
1187
|
+
template_dict["mutable_string"] = f"{self._translate('mutable', 'Mutable')} {mutable_percentage}%"
|
|
877
1188
|
|
|
878
1189
|
# Get houses list for main subject
|
|
879
1190
|
first_subject_houses_list = get_houses_list(self.first_obj)
|
|
@@ -933,37 +1244,60 @@ class ChartDrawer:
|
|
|
933
1244
|
template_dict["makeAspects"] = self._draw_all_aspects_lines(self.main_radius, self.main_radius - self.third_circle_radius)
|
|
934
1245
|
|
|
935
1246
|
# Top left section
|
|
936
|
-
latitude_string = convert_latitude_coordinate_to_string(
|
|
937
|
-
|
|
1247
|
+
latitude_string = convert_latitude_coordinate_to_string(
|
|
1248
|
+
self.geolat,
|
|
1249
|
+
self._translate("north", "North"),
|
|
1250
|
+
self._translate("south", "South"),
|
|
1251
|
+
)
|
|
1252
|
+
longitude_string = convert_longitude_coordinate_to_string(
|
|
1253
|
+
self.geolon,
|
|
1254
|
+
self._translate("east", "East"),
|
|
1255
|
+
self._translate("west", "West"),
|
|
1256
|
+
)
|
|
938
1257
|
|
|
939
|
-
template_dict["top_left_0"] = f'{self.
|
|
1258
|
+
template_dict["top_left_0"] = f'{self._translate("location", "Location")}:'
|
|
940
1259
|
template_dict["top_left_1"] = f"{self.first_obj.city}, {self.first_obj.nation}"
|
|
941
|
-
template_dict["top_left_2"] = f"{self.
|
|
942
|
-
template_dict["top_left_3"] = f"{self.
|
|
1260
|
+
template_dict["top_left_2"] = f"{self._translate('latitude', 'Latitude')}: {latitude_string}"
|
|
1261
|
+
template_dict["top_left_3"] = f"{self._translate('longitude', 'Longitude')}: {longitude_string}"
|
|
943
1262
|
template_dict["top_left_4"] = format_datetime_with_timezone(self.first_obj.iso_formatted_local_datetime) # type: ignore
|
|
944
|
-
localized_weekday = self.
|
|
945
|
-
|
|
1263
|
+
localized_weekday = self._translate(
|
|
1264
|
+
f"weekdays.{self.first_obj.day_of_week}",
|
|
1265
|
+
self.first_obj.day_of_week, # type: ignore[arg-type]
|
|
1266
|
+
)
|
|
1267
|
+
template_dict["top_left_5"] = f"{self._translate('day_of_week', 'Day of Week')}: {localized_weekday}" # type: ignore
|
|
946
1268
|
|
|
947
1269
|
# Bottom left section
|
|
948
1270
|
if self.first_obj.zodiac_type == "Tropic":
|
|
949
|
-
zodiac_info = f"{self.
|
|
1271
|
+
zodiac_info = f"{self._translate('zodiac', 'Zodiac')}: {self._translate('tropical', 'Tropical')}"
|
|
950
1272
|
else:
|
|
951
1273
|
mode_const = "SIDM_" + self.first_obj.sidereal_mode # type: ignore
|
|
952
1274
|
mode_name = swe.get_ayanamsa_name(getattr(swe, mode_const))
|
|
953
|
-
zodiac_info = f"{self.
|
|
1275
|
+
zodiac_info = f"{self._translate('ayanamsa', 'Ayanamsa')}: {mode_name}"
|
|
954
1276
|
|
|
955
1277
|
template_dict["bottom_left_0"] = zodiac_info
|
|
956
|
-
template_dict["bottom_left_1"] =
|
|
1278
|
+
template_dict["bottom_left_1"] = (
|
|
1279
|
+
f"{self._translate('domification', 'Domification')}: "
|
|
1280
|
+
f"{self._translate('houses_system_' + self.first_obj.houses_system_identifier, self.first_obj.houses_system_name)}"
|
|
1281
|
+
)
|
|
957
1282
|
|
|
958
1283
|
# Lunar phase information (optional)
|
|
959
1284
|
if self.first_obj.lunar_phase is not None:
|
|
960
|
-
template_dict["bottom_left_2"] =
|
|
961
|
-
|
|
1285
|
+
template_dict["bottom_left_2"] = (
|
|
1286
|
+
f'{self._translate("lunation_day", "Lunation Day")}: '
|
|
1287
|
+
f'{self.first_obj.lunar_phase.get("moon_phase", "")}'
|
|
1288
|
+
)
|
|
1289
|
+
template_dict["bottom_left_3"] = (
|
|
1290
|
+
f'{self._translate("lunar_phase", "Lunar Phase")}: '
|
|
1291
|
+
f'{self._translate(self.first_obj.lunar_phase.moon_phase_name.lower().replace(" ", "_"), self.first_obj.lunar_phase.moon_phase_name)}'
|
|
1292
|
+
)
|
|
962
1293
|
else:
|
|
963
1294
|
template_dict["bottom_left_2"] = ""
|
|
964
1295
|
template_dict["bottom_left_3"] = ""
|
|
965
1296
|
|
|
966
|
-
template_dict["bottom_left_4"] =
|
|
1297
|
+
template_dict["bottom_left_4"] = (
|
|
1298
|
+
f'{self._translate("perspective_type", "Perspective")}: '
|
|
1299
|
+
f'{self._translate(self.first_obj.perspective_type.lower().replace(" ", "_"), self.first_obj.perspective_type)}'
|
|
1300
|
+
)
|
|
967
1301
|
|
|
968
1302
|
# Moon phase section calculations
|
|
969
1303
|
if self.first_obj.lunar_phase is not None:
|
|
@@ -975,7 +1309,7 @@ class ChartDrawer:
|
|
|
975
1309
|
template_dict["makeMainHousesGrid"] = draw_main_house_grid(
|
|
976
1310
|
main_subject_houses_list=first_subject_houses_list,
|
|
977
1311
|
text_color=self.chart_colors_settings["paper_0"],
|
|
978
|
-
house_cusp_generale_name_label=self.
|
|
1312
|
+
house_cusp_generale_name_label=self._translate("cusp", "Cusp"),
|
|
979
1313
|
)
|
|
980
1314
|
template_dict["makeSecondaryHousesGrid"] = ""
|
|
981
1315
|
|
|
@@ -1005,12 +1339,12 @@ class ChartDrawer:
|
|
|
1005
1339
|
)
|
|
1006
1340
|
|
|
1007
1341
|
template_dict["makeMainPlanetGrid"] = draw_main_planet_grid(
|
|
1008
|
-
planets_and_houses_grid_title=self.
|
|
1342
|
+
planets_and_houses_grid_title=self._translate("planets_and_house", "Points for"),
|
|
1009
1343
|
subject_name=self.first_obj.name,
|
|
1010
1344
|
available_kerykeion_celestial_points=self.available_kerykeion_celestial_points,
|
|
1011
1345
|
chart_type=self.chart_type,
|
|
1012
1346
|
text_color=self.chart_colors_settings["paper_0"],
|
|
1013
|
-
celestial_point_language=self.
|
|
1347
|
+
celestial_point_language=self._language_model.celestial_points,
|
|
1014
1348
|
)
|
|
1015
1349
|
template_dict["makeSecondaryPlanetGrid"] = ""
|
|
1016
1350
|
template_dict["makeHouseComparisonGrid"] = ""
|
|
@@ -1066,25 +1400,25 @@ class ChartDrawer:
|
|
|
1066
1400
|
# First subject
|
|
1067
1401
|
latitude = convert_latitude_coordinate_to_string(
|
|
1068
1402
|
self.first_obj.first_subject.lat, # type: ignore
|
|
1069
|
-
self.
|
|
1070
|
-
self.
|
|
1403
|
+
self._translate("north_letter", "N"),
|
|
1404
|
+
self._translate("south_letter", "S"),
|
|
1071
1405
|
)
|
|
1072
1406
|
longitude = convert_longitude_coordinate_to_string(
|
|
1073
1407
|
self.first_obj.first_subject.lng, # type: ignore
|
|
1074
|
-
self.
|
|
1075
|
-
self.
|
|
1408
|
+
self._translate("east_letter", "E"),
|
|
1409
|
+
self._translate("west_letter", "W"),
|
|
1076
1410
|
)
|
|
1077
1411
|
|
|
1078
1412
|
# Second subject
|
|
1079
1413
|
latitude_string = convert_latitude_coordinate_to_string(
|
|
1080
1414
|
self.first_obj.second_subject.lat, # type: ignore
|
|
1081
|
-
self.
|
|
1082
|
-
self.
|
|
1415
|
+
self._translate("north_letter", "N"),
|
|
1416
|
+
self._translate("south_letter", "S"),
|
|
1083
1417
|
)
|
|
1084
1418
|
longitude_string = convert_longitude_coordinate_to_string(
|
|
1085
1419
|
self.first_obj.second_subject.lng, # type: ignore
|
|
1086
|
-
self.
|
|
1087
|
-
self.
|
|
1420
|
+
self._translate("east_letter", "E"),
|
|
1421
|
+
self._translate("west_letter", "W"),
|
|
1088
1422
|
)
|
|
1089
1423
|
|
|
1090
1424
|
template_dict["top_left_0"] = f"{self.first_obj.first_subject.name}" # type: ignore
|
|
@@ -1096,16 +1430,16 @@ class ChartDrawer:
|
|
|
1096
1430
|
|
|
1097
1431
|
# Bottom left section
|
|
1098
1432
|
if self.first_obj.zodiac_type == "Tropic":
|
|
1099
|
-
zodiac_info = f"{self.
|
|
1433
|
+
zodiac_info = f"{self._translate('zodiac', 'Zodiac')}: {self._translate('tropical', 'Tropical')}"
|
|
1100
1434
|
else:
|
|
1101
1435
|
mode_const = "SIDM_" + self.first_obj.sidereal_mode # type: ignore
|
|
1102
1436
|
mode_name = swe.get_ayanamsa_name(getattr(swe, mode_const))
|
|
1103
|
-
zodiac_info = f"{self.
|
|
1437
|
+
zodiac_info = f"{self._translate('ayanamsa', 'Ayanamsa')}: {mode_name}"
|
|
1104
1438
|
|
|
1105
1439
|
template_dict["bottom_left_0"] = zodiac_info
|
|
1106
|
-
template_dict["bottom_left_1"] = f"{self.
|
|
1107
|
-
template_dict["bottom_left_2"] = f'{self.
|
|
1108
|
-
template_dict["bottom_left_3"] = f'{self.
|
|
1440
|
+
template_dict["bottom_left_1"] = f"{self._translate('houses_system_' + self.first_obj.houses_system_identifier, self.first_obj.houses_system_name)} {self._translate('houses', 'Houses')}"
|
|
1441
|
+
template_dict["bottom_left_2"] = f'{self._translate("perspective_type", "Perspective")}: {self.first_obj.first_subject.perspective_type}' # type: ignore
|
|
1442
|
+
template_dict["bottom_left_3"] = f'{self._translate("composite_chart", "Composite Chart")} - {self._translate("midpoints", "Midpoints")}'
|
|
1109
1443
|
template_dict["bottom_left_4"] = ""
|
|
1110
1444
|
|
|
1111
1445
|
# Moon phase section calculations
|
|
@@ -1118,7 +1452,7 @@ class ChartDrawer:
|
|
|
1118
1452
|
template_dict["makeMainHousesGrid"] = draw_main_house_grid(
|
|
1119
1453
|
main_subject_houses_list=first_subject_houses_list,
|
|
1120
1454
|
text_color=self.chart_colors_settings["paper_0"],
|
|
1121
|
-
house_cusp_generale_name_label=self.
|
|
1455
|
+
house_cusp_generale_name_label=self._translate("cusp", "Cusp"),
|
|
1122
1456
|
)
|
|
1123
1457
|
template_dict["makeSecondaryHousesGrid"] = ""
|
|
1124
1458
|
|
|
@@ -1147,15 +1481,19 @@ class ChartDrawer:
|
|
|
1147
1481
|
external_view=self.external_view,
|
|
1148
1482
|
)
|
|
1149
1483
|
|
|
1150
|
-
subject_name =
|
|
1484
|
+
subject_name = (
|
|
1485
|
+
f"{self.first_obj.first_subject.name}"
|
|
1486
|
+
f" {self._translate('and_word', '&')} "
|
|
1487
|
+
f"{self.first_obj.second_subject.name}"
|
|
1488
|
+
) # type: ignore
|
|
1151
1489
|
|
|
1152
1490
|
template_dict["makeMainPlanetGrid"] = draw_main_planet_grid(
|
|
1153
|
-
planets_and_houses_grid_title=self.
|
|
1491
|
+
planets_and_houses_grid_title=self._translate("planets_and_house", "Points for"),
|
|
1154
1492
|
subject_name=subject_name,
|
|
1155
1493
|
available_kerykeion_celestial_points=self.available_kerykeion_celestial_points,
|
|
1156
1494
|
chart_type=self.chart_type,
|
|
1157
1495
|
text_color=self.chart_colors_settings["paper_0"],
|
|
1158
|
-
celestial_point_language=self.
|
|
1496
|
+
celestial_point_language=self._language_model.celestial_points,
|
|
1159
1497
|
)
|
|
1160
1498
|
template_dict["makeSecondaryPlanetGrid"] = ""
|
|
1161
1499
|
template_dict["makeHouseComparisonGrid"] = ""
|
|
@@ -1214,52 +1552,58 @@ class ChartDrawer:
|
|
|
1214
1552
|
|
|
1215
1553
|
# Aspects
|
|
1216
1554
|
if self.double_chart_aspect_grid_type == "list":
|
|
1217
|
-
title = f'{self.first_obj.name} - {self.
|
|
1555
|
+
title = f'{self.first_obj.name} - {self._translate("transit_aspects", "Transit Aspects")}'
|
|
1218
1556
|
template_dict["makeAspectGrid"] = ""
|
|
1219
|
-
template_dict["makeDoubleChartAspectList"] = draw_transit_aspect_list(
|
|
1557
|
+
template_dict["makeDoubleChartAspectList"] = draw_transit_aspect_list(
|
|
1558
|
+
title,
|
|
1559
|
+
self.aspects_list,
|
|
1560
|
+
self.planets_settings,
|
|
1561
|
+
self.aspects_settings,
|
|
1562
|
+
chart_height=self.height,
|
|
1563
|
+
) # type: ignore[arg-type]
|
|
1220
1564
|
else:
|
|
1221
1565
|
template_dict["makeAspectGrid"] = ""
|
|
1222
1566
|
template_dict["makeDoubleChartAspectList"] = draw_transit_aspect_grid(
|
|
1223
1567
|
self.chart_colors_settings["paper_0"],
|
|
1224
1568
|
self.available_planets_setting,
|
|
1225
1569
|
self.aspects_list,
|
|
1226
|
-
|
|
1227
|
-
|
|
1570
|
+
600,
|
|
1571
|
+
520,
|
|
1228
1572
|
)
|
|
1229
1573
|
|
|
1230
1574
|
template_dict["makeAspects"] = self._draw_all_transit_aspects_lines(self.main_radius, self.main_radius - 160)
|
|
1231
1575
|
|
|
1232
1576
|
# Top left section
|
|
1233
|
-
latitude_string = convert_latitude_coordinate_to_string(self.geolat, self.
|
|
1234
|
-
longitude_string = convert_longitude_coordinate_to_string(self.geolon, self.
|
|
1577
|
+
latitude_string = convert_latitude_coordinate_to_string(self.geolat, self._translate("north", "North"), self._translate("south", "South"))
|
|
1578
|
+
longitude_string = convert_longitude_coordinate_to_string(self.geolon, self._translate("east", "East"), self._translate("west", "West"))
|
|
1235
1579
|
|
|
1236
|
-
template_dict["top_left_0"] =
|
|
1580
|
+
template_dict["top_left_0"] = f"{self.first_obj.name}"
|
|
1237
1581
|
template_dict["top_left_1"] = f"{format_location_string(self.first_obj.city)}, {self.first_obj.nation}" # type: ignore
|
|
1238
1582
|
template_dict["top_left_2"] = format_datetime_with_timezone(self.first_obj.iso_formatted_local_datetime) # type: ignore
|
|
1239
|
-
template_dict["top_left_3"] = f"{self.
|
|
1240
|
-
template_dict["top_left_4"] = f"{self.
|
|
1241
|
-
template_dict["top_left_5"] = ""#f"{self.
|
|
1583
|
+
template_dict["top_left_3"] = f"{self._translate('latitude', 'Latitude')}: {latitude_string}"
|
|
1584
|
+
template_dict["top_left_4"] = f"{self._translate('longitude', 'Longitude')}: {longitude_string}"
|
|
1585
|
+
template_dict["top_left_5"] = ""#f"{self._translate('type', 'Type')}: {self._translate(self.chart_type, self.chart_type)}"
|
|
1242
1586
|
|
|
1243
1587
|
# Bottom left section
|
|
1244
1588
|
if self.first_obj.zodiac_type == "Tropic":
|
|
1245
|
-
zodiac_info = f"{self.
|
|
1589
|
+
zodiac_info = f"{self._translate('zodiac', 'Zodiac')}: {self._translate('tropical', 'Tropical')}"
|
|
1246
1590
|
else:
|
|
1247
1591
|
mode_const = "SIDM_" + self.first_obj.sidereal_mode # type: ignore
|
|
1248
1592
|
mode_name = swe.get_ayanamsa_name(getattr(swe, mode_const))
|
|
1249
|
-
zodiac_info = f"{self.
|
|
1593
|
+
zodiac_info = f"{self._translate('ayanamsa', 'Ayanamsa')}: {mode_name}"
|
|
1250
1594
|
|
|
1251
1595
|
template_dict["bottom_left_0"] = zodiac_info
|
|
1252
|
-
template_dict["bottom_left_1"] = f"{self.
|
|
1596
|
+
template_dict["bottom_left_1"] = f"{self._translate('domification', 'Domification')}: {self._translate('houses_system_' + self.first_obj.houses_system_identifier, self.first_obj.houses_system_name)}"
|
|
1253
1597
|
|
|
1254
1598
|
# Lunar phase information from second object (Transit) (optional)
|
|
1255
1599
|
if self.second_obj is not None and hasattr(self.second_obj, 'lunar_phase') and self.second_obj.lunar_phase is not None:
|
|
1256
|
-
template_dict["bottom_left_2"] = f'{self.
|
|
1257
|
-
template_dict["bottom_left_3"] = f'{self.
|
|
1600
|
+
template_dict["bottom_left_2"] = f'{self._translate("lunation_day", "Lunation Day")}: {self.second_obj.lunar_phase.get("moon_phase", "")}' # type: ignore
|
|
1601
|
+
template_dict["bottom_left_3"] = f'{self._translate("lunar_phase", "Lunar Phase")}: {self._translate(self.second_obj.lunar_phase.moon_phase_name.lower().replace(" ", "_"), self.second_obj.lunar_phase.moon_phase_name)}'
|
|
1258
1602
|
else:
|
|
1259
1603
|
template_dict["bottom_left_2"] = ""
|
|
1260
1604
|
template_dict["bottom_left_3"] = ""
|
|
1261
1605
|
|
|
1262
|
-
template_dict["bottom_left_4"] = f'{self.
|
|
1606
|
+
template_dict["bottom_left_4"] = f'{self._translate("perspective_type", "Perspective")}: {self._translate(self.second_obj.perspective_type.lower().replace(" ", "_"), self.second_obj.perspective_type)}' # type: ignore
|
|
1263
1607
|
|
|
1264
1608
|
# Moon phase section calculations - use first_obj for visualization
|
|
1265
1609
|
if self.first_obj.lunar_phase is not None:
|
|
@@ -1271,12 +1615,12 @@ class ChartDrawer:
|
|
|
1271
1615
|
template_dict["makeMainHousesGrid"] = draw_main_house_grid(
|
|
1272
1616
|
main_subject_houses_list=first_subject_houses_list,
|
|
1273
1617
|
text_color=self.chart_colors_settings["paper_0"],
|
|
1274
|
-
house_cusp_generale_name_label=self.
|
|
1618
|
+
house_cusp_generale_name_label=self._translate("cusp", "Cusp"),
|
|
1275
1619
|
)
|
|
1276
1620
|
# template_dict["makeSecondaryHousesGrid"] = draw_secondary_house_grid(
|
|
1277
1621
|
# secondary_subject_houses_list=second_subject_houses_list,
|
|
1278
1622
|
# text_color=self.chart_colors_settings["paper_0"],
|
|
1279
|
-
# house_cusp_generale_name_label=self.
|
|
1623
|
+
# house_cusp_generale_name_label=self._translate("cusp", "Cusp"),
|
|
1280
1624
|
# )
|
|
1281
1625
|
template_dict["makeSecondaryHousesGrid"] = ""
|
|
1282
1626
|
|
|
@@ -1309,15 +1653,17 @@ class ChartDrawer:
|
|
|
1309
1653
|
)
|
|
1310
1654
|
|
|
1311
1655
|
# Planet grids
|
|
1312
|
-
|
|
1313
|
-
|
|
1656
|
+
first_name_label = self._truncate_name(self.first_obj.name)
|
|
1657
|
+
transit_label = self._translate("transit", "Transit")
|
|
1658
|
+
first_return_grid_title = f"{first_name_label} ({self._translate('inner_wheel', 'Inner Wheel')})"
|
|
1659
|
+
second_return_grid_title = f"{transit_label} ({self._translate('outer_wheel', 'Outer Wheel')})"
|
|
1314
1660
|
template_dict["makeMainPlanetGrid"] = draw_main_planet_grid(
|
|
1315
1661
|
planets_and_houses_grid_title="",
|
|
1316
1662
|
subject_name=first_return_grid_title,
|
|
1317
1663
|
available_kerykeion_celestial_points=self.available_kerykeion_celestial_points,
|
|
1318
1664
|
chart_type=self.chart_type,
|
|
1319
1665
|
text_color=self.chart_colors_settings["paper_0"],
|
|
1320
|
-
celestial_point_language=self.
|
|
1666
|
+
celestial_point_language=self._language_model.celestial_points,
|
|
1321
1667
|
)
|
|
1322
1668
|
|
|
1323
1669
|
template_dict["makeSecondaryPlanetGrid"] = draw_secondary_planet_grid(
|
|
@@ -1326,7 +1672,7 @@ class ChartDrawer:
|
|
|
1326
1672
|
second_subject_available_kerykeion_celestial_points=self.t_available_kerykeion_celestial_points,
|
|
1327
1673
|
chart_type=self.chart_type,
|
|
1328
1674
|
text_color=self.chart_colors_settings["paper_0"],
|
|
1329
|
-
celestial_point_language=self.
|
|
1675
|
+
celestial_point_language=self._language_model.celestial_points,
|
|
1330
1676
|
)
|
|
1331
1677
|
|
|
1332
1678
|
# House comparison grid
|
|
@@ -1339,12 +1685,12 @@ class ChartDrawer:
|
|
|
1339
1685
|
|
|
1340
1686
|
template_dict["makeHouseComparisonGrid"] = draw_single_house_comparison_grid(
|
|
1341
1687
|
house_comparison,
|
|
1342
|
-
celestial_point_language=self.
|
|
1688
|
+
celestial_point_language=self._language_model.celestial_points,
|
|
1343
1689
|
active_points=self.active_points,
|
|
1344
1690
|
points_owner_subject_number=2, # The second subject is the Transit
|
|
1345
|
-
house_position_comparison_label=self.
|
|
1346
|
-
return_point_label=self.
|
|
1347
|
-
natal_house_label=self.
|
|
1691
|
+
house_position_comparison_label=self._translate("house_position_comparison", "House Position Comparison"),
|
|
1692
|
+
return_point_label=self._translate("transit_point", "Transit Point"),
|
|
1693
|
+
natal_house_label=self._translate("house_position", "Natal House"),
|
|
1348
1694
|
x_position=980,
|
|
1349
1695
|
)
|
|
1350
1696
|
|
|
@@ -1390,10 +1736,11 @@ class ChartDrawer:
|
|
|
1390
1736
|
if self.double_chart_aspect_grid_type == "list":
|
|
1391
1737
|
template_dict["makeAspectGrid"] = ""
|
|
1392
1738
|
template_dict["makeDoubleChartAspectList"] = draw_transit_aspect_list(
|
|
1393
|
-
f"{self.first_obj.name} - {self.second_obj.name} {self.
|
|
1739
|
+
f"{self.first_obj.name} - {self.second_obj.name} {self._translate('synastry_aspects', 'Synastry Aspects')}", # type: ignore[union-attr]
|
|
1394
1740
|
self.aspects_list,
|
|
1395
1741
|
self.planets_settings, # type: ignore[arg-type]
|
|
1396
|
-
self.aspects_settings # type: ignore[arg-type]
|
|
1742
|
+
self.aspects_settings, # type: ignore[arg-type]
|
|
1743
|
+
chart_height=self.height,
|
|
1397
1744
|
)
|
|
1398
1745
|
else:
|
|
1399
1746
|
template_dict["makeAspectGrid"] = ""
|
|
@@ -1417,18 +1764,18 @@ class ChartDrawer:
|
|
|
1417
1764
|
|
|
1418
1765
|
# Bottom left section
|
|
1419
1766
|
if self.first_obj.zodiac_type == "Tropic":
|
|
1420
|
-
zodiac_info = f"{self.
|
|
1767
|
+
zodiac_info = f"{self._translate('zodiac', 'Zodiac')}: {self._translate('tropical', 'Tropical')}"
|
|
1421
1768
|
else:
|
|
1422
1769
|
mode_const = "SIDM_" + self.first_obj.sidereal_mode # type: ignore
|
|
1423
1770
|
mode_name = swe.get_ayanamsa_name(getattr(swe, mode_const))
|
|
1424
|
-
zodiac_info = f"{self.
|
|
1771
|
+
zodiac_info = f"{self._translate('ayanamsa', 'Ayanamsa')}: {mode_name}"
|
|
1425
1772
|
|
|
1426
1773
|
template_dict["bottom_left_0"] = ""
|
|
1427
1774
|
# FIXME!
|
|
1428
1775
|
template_dict["bottom_left_1"] = "" # f"Compatibility Score: {16}/44" # type: ignore
|
|
1429
1776
|
template_dict["bottom_left_2"] = zodiac_info
|
|
1430
|
-
template_dict["bottom_left_3"] = f"{self.
|
|
1431
|
-
template_dict["bottom_left_4"] = f'{self.
|
|
1777
|
+
template_dict["bottom_left_3"] = f"{self._translate('houses_system_' + self.first_obj.houses_system_identifier, self.first_obj.houses_system_name)} {self._translate('houses', 'Houses')}"
|
|
1778
|
+
template_dict["bottom_left_4"] = f'{self._translate("perspective_type", "Perspective")}: {self._translate(self.first_obj.perspective_type.lower().replace(" ", "_"), self.first_obj.perspective_type)}'
|
|
1432
1779
|
|
|
1433
1780
|
# Moon phase section calculations
|
|
1434
1781
|
template_dict["makeLunarPhase"] = ""
|
|
@@ -1437,13 +1784,13 @@ class ChartDrawer:
|
|
|
1437
1784
|
template_dict["makeMainHousesGrid"] = draw_main_house_grid(
|
|
1438
1785
|
main_subject_houses_list=first_subject_houses_list,
|
|
1439
1786
|
text_color=self.chart_colors_settings["paper_0"],
|
|
1440
|
-
house_cusp_generale_name_label=self.
|
|
1787
|
+
house_cusp_generale_name_label=self._translate("cusp", "Cusp"),
|
|
1441
1788
|
)
|
|
1442
1789
|
|
|
1443
1790
|
template_dict["makeSecondaryHousesGrid"] = draw_secondary_house_grid(
|
|
1444
1791
|
secondary_subject_houses_list=second_subject_houses_list,
|
|
1445
1792
|
text_color=self.chart_colors_settings["paper_0"],
|
|
1446
|
-
house_cusp_generale_name_label=self.
|
|
1793
|
+
house_cusp_generale_name_label=self._translate("cusp", "Cusp"),
|
|
1447
1794
|
)
|
|
1448
1795
|
|
|
1449
1796
|
template_dict["makeHouses"] = draw_houses_cusps_and_text_number(
|
|
@@ -1475,23 +1822,63 @@ class ChartDrawer:
|
|
|
1475
1822
|
)
|
|
1476
1823
|
|
|
1477
1824
|
# Planet grid
|
|
1825
|
+
first_name_label = self._truncate_name(self.first_obj.name, 18, "…") # type: ignore[union-attr]
|
|
1826
|
+
second_name_label = self._truncate_name(self.second_obj.name, 18, "…") # type: ignore[union-attr]
|
|
1478
1827
|
template_dict["makeMainPlanetGrid"] = draw_main_planet_grid(
|
|
1479
1828
|
planets_and_houses_grid_title="",
|
|
1480
|
-
subject_name=f"{
|
|
1829
|
+
subject_name=f"{first_name_label} ({self._translate('inner_wheel', 'Inner Wheel')})",
|
|
1481
1830
|
available_kerykeion_celestial_points=self.available_kerykeion_celestial_points,
|
|
1482
1831
|
chart_type=self.chart_type,
|
|
1483
1832
|
text_color=self.chart_colors_settings["paper_0"],
|
|
1484
|
-
celestial_point_language=self.
|
|
1833
|
+
celestial_point_language=self._language_model.celestial_points,
|
|
1485
1834
|
)
|
|
1486
1835
|
template_dict["makeSecondaryPlanetGrid"] = draw_secondary_planet_grid(
|
|
1487
1836
|
planets_and_houses_grid_title="",
|
|
1488
|
-
second_subject_name= f"{
|
|
1837
|
+
second_subject_name= f"{second_name_label} ({self._translate('outer_wheel', 'Outer Wheel')})", # type: ignore
|
|
1489
1838
|
second_subject_available_kerykeion_celestial_points=self.t_available_kerykeion_celestial_points,
|
|
1490
1839
|
chart_type=self.chart_type,
|
|
1491
1840
|
text_color=self.chart_colors_settings["paper_0"],
|
|
1492
|
-
celestial_point_language=self.
|
|
1841
|
+
celestial_point_language=self._language_model.celestial_points,
|
|
1493
1842
|
)
|
|
1494
|
-
|
|
1843
|
+
house_comparison_factory = HouseComparisonFactory(
|
|
1844
|
+
first_subject=self.first_obj, # type: ignore[arg-type]
|
|
1845
|
+
second_subject=self.second_obj, # type: ignore[arg-type]
|
|
1846
|
+
active_points=self.active_points,
|
|
1847
|
+
)
|
|
1848
|
+
house_comparison = house_comparison_factory.get_house_comparison()
|
|
1849
|
+
|
|
1850
|
+
first_subject_label = self._truncate_name(self.first_obj.name, 8, "…", True) # type: ignore[union-attr]
|
|
1851
|
+
second_subject_label = self._truncate_name(self.second_obj.name, 8, "…", True) # type: ignore[union-attr]
|
|
1852
|
+
point_column_label = self._translate("point", "Point")
|
|
1853
|
+
comparison_label = self._translate("house_position_comparison", "House Position Comparison")
|
|
1854
|
+
|
|
1855
|
+
first_subject_grid = draw_house_comparison_grid(
|
|
1856
|
+
house_comparison,
|
|
1857
|
+
celestial_point_language=self._language_model.celestial_points,
|
|
1858
|
+
active_points=self.active_points,
|
|
1859
|
+
points_owner_subject_number=1,
|
|
1860
|
+
house_position_comparison_label=comparison_label,
|
|
1861
|
+
return_point_label=first_subject_label + " " + point_column_label,
|
|
1862
|
+
return_label=first_subject_label,
|
|
1863
|
+
radix_label=second_subject_label,
|
|
1864
|
+
x_position=1090,
|
|
1865
|
+
y_position=0,
|
|
1866
|
+
)
|
|
1867
|
+
|
|
1868
|
+
second_subject_grid = draw_house_comparison_grid(
|
|
1869
|
+
house_comparison,
|
|
1870
|
+
celestial_point_language=self._language_model.celestial_points,
|
|
1871
|
+
active_points=self.active_points,
|
|
1872
|
+
points_owner_subject_number=2,
|
|
1873
|
+
house_position_comparison_label="",
|
|
1874
|
+
return_point_label=second_subject_label + " " + point_column_label,
|
|
1875
|
+
return_label=second_subject_label,
|
|
1876
|
+
radix_label=first_subject_label,
|
|
1877
|
+
x_position=1290,
|
|
1878
|
+
y_position=0,
|
|
1879
|
+
)
|
|
1880
|
+
|
|
1881
|
+
template_dict["makeHouseComparisonGrid"] = first_subject_grid + second_subject_grid
|
|
1495
1882
|
|
|
1496
1883
|
elif self.chart_type == "DualReturnChart":
|
|
1497
1884
|
# Set viewbox dynamically
|
|
@@ -1533,9 +1920,16 @@ class ChartDrawer:
|
|
|
1533
1920
|
|
|
1534
1921
|
# Aspects
|
|
1535
1922
|
if self.double_chart_aspect_grid_type == "list":
|
|
1536
|
-
title = self.
|
|
1923
|
+
title = self._translate("return_aspects", "Natal to Return Aspects")
|
|
1537
1924
|
template_dict["makeAspectGrid"] = ""
|
|
1538
|
-
template_dict["makeDoubleChartAspectList"] = draw_transit_aspect_list(
|
|
1925
|
+
template_dict["makeDoubleChartAspectList"] = draw_transit_aspect_list(
|
|
1926
|
+
title,
|
|
1927
|
+
self.aspects_list,
|
|
1928
|
+
self.planets_settings,
|
|
1929
|
+
self.aspects_settings,
|
|
1930
|
+
max_columns=7,
|
|
1931
|
+
chart_height=self.height,
|
|
1932
|
+
) # type: ignore[arg-type]
|
|
1539
1933
|
else:
|
|
1540
1934
|
template_dict["makeAspectGrid"] = ""
|
|
1541
1935
|
template_dict["makeDoubleChartAspectList"] = draw_transit_aspect_grid(
|
|
@@ -1551,17 +1945,17 @@ class ChartDrawer:
|
|
|
1551
1945
|
|
|
1552
1946
|
# Top left section
|
|
1553
1947
|
# Subject
|
|
1554
|
-
latitude_string = convert_latitude_coordinate_to_string(self.first_obj.lat, self.
|
|
1555
|
-
longitude_string = convert_longitude_coordinate_to_string(self.first_obj.lng, self.
|
|
1948
|
+
latitude_string = convert_latitude_coordinate_to_string(self.first_obj.lat, self._translate("north", "North"), self._translate("south", "South")) # type: ignore
|
|
1949
|
+
longitude_string = convert_longitude_coordinate_to_string(self.first_obj.lng, self._translate("east", "East"), self._translate("west", "West")) # type: ignore
|
|
1556
1950
|
|
|
1557
1951
|
# Return
|
|
1558
|
-
return_latitude_string = convert_latitude_coordinate_to_string(self.second_obj.lat, self.
|
|
1559
|
-
return_longitude_string = convert_longitude_coordinate_to_string(self.second_obj.lng, self.
|
|
1952
|
+
return_latitude_string = convert_latitude_coordinate_to_string(self.second_obj.lat, self._translate("north", "North"), self._translate("south", "South")) # type: ignore
|
|
1953
|
+
return_longitude_string = convert_longitude_coordinate_to_string(self.second_obj.lng, self._translate("east", "East"), self._translate("west", "West")) # type: ignore
|
|
1560
1954
|
|
|
1561
1955
|
if self.second_obj is not None and hasattr(self.second_obj, 'return_type') and self.second_obj.return_type == "Solar":
|
|
1562
|
-
template_dict["top_left_0"] = f"{self.
|
|
1956
|
+
template_dict["top_left_0"] = f"{self._translate('solar_return', 'Solar Return')}:"
|
|
1563
1957
|
else:
|
|
1564
|
-
template_dict["top_left_0"] = f"{self.
|
|
1958
|
+
template_dict["top_left_0"] = f"{self._translate('lunar_return', 'Lunar Return')}:"
|
|
1565
1959
|
template_dict["top_left_1"] = format_datetime_with_timezone(self.second_obj.iso_formatted_local_datetime) # type: ignore
|
|
1566
1960
|
template_dict["top_left_2"] = f"{return_latitude_string} / {return_longitude_string}"
|
|
1567
1961
|
template_dict["top_left_3"] = f"{self.first_obj.name}"
|
|
@@ -1570,24 +1964,24 @@ class ChartDrawer:
|
|
|
1570
1964
|
|
|
1571
1965
|
# Bottom left section
|
|
1572
1966
|
if self.first_obj.zodiac_type == "Tropic":
|
|
1573
|
-
zodiac_info = f"{self.
|
|
1967
|
+
zodiac_info = f"{self._translate('zodiac', 'Zodiac')}: {self._translate('tropical', 'Tropical')}"
|
|
1574
1968
|
else:
|
|
1575
1969
|
mode_const = "SIDM_" + self.first_obj.sidereal_mode # type: ignore
|
|
1576
1970
|
mode_name = swe.get_ayanamsa_name(getattr(swe, mode_const))
|
|
1577
|
-
zodiac_info = f"{self.
|
|
1971
|
+
zodiac_info = f"{self._translate('ayanamsa', 'Ayanamsa')}: {mode_name}"
|
|
1578
1972
|
|
|
1579
1973
|
template_dict["bottom_left_0"] = zodiac_info
|
|
1580
|
-
template_dict["bottom_left_1"] = f"{self.
|
|
1974
|
+
template_dict["bottom_left_1"] = f"{self._translate('domification', 'Domification')}: {self._translate('houses_system_' + self.first_obj.houses_system_identifier, self.first_obj.houses_system_name)}"
|
|
1581
1975
|
|
|
1582
1976
|
# Lunar phase information (optional)
|
|
1583
1977
|
if self.first_obj.lunar_phase is not None:
|
|
1584
|
-
template_dict["bottom_left_2"] = f'{self.
|
|
1585
|
-
template_dict["bottom_left_3"] = f'{self.
|
|
1978
|
+
template_dict["bottom_left_2"] = f'{self._translate("lunation_day", "Lunation Day")}: {self.first_obj.lunar_phase.get("moon_phase", "")}'
|
|
1979
|
+
template_dict["bottom_left_3"] = f'{self._translate("lunar_phase", "Lunar Phase")}: {self._translate(self.first_obj.lunar_phase.moon_phase_name.lower().replace(" ", "_"), self.first_obj.lunar_phase.moon_phase_name)}'
|
|
1586
1980
|
else:
|
|
1587
1981
|
template_dict["bottom_left_2"] = ""
|
|
1588
1982
|
template_dict["bottom_left_3"] = ""
|
|
1589
1983
|
|
|
1590
|
-
template_dict["bottom_left_4"] = f'{self.
|
|
1984
|
+
template_dict["bottom_left_4"] = f'{self._translate("perspective_type", "Perspective")}: {self._translate(self.first_obj.perspective_type.lower().replace(" ", "_"), self.first_obj.perspective_type)}'
|
|
1591
1985
|
|
|
1592
1986
|
# Moon phase section calculations
|
|
1593
1987
|
if self.first_obj.lunar_phase is not None:
|
|
@@ -1599,13 +1993,13 @@ class ChartDrawer:
|
|
|
1599
1993
|
template_dict["makeMainHousesGrid"] = draw_main_house_grid(
|
|
1600
1994
|
main_subject_houses_list=first_subject_houses_list,
|
|
1601
1995
|
text_color=self.chart_colors_settings["paper_0"],
|
|
1602
|
-
house_cusp_generale_name_label=self.
|
|
1996
|
+
house_cusp_generale_name_label=self._translate("cusp", "Cusp"),
|
|
1603
1997
|
)
|
|
1604
1998
|
|
|
1605
1999
|
template_dict["makeSecondaryHousesGrid"] = draw_secondary_house_grid(
|
|
1606
2000
|
secondary_subject_houses_list=second_subject_houses_list,
|
|
1607
2001
|
text_color=self.chart_colors_settings["paper_0"],
|
|
1608
|
-
house_cusp_generale_name_label=self.
|
|
2002
|
+
house_cusp_generale_name_label=self._translate("cusp", "Cusp"),
|
|
1609
2003
|
)
|
|
1610
2004
|
|
|
1611
2005
|
template_dict["makeHouses"] = draw_houses_cusps_and_text_number(
|
|
@@ -1637,19 +2031,20 @@ class ChartDrawer:
|
|
|
1637
2031
|
)
|
|
1638
2032
|
|
|
1639
2033
|
# Planet grid
|
|
2034
|
+
first_name_label = self._truncate_name(self.first_obj.name)
|
|
1640
2035
|
if self.second_obj is not None and hasattr(self.second_obj, 'return_type') and self.second_obj.return_type == "Solar":
|
|
1641
|
-
first_return_grid_title = f"{
|
|
1642
|
-
second_return_grid_title = f"{self.
|
|
2036
|
+
first_return_grid_title = f"{first_name_label} ({self._translate('inner_wheel', 'Inner Wheel')})"
|
|
2037
|
+
second_return_grid_title = f"{self._translate('solar_return', 'Solar Return')} ({self._translate('outer_wheel', 'Outer Wheel')})"
|
|
1643
2038
|
else:
|
|
1644
|
-
first_return_grid_title = f"{
|
|
1645
|
-
second_return_grid_title = f'{self.
|
|
2039
|
+
first_return_grid_title = f"{first_name_label} ({self._translate('inner_wheel', 'Inner Wheel')})"
|
|
2040
|
+
second_return_grid_title = f'{self._translate("lunar_return", "Lunar Return")} ({self._translate("outer_wheel", "Outer Wheel")})'
|
|
1646
2041
|
template_dict["makeMainPlanetGrid"] = draw_main_planet_grid(
|
|
1647
2042
|
planets_and_houses_grid_title="",
|
|
1648
2043
|
subject_name=first_return_grid_title,
|
|
1649
2044
|
available_kerykeion_celestial_points=self.available_kerykeion_celestial_points,
|
|
1650
2045
|
chart_type=self.chart_type,
|
|
1651
2046
|
text_color=self.chart_colors_settings["paper_0"],
|
|
1652
|
-
celestial_point_language=self.
|
|
2047
|
+
celestial_point_language=self._language_model.celestial_points,
|
|
1653
2048
|
)
|
|
1654
2049
|
template_dict["makeSecondaryPlanetGrid"] = draw_secondary_planet_grid(
|
|
1655
2050
|
planets_and_houses_grid_title="",
|
|
@@ -1657,7 +2052,7 @@ class ChartDrawer:
|
|
|
1657
2052
|
second_subject_available_kerykeion_celestial_points=self.t_available_kerykeion_celestial_points,
|
|
1658
2053
|
chart_type=self.chart_type,
|
|
1659
2054
|
text_color=self.chart_colors_settings["paper_0"],
|
|
1660
|
-
celestial_point_language=self.
|
|
2055
|
+
celestial_point_language=self._language_model.celestial_points,
|
|
1661
2056
|
)
|
|
1662
2057
|
|
|
1663
2058
|
house_comparison_factory = HouseComparisonFactory(
|
|
@@ -1669,13 +2064,13 @@ class ChartDrawer:
|
|
|
1669
2064
|
|
|
1670
2065
|
template_dict["makeHouseComparisonGrid"] = draw_house_comparison_grid(
|
|
1671
2066
|
house_comparison,
|
|
1672
|
-
celestial_point_language=self.
|
|
2067
|
+
celestial_point_language=self._language_model.celestial_points,
|
|
1673
2068
|
active_points=self.active_points,
|
|
1674
2069
|
points_owner_subject_number=2, # The second subject is the Solar Return
|
|
1675
|
-
house_position_comparison_label=self.
|
|
1676
|
-
return_point_label=self.
|
|
1677
|
-
return_label=self.
|
|
1678
|
-
radix_label=self.
|
|
2070
|
+
house_position_comparison_label=self._translate("house_position_comparison", "House Position Comparison"),
|
|
2071
|
+
return_point_label=self._translate("return_point", "Return Point"),
|
|
2072
|
+
return_label=self._translate("Return", "DualReturnChart"),
|
|
2073
|
+
radix_label=self._translate("Natal", "Natal"),
|
|
1679
2074
|
)
|
|
1680
2075
|
|
|
1681
2076
|
elif self.chart_type == "SingleReturnChart":
|
|
@@ -1726,40 +2121,40 @@ class ChartDrawer:
|
|
|
1726
2121
|
template_dict["makeAspects"] = self._draw_all_aspects_lines(self.main_radius, self.main_radius - self.third_circle_radius)
|
|
1727
2122
|
|
|
1728
2123
|
# Top left section
|
|
1729
|
-
latitude_string = convert_latitude_coordinate_to_string(self.geolat, self.
|
|
1730
|
-
longitude_string = convert_longitude_coordinate_to_string(self.geolon, self.
|
|
2124
|
+
latitude_string = convert_latitude_coordinate_to_string(self.geolat, self._translate("north", "North"), self._translate("south", "South"))
|
|
2125
|
+
longitude_string = convert_longitude_coordinate_to_string(self.geolon, self._translate("east", "East"), self._translate("west", "West"))
|
|
1731
2126
|
|
|
1732
|
-
template_dict["top_left_0"] = f'{self.
|
|
2127
|
+
template_dict["top_left_0"] = f'{self._translate("info", "Info")}:'
|
|
1733
2128
|
template_dict["top_left_1"] = format_datetime_with_timezone(self.first_obj.iso_formatted_local_datetime) # type: ignore
|
|
1734
2129
|
template_dict["top_left_2"] = f"{self.first_obj.city}, {self.first_obj.nation}"
|
|
1735
|
-
template_dict["top_left_3"] = f"{self.
|
|
1736
|
-
template_dict["top_left_4"] = f"{self.
|
|
2130
|
+
template_dict["top_left_3"] = f"{self._translate('latitude', 'Latitude')}: {latitude_string}"
|
|
2131
|
+
template_dict["top_left_4"] = f"{self._translate('longitude', 'Longitude')}: {longitude_string}"
|
|
1737
2132
|
|
|
1738
2133
|
if hasattr(self.first_obj, 'return_type') and self.first_obj.return_type == "Solar":
|
|
1739
|
-
template_dict["top_left_5"] = f"{self.
|
|
2134
|
+
template_dict["top_left_5"] = f"{self._translate('type', 'Type')}: {self._translate('solar_return', 'Solar Return')}"
|
|
1740
2135
|
else:
|
|
1741
|
-
template_dict["top_left_5"] = f"{self.
|
|
2136
|
+
template_dict["top_left_5"] = f"{self._translate('type', 'Type')}: {self._translate('lunar_return', 'Lunar Return')}"
|
|
1742
2137
|
|
|
1743
2138
|
# Bottom left section
|
|
1744
2139
|
if self.first_obj.zodiac_type == "Tropic":
|
|
1745
|
-
zodiac_info = f"{self.
|
|
2140
|
+
zodiac_info = f"{self._translate('zodiac', 'Zodiac')}: {self._translate('tropical', 'Tropical')}"
|
|
1746
2141
|
else:
|
|
1747
2142
|
mode_const = "SIDM_" + self.first_obj.sidereal_mode # type: ignore
|
|
1748
2143
|
mode_name = swe.get_ayanamsa_name(getattr(swe, mode_const))
|
|
1749
|
-
zodiac_info = f"{self.
|
|
2144
|
+
zodiac_info = f"{self._translate('ayanamsa', 'Ayanamsa')}: {mode_name}"
|
|
1750
2145
|
|
|
1751
2146
|
template_dict["bottom_left_0"] = zodiac_info
|
|
1752
|
-
template_dict["bottom_left_1"] = f"{self.
|
|
2147
|
+
template_dict["bottom_left_1"] = f"{self._translate('houses_system_' + self.first_obj.houses_system_identifier, self.first_obj.houses_system_name)} {self._translate('houses', 'Houses')}"
|
|
1753
2148
|
|
|
1754
2149
|
# Lunar phase information (optional)
|
|
1755
2150
|
if self.first_obj.lunar_phase is not None:
|
|
1756
|
-
template_dict["bottom_left_2"] = f'{self.
|
|
1757
|
-
template_dict["bottom_left_3"] = f'{self.
|
|
2151
|
+
template_dict["bottom_left_2"] = f'{self._translate("lunation_day", "Lunation Day")}: {self.first_obj.lunar_phase.get("moon_phase", "")}'
|
|
2152
|
+
template_dict["bottom_left_3"] = f'{self._translate("lunar_phase", "Lunar Phase")}: {self._translate(self.first_obj.lunar_phase.moon_phase_name.lower().replace(" ", "_"), self.first_obj.lunar_phase.moon_phase_name)}'
|
|
1758
2153
|
else:
|
|
1759
2154
|
template_dict["bottom_left_2"] = ""
|
|
1760
2155
|
template_dict["bottom_left_3"] = ""
|
|
1761
2156
|
|
|
1762
|
-
template_dict["bottom_left_4"] = f'{self.
|
|
2157
|
+
template_dict["bottom_left_4"] = f'{self._translate("perspective_type", "Perspective")}: {self._translate(self.first_obj.perspective_type.lower().replace(" ", "_"), self.first_obj.perspective_type)}'
|
|
1763
2158
|
|
|
1764
2159
|
# Moon phase section calculations
|
|
1765
2160
|
if self.first_obj.lunar_phase is not None:
|
|
@@ -1771,7 +2166,7 @@ class ChartDrawer:
|
|
|
1771
2166
|
template_dict["makeMainHousesGrid"] = draw_main_house_grid(
|
|
1772
2167
|
main_subject_houses_list=first_subject_houses_list,
|
|
1773
2168
|
text_color=self.chart_colors_settings["paper_0"],
|
|
1774
|
-
house_cusp_generale_name_label=self.
|
|
2169
|
+
house_cusp_generale_name_label=self._translate("cusp", "Cusp"),
|
|
1775
2170
|
)
|
|
1776
2171
|
template_dict["makeSecondaryHousesGrid"] = ""
|
|
1777
2172
|
|
|
@@ -1801,12 +2196,12 @@ class ChartDrawer:
|
|
|
1801
2196
|
)
|
|
1802
2197
|
|
|
1803
2198
|
template_dict["makeMainPlanetGrid"] = draw_main_planet_grid(
|
|
1804
|
-
planets_and_houses_grid_title=self.
|
|
2199
|
+
planets_and_houses_grid_title=self._translate("planets_and_house", "Points for"),
|
|
1805
2200
|
subject_name=self.first_obj.name,
|
|
1806
2201
|
available_kerykeion_celestial_points=self.available_kerykeion_celestial_points,
|
|
1807
2202
|
chart_type=self.chart_type,
|
|
1808
2203
|
text_color=self.chart_colors_settings["paper_0"],
|
|
1809
|
-
celestial_point_language=self.
|
|
2204
|
+
celestial_point_language=self._language_model.celestial_points,
|
|
1810
2205
|
)
|
|
1811
2206
|
template_dict["makeSecondaryPlanetGrid"] = ""
|
|
1812
2207
|
template_dict["makeHouseComparisonGrid"] = ""
|