kerykeion 5.1.10__py3-none-any.whl → 5.1.12__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.

@@ -211,6 +211,7 @@ class ChartDrawer:
211
211
  active_aspects: List[ActiveAspect]
212
212
  transparent_background: bool
213
213
  external_view: bool
214
+ show_house_position_comparison: bool
214
215
  custom_title: Union[str, None]
215
216
  _language_model: KerykeionLanguageModel
216
217
  _fallback_language_model: KerykeionLanguageModel
@@ -249,6 +250,7 @@ class ChartDrawer:
249
250
  celestial_points_settings: list[dict] = DEFAULT_CELESTIAL_POINTS_SETTINGS,
250
251
  aspects_settings: list[dict] = DEFAULT_CHART_ASPECTS_SETTINGS,
251
252
  custom_title: Union[str, None] = None,
253
+ show_house_position_comparison: bool = True,
252
254
  auto_size: bool = True,
253
255
  padding: int = 20,
254
256
  ):
@@ -275,6 +277,9 @@ class ChartDrawer:
275
277
  Whether to use a transparent background instead of the theme color. Defaults to False.
276
278
  custom_title (str or None, optional):
277
279
  Custom title for the chart. If None, the default title will be used based on chart type. Defaults to None.
280
+ show_house_position_comparison (bool, optional):
281
+ Whether to render the house position comparison grid (when supported by the chart type).
282
+ Defaults to True. Set to False to hide the table and reclaim horizontal space.
278
283
  """
279
284
  # --------------------
280
285
  # COMMON INITIALIZATION
@@ -287,6 +292,7 @@ class ChartDrawer:
287
292
  self.planets_settings = [dict(body) for body in celestial_points_settings]
288
293
  self.aspects_settings = [dict(aspect) for aspect in aspects_settings]
289
294
  self.custom_title = custom_title
295
+ self.show_house_position_comparison = show_house_position_comparison
290
296
  self.auto_size = auto_size
291
297
  self._padding = padding
292
298
  self._vertical_offsets: dict[str, int] = self._BASE_VERTICAL_OFFSETS.copy()
@@ -462,6 +468,8 @@ class ChartDrawer:
462
468
  self.second_circle_radius = 36
463
469
  self.third_circle_radius = 120
464
470
 
471
+ self._apply_house_comparison_width_override()
472
+
465
473
  # --------------------
466
474
  # FINAL COMMON SETUP FROM CHART DATA
467
475
  # --------------------
@@ -614,7 +622,7 @@ class ChartDrawer:
614
622
 
615
623
  # Move title up for synastry charts
616
624
  offsets["title"] = -10
617
-
625
+
618
626
  offsets["wheel"] += delta_height
619
627
  offsets["aspect_grid"] += delta_height
620
628
  offsets["aspect_list"] += delta_height
@@ -670,6 +678,19 @@ class ChartDrawer:
670
678
 
671
679
  return collected
672
680
 
681
+ def _apply_house_comparison_width_override(self) -> None:
682
+ """Shrink chart width when the optional house comparison grid is hidden."""
683
+ if self.show_house_position_comparison:
684
+ return
685
+
686
+ if self.chart_type == "Synastry":
687
+ self.width = self._DEFAULT_FULL_WIDTH
688
+ elif self.chart_type == "DualReturnChart":
689
+ self.width = self._DEFAULT_FULL_WIDTH_WITH_TABLE if self.double_chart_aspect_grid_type == "table" else self._DEFAULT_FULL_WIDTH
690
+ elif self.chart_type == "Transit":
691
+ # Transit charts already use the compact width unless the aspect grid table is requested.
692
+ self.width = self._DEFAULT_FULL_WIDTH_WITH_TABLE if self.double_chart_aspect_grid_type == "table" else self._DEFAULT_FULL_WIDTH
693
+
673
694
  def _dynamic_viewbox(self) -> str:
674
695
  """Return the viewBox string based on current width/height with vertical padding."""
675
696
  min_y = -self._VERTICAL_PADDING_TOP
@@ -779,7 +800,7 @@ class ChartDrawer:
779
800
  # Secondary houses grid default x ~ 1015
780
801
  secondary_houses_grid_right = 1015 + 120
781
802
  extents.append(secondary_houses_grid_right)
782
- if self.second_obj is not None:
803
+ if self.show_house_position_comparison and self.second_obj is not None:
783
804
  point_column_label = self._translate("point", "Point")
784
805
  first_subject_label = self._truncate_name(self.first_obj.name, 8, "…", True) # type: ignore[union-attr]
785
806
  second_subject_label = self._truncate_name(self.second_obj.name, 8, "…", True) # type: ignore[union-attr]
@@ -812,33 +833,35 @@ class ChartDrawer:
812
833
 
813
834
  if self.chart_type == "Transit":
814
835
  # House comparison grid at x ~ 1030
815
- transit_columns = [
816
- self._translate("transit_point", "Transit Point"),
817
- self._translate("house_position", "Natal House"),
818
- ]
819
- transit_grid_width = self._estimate_house_comparison_grid_width(
820
- column_labels=transit_columns,
821
- include_radix_column=False,
822
- include_title=True,
823
- minimum_width=170.0,
824
- )
825
- house_comparison_grid_right = 980 + transit_grid_width
826
- extents.append(house_comparison_grid_right)
836
+ if self.show_house_position_comparison:
837
+ transit_columns = [
838
+ self._translate("transit_point", "Transit Point"),
839
+ self._translate("house_position", "Natal House"),
840
+ ]
841
+ transit_grid_width = self._estimate_house_comparison_grid_width(
842
+ column_labels=transit_columns,
843
+ include_radix_column=False,
844
+ include_title=True,
845
+ minimum_width=170.0,
846
+ )
847
+ house_comparison_grid_right = 980 + transit_grid_width
848
+ extents.append(house_comparison_grid_right)
827
849
 
828
850
  if self.chart_type == "DualReturnChart":
829
851
  # House comparison grid translated to x ~ 1100
830
- dual_return_columns = [
831
- self._translate("return_point", "Return Point"),
832
- self._translate("Return", "DualReturnChart"),
833
- self._translate("Natal", "Natal"),
834
- ]
835
- dual_return_grid_width = self._estimate_house_comparison_grid_width(
836
- column_labels=dual_return_columns,
837
- include_radix_column=True,
838
- include_title=True,
839
- )
840
- house_comparison_grid_right = 1100 + dual_return_grid_width
841
- extents.append(house_comparison_grid_right)
852
+ if self.show_house_position_comparison:
853
+ dual_return_columns = [
854
+ self._translate("return_point", "Return Point"),
855
+ self._translate("Return", "DualReturnChart"),
856
+ self._translate("Natal", "Natal"),
857
+ ]
858
+ dual_return_grid_width = self._estimate_house_comparison_grid_width(
859
+ column_labels=dual_return_columns,
860
+ include_radix_column=True,
861
+ include_title=True,
862
+ )
863
+ house_comparison_grid_right = 1100 + dual_return_grid_width
864
+ extents.append(house_comparison_grid_right)
842
865
 
843
866
  # Conservative safety padding
844
867
  return int(max(extents) + self._padding)
@@ -1168,17 +1191,24 @@ class ChartDrawer:
1168
1191
 
1169
1192
  return name[:max_length-1] + ellipsis_symbol
1170
1193
 
1171
- def _get_chart_title(self) -> str:
1194
+ def _get_chart_title(self, custom_title_override: Union[str, None] = None) -> str:
1172
1195
  """
1173
1196
  Generate the chart title based on chart type and custom title settings.
1174
1197
 
1175
1198
  If a custom title is provided, it will be used. Otherwise, generates the
1176
1199
  appropriate default title based on the chart type and subjects.
1177
1200
 
1201
+ Args:
1202
+ custom_title_override (str | None): Explicit override supplied at render time.
1203
+
1178
1204
  Returns:
1179
1205
  str: The chart title to display (max ~40 characters).
1180
1206
  """
1181
- # If custom title is provided, use it
1207
+ # If a kwarg override is provided, use it
1208
+ if custom_title_override is not None:
1209
+ return custom_title_override
1210
+
1211
+ # If custom title is provided at initialization, use it
1182
1212
  if self.custom_title is not None:
1183
1213
  return self.custom_title
1184
1214
 
@@ -1236,13 +1266,16 @@ class ChartDrawer:
1236
1266
  # Fallback for unknown chart types
1237
1267
  return self._truncate_name(self.first_obj.name)
1238
1268
 
1239
- def _create_template_dictionary(self) -> ChartTemplateModel:
1269
+ def _create_template_dictionary(self, *, custom_title: Union[str, None] = None) -> ChartTemplateModel:
1240
1270
  """
1241
1271
  Assemble chart data and rendering instructions into a template dictionary.
1242
1272
 
1243
1273
  Gathers styling, dimensions, and SVG fragments for chart components based on
1244
1274
  chart type and subjects.
1245
1275
 
1276
+ Args:
1277
+ custom_title (str | None): Optional runtime override for the chart title.
1278
+
1246
1279
  Returns:
1247
1280
  ChartTemplateModel: Populated structure of template variables.
1248
1281
  """
@@ -1333,7 +1366,7 @@ class ChartDrawer:
1333
1366
  first_subject_houses_list = get_houses_list(self.first_obj)
1334
1367
 
1335
1368
  # Chart title
1336
- template_dict["stringTitle"] = self._get_chart_title()
1369
+ template_dict["stringTitle"] = self._get_chart_title(custom_title_override=custom_title)
1337
1370
 
1338
1371
  # ------------------------------- #
1339
1372
  # CHART TYPE SPECIFIC SETTINGS #
@@ -1872,23 +1905,26 @@ class ChartDrawer:
1872
1905
  )
1873
1906
 
1874
1907
  # House comparison grid
1875
- house_comparison_factory = HouseComparisonFactory(
1876
- first_subject=self.first_obj, # type: ignore[arg-type]
1877
- second_subject=self.second_obj, # type: ignore[arg-type]
1878
- active_points=self.active_points,
1879
- )
1880
- house_comparison = house_comparison_factory.get_house_comparison()
1881
-
1882
- template_dict["makeHouseComparisonGrid"] = draw_single_house_comparison_grid(
1883
- house_comparison,
1884
- celestial_point_language=self._language_model.celestial_points,
1885
- active_points=self.active_points,
1886
- points_owner_subject_number=2, # The second subject is the Transit
1887
- house_position_comparison_label=self._translate("house_position_comparison", "House Position Comparison"),
1888
- return_point_label=self._translate("transit_point", "Transit Point"),
1889
- natal_house_label=self._translate("house_position", "Natal House"),
1890
- x_position=980,
1891
- )
1908
+ if self.show_house_position_comparison:
1909
+ house_comparison_factory = HouseComparisonFactory(
1910
+ first_subject=self.first_obj, # type: ignore[arg-type]
1911
+ second_subject=self.second_obj, # type: ignore[arg-type]
1912
+ active_points=self.active_points,
1913
+ )
1914
+ house_comparison = house_comparison_factory.get_house_comparison()
1915
+
1916
+ template_dict["makeHouseComparisonGrid"] = draw_single_house_comparison_grid(
1917
+ house_comparison,
1918
+ celestial_point_language=self._language_model.celestial_points,
1919
+ active_points=self.active_points,
1920
+ points_owner_subject_number=2, # The second subject is the Transit
1921
+ house_position_comparison_label=self._translate("house_position_comparison", "House Position Comparison"),
1922
+ return_point_label=self._translate("transit_point", "Transit Point"),
1923
+ natal_house_label=self._translate("house_position", "Natal House"),
1924
+ x_position=980,
1925
+ )
1926
+ else:
1927
+ template_dict["makeHouseComparisonGrid"] = ""
1892
1928
 
1893
1929
  elif self.chart_type == "Synastry":
1894
1930
  # Set viewbox dynamically
@@ -2036,45 +2072,48 @@ class ChartDrawer:
2036
2072
  text_color=self.chart_colors_settings["paper_0"],
2037
2073
  celestial_point_language=self._language_model.celestial_points,
2038
2074
  )
2039
- house_comparison_factory = HouseComparisonFactory(
2040
- first_subject=self.first_obj, # type: ignore[arg-type]
2041
- second_subject=self.second_obj, # type: ignore[arg-type]
2042
- active_points=self.active_points,
2043
- )
2044
- house_comparison = house_comparison_factory.get_house_comparison()
2045
-
2046
- first_subject_label = self._truncate_name(self.first_obj.name, 8, "…", True) # type: ignore[union-attr]
2047
- second_subject_label = self._truncate_name(self.second_obj.name, 8, "…", True) # type: ignore[union-attr]
2048
- point_column_label = self._translate("point", "Point")
2049
- comparison_label = self._translate("house_position_comparison", "House Position Comparison")
2075
+ if self.show_house_position_comparison:
2076
+ house_comparison_factory = HouseComparisonFactory(
2077
+ first_subject=self.first_obj, # type: ignore[arg-type]
2078
+ second_subject=self.second_obj, # type: ignore[arg-type]
2079
+ active_points=self.active_points,
2080
+ )
2081
+ house_comparison = house_comparison_factory.get_house_comparison()
2082
+
2083
+ first_subject_label = self._truncate_name(self.first_obj.name, 8, "…", True) # type: ignore[union-attr]
2084
+ second_subject_label = self._truncate_name(self.second_obj.name, 8, "", True) # type: ignore[union-attr]
2085
+ point_column_label = self._translate("point", "Point")
2086
+ comparison_label = self._translate("house_position_comparison", "House Position Comparison")
2087
+
2088
+ first_subject_grid = draw_house_comparison_grid(
2089
+ house_comparison,
2090
+ celestial_point_language=self._language_model.celestial_points,
2091
+ active_points=self.active_points,
2092
+ points_owner_subject_number=1,
2093
+ house_position_comparison_label=comparison_label,
2094
+ return_point_label=first_subject_label + " " + point_column_label,
2095
+ return_label=first_subject_label,
2096
+ radix_label=second_subject_label,
2097
+ x_position=1090,
2098
+ y_position=0,
2099
+ )
2050
2100
 
2051
- first_subject_grid = draw_house_comparison_grid(
2052
- house_comparison,
2053
- celestial_point_language=self._language_model.celestial_points,
2054
- active_points=self.active_points,
2055
- points_owner_subject_number=1,
2056
- house_position_comparison_label=comparison_label,
2057
- return_point_label=first_subject_label + " " + point_column_label,
2058
- return_label=first_subject_label,
2059
- radix_label=second_subject_label,
2060
- x_position=1090,
2061
- y_position=0,
2062
- )
2063
-
2064
- second_subject_grid = draw_house_comparison_grid(
2065
- house_comparison,
2066
- celestial_point_language=self._language_model.celestial_points,
2067
- active_points=self.active_points,
2068
- points_owner_subject_number=2,
2069
- house_position_comparison_label="",
2070
- return_point_label=second_subject_label + " " + point_column_label,
2071
- return_label=second_subject_label,
2072
- radix_label=first_subject_label,
2073
- x_position=1290,
2074
- y_position=0,
2075
- )
2101
+ second_subject_grid = draw_house_comparison_grid(
2102
+ house_comparison,
2103
+ celestial_point_language=self._language_model.celestial_points,
2104
+ active_points=self.active_points,
2105
+ points_owner_subject_number=2,
2106
+ house_position_comparison_label="",
2107
+ return_point_label=second_subject_label + " " + point_column_label,
2108
+ return_label=second_subject_label,
2109
+ radix_label=first_subject_label,
2110
+ x_position=1290,
2111
+ y_position=0,
2112
+ )
2076
2113
 
2077
- template_dict["makeHouseComparisonGrid"] = first_subject_grid + second_subject_grid
2114
+ template_dict["makeHouseComparisonGrid"] = first_subject_grid + second_subject_grid
2115
+ else:
2116
+ template_dict["makeHouseComparisonGrid"] = ""
2078
2117
 
2079
2118
  elif self.chart_type == "DualReturnChart":
2080
2119
  # Set viewbox dynamically
@@ -2251,23 +2290,26 @@ class ChartDrawer:
2251
2290
  celestial_point_language=self._language_model.celestial_points,
2252
2291
  )
2253
2292
 
2254
- house_comparison_factory = HouseComparisonFactory(
2255
- first_subject=self.first_obj, # type: ignore[arg-type]
2256
- second_subject=self.second_obj, # type: ignore[arg-type]
2257
- active_points=self.active_points,
2258
- )
2259
- house_comparison = house_comparison_factory.get_house_comparison()
2260
-
2261
- template_dict["makeHouseComparisonGrid"] = draw_house_comparison_grid(
2262
- house_comparison,
2263
- celestial_point_language=self._language_model.celestial_points,
2264
- active_points=self.active_points,
2265
- points_owner_subject_number=2, # The second subject is the Solar Return
2266
- house_position_comparison_label=self._translate("house_position_comparison", "House Position Comparison"),
2267
- return_point_label=self._translate("return_point", "Return Point"),
2268
- return_label=self._translate("Return", "DualReturnChart"),
2269
- radix_label=self._translate("Natal", "Natal"),
2270
- )
2293
+ if self.show_house_position_comparison:
2294
+ house_comparison_factory = HouseComparisonFactory(
2295
+ first_subject=self.first_obj, # type: ignore[arg-type]
2296
+ second_subject=self.second_obj, # type: ignore[arg-type]
2297
+ active_points=self.active_points,
2298
+ )
2299
+ house_comparison = house_comparison_factory.get_house_comparison()
2300
+
2301
+ template_dict["makeHouseComparisonGrid"] = draw_house_comparison_grid(
2302
+ house_comparison,
2303
+ celestial_point_language=self._language_model.celestial_points,
2304
+ active_points=self.active_points,
2305
+ points_owner_subject_number=2, # The second subject is the Solar Return
2306
+ house_position_comparison_label=self._translate("house_position_comparison", "House Position Comparison"),
2307
+ return_point_label=self._translate("return_point", "Return Point"),
2308
+ return_label=self._translate("Return", "DualReturnChart"),
2309
+ radix_label=self._translate("Natal", "Natal"),
2310
+ )
2311
+ else:
2312
+ template_dict["makeHouseComparisonGrid"] = ""
2271
2313
 
2272
2314
  elif self.chart_type == "SingleReturnChart":
2273
2315
  # Set viewbox dynamically
@@ -2404,7 +2446,7 @@ class ChartDrawer:
2404
2446
 
2405
2447
  return ChartTemplateModel(**template_dict)
2406
2448
 
2407
- def generate_svg_string(self, minify: bool = False, remove_css_variables=False) -> str:
2449
+ def generate_svg_string(self, minify: bool = False, remove_css_variables=False, *, custom_title: Union[str, None] = None) -> str:
2408
2450
  """
2409
2451
  Render the full chart SVG as a string.
2410
2452
 
@@ -2414,11 +2456,12 @@ class ChartDrawer:
2414
2456
  Args:
2415
2457
  minify (bool): Remove whitespace and quotes for compactness.
2416
2458
  remove_css_variables (bool): Embed CSS variable definitions.
2459
+ custom_title (str or None): Optional override for the SVG title.
2417
2460
 
2418
2461
  Returns:
2419
2462
  str: SVG markup as a string.
2420
2463
  """
2421
- td = self._create_template_dictionary()
2464
+ td = self._create_template_dictionary(custom_title=custom_title)
2422
2465
 
2423
2466
  DATA_DIR = Path(__file__).parent
2424
2467
  xml_svg = DATA_DIR / "templates" / "chart.xml"
@@ -2431,8 +2474,6 @@ class ChartDrawer:
2431
2474
 
2432
2475
  logger.debug("Template dictionary includes %s fields", len(td.model_dump()))
2433
2476
 
2434
- self._create_template_dictionary()
2435
-
2436
2477
  if remove_css_variables:
2437
2478
  template = inline_css_variables_in_svg(template)
2438
2479
 
@@ -2444,7 +2485,7 @@ class ChartDrawer:
2444
2485
 
2445
2486
  return template
2446
2487
 
2447
- def save_svg(self, output_path: Union[str, Path, None] = None, filename: Union[str, None] = None, minify: bool = False, remove_css_variables=False):
2488
+ def save_svg(self, output_path: Union[str, Path, None] = None, filename: Union[str, None] = None, minify: bool = False, remove_css_variables=False, *, custom_title: Union[str, None] = None):
2448
2489
  """
2449
2490
  Generate and save the full chart SVG to disk.
2450
2491
 
@@ -2458,12 +2499,13 @@ class ChartDrawer:
2458
2499
  If None, uses the default pattern: "{subject.name} - {chart_type} Chart".
2459
2500
  minify (bool): Pass-through to generate_svg_string for compact output.
2460
2501
  remove_css_variables (bool): Pass-through to generate_svg_string to embed CSS variables.
2502
+ custom_title (str or None): Optional override for the SVG title.
2461
2503
 
2462
2504
  Returns:
2463
2505
  None
2464
2506
  """
2465
2507
 
2466
- self.template = self.generate_svg_string(minify, remove_css_variables)
2508
+ self.template = self.generate_svg_string(minify, remove_css_variables, custom_title=custom_title)
2467
2509
 
2468
2510
  # Convert output_path to Path object, default to home directory
2469
2511
  output_directory = Path(output_path) if output_path is not None else Path.home()
@@ -20,52 +20,52 @@
20
20
  Main Chart -->
21
21
  <g kr:node="Main_Chart">
22
22
  <g kr:node="Top_Left_Text" transform="translate(0,$title_translate_y)">
23
- <text x="20" y="22" style="fill: $paper_color_0; font-size: 24px">$stringTitle</text>
24
- <text x="20" y="58" style="fill: $paper_color_0; font-size: 10px">$top_left_0</text>
25
- <text x="20" y="70" style="fill: $paper_color_0; font-size: 10px">$top_left_1</text>
26
- <text x="20" y="82" style="fill: $paper_color_0; font-size: 10px">$top_left_2</text>
27
- <text x="20" y="94" style="fill: $paper_color_0; font-size: 10px">$top_left_3</text>
28
- <text x="20" y="106" style="fill: $paper_color_0; font-size: 10px">$top_left_4</text>
29
- <text x="20" y="118" style="fill: $paper_color_0; font-size: 10px">$top_left_5</text>
23
+ <text kr:node="Chart_Title" x="20" y="22" style="fill: $paper_color_0; font-size: 24px">$stringTitle</text>
24
+ <text kr:node="Top_Left_Text_0" x="20" y="58" style="fill: $paper_color_0; font-size: 10px">$top_left_0</text>
25
+ <text kr:node="Top_Left_Text_1" x="20" y="70" style="fill: $paper_color_0; font-size: 10px">$top_left_1</text>
26
+ <text kr:node="Top_Left_Text_2" x="20" y="82" style="fill: $paper_color_0; font-size: 10px">$top_left_2</text>
27
+ <text kr:node="Top_Left_Text_3" x="20" y="94" style="fill: $paper_color_0; font-size: 10px">$top_left_3</text>
28
+ <text kr:node="Top_Left_Text_4" x="20" y="106" style="fill: $paper_color_0; font-size: 10px">$top_left_4</text>
29
+ <text kr:node="Top_Left_Text_5" x="20" y="118" style="fill: $paper_color_0; font-size: 10px">$top_left_5</text>
30
30
  </g>
31
31
 
32
32
  <!-- Elements -->
33
33
  <g kr:node="Elements_Percentages" transform="translate(0,$elements_translate_y)">
34
- <text x="20" y="138" style="fill: $paper_color_0; font-size: 10px;">$elements_string</text>
35
- <text x="20" y="152"
34
+ <text kr:node="Elements_Text" x="20" y="138" style="fill: $paper_color_0; font-size: 10px;">$elements_string</text>
35
+ <text kr:node="Fire_Text" x="20" y="152"
36
36
  style="fill: var(--kerykeion-chart-color-fire-percentage); font-size: 10px;">
37
37
  $fire_string</text>
38
- <text x="20" y="164"
38
+ <text kr:node="Earth_Text" x="20" y="164"
39
39
  style="fill: var(--kerykeion-chart-color-earth-percentage); font-size: 10px;">
40
40
  $earth_string</text>
41
- <text x="20" y="176"
41
+ <text kr:node="Air_Text" x="20" y="176"
42
42
  style="fill: var(--kerykeion-chart-color-air-percentage); font-size: 10px;">
43
43
  $air_string</text>
44
- <text x="20" y="188"
44
+ <text kr:node="Water_Text" x="20" y="188"
45
45
  style="fill: var(--kerykeion-chart-color-water-percentage); font-size: 10px;">
46
46
  $water_string</text>
47
47
  </g>
48
48
 
49
49
  <!-- Qualities -->
50
50
  <g kr:node="Qualities_Percentages" transform="translate(0,$qualities_translate_y)">
51
- <text x="20" y="208" style="fill: $paper_color_0; font-size: 10px;">$qualities_string</text>
52
- <text x="20" y="222"
51
+ <text kr:node="Qualities_Text" x="20" y="208" style="fill: $paper_color_0; font-size: 10px;">$qualities_string</text>
52
+ <text kr:node="Cardinal_Text" x="20" y="222"
53
53
  style="fill: var(--kerykeion-chart-color-cardinal-percentage); font-size: 10px;">
54
54
  $cardinal_string</text>
55
- <text x="20" y="234"
55
+ <text kr:node="Fixed_Text" x="20" y="234"
56
56
  style="fill: var(--kerykeion-chart-color-fixed-percentage); font-size: 10px;">
57
57
  $fixed_string</text>
58
- <text x="20" y="246"
58
+ <text kr:node="Mutable_Text" x="20" y="246"
59
59
  style="fill: var(--kerykeion-chart-color-mutable-percentage); font-size: 10px;">
60
60
  $mutable_string</text>
61
61
  </g>
62
62
 
63
63
  <g kr:node="Bottom_Left_Text" transform="translate(0,$bottom_left_translate_y)">
64
- <text x="20" y="452" style="fill: $paper_color_0; font-size: 10px">$bottom_left_0</text>
65
- <text x="20" y="466" style="fill: $paper_color_0; font-size: 10px">$bottom_left_1</text>
66
- <text x="20" y="480" style="fill: $paper_color_0; font-size: 10px">$bottom_left_2</text>
67
- <text x="20" y="494" style="fill: $paper_color_0; font-size: 10px">$bottom_left_3</text>
68
- <text x="20" y="508" style="fill: $paper_color_0; font-size: 10px">$bottom_left_4</text>
64
+ <text kr:node="Bottom_Left_Text_0" x="20" y="452" style="fill: $paper_color_0; font-size: 10px">$bottom_left_0</text>
65
+ <text kr:node="Bottom_Left_Text_1" x="20" y="466" style="fill: $paper_color_0; font-size: 10px">$bottom_left_1</text>
66
+ <text kr:node="Bottom_Left_Text_2" x="20" y="480" style="fill: $paper_color_0; font-size: 10px">$bottom_left_2</text>
67
+ <text kr:node="Bottom_Left_Text_3" x="20" y="494" style="fill: $paper_color_0; font-size: 10px">$bottom_left_3</text>
68
+ <text kr:node="Bottom_Left_Text_4" x="20" y="508" style="fill: $paper_color_0; font-size: 10px">$bottom_left_4</text>
69
69
  </g>
70
70
 
71
71
  <!-- Lunar Phase -->
@@ -738,4 +738,4 @@
738
738
  />
739
739
  </symbol>
740
740
  </defs>
741
- </svg>
741
+ </svg>
kerykeion/report.py CHANGED
@@ -34,7 +34,6 @@ ASPECT_SYMBOLS = {
34
34
  MOVEMENT_SYMBOLS = {
35
35
  "Applying": "→",
36
36
  "Separating": "←",
37
- "Exact": "✓",
38
37
  }
39
38
 
40
39
 
@@ -17,8 +17,14 @@ SignNumbers = Literal[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
17
17
  """Literal type for Zodiac Sign Numbers, the signs are numbered in order starting from Aries (0) to Pis (11)"""
18
18
 
19
19
 
20
- AspectMovementType = Literal["Applying", "Separating", "Exact"]
21
- """Literal type for Aspect Movement: Applying (planets moving toward exact aspect), Separating (planets moving away), or Exact (within tight orb)"""
20
+ AspectMovementType = Literal["Applying", "Separating", "Fixed"]
21
+ """Literal type for Aspect Movement.
22
+
23
+ Values:
24
+ - "Applying": planets are moving toward the exact aspect (orb decreasing).
25
+ - "Separating": planets are moving away from the exact aspect (orb increasing).
26
+ - "Fixed": both points are effectively fixed so the orb does not change over time.
27
+ """
22
28
 
23
29
 
24
30
  Houses = Literal["First_House", "Second_House", "Third_House", "Fourth_House", "Fifth_House", "Sixth_House", "Seventh_House", "Eighth_House", "Ninth_House", "Tenth_House", "Eleventh_House", "Twelfth_House"]
@@ -299,8 +299,8 @@ class AspectModel(SubscriptableBaseModel):
299
299
  p1: int
300
300
  p2: int
301
301
  aspect_movement: AspectMovementType = Field(
302
- description="Indicates whether the aspect is applying (planets moving toward exact aspect), "
303
- "separating (planets moving away from exact aspect), or exact (within tight orb)."
302
+ description="Indicates whether the aspect is applying (orb decreasing), "
303
+ "separating (orb increasing), or fixed (no relative motion)."
304
304
  )
305
305
 
306
306