kerykeion.charts.charts_utils

  1import math
  2import datetime
  3from kerykeion.kr_types import KerykeionException, ChartType
  4from typing import Union
  5
  6
  7def decHourJoin(inH: int, inM: int, inS: int) -> float:
  8    """Join hour, minutes, seconds, timezone integer to hour float.
  9
 10    Args:
 11        - inH (int): hour
 12        - inM (int): minutes
 13        - inS (int): seconds
 14    Returns:
 15        float: hour in float format
 16    """
 17
 18    dh = float(inH)
 19    dm = float(inM) / 60
 20    ds = float(inS) / 3600
 21    output = dh + dm + ds
 22    return output
 23
 24
 25def degreeDiff(a: Union[int, float], b: Union[int, float]) -> float:
 26    """Calculate the difference between two degrees.
 27
 28    Args:
 29        - a (int | float): first degree
 30        - b (int | float): second degree
 31
 32    Returns:
 33        float: difference between a and b
 34    """
 35
 36    out = float()
 37    if a > b:
 38        out = a - b
 39    if a < b:
 40        out = b - a
 41    if out > 180.0:
 42        out = 360.0 - out
 43    return out
 44
 45
 46def offsetToTz(datetime_offset: Union[datetime.timedelta, None]) -> float:
 47    """Convert datetime offset to float in hours.
 48
 49    Args:
 50        - datetime_offset (datetime.timedelta): datetime offset
 51
 52    Returns:
 53        - float: offset in hours
 54    """
 55
 56    if datetime_offset is None:
 57        raise KerykeionException("datetime_offset is None")
 58
 59    # days to hours
 60    dh = float(datetime_offset.days * 24)
 61    # seconds to hours
 62    sh = float(datetime_offset.seconds / 3600.0)
 63    # total hours
 64    output = dh + sh
 65    return output
 66
 67
 68def sliceToX(slice: Union[int, float], radius: Union[int, float], offset: Union[int, float]) -> float:
 69    """Calculates the x-coordinate of a point on a circle based on the slice, radius, and offset.
 70
 71    Args:
 72        - slice (int | float): Represents the
 73            slice of the circle to calculate the x-coordinate for.
 74            It must be  between 0 and 11 (inclusive).
 75        - radius (int | float): Represents the radius of the circle.
 76        - offset (int | float): Represents the offset in degrees.
 77            It must be between 0 and 360 (inclusive).
 78
 79    Returns:
 80        float: The x-coordinate of the point on the circle.
 81
 82    Example:
 83        >>> import math
 84        >>> sliceToX(3, 5, 45)
 85        2.5000000000000018
 86    """
 87
 88    plus = (math.pi * offset) / 180
 89    radial = ((math.pi / 6) * slice) + plus
 90    return radius * (math.cos(radial) + 1)
 91
 92
 93def sliceToY(slice: Union[int, float], r: Union[int, float], offset: Union[int, float]) -> float:
 94    """Calculates the y-coordinate of a point on a circle based on the slice, radius, and offset.
 95
 96    Args:
 97        - slice (int | float): Represents the slice of the circle to calculate
 98            the y-coordinate for. It must be between 0 and 11 (inclusive).
 99        - r (int | float): Represents the radius of the circle.
100        - offset (int | float): Represents the offset in degrees.
101            It must be between 0 and 360 (inclusive).
102
103    Returns:
104        float: The y-coordinate of the point on the circle.
105
106    Example:
107        >>> import math
108        >>> __sliceToY(3, 5, 45)
109        -4.330127018922194
110    """
111    plus = (math.pi * offset) / 180
112    radial = ((math.pi / 6) * slice) + plus
113    return r * ((math.sin(radial) / -1) + 1)
114
115
116def draw_zodiac_slice(
117    c1: Union[int, float],
118    chart_type: ChartType,
119    seventh_house_degree_ut: Union[int, float],
120    num: int,
121    r: Union[int, float],
122    style: str,
123    type: str,
124) -> str:
125    """Draws a zodiac slice based on the given parameters.
126
127    Args:
128        - c1 (Union[int, float]): The value of c1.
129        - chart_type (ChartType): The type of chart.
130        - seventh_house_degree_ut (Union[int, float]): The degree of the seventh house.
131        - num (int): The number of the sign. Note: In OpenAstro it did refer to self.zodiac,
132            which is a list of the signs in order, starting with Aries. Eg:
133            {"name": "aries", "element": "fire"}
134        - r (Union[int, float]): The value of r.
135        - style (str): The CSS inline style.
136        - type (str): The type ?. In OpenAstro, it was the symbol of the sign. Eg: "aries".
137            self.zodiac[i]["name"]
138
139    Returns:
140        - str: The zodiac slice and symbol as an SVG path.
141    """
142
143    # pie slices
144    offset = 360 - seventh_house_degree_ut
145    # check transit
146    if chart_type == "Transit" or chart_type == "Synastry":
147        dropin = 0
148    else:
149        dropin = c1
150    slice = f'<path d="M{str(r)},{str(r)} L{str(dropin + sliceToX(num, r - dropin, offset))},{str(dropin + sliceToY(num, r - dropin, offset))} A{str(r - dropin)},{str(r - dropin)} 0 0,0 {str(dropin + sliceToX(num + 1, r - dropin, offset))},{str(dropin + sliceToY(num + 1, r - dropin, offset))} z" style="{style}"/>'
151
152    # symbols
153    offset = offset + 15
154    # check transit
155    if chart_type == "Transit" or chart_type == "Synastry":
156        dropin = 54
157    else:
158        dropin = 18 + c1
159    sign = f'<g transform="translate(-16,-16)"><use x="{str(dropin + sliceToX(num, r - dropin, offset))}" y="{str(dropin + sliceToY(num, r - dropin, offset))}" xlink:href="#{type}" /></g>'
160
161    return slice + "" + sign
162
163
164def convert_latitude_coordinate_to_string(coord: Union[int, float], north_label: str, south_label: str) -> str:
165    """Converts a floating point latitude to string with
166    degree, minutes and seconds and the appropriate sign
167    (north or south). Eg. 52.1234567 -> 52°7'25" N
168
169    Args:
170        - coord (float | int): latitude in floating or integer format
171        - north_label (str): String label for north
172        - south_label (str): String label for south
173    Returns:
174        - str: latitude in string format with degree, minutes,
175        seconds and sign (N/S)
176    """
177
178    sign = north_label
179    if coord < 0.0:
180        sign = south_label
181        coord = abs(coord)
182    deg = int(coord)
183    min = int((float(coord) - deg) * 60)
184    sec = int(round(float(((float(coord) - deg) * 60) - min) * 60.0))
185    return f"{deg}°{min}'{sec}\" {sign}"
186
187
188def convert_longitude_coordinate_to_string(coord: Union[int, float], east_label: str, west_label: str) -> str:
189    """Converts a floating point longitude to string with
190    degree, minutes and seconds and the appropriate sign
191    (east or west). Eg. 52.1234567 -> 52°7'25" E
192
193    Args:
194        - coord (float|int): longitude in floating point format
195        - east_label (str): String label for east
196        - west_label (str): String label for west
197    Returns:
198        str: longitude in string format with degree, minutes,
199            seconds and sign (E/W)
200    """
201
202    sign = east_label
203    if coord < 0.0:
204        sign = west_label
205        coord = abs(coord)
206    deg = int(coord)
207    min = int((float(coord) - deg) * 60)
208    sec = int(round(float(((float(coord) - deg) * 60) - min) * 60.0))
209    return f"{deg}°{min}'{sec}\" {sign}"
210
211
212def draw_aspect_line(
213    r: Union[int, float],
214    ar: Union[int, float],
215    degA: Union[int, float],
216    degB: Union[int, float],
217    color: str,
218    seventh_house_degree_ut: Union[int, float],
219) -> str:
220    """Draws svg aspects: ring, aspect ring, degreeA degreeB
221
222    Args:
223        - r (Union[int, float]): The value of r.
224        - ar (Union[int, float]): The value of ar.
225        - degA (Union[int, float]): The degree of A.
226        - degB (Union[int, float]): The degree of B.
227        - color (str): The color of the aspect.
228        - seventh_house_degree_ut (Union[int, float]): The degree of the seventh house.
229
230    Returns:
231        str: The SVG line element as a string.
232    """
233
234    first_offset = (int(seventh_house_degree_ut) / -1) + int(degA)
235    x1 = sliceToX(0, ar, first_offset) + (r - ar)
236    y1 = sliceToY(0, ar, first_offset) + (r - ar)
237
238    second_offset = (int(seventh_house_degree_ut) / -1) + int(degB)
239    x2 = sliceToX(0, ar, second_offset) + (r - ar)
240    y2 = sliceToY(0, ar, second_offset) + (r - ar)
241
242    out = f'<line class="aspect" x1="{x1}" y1="{y1}" x2="{x2}" y2="{y2}" style="stroke: {color}; stroke-width: 1; stroke-opacity: .9;"/>'
243
244    return out
245
246
247def draw_elements_percentages(
248    fire_label: str,
249    fire_points: float,
250    earth_label: str,
251    earth_points: float,
252    air_label: str,
253    air_points: float,
254    water_label: str,
255    water_points: float,
256) -> str:
257    """Draw the elements grid.
258
259    Args:
260        - fire_label (str): Label for fire
261        - fire_points (float): Points for fire
262        - earth_label (str): Label for earth
263        - earth_points (float): Points for earth
264        - air_label (str): Label for air
265        - air_points (float): Points for air
266        - water_label (str): Label for water
267        - water_points (float): Points for water
268
269    Returns:
270        str: The SVG elements grid as a string.
271    """
272    total = fire_points + earth_points + air_points + water_points
273
274    fire_percentage = int(round(100 * fire_points / total))
275    earth_percentage = int(round(100 * earth_points / total))
276    air_percentage = int(round(100 * air_points / total))
277    water_percentage = int(round(100 * water_points / total))
278
279    out = '<g transform="translate(-30,79)">'
280    out += f'<text y="0" style="fill:#ff6600; font-size: 10px;">{fire_label}  {str(fire_percentage)}%</text>'
281    out += f'<text y="12" style="fill:#6a2d04; font-size: 10px;">{earth_label} {str(earth_percentage)}%</text>'
282    out += f'<text y="24" style="fill:#6f76d1; font-size: 10px;">{air_label}   {str(air_percentage)}%</text>'
283    out += f'<text y="36" style="fill:#630e73; font-size: 10px;">{water_label} {str(water_percentage)}%</text>'
284    out += "</g>"
285
286    return out
287
288
289def convert_decimal_to_degree_string(dec: float, type="3") -> str:
290    """
291    Coverts decimal float to degrees in format a°b'c".
292
293    Args:
294        - dec (float): decimal float
295        - type (str): type of format:
296            - 1: a°
297            - 2: a°b'
298            - 3: a°b'c"
299
300    Returns:
301        str: degrees in format a°b'c"
302    """
303
304    dec = float(dec)
305    a = int(dec)
306    a_new = (dec - float(a)) * 60.0
307    b_rounded = int(round(a_new))
308    b = int(a_new)
309    c = int(round((a_new - float(b)) * 60.0))
310
311    if type == "3":
312        out = f"{a:02d}&#176;{b:02d}&#39;{c:02d}&#34;"
313    elif type == "2":
314        out = f"{a:02d}&#176;{b_rounded:02d}&#39;"
315    elif type == "1":
316        out = f"{a:02d}&#176;"
317    else:
318        raise KerykeionException(f"Wrong type: {type}, it must be 1, 2 or 3.")
319
320    return str(out)
321
322
323def draw_transit_ring_degree_steps(r: Union[int, float], seventh_house_degree_ut: Union[int, float]) -> str:
324    """Draws the transit ring degree steps.
325
326    Args:
327        - r (Union[int, float]): The value of r.
328        - seventh_house_degree_ut (Union[int, float]): The degree of the seventh house.
329
330    Returns:
331        str: The SVG path of the transit ring degree steps.
332    """
333
334    out = '<g id="transitRingDegreeSteps">'
335    for i in range(72):
336        offset = float(i * 5) - seventh_house_degree_ut
337        if offset < 0:
338            offset = offset + 360.0
339        elif offset > 360:
340            offset = offset - 360.0
341        x1 = sliceToX(0, r, offset)
342        y1 = sliceToY(0, r, offset)
343        x2 = sliceToX(0, r + 2, offset) - 2
344        y2 = sliceToY(0, r + 2, offset) - 2
345        out += f'<line x1="{x1}" y1="{y1}" x2="{x2}" y2="{y2}" style="stroke: #F00; stroke-width: 1px; stroke-opacity:.9;"/>'
346    out += "</g>"
347    
348    return out
349
350
351def draw_degree_ring(r: Union[int, float], c1: Union[int, float], seventh_house_degree_ut: Union[int, float], stroke_color: str) -> str:
352    """Draws the degree ring.
353    
354    Args:
355        - r (Union[int, float]): The value of r.
356        - c1 (Union[int, float]): The value of c1.
357        - seventh_house_degree_ut (Union[int, float]): The degree of the seventh house.
358        - stroke_color (str): The color of the stroke.
359        
360    Returns:
361        str: The SVG path of the degree ring.
362    """
363    out = '<g id="degreeRing">'
364    for i in range(72):
365        offset = float(i * 5) - seventh_house_degree_ut
366        if offset < 0:
367            offset = offset + 360.0
368        elif offset > 360:
369            offset = offset - 360.0
370        x1 = sliceToX(0, r - c1, offset) + c1
371        y1 = sliceToY(0, r - c1, offset) + c1
372        x2 = sliceToX(0, r + 2 - c1, offset) - 2 + c1
373        y2 = sliceToY(0, r + 2 - c1, offset) - 2 + c1
374
375        out += f'<line x1="{x1}" y1="{y1}" x2="{x2}" y2="{y2}" style="stroke: {stroke_color}; stroke-width: 1px; stroke-opacity:.9;"/>'
376    out += "</g>"
377    
378    return out
379
380def draw_transit_ring(r: Union[int, float], paper_1_color: str, zodiac_transit_ring_3_color: str) -> str:
381    """
382    Draws the transit ring.
383    
384    Args:
385        - r (Union[int, float]): The value of r.
386        - paper_1_color (str): The color of paper 1.
387        - zodiac_transit_ring_3_color (str): The color of the zodiac transit ring
388        
389    Returns:
390        str: The SVG path of the transit ring.
391    """
392    radius_offset = 18
393
394    out = f'<circle cx="{r}" cy="{r}" r="{r - radius_offset}" style="fill: none; stroke: {paper_1_color}; stroke-width: 36px; stroke-opacity: .4;"/>'
395    out += f'<circle cx="{r}" cy="{r}" r="{r}" style="fill: none; stroke: {zodiac_transit_ring_3_color}; stroke-width: 1px; stroke-opacity: .6;"/>'
396
397    return out
398
399
400def draw_first_circle(r: Union[int, float], stroke_color: str, chart_type: ChartType, c1: Union[int, float, None] = None) -> str:
401    """
402    Draws the first circle.
403    
404    Args:
405        - r (Union[int, float]): The value of r.
406        - color (str): The color of the circle.
407        - chart_type (ChartType): The type of chart.
408        - c1 (Union[int, float]): The value of c1.
409        
410    Returns:
411        str: The SVG path of the first circle.
412    """
413    if chart_type == "Synastry" or chart_type == "Transit":
414        return f'<circle cx="{r}" cy="{r}" r="{r - 36}" style="fill: none; stroke: {stroke_color}; stroke-width: 1px; stroke-opacity:.4;" />'
415    else:
416        if c1 is None:
417            raise KerykeionException("c1 is None")
418
419        return f'<circle cx="{r}" cy="{r}" r="{r - c1}" style="fill: none; stroke: {stroke_color}; stroke-width: 1px; " />'
420
421
422def draw_second_circle(r: Union[int, float], stroke_color: str, fill_color: str, chart_type: ChartType, c2: Union[int, float, None] = None) -> str:
423    """
424    Draws the second circle.
425    
426    Args:
427        - r (Union[int, float]): The value of r.
428        - stroke_color (str): The color of the stroke.
429        - fill_color (str): The color of the fill.
430        - chart_type (ChartType): The type of chart.
431        - c2 (Union[int, float]): The value of c2.
432        
433    Returns:
434        str: The SVG path of the second circle.
435    """
436    
437    if chart_type == "Synastry" or chart_type == "Transit":
438        return f'<circle cx="{r}" cy="{r}" r="{r - 72}" style="fill: {fill_color}; fill-opacity:.4; stroke: {stroke_color}; stroke-opacity:.4; stroke-width: 1px" />'
439    
440    else:
441        if c2 is None:
442            raise KerykeionException("c2 is None")
443
444        return f'<circle cx="{r}" cy="{r}" r="{r - c2}" style="fill: {fill_color}; fill-opacity:.2; stroke: {stroke_color}; stroke-opacity:.4; stroke-width: 1px" />'
def decHourJoin(inH: int, inM: int, inS: int) -> float:
 8def decHourJoin(inH: int, inM: int, inS: int) -> float:
 9    """Join hour, minutes, seconds, timezone integer to hour float.
10
11    Args:
12        - inH (int): hour
13        - inM (int): minutes
14        - inS (int): seconds
15    Returns:
16        float: hour in float format
17    """
18
19    dh = float(inH)
20    dm = float(inM) / 60
21    ds = float(inS) / 3600
22    output = dh + dm + ds
23    return output

Join hour, minutes, seconds, timezone integer to hour float.

Args: - inH (int): hour - inM (int): minutes - inS (int): seconds Returns: float: hour in float format

def degreeDiff(a: Union[int, float], b: Union[int, float]) -> float:
26def degreeDiff(a: Union[int, float], b: Union[int, float]) -> float:
27    """Calculate the difference between two degrees.
28
29    Args:
30        - a (int | float): first degree
31        - b (int | float): second degree
32
33    Returns:
34        float: difference between a and b
35    """
36
37    out = float()
38    if a > b:
39        out = a - b
40    if a < b:
41        out = b - a
42    if out > 180.0:
43        out = 360.0 - out
44    return out

Calculate the difference between two degrees.

Args: - a (int | float): first degree - b (int | float): second degree

Returns: float: difference between a and b

def offsetToTz(datetime_offset: Optional[datetime.timedelta]) -> float:
47def offsetToTz(datetime_offset: Union[datetime.timedelta, None]) -> float:
48    """Convert datetime offset to float in hours.
49
50    Args:
51        - datetime_offset (datetime.timedelta): datetime offset
52
53    Returns:
54        - float: offset in hours
55    """
56
57    if datetime_offset is None:
58        raise KerykeionException("datetime_offset is None")
59
60    # days to hours
61    dh = float(datetime_offset.days * 24)
62    # seconds to hours
63    sh = float(datetime_offset.seconds / 3600.0)
64    # total hours
65    output = dh + sh
66    return output

Convert datetime offset to float in hours.

Args: - datetime_offset (datetime.timedelta): datetime offset

Returns: - float: offset in hours

def sliceToX( slice: Union[int, float], radius: Union[int, float], offset: Union[int, float]) -> float:
69def sliceToX(slice: Union[int, float], radius: Union[int, float], offset: Union[int, float]) -> float:
70    """Calculates the x-coordinate of a point on a circle based on the slice, radius, and offset.
71
72    Args:
73        - slice (int | float): Represents the
74            slice of the circle to calculate the x-coordinate for.
75            It must be  between 0 and 11 (inclusive).
76        - radius (int | float): Represents the radius of the circle.
77        - offset (int | float): Represents the offset in degrees.
78            It must be between 0 and 360 (inclusive).
79
80    Returns:
81        float: The x-coordinate of the point on the circle.
82
83    Example:
84        >>> import math
85        >>> sliceToX(3, 5, 45)
86        2.5000000000000018
87    """
88
89    plus = (math.pi * offset) / 180
90    radial = ((math.pi / 6) * slice) + plus
91    return radius * (math.cos(radial) + 1)

Calculates the x-coordinate of a point on a circle based on the slice, radius, and offset.

Args: - slice (int | float): Represents the slice of the circle to calculate the x-coordinate for. It must be between 0 and 11 (inclusive). - radius (int | float): Represents the radius of the circle. - offset (int | float): Represents the offset in degrees. It must be between 0 and 360 (inclusive).

Returns: float: The x-coordinate of the point on the circle.

Example:

import math sliceToX(3, 5, 45) 2.5000000000000018

def sliceToY( slice: Union[int, float], r: Union[int, float], offset: Union[int, float]) -> float:
 94def sliceToY(slice: Union[int, float], r: Union[int, float], offset: Union[int, float]) -> float:
 95    """Calculates the y-coordinate of a point on a circle based on the slice, radius, and offset.
 96
 97    Args:
 98        - slice (int | float): Represents the slice of the circle to calculate
 99            the y-coordinate for. It must be between 0 and 11 (inclusive).
100        - r (int | float): Represents the radius of the circle.
101        - offset (int | float): Represents the offset in degrees.
102            It must be between 0 and 360 (inclusive).
103
104    Returns:
105        float: The y-coordinate of the point on the circle.
106
107    Example:
108        >>> import math
109        >>> __sliceToY(3, 5, 45)
110        -4.330127018922194
111    """
112    plus = (math.pi * offset) / 180
113    radial = ((math.pi / 6) * slice) + plus
114    return r * ((math.sin(radial) / -1) + 1)

Calculates the y-coordinate of a point on a circle based on the slice, radius, and offset.

Args: - slice (int | float): Represents the slice of the circle to calculate the y-coordinate for. It must be between 0 and 11 (inclusive). - r (int | float): Represents the radius of the circle. - offset (int | float): Represents the offset in degrees. It must be between 0 and 360 (inclusive).

Returns: float: The y-coordinate of the point on the circle.

Example:

import math __sliceToY(3, 5, 45) -4.330127018922194

def draw_zodiac_slice( c1: Union[int, float], chart_type: Literal['Natal', 'ExternalNatal', 'Synastry', 'Transit'], seventh_house_degree_ut: Union[int, float], num: int, r: Union[int, float], style: str, type: str) -> str:
117def draw_zodiac_slice(
118    c1: Union[int, float],
119    chart_type: ChartType,
120    seventh_house_degree_ut: Union[int, float],
121    num: int,
122    r: Union[int, float],
123    style: str,
124    type: str,
125) -> str:
126    """Draws a zodiac slice based on the given parameters.
127
128    Args:
129        - c1 (Union[int, float]): The value of c1.
130        - chart_type (ChartType): The type of chart.
131        - seventh_house_degree_ut (Union[int, float]): The degree of the seventh house.
132        - num (int): The number of the sign. Note: In OpenAstro it did refer to self.zodiac,
133            which is a list of the signs in order, starting with Aries. Eg:
134            {"name": "aries", "element": "fire"}
135        - r (Union[int, float]): The value of r.
136        - style (str): The CSS inline style.
137        - type (str): The type ?. In OpenAstro, it was the symbol of the sign. Eg: "aries".
138            self.zodiac[i]["name"]
139
140    Returns:
141        - str: The zodiac slice and symbol as an SVG path.
142    """
143
144    # pie slices
145    offset = 360 - seventh_house_degree_ut
146    # check transit
147    if chart_type == "Transit" or chart_type == "Synastry":
148        dropin = 0
149    else:
150        dropin = c1
151    slice = f'<path d="M{str(r)},{str(r)} L{str(dropin + sliceToX(num, r - dropin, offset))},{str(dropin + sliceToY(num, r - dropin, offset))} A{str(r - dropin)},{str(r - dropin)} 0 0,0 {str(dropin + sliceToX(num + 1, r - dropin, offset))},{str(dropin + sliceToY(num + 1, r - dropin, offset))} z" style="{style}"/>'
152
153    # symbols
154    offset = offset + 15
155    # check transit
156    if chart_type == "Transit" or chart_type == "Synastry":
157        dropin = 54
158    else:
159        dropin = 18 + c1
160    sign = f'<g transform="translate(-16,-16)"><use x="{str(dropin + sliceToX(num, r - dropin, offset))}" y="{str(dropin + sliceToY(num, r - dropin, offset))}" xlink:href="#{type}" /></g>'
161
162    return slice + "" + sign

Draws a zodiac slice based on the given parameters.

Args: - c1 (Union[int, float]): The value of c1. - chart_type (ChartType): The type of chart. - seventh_house_degree_ut (Union[int, float]): The degree of the seventh house. - num (int): The number of the sign. Note: In OpenAstro it did refer to self.zodiac, which is a list of the signs in order, starting with Aries. Eg: {"name": "aries", "element": "fire"} - r (Union[int, float]): The value of r. - style (str): The CSS inline style. - type (str): The type ?. In OpenAstro, it was the symbol of the sign. Eg: "aries". self.zodiac[i]["name"]

Returns: - str: The zodiac slice and symbol as an SVG path.

def convert_latitude_coordinate_to_string(coord: Union[int, float], north_label: str, south_label: str) -> str:
165def convert_latitude_coordinate_to_string(coord: Union[int, float], north_label: str, south_label: str) -> str:
166    """Converts a floating point latitude to string with
167    degree, minutes and seconds and the appropriate sign
168    (north or south). Eg. 52.1234567 -> 52°7'25" N
169
170    Args:
171        - coord (float | int): latitude in floating or integer format
172        - north_label (str): String label for north
173        - south_label (str): String label for south
174    Returns:
175        - str: latitude in string format with degree, minutes,
176        seconds and sign (N/S)
177    """
178
179    sign = north_label
180    if coord < 0.0:
181        sign = south_label
182        coord = abs(coord)
183    deg = int(coord)
184    min = int((float(coord) - deg) * 60)
185    sec = int(round(float(((float(coord) - deg) * 60) - min) * 60.0))
186    return f"{deg}°{min}'{sec}\" {sign}"

Converts a floating point latitude to string with degree, minutes and seconds and the appropriate sign (north or south). Eg. 52.1234567 -> 52°7'25" N

Args: - coord (float | int): latitude in floating or integer format - north_label (str): String label for north - south_label (str): String label for south Returns: - str: latitude in string format with degree, minutes, seconds and sign (N/S)

def convert_longitude_coordinate_to_string(coord: Union[int, float], east_label: str, west_label: str) -> str:
189def convert_longitude_coordinate_to_string(coord: Union[int, float], east_label: str, west_label: str) -> str:
190    """Converts a floating point longitude to string with
191    degree, minutes and seconds and the appropriate sign
192    (east or west). Eg. 52.1234567 -> 52°7'25" E
193
194    Args:
195        - coord (float|int): longitude in floating point format
196        - east_label (str): String label for east
197        - west_label (str): String label for west
198    Returns:
199        str: longitude in string format with degree, minutes,
200            seconds and sign (E/W)
201    """
202
203    sign = east_label
204    if coord < 0.0:
205        sign = west_label
206        coord = abs(coord)
207    deg = int(coord)
208    min = int((float(coord) - deg) * 60)
209    sec = int(round(float(((float(coord) - deg) * 60) - min) * 60.0))
210    return f"{deg}°{min}'{sec}\" {sign}"

Converts a floating point longitude to string with degree, minutes and seconds and the appropriate sign (east or west). Eg. 52.1234567 -> 52°7'25" E

Args: - coord (float|int): longitude in floating point format - east_label (str): String label for east - west_label (str): String label for west Returns: str: longitude in string format with degree, minutes, seconds and sign (E/W)

def draw_aspect_line( r: Union[int, float], ar: Union[int, float], degA: Union[int, float], degB: Union[int, float], color: str, seventh_house_degree_ut: Union[int, float]) -> str:
213def draw_aspect_line(
214    r: Union[int, float],
215    ar: Union[int, float],
216    degA: Union[int, float],
217    degB: Union[int, float],
218    color: str,
219    seventh_house_degree_ut: Union[int, float],
220) -> str:
221    """Draws svg aspects: ring, aspect ring, degreeA degreeB
222
223    Args:
224        - r (Union[int, float]): The value of r.
225        - ar (Union[int, float]): The value of ar.
226        - degA (Union[int, float]): The degree of A.
227        - degB (Union[int, float]): The degree of B.
228        - color (str): The color of the aspect.
229        - seventh_house_degree_ut (Union[int, float]): The degree of the seventh house.
230
231    Returns:
232        str: The SVG line element as a string.
233    """
234
235    first_offset = (int(seventh_house_degree_ut) / -1) + int(degA)
236    x1 = sliceToX(0, ar, first_offset) + (r - ar)
237    y1 = sliceToY(0, ar, first_offset) + (r - ar)
238
239    second_offset = (int(seventh_house_degree_ut) / -1) + int(degB)
240    x2 = sliceToX(0, ar, second_offset) + (r - ar)
241    y2 = sliceToY(0, ar, second_offset) + (r - ar)
242
243    out = f'<line class="aspect" x1="{x1}" y1="{y1}" x2="{x2}" y2="{y2}" style="stroke: {color}; stroke-width: 1; stroke-opacity: .9;"/>'
244
245    return out

Draws svg aspects: ring, aspect ring, degreeA degreeB

Args: - r (Union[int, float]): The value of r. - ar (Union[int, float]): The value of ar. - degA (Union[int, float]): The degree of A. - degB (Union[int, float]): The degree of B. - color (str): The color of the aspect. - seventh_house_degree_ut (Union[int, float]): The degree of the seventh house.

Returns: str: The SVG line element as a string.

def draw_elements_percentages( fire_label: str, fire_points: float, earth_label: str, earth_points: float, air_label: str, air_points: float, water_label: str, water_points: float) -> str:
248def draw_elements_percentages(
249    fire_label: str,
250    fire_points: float,
251    earth_label: str,
252    earth_points: float,
253    air_label: str,
254    air_points: float,
255    water_label: str,
256    water_points: float,
257) -> str:
258    """Draw the elements grid.
259
260    Args:
261        - fire_label (str): Label for fire
262        - fire_points (float): Points for fire
263        - earth_label (str): Label for earth
264        - earth_points (float): Points for earth
265        - air_label (str): Label for air
266        - air_points (float): Points for air
267        - water_label (str): Label for water
268        - water_points (float): Points for water
269
270    Returns:
271        str: The SVG elements grid as a string.
272    """
273    total = fire_points + earth_points + air_points + water_points
274
275    fire_percentage = int(round(100 * fire_points / total))
276    earth_percentage = int(round(100 * earth_points / total))
277    air_percentage = int(round(100 * air_points / total))
278    water_percentage = int(round(100 * water_points / total))
279
280    out = '<g transform="translate(-30,79)">'
281    out += f'<text y="0" style="fill:#ff6600; font-size: 10px;">{fire_label}  {str(fire_percentage)}%</text>'
282    out += f'<text y="12" style="fill:#6a2d04; font-size: 10px;">{earth_label} {str(earth_percentage)}%</text>'
283    out += f'<text y="24" style="fill:#6f76d1; font-size: 10px;">{air_label}   {str(air_percentage)}%</text>'
284    out += f'<text y="36" style="fill:#630e73; font-size: 10px;">{water_label} {str(water_percentage)}%</text>'
285    out += "</g>"
286
287    return out

Draw the elements grid.

Args: - fire_label (str): Label for fire - fire_points (float): Points for fire - earth_label (str): Label for earth - earth_points (float): Points for earth - air_label (str): Label for air - air_points (float): Points for air - water_label (str): Label for water - water_points (float): Points for water

Returns: str: The SVG elements grid as a string.

def convert_decimal_to_degree_string(dec: float, type='3') -> str:
290def convert_decimal_to_degree_string(dec: float, type="3") -> str:
291    """
292    Coverts decimal float to degrees in format a°b'c".
293
294    Args:
295        - dec (float): decimal float
296        - type (str): type of format:
297            - 1: a°
298            - 2: a°b'
299            - 3: a°b'c"
300
301    Returns:
302        str: degrees in format a°b'c"
303    """
304
305    dec = float(dec)
306    a = int(dec)
307    a_new = (dec - float(a)) * 60.0
308    b_rounded = int(round(a_new))
309    b = int(a_new)
310    c = int(round((a_new - float(b)) * 60.0))
311
312    if type == "3":
313        out = f"{a:02d}&#176;{b:02d}&#39;{c:02d}&#34;"
314    elif type == "2":
315        out = f"{a:02d}&#176;{b_rounded:02d}&#39;"
316    elif type == "1":
317        out = f"{a:02d}&#176;"
318    else:
319        raise KerykeionException(f"Wrong type: {type}, it must be 1, 2 or 3.")
320
321    return str(out)

Coverts decimal float to degrees in format a°b'c".

Args: - dec (float): decimal float - type (str): type of format: - 1: a° - 2: a°b' - 3: a°b'c"

Returns: str: degrees in format a°b'c"

def draw_transit_ring_degree_steps(r: Union[int, float], seventh_house_degree_ut: Union[int, float]) -> str:
324def draw_transit_ring_degree_steps(r: Union[int, float], seventh_house_degree_ut: Union[int, float]) -> str:
325    """Draws the transit ring degree steps.
326
327    Args:
328        - r (Union[int, float]): The value of r.
329        - seventh_house_degree_ut (Union[int, float]): The degree of the seventh house.
330
331    Returns:
332        str: The SVG path of the transit ring degree steps.
333    """
334
335    out = '<g id="transitRingDegreeSteps">'
336    for i in range(72):
337        offset = float(i * 5) - seventh_house_degree_ut
338        if offset < 0:
339            offset = offset + 360.0
340        elif offset > 360:
341            offset = offset - 360.0
342        x1 = sliceToX(0, r, offset)
343        y1 = sliceToY(0, r, offset)
344        x2 = sliceToX(0, r + 2, offset) - 2
345        y2 = sliceToY(0, r + 2, offset) - 2
346        out += f'<line x1="{x1}" y1="{y1}" x2="{x2}" y2="{y2}" style="stroke: #F00; stroke-width: 1px; stroke-opacity:.9;"/>'
347    out += "</g>"
348    
349    return out

Draws the transit ring degree steps.

Args: - r (Union[int, float]): The value of r. - seventh_house_degree_ut (Union[int, float]): The degree of the seventh house.

Returns: str: The SVG path of the transit ring degree steps.

def draw_degree_ring( r: Union[int, float], c1: Union[int, float], seventh_house_degree_ut: Union[int, float], stroke_color: str) -> str:
352def draw_degree_ring(r: Union[int, float], c1: Union[int, float], seventh_house_degree_ut: Union[int, float], stroke_color: str) -> str:
353    """Draws the degree ring.
354    
355    Args:
356        - r (Union[int, float]): The value of r.
357        - c1 (Union[int, float]): The value of c1.
358        - seventh_house_degree_ut (Union[int, float]): The degree of the seventh house.
359        - stroke_color (str): The color of the stroke.
360        
361    Returns:
362        str: The SVG path of the degree ring.
363    """
364    out = '<g id="degreeRing">'
365    for i in range(72):
366        offset = float(i * 5) - seventh_house_degree_ut
367        if offset < 0:
368            offset = offset + 360.0
369        elif offset > 360:
370            offset = offset - 360.0
371        x1 = sliceToX(0, r - c1, offset) + c1
372        y1 = sliceToY(0, r - c1, offset) + c1
373        x2 = sliceToX(0, r + 2 - c1, offset) - 2 + c1
374        y2 = sliceToY(0, r + 2 - c1, offset) - 2 + c1
375
376        out += f'<line x1="{x1}" y1="{y1}" x2="{x2}" y2="{y2}" style="stroke: {stroke_color}; stroke-width: 1px; stroke-opacity:.9;"/>'
377    out += "</g>"
378    
379    return out

Draws the degree ring.

Args: - r (Union[int, float]): The value of r. - c1 (Union[int, float]): The value of c1. - seventh_house_degree_ut (Union[int, float]): The degree of the seventh house. - stroke_color (str): The color of the stroke.

Returns: str: The SVG path of the degree ring.

def draw_transit_ring( r: Union[int, float], paper_1_color: str, zodiac_transit_ring_3_color: str) -> str:
381def draw_transit_ring(r: Union[int, float], paper_1_color: str, zodiac_transit_ring_3_color: str) -> str:
382    """
383    Draws the transit ring.
384    
385    Args:
386        - r (Union[int, float]): The value of r.
387        - paper_1_color (str): The color of paper 1.
388        - zodiac_transit_ring_3_color (str): The color of the zodiac transit ring
389        
390    Returns:
391        str: The SVG path of the transit ring.
392    """
393    radius_offset = 18
394
395    out = f'<circle cx="{r}" cy="{r}" r="{r - radius_offset}" style="fill: none; stroke: {paper_1_color}; stroke-width: 36px; stroke-opacity: .4;"/>'
396    out += f'<circle cx="{r}" cy="{r}" r="{r}" style="fill: none; stroke: {zodiac_transit_ring_3_color}; stroke-width: 1px; stroke-opacity: .6;"/>'
397
398    return out

Draws the transit ring.

Args: - r (Union[int, float]): The value of r. - paper_1_color (str): The color of paper 1. - zodiac_transit_ring_3_color (str): The color of the zodiac transit ring

Returns: str: The SVG path of the transit ring.

def draw_first_circle( r: Union[int, float], stroke_color: str, chart_type: Literal['Natal', 'ExternalNatal', 'Synastry', 'Transit'], c1: Union[int, float, NoneType] = None) -> str:
401def draw_first_circle(r: Union[int, float], stroke_color: str, chart_type: ChartType, c1: Union[int, float, None] = None) -> str:
402    """
403    Draws the first circle.
404    
405    Args:
406        - r (Union[int, float]): The value of r.
407        - color (str): The color of the circle.
408        - chart_type (ChartType): The type of chart.
409        - c1 (Union[int, float]): The value of c1.
410        
411    Returns:
412        str: The SVG path of the first circle.
413    """
414    if chart_type == "Synastry" or chart_type == "Transit":
415        return f'<circle cx="{r}" cy="{r}" r="{r - 36}" style="fill: none; stroke: {stroke_color}; stroke-width: 1px; stroke-opacity:.4;" />'
416    else:
417        if c1 is None:
418            raise KerykeionException("c1 is None")
419
420        return f'<circle cx="{r}" cy="{r}" r="{r - c1}" style="fill: none; stroke: {stroke_color}; stroke-width: 1px; " />'

Draws the first circle.

Args: - r (Union[int, float]): The value of r. - color (str): The color of the circle. - chart_type (ChartType): The type of chart. - c1 (Union[int, float]): The value of c1.

Returns: str: The SVG path of the first circle.

def draw_second_circle( r: Union[int, float], stroke_color: str, fill_color: str, chart_type: Literal['Natal', 'ExternalNatal', 'Synastry', 'Transit'], c2: Union[int, float, NoneType] = None) -> str:
423def draw_second_circle(r: Union[int, float], stroke_color: str, fill_color: str, chart_type: ChartType, c2: Union[int, float, None] = None) -> str:
424    """
425    Draws the second circle.
426    
427    Args:
428        - r (Union[int, float]): The value of r.
429        - stroke_color (str): The color of the stroke.
430        - fill_color (str): The color of the fill.
431        - chart_type (ChartType): The type of chart.
432        - c2 (Union[int, float]): The value of c2.
433        
434    Returns:
435        str: The SVG path of the second circle.
436    """
437    
438    if chart_type == "Synastry" or chart_type == "Transit":
439        return f'<circle cx="{r}" cy="{r}" r="{r - 72}" style="fill: {fill_color}; fill-opacity:.4; stroke: {stroke_color}; stroke-opacity:.4; stroke-width: 1px" />'
440    
441    else:
442        if c2 is None:
443            raise KerykeionException("c2 is None")
444
445        return f'<circle cx="{r}" cy="{r}" r="{r - c2}" style="fill: {fill_color}; fill-opacity:.2; stroke: {stroke_color}; stroke-opacity:.4; stroke-width: 1px" />'

Draws the second circle.

Args: - r (Union[int, float]): The value of r. - stroke_color (str): The color of the stroke. - fill_color (str): The color of the fill. - chart_type (ChartType): The type of chart. - c2 (Union[int, float]): The value of c2.

Returns: str: The SVG path of the second circle.