starplot 0.12.5__py2.py3-none-any.whl → 0.14.0__py2.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 starplot might be problematic. Click here for more details.

Files changed (73) hide show
  1. starplot/__init__.py +3 -2
  2. starplot/base.py +408 -95
  3. starplot/callables.py +61 -7
  4. starplot/coordinates.py +6 -0
  5. starplot/data/bayer.py +1532 -3
  6. starplot/data/constellations.py +564 -2
  7. starplot/data/flamsteed.py +2682 -0
  8. starplot/data/library/constellation_borders_inv.gpkg +0 -0
  9. starplot/data/library/constellation_lines_hips.json +3 -1
  10. starplot/data/stars.py +408 -87
  11. starplot/geometry.py +82 -0
  12. starplot/horizon.py +458 -0
  13. starplot/map.py +97 -284
  14. starplot/models/base.py +9 -2
  15. starplot/models/constellation.py +1 -1
  16. starplot/optic.py +32 -14
  17. starplot/plotters/__init__.py +2 -0
  18. starplot/plotters/constellations.py +339 -0
  19. starplot/plotters/dsos.py +5 -1
  20. starplot/plotters/experimental.py +171 -0
  21. starplot/plotters/milkyway.py +41 -0
  22. starplot/plotters/stars.py +143 -13
  23. starplot/styles/base.py +308 -169
  24. starplot/styles/ext/antique.yml +54 -46
  25. starplot/styles/ext/blue_dark.yml +39 -45
  26. starplot/styles/ext/blue_light.yml +49 -30
  27. starplot/styles/ext/blue_medium.yml +53 -50
  28. starplot/styles/ext/cb_wong.yml +16 -7
  29. starplot/styles/ext/grayscale.yml +17 -10
  30. starplot/styles/ext/grayscale_dark.yml +18 -8
  31. starplot/styles/ext/map.yml +10 -7
  32. starplot/styles/ext/nord.yml +38 -38
  33. starplot/styles/ext/optic.yml +7 -5
  34. starplot/styles/fonts-library/gfs-didot/DESCRIPTION.en_us.html +9 -0
  35. starplot/styles/fonts-library/gfs-didot/GFSDidot-Regular.ttf +0 -0
  36. starplot/styles/fonts-library/gfs-didot/METADATA.pb +16 -0
  37. starplot/styles/fonts-library/gfs-didot/OFL.txt +94 -0
  38. starplot/styles/fonts-library/hind/DESCRIPTION.en_us.html +28 -0
  39. starplot/styles/fonts-library/hind/Hind-Bold.ttf +0 -0
  40. starplot/styles/fonts-library/hind/Hind-Light.ttf +0 -0
  41. starplot/styles/fonts-library/hind/Hind-Medium.ttf +0 -0
  42. starplot/styles/fonts-library/hind/Hind-Regular.ttf +0 -0
  43. starplot/styles/fonts-library/hind/Hind-SemiBold.ttf +0 -0
  44. starplot/styles/fonts-library/hind/METADATA.pb +58 -0
  45. starplot/styles/fonts-library/hind/OFL.txt +93 -0
  46. starplot/styles/fonts-library/inter/Inter-Black.ttf +0 -0
  47. starplot/styles/fonts-library/inter/Inter-BlackItalic.ttf +0 -0
  48. starplot/styles/fonts-library/inter/Inter-Bold.ttf +0 -0
  49. starplot/styles/fonts-library/inter/Inter-BoldItalic.ttf +0 -0
  50. starplot/styles/fonts-library/inter/Inter-ExtraBold.ttf +0 -0
  51. starplot/styles/fonts-library/inter/Inter-ExtraBoldItalic.ttf +0 -0
  52. starplot/styles/fonts-library/inter/Inter-ExtraLight.ttf +0 -0
  53. starplot/styles/fonts-library/inter/Inter-ExtraLightItalic.ttf +0 -0
  54. starplot/styles/fonts-library/inter/Inter-Italic.ttf +0 -0
  55. starplot/styles/fonts-library/inter/Inter-Light.ttf +0 -0
  56. starplot/styles/fonts-library/inter/Inter-LightItalic.ttf +0 -0
  57. starplot/styles/fonts-library/inter/Inter-Medium.ttf +0 -0
  58. starplot/styles/fonts-library/inter/Inter-MediumItalic.ttf +0 -0
  59. starplot/styles/fonts-library/inter/Inter-Regular.ttf +0 -0
  60. starplot/styles/fonts-library/inter/Inter-SemiBold.ttf +0 -0
  61. starplot/styles/fonts-library/inter/Inter-SemiBoldItalic.ttf +0 -0
  62. starplot/styles/fonts-library/inter/Inter-Thin.ttf +0 -0
  63. starplot/styles/fonts-library/inter/Inter-ThinItalic.ttf +0 -0
  64. starplot/styles/fonts-library/inter/LICENSE.txt +92 -0
  65. starplot/styles/fonts.py +15 -0
  66. starplot/styles/markers.py +207 -6
  67. starplot/utils.py +19 -0
  68. starplot/warnings.py +16 -0
  69. {starplot-0.12.5.dist-info → starplot-0.14.0.dist-info}/METADATA +12 -12
  70. starplot-0.14.0.dist-info/RECORD +107 -0
  71. starplot-0.12.5.dist-info/RECORD +0 -67
  72. {starplot-0.12.5.dist-info → starplot-0.14.0.dist-info}/LICENSE +0 -0
  73. {starplot-0.12.5.dist-info → starplot-0.14.0.dist-info}/WHEEL +0 -0
starplot/styles/base.py CHANGED
@@ -1,8 +1,8 @@
1
1
  import json
2
+
2
3
  from enum import Enum
3
4
  from pathlib import Path
4
- from typing import Optional, Union
5
- from functools import cache
5
+ from typing import Optional, Union, List
6
6
 
7
7
  import yaml
8
8
 
@@ -14,7 +14,14 @@ from typing_extensions import Annotated
14
14
 
15
15
  from starplot.data.dsos import DsoType
16
16
  from starplot.styles.helpers import merge_dict
17
- from starplot.styles.markers import ellipse, circle_cross, circle_line
17
+ from starplot.styles.markers import (
18
+ ellipse,
19
+ circle_cross,
20
+ circle_crosshair,
21
+ circle_line,
22
+ circle_dot,
23
+ circle_dotted_rings,
24
+ )
18
25
 
19
26
 
20
27
  ColorStr = Annotated[
@@ -26,10 +33,11 @@ ColorStr = Annotated[
26
33
  ]
27
34
 
28
35
 
29
- FONT_SCALE = 2
30
-
31
36
  HERE = Path(__file__).resolve().parent
32
37
 
38
+ PI = 3.141592653589793
39
+ SQR_2 = 1.41421356237
40
+
33
41
 
34
42
  class BaseStyle(BaseModel):
35
43
  __hash__ = object.__hash__
@@ -97,9 +105,6 @@ class MarkerSymbolEnum(str, Enum):
97
105
  SQUARE_STRIPES_DIAGONAL = "square_stripes_diagonal"
98
106
  """\u25A8"""
99
107
 
100
- # SQUARE_CROSSHAIR = "square_crosshair"
101
- # """\u2BD0"""
102
-
103
108
  STAR = "star"
104
109
  """\u2605"""
105
110
 
@@ -118,11 +123,19 @@ class MarkerSymbolEnum(str, Enum):
118
123
  CIRCLE_CROSS = "circle_cross"
119
124
  """\u1AA0"""
120
125
 
126
+ CIRCLE_CROSSHAIR = "circle_crosshair"
127
+ """No preview available, but this is the standard symbol for planetary nebulae"""
128
+
129
+ CIRCLE_DOT = "circle_dot"
130
+ """\u29BF"""
131
+
121
132
  CIRCLE_DOTTED_EDGE = "circle_dotted_edge"
122
133
  """\u25CC"""
123
134
 
135
+ CIRCLE_DOTTED_RINGS = "circle_dotted_rings"
136
+
124
137
  CIRCLE_LINE = "circle_line"
125
- """\u29B5"""
138
+ """\u29B5 the standard symbol for double stars"""
126
139
 
127
140
  COMET = "comet"
128
141
  """\u2604"""
@@ -150,7 +163,10 @@ class MarkerSymbolEnum(str, Enum):
150
163
  MarkerSymbolEnum.TRIANGLE: "^",
151
164
  MarkerSymbolEnum.CIRCLE_PLUS: "$\u2295$",
152
165
  MarkerSymbolEnum.CIRCLE_CROSS: circle_cross(),
166
+ MarkerSymbolEnum.CIRCLE_CROSSHAIR: circle_crosshair(),
167
+ MarkerSymbolEnum.CIRCLE_DOT: circle_dot(),
153
168
  MarkerSymbolEnum.CIRCLE_DOTTED_EDGE: "$\u25CC$",
169
+ MarkerSymbolEnum.CIRCLE_DOTTED_RINGS: circle_dotted_rings(),
154
170
  MarkerSymbolEnum.CIRCLE_LINE: circle_line(),
155
171
  MarkerSymbolEnum.COMET: "$\u2604$",
156
172
  MarkerSymbolEnum.STAR_8: "$\u2734$",
@@ -188,6 +204,8 @@ class AnchorPointEnum(str, Enum):
188
204
  """Options for the anchor point of labels"""
189
205
 
190
206
  CENTER = "center"
207
+ LEFT_CENTER = "left center"
208
+ RIGHT_CENTER = "right center"
191
209
  TOP_LEFT = "top left"
192
210
  TOP_RIGHT = "top right"
193
211
  TOP_CENTER = "top center"
@@ -219,9 +237,20 @@ class AnchorPointEnum(str, Enum):
219
237
  elif self.value == AnchorPointEnum.CENTER:
220
238
  style["va"] = "center"
221
239
  style["ha"] = "center"
240
+ elif self.value == AnchorPointEnum.LEFT_CENTER:
241
+ style["va"] = "center"
242
+ style["ha"] = "right"
243
+ elif self.value == AnchorPointEnum.RIGHT_CENTER:
244
+ style["va"] = "center"
245
+ style["ha"] = "left"
222
246
 
223
247
  return style
224
248
 
249
+ @staticmethod
250
+ def from_str(value: str) -> "AnchorPointEnum":
251
+ options = {ap.value: ap for ap in AnchorPointEnum}
252
+ return options.get(value)
253
+
225
254
 
226
255
  class ZOrderEnum(int, Enum):
227
256
  """
@@ -245,19 +274,6 @@ class ZOrderEnum(int, Enum):
245
274
  class MarkerStyle(BaseStyle):
246
275
  """
247
276
  Styling properties for markers.
248
-
249
- ???- tip "Example Usage"
250
- Creates a style for a red triangle marker:
251
- ```python
252
- m = MarkerStyle(
253
- color="#b13737",
254
- symbol="triangle",
255
- size=8,
256
- fill="full",
257
- alpha=1.0,
258
- zorder=100,
259
- )
260
- ```
261
277
  """
262
278
 
263
279
  color: Optional[ColorStr] = ColorStr("#000")
@@ -266,14 +282,20 @@ class MarkerStyle(BaseStyle):
266
282
  edge_color: Optional[ColorStr] = ColorStr("#000")
267
283
  """Edge color of marker. Can be a hex, rgb, hsl, or word string."""
268
284
 
269
- edge_width: int = 1
270
- """Edge width of marker. Not available for all marker symbols."""
285
+ edge_width: float = 1
286
+ """Edge width of marker, in points. Not available for all marker symbols."""
287
+
288
+ line_style: Union[LineStyleEnum, tuple] = LineStyleEnum.SOLID
289
+ """Edge line style. Can be a predefined value in `LineStyleEnum` or a [Matplotlib linestyle tuple](https://matplotlib.org/stable/gallery/lines_bars_and_markers/linestyles.html)."""
290
+
291
+ dash_capstyle: DashCapStyleEnum = DashCapStyleEnum.PROJECTING
292
+ """Style of dash endpoints"""
271
293
 
272
294
  symbol: MarkerSymbolEnum = MarkerSymbolEnum.POINT
273
295
  """Symbol for marker"""
274
296
 
275
- size: int = 4
276
- """Relative size of marker"""
297
+ size: float = 22
298
+ """Size of marker in points"""
277
299
 
278
300
  fill: FillStyleEnum = FillStyleEnum.NONE
279
301
  """Fill style of marker"""
@@ -281,53 +303,59 @@ class MarkerStyle(BaseStyle):
281
303
  alpha: float = 1.0
282
304
  """Alpha value (controls transparency)"""
283
305
 
284
- zorder: int = -1
306
+ zorder: int = ZOrderEnum.LAYER_2
285
307
  """Zorder of marker"""
286
308
 
287
309
  @property
288
310
  def symbol_matplot(self) -> str:
289
311
  return MarkerSymbolEnum(self.symbol).as_matplot()
290
312
 
291
- @cache
292
- def matplot_kwargs(self, size_multiplier: float = 1.0) -> dict:
313
+ def matplot_kwargs(self, scale: float = 1.0) -> dict:
293
314
  return dict(
294
315
  color=self.color.as_hex() if self.color else "none",
295
316
  markeredgecolor=self.edge_color.as_hex() if self.edge_color else "none",
296
317
  marker=MarkerSymbolEnum(self.symbol).as_matplot(),
297
- markersize=self.size * size_multiplier * FONT_SCALE,
318
+ markersize=self.size * scale,
298
319
  fillstyle=self.fill,
299
320
  alpha=self.alpha,
300
321
  zorder=self.zorder,
301
322
  )
302
323
 
324
+ def matplot_scatter_kwargs(self, scale: float = 1.0) -> dict:
325
+ plot_kwargs = self.matplot_kwargs(scale)
326
+ plot_kwargs["edgecolors"] = plot_kwargs.pop("markeredgecolor")
327
+
328
+ # matplotlib's plot() function takes the marker size in points diameter
329
+ # and the scatter() function takes it in points squared
330
+ plot_kwargs["s"] = ((plot_kwargs.pop("markersize") / scale) ** 2) * (scale**2)
331
+
332
+ plot_kwargs["c"] = plot_kwargs.pop("color")
333
+ plot_kwargs["linewidths"] = self.edge_width * scale
334
+ plot_kwargs["linestyle"] = self.line_style
335
+ plot_kwargs["capstyle"] = self.dash_capstyle
336
+
337
+ plot_kwargs.pop("fillstyle")
338
+
339
+ return plot_kwargs
340
+
303
341
  def to_polygon_style(self):
304
342
  return PolygonStyle(
305
343
  fill_color=self.color.as_hex() if self.color else None,
306
344
  edge_color=self.edge_color.as_hex() if self.edge_color else None,
345
+ edge_width=self.edge_width,
307
346
  alpha=self.alpha,
308
347
  zorder=self.zorder,
348
+ line_style=self.line_style,
309
349
  )
310
350
 
311
351
 
312
352
  class LineStyle(BaseStyle):
313
353
  """
314
354
  Styling properties for lines.
315
-
316
- ???- tip "Example Usage"
317
- Creates a style for a dashed green line:
318
- ```python
319
- ls = LineStyle(
320
- width=2,
321
- color="#6ba832",
322
- style="dashed",
323
- alpha=0.2,
324
- zorder=-10,
325
- )
326
- ```
327
355
  """
328
356
 
329
- width: float = 2
330
- """Width of line"""
357
+ width: float = 4
358
+ """Width of line in points"""
331
359
 
332
360
  color: ColorStr = ColorStr("#000")
333
361
  """Color of the line. Can be a hex, rgb, hsl, or word string."""
@@ -341,17 +369,17 @@ class LineStyle(BaseStyle):
341
369
  alpha: float = 1.0
342
370
  """Alpha value (controls transparency)"""
343
371
 
344
- zorder: int = -1
372
+ zorder: int = ZOrderEnum.LAYER_2
345
373
  """Zorder of the line"""
346
374
 
347
375
  edge_width: int = 0
348
- """Width of the line's edge. _If the width or color is falsey then the line will NOT be drawn with an edge._"""
376
+ """Width of the line's edge in points. _If the width or color is falsey then the line will NOT be drawn with an edge._"""
349
377
 
350
378
  edge_color: Optional[ColorStr] = None
351
379
  """Edge color of the line. _If the width or color is falsey then the line will NOT be drawn with an edge._"""
352
380
 
353
- def matplot_kwargs(self, size_multiplier: float = 1.0) -> dict:
354
- line_width = self.width * size_multiplier
381
+ def matplot_kwargs(self, scale: float = 1.0) -> dict:
382
+ line_width = self.width * scale
355
383
 
356
384
  result = dict(
357
385
  color=self.color.as_hex(),
@@ -365,32 +393,27 @@ class LineStyle(BaseStyle):
365
393
  if self.edge_width and self.edge_color:
366
394
  result["path_effects"] = [
367
395
  patheffects.withStroke(
368
- linewidth=line_width + 2 * self.edge_width * size_multiplier,
396
+ linewidth=line_width + 2 * self.edge_width * scale,
369
397
  foreground=self.edge_color.as_hex(),
370
398
  )
371
399
  ]
372
400
 
373
401
  return result
374
402
 
403
+ def matplot_line_collection_kwargs(self, scale: float = 1.0) -> dict:
404
+ plot_kwargs = self.matplot_kwargs(scale)
405
+ plot_kwargs["linewidths"] = plot_kwargs.pop("linewidth")
406
+ plot_kwargs["colors"] = plot_kwargs.pop("color")
407
+ return plot_kwargs
408
+
375
409
 
376
410
  class PolygonStyle(BaseStyle):
377
411
  """
378
412
  Styling properties for polygons.
379
-
380
- ???- tip "Example Usage"
381
- Creates a style for a partially transparent blue polygon:
382
- ```python
383
- ps = PolygonStyle(
384
- color="#d9d9d9",
385
- alpha=0.36,
386
- edge_width=0,
387
- zorder=-10000,
388
- )
389
- ```
390
413
  """
391
414
 
392
- edge_width: int = 1
393
- """Width of the polygon's edge"""
415
+ edge_width: float = 1
416
+ """Width of the polygon's edge in points"""
394
417
 
395
418
  color: Optional[ColorStr] = None
396
419
  """If specified, this will be the fill color AND edge color of the polygon"""
@@ -410,12 +433,12 @@ class PolygonStyle(BaseStyle):
410
433
  zorder: int = -1
411
434
  """Zorder of the polygon"""
412
435
 
413
- def matplot_kwargs(self, size_multiplier: float = 1.0) -> dict:
436
+ def matplot_kwargs(self, scale: float = 1.0) -> dict:
414
437
  styles = dict(
415
438
  edgecolor=self.edge_color.as_hex() if self.edge_color else "none",
416
439
  facecolor=self.fill_color.as_hex() if self.fill_color else "none",
417
- fill=True if self.fill_color else False,
418
- linewidth=self.edge_width * size_multiplier,
440
+ fill=True if self.fill_color or self.color else False,
441
+ linewidth=self.edge_width * scale,
419
442
  linestyle=self.line_style,
420
443
  alpha=self.alpha,
421
444
  zorder=self.zorder,
@@ -426,27 +449,29 @@ class PolygonStyle(BaseStyle):
426
449
 
427
450
  return styles
428
451
 
452
+ def to_marker_style(self, symbol: MarkerSymbolEnum):
453
+ color = self.color.as_hex() if self.color else None
454
+ fill_color = self.fill_color.as_hex() if self.fill_color else None
455
+ fill_style = FillStyleEnum.FULL if color or fill_color else FillStyleEnum.NONE
456
+ return MarkerStyle(
457
+ symbol=symbol,
458
+ color=color or fill_color,
459
+ fill=fill_style,
460
+ edge_color=self.edge_color.as_hex() if self.edge_color else None,
461
+ edge_width=self.edge_width,
462
+ alpha=self.alpha,
463
+ zorder=self.zorder,
464
+ line_style=self.line_style,
465
+ )
466
+
429
467
 
430
468
  class LabelStyle(BaseStyle):
431
469
  """
432
470
  Styling properties for a label.
433
-
434
- ???- tip "Example Usage"
435
- Creates a style for a bold blue label:
436
- ```python
437
- ls = LabelStyle(
438
- font_color="blue",
439
- font_weight="bold",
440
- zorder=1,
441
- )
442
- ```
443
471
  """
444
472
 
445
- anchor_point: AnchorPointEnum = AnchorPointEnum.BOTTOM_RIGHT
446
- """Anchor point of label"""
447
-
448
- font_size: int = 8
449
- """Relative font size of the label"""
473
+ font_size: float = 15
474
+ """Font size of the label, in points"""
450
475
 
451
476
  font_weight: FontWeightEnum = FontWeightEnum.NORMAL
452
477
  """Font weight (e.g. normal, bold, ultra bold, etc)"""
@@ -460,28 +485,50 @@ class LabelStyle(BaseStyle):
460
485
  font_style: FontStyleEnum = FontStyleEnum.NORMAL
461
486
  """Style of the label (e.g. normal, italic, etc)"""
462
487
 
463
- font_name: Optional[str] = None
488
+ font_name: Optional[str] = "Inter"
464
489
  """Name of the font to use"""
465
490
 
466
491
  font_family: Optional[str] = None
467
492
  """Font family (e.g. 'monospace', 'sans-serif', 'serif', etc)"""
468
493
 
469
- line_spacing: Optional[int] = None
494
+ line_spacing: Optional[float] = None
470
495
  """Spacing between lines of text"""
471
496
 
472
- offset_x: int = 0
473
- """Horizontal offset of the label, in pixels. Negative values supported."""
497
+ anchor_point: AnchorPointEnum = AnchorPointEnum.BOTTOM_RIGHT
498
+ """Anchor point of label"""
499
+
500
+ border_width: float = 0
501
+ """Width of border (also known as 'halos') around the text, in points"""
474
502
 
475
- offset_y: int = 0
476
- """Vertical offset of the label, in pixels. Negative values supported."""
503
+ border_color: Optional[ColorStr] = None
504
+ """Color of border (also known as 'halos') around the text"""
505
+
506
+ offset_x: Union[float, int, str] = 0
507
+ """
508
+ Horizontal offset of the label, in points. Negative values supported.
509
+
510
+
511
+ **Auto Mode** (_experimental_): If the label is plotted as part of a marker (e.g. stars, via `marker()`, etc), then you can also
512
+ specify the offset as `"auto"` which will calculate the offset automatically based on the marker's size and place
513
+ the label just outside the marker (avoiding overlapping). To enable "auto" mode you have to specify BOTH offsets (x and y) as "auto."
514
+ """
477
515
 
478
- zorder: int = 101
516
+ offset_y: Union[float, int, str] = 0
517
+ """
518
+ Vertical offset of the label, in points. Negative values supported.
519
+
520
+ **Auto Mode** (_experimental_): If the label is plotted as part of a marker (e.g. stars, via `marker()`, etc), then you can also
521
+ specify the offset as `"auto"` which will calculate the offset automatically based on the marker's size and place
522
+ the label just outside the marker (avoiding overlapping). To enable "auto" mode you have to specify BOTH offsets (x and y) as "auto."
523
+ """
524
+
525
+ zorder: int = ZOrderEnum.LAYER_4
479
526
  """Zorder of the label"""
480
527
 
481
- def matplot_kwargs(self, size_multiplier: float = 1.0) -> dict:
528
+ def matplot_kwargs(self, scale: float = 1.0) -> dict:
482
529
  style = dict(
483
530
  color=self.font_color.as_hex(),
484
- fontsize=self.font_size * size_multiplier * FONT_SCALE,
531
+ fontsize=self.font_size * scale,
485
532
  fontstyle=self.font_style,
486
533
  fontname=self.font_name,
487
534
  weight=self.font_weight,
@@ -494,10 +541,45 @@ class LabelStyle(BaseStyle):
494
541
  if self.line_spacing:
495
542
  style["linespacing"] = self.line_spacing
496
543
 
544
+ if self.border_width != 0 and self.border_color is not None:
545
+ style["path_effects"] = [
546
+ patheffects.withStroke(
547
+ linewidth=self.border_width * scale,
548
+ foreground=self.border_color.as_hex(),
549
+ )
550
+ ]
551
+
497
552
  style.update(AnchorPointEnum(self.anchor_point).as_matplot())
498
553
 
499
554
  return style
500
555
 
556
+ def offset_from_marker(self, marker_symbol, marker_size, scale: float = 1.0):
557
+ if self.offset_x != "auto" or self.offset_y != "auto":
558
+ return self
559
+
560
+ new_style = self.model_copy()
561
+
562
+ x_direction = -1 if new_style.anchor_point.endswith("left") else 1
563
+ y_direction = -1 if new_style.anchor_point.startswith("bottom") else 1
564
+
565
+ offset = (marker_size**0.5 / 2) / scale
566
+
567
+ # matplotlib seems to use marker size differently depending on symbol (for scatter)
568
+ # it is NOT strictly the area of the bounding box of the marker
569
+ if marker_symbol in [MarkerSymbolEnum.POINT]:
570
+ offset /= PI
571
+
572
+ elif marker_symbol != MarkerSymbolEnum.SQUARE:
573
+ offset /= SQR_2
574
+ offset *= scale
575
+
576
+ offset += 1.1
577
+
578
+ new_style.offset_x = offset * float(x_direction)
579
+ new_style.offset_y = offset * float(y_direction)
580
+
581
+ return new_style
582
+
501
583
 
502
584
  class ObjectStyle(BaseStyle):
503
585
  """Defines the style for a sky object (e.g. star, DSO)"""
@@ -540,8 +622,8 @@ class LegendStyle(BaseStyle):
540
622
  label_padding: float = 1.6
541
623
  """Padding between legend labels"""
542
624
 
543
- symbol_size: int = 16
544
- """Relative size of symbols in the legend"""
625
+ symbol_size: int = 34
626
+ """Size of symbols in the legend, in points"""
545
627
 
546
628
  symbol_padding: float = 0.2
547
629
  """Padding between each symbol and its label"""
@@ -549,8 +631,8 @@ class LegendStyle(BaseStyle):
549
631
  border_padding: float = 1.28
550
632
  """Padding around legend border"""
551
633
 
552
- font_size: int = 9
553
- """Relative font size of the legend labels"""
634
+ font_size: int = 23
635
+ """Font size of the legend labels, in points"""
554
636
 
555
637
  font_color: ColorStr = ColorStr("#000")
556
638
  """Font color for legend labels"""
@@ -558,12 +640,12 @@ class LegendStyle(BaseStyle):
558
640
  zorder: int = ZOrderEnum.LAYER_5
559
641
  """Zorder of the legend"""
560
642
 
561
- def matplot_kwargs(self, size_multiplier: float = 1.0) -> dict:
643
+ def matplot_kwargs(self, scale: float = 1.0) -> dict:
562
644
  return dict(
563
645
  loc=self.location,
564
646
  ncols=self.num_columns,
565
647
  framealpha=self.background_alpha,
566
- fontsize=self.font_size * size_multiplier * FONT_SCALE,
648
+ fontsize=self.font_size * scale,
567
649
  labelcolor=self.font_color.as_hex(),
568
650
  borderpad=self.border_padding,
569
651
  labelspacing=self.label_padding,
@@ -578,16 +660,27 @@ class PlotStyle(BaseStyle):
578
660
  Defines the styling for a plot
579
661
  """
580
662
 
581
- # Base
582
663
  background_color: ColorStr = ColorStr("#fff")
583
664
  """Background color of the map region"""
584
665
 
585
666
  figure_background_color: ColorStr = ColorStr("#fff")
586
667
 
587
- text_border_width: int = 3
668
+ text_border_width: int = 2
669
+ """Text border (aka halos) width. This will apply to _all_ text labels on the plot. If you'd like to control these borders by object type, then set this global width to `0` and refer to the label style's `border_width` and `border_color` properties."""
670
+
588
671
  text_border_color: ColorStr = ColorStr("#fff")
589
- text_offset_x: float = 0.005
590
- text_offset_y: float = 0.005
672
+
673
+ text_anchor_fallbacks: List[AnchorPointEnum] = [
674
+ AnchorPointEnum.BOTTOM_RIGHT,
675
+ AnchorPointEnum.TOP_LEFT,
676
+ AnchorPointEnum.TOP_RIGHT,
677
+ AnchorPointEnum.BOTTOM_LEFT,
678
+ AnchorPointEnum.BOTTOM_CENTER,
679
+ AnchorPointEnum.TOP_CENTER,
680
+ AnchorPointEnum.RIGHT_CENTER,
681
+ AnchorPointEnum.LEFT_CENTER,
682
+ ]
683
+ """If a label's preferred anchor point results in a collision, then these fallbacks will be tried in sequence until a collision-free position is found."""
591
684
 
592
685
  # Borders
593
686
  border_font_size: int = 18
@@ -608,10 +701,10 @@ class PlotStyle(BaseStyle):
608
701
 
609
702
  # Info text
610
703
  info_text: LabelStyle = LabelStyle(
611
- font_size=10,
704
+ font_size=30,
612
705
  zorder=ZOrderEnum.LAYER_5,
613
- font_family="monospace",
614
- line_spacing=2,
706
+ font_family="Inter",
707
+ line_spacing=1.2,
615
708
  anchor_point=AnchorPointEnum.BOTTOM_CENTER,
616
709
  )
617
710
  """Styling for info text (only applies to zenith and optic plots)"""
@@ -619,31 +712,55 @@ class PlotStyle(BaseStyle):
619
712
  # Stars
620
713
  star: ObjectStyle = ObjectStyle(
621
714
  marker=MarkerStyle(
622
- fill=FillStyleEnum.FULL, zorder=ZOrderEnum.LAYER_3, size=36, edge_color=None
715
+ fill=FillStyleEnum.FULL,
716
+ zorder=ZOrderEnum.LAYER_3 + 1,
717
+ size=40,
718
+ edge_color=None,
623
719
  ),
624
720
  label=LabelStyle(
625
- font_size=9, font_weight=FontWeightEnum.BOLD, zorder=ZOrderEnum.LAYER_4
721
+ font_size=24,
722
+ font_weight=FontWeightEnum.BOLD,
723
+ zorder=ZOrderEnum.LAYER_3 + 2,
724
+ offset_x="auto",
725
+ offset_y="auto",
626
726
  ),
627
727
  )
628
728
  """Styling for stars *(see [`ObjectStyle`][starplot.styles.ObjectStyle])*"""
629
729
 
630
730
  bayer_labels: LabelStyle = LabelStyle(
631
- font_size=7,
731
+ font_size=21,
632
732
  font_weight=FontWeightEnum.LIGHT,
733
+ font_name="GFS Didot",
633
734
  zorder=ZOrderEnum.LAYER_4,
634
735
  anchor_point=AnchorPointEnum.TOP_LEFT,
736
+ offset_x="auto",
737
+ offset_y="auto",
635
738
  )
636
739
  """Styling for Bayer labels of stars"""
637
740
 
741
+ flamsteed_labels: LabelStyle = LabelStyle(
742
+ font_size=13,
743
+ font_weight=FontWeightEnum.NORMAL,
744
+ zorder=ZOrderEnum.LAYER_4,
745
+ anchor_point=AnchorPointEnum.BOTTOM_LEFT,
746
+ offset_x="auto",
747
+ offset_y="auto",
748
+ )
749
+ """Styling for Flamsteed number labels of stars"""
750
+
638
751
  planets: ObjectStyle = ObjectStyle(
639
752
  marker=MarkerStyle(
640
753
  symbol=MarkerSymbolEnum.CIRCLE,
641
- size=4,
754
+ size=28,
642
755
  fill=FillStyleEnum.LEFT,
756
+ zorder=ZOrderEnum.LAYER_3,
757
+ alpha=1,
643
758
  ),
644
759
  label=LabelStyle(
645
- font_size=8,
760
+ font_size=28,
646
761
  font_weight=FontWeightEnum.BOLD,
762
+ offset_x="auto",
763
+ offset_y="auto",
647
764
  ),
648
765
  )
649
766
  """Styling for planets"""
@@ -651,15 +768,17 @@ class PlotStyle(BaseStyle):
651
768
  moon: ObjectStyle = ObjectStyle(
652
769
  marker=MarkerStyle(
653
770
  symbol=MarkerSymbolEnum.CIRCLE,
654
- size=14,
771
+ size=50,
655
772
  fill=FillStyleEnum.FULL,
656
773
  color="#c8c8c8",
657
774
  alpha=1,
658
775
  zorder=ZOrderEnum.LAYER_4,
659
776
  ),
660
777
  label=LabelStyle(
661
- font_size=8,
778
+ font_size=28,
662
779
  font_weight=FontWeightEnum.BOLD,
780
+ offset_x="auto",
781
+ offset_y="auto",
663
782
  ),
664
783
  )
665
784
  """Styling for the moon"""
@@ -667,13 +786,13 @@ class PlotStyle(BaseStyle):
667
786
  sun: ObjectStyle = ObjectStyle(
668
787
  marker=MarkerStyle(
669
788
  symbol=MarkerSymbolEnum.SUN,
670
- size=14,
789
+ size=80,
671
790
  fill=FillStyleEnum.FULL,
672
791
  color="#000",
673
792
  zorder=ZOrderEnum.LAYER_4 - 100,
674
793
  ),
675
794
  label=LabelStyle(
676
- font_size=8,
795
+ font_size=28,
677
796
  font_weight=FontWeightEnum.BOLD,
678
797
  ),
679
798
  )
@@ -683,14 +802,17 @@ class PlotStyle(BaseStyle):
683
802
  dso_open_cluster: ObjectStyle = ObjectStyle(
684
803
  marker=MarkerStyle(
685
804
  symbol=MarkerSymbolEnum.CIRCLE,
686
- size=7,
687
805
  fill=FillStyleEnum.FULL,
806
+ line_style=(0, (1, 2)),
807
+ edge_width=1.3,
808
+ zorder=ZOrderEnum.LAYER_3 - 1,
688
809
  ),
689
810
  label=LabelStyle(
690
- font_size=7,
691
- font_weight=FontWeightEnum.LIGHT,
692
- offset_x=10,
693
- offset_y=-10,
811
+ # font_weight=FontWeightEnum.LIGHT,
812
+ # offset_x=7,
813
+ # offset_y=-6,
814
+ offset_x="auto",
815
+ offset_y="auto",
694
816
  ),
695
817
  )
696
818
  """Styling for open star clusters"""
@@ -698,14 +820,15 @@ class PlotStyle(BaseStyle):
698
820
  dso_association_stars: ObjectStyle = ObjectStyle(
699
821
  marker=MarkerStyle(
700
822
  symbol=MarkerSymbolEnum.CIRCLE,
701
- size=7,
702
823
  fill=FillStyleEnum.FULL,
824
+ line_style=(0, (1, 2)),
825
+ edge_width=1.3,
826
+ zorder=ZOrderEnum.LAYER_3 - 1,
703
827
  ),
704
828
  label=LabelStyle(
705
- font_size=7,
706
829
  font_weight=FontWeightEnum.LIGHT,
707
- offset_x=10,
708
- offset_y=-10,
830
+ offset_x=7,
831
+ offset_y=-6,
709
832
  ),
710
833
  )
711
834
  """Styling for associations of stars"""
@@ -713,143 +836,161 @@ class PlotStyle(BaseStyle):
713
836
  dso_globular_cluster: ObjectStyle = ObjectStyle(
714
837
  marker=MarkerStyle(
715
838
  symbol=MarkerSymbolEnum.CIRCLE_CROSS,
716
- size=7,
717
839
  fill=FillStyleEnum.FULL,
718
840
  color="#555",
719
841
  alpha=0.8,
842
+ edge_width=1.2,
843
+ zorder=ZOrderEnum.LAYER_3 - 1,
720
844
  ),
721
- label=LabelStyle(font_size=7, offset_x=10, offset_y=-10),
845
+ label=LabelStyle(offset_x=7, offset_y=-6),
722
846
  )
723
847
  """Styling for globular star clusters"""
724
848
 
725
849
  dso_galaxy: ObjectStyle = ObjectStyle(
726
850
  marker=MarkerStyle(
727
- symbol=MarkerSymbolEnum.ELLIPSE, size=7, fill=FillStyleEnum.FULL
851
+ symbol=MarkerSymbolEnum.ELLIPSE,
852
+ fill=FillStyleEnum.FULL,
853
+ zorder=ZOrderEnum.LAYER_3 - 1,
728
854
  ),
729
- label=LabelStyle(font_size=7, offset_x=10, offset_y=-10),
855
+ label=LabelStyle(offset_x=1, offset_y=-1),
730
856
  )
731
857
  """Styling for galaxies"""
732
858
 
733
859
  dso_nebula: ObjectStyle = ObjectStyle(
734
860
  marker=MarkerStyle(
735
- symbol=MarkerSymbolEnum.SQUARE, size=7, fill=FillStyleEnum.FULL
861
+ symbol=MarkerSymbolEnum.SQUARE,
862
+ fill=FillStyleEnum.FULL,
863
+ zorder=ZOrderEnum.LAYER_3 - 1,
736
864
  ),
737
- label=LabelStyle(font_size=7, offset_x=10, offset_y=-10),
865
+ label=LabelStyle(offset_x=1, offset_y=-1),
738
866
  )
739
867
  """Styling for nebulas"""
740
868
 
869
+ dso_planetary_nebula: ObjectStyle = ObjectStyle(
870
+ marker=MarkerStyle(
871
+ symbol=MarkerSymbolEnum.CIRCLE_CROSSHAIR,
872
+ fill=FillStyleEnum.FULL,
873
+ edge_width=1.6,
874
+ size=26,
875
+ zorder=ZOrderEnum.LAYER_3 - 1,
876
+ ),
877
+ label=LabelStyle(offset_x=1, offset_y=-1),
878
+ )
879
+ """Styling for planetary nebulas"""
880
+
741
881
  dso_double_star: ObjectStyle = ObjectStyle(
742
882
  marker=MarkerStyle(
743
- symbol=MarkerSymbolEnum.CIRCLE, size=7, fill=FillStyleEnum.TOP
883
+ symbol=MarkerSymbolEnum.CIRCLE_LINE,
884
+ fill=FillStyleEnum.TOP,
885
+ zorder=ZOrderEnum.LAYER_3 - 1,
744
886
  ),
745
- label=LabelStyle(font_size=7),
887
+ label=LabelStyle(offset_x=1, offset_y=-1),
746
888
  )
747
889
  """Styling for double stars"""
748
890
 
749
891
  dso_dark_nebula: ObjectStyle = ObjectStyle(
750
892
  marker=MarkerStyle(
751
893
  symbol=MarkerSymbolEnum.SQUARE,
752
- size=7,
753
894
  fill=FillStyleEnum.TOP,
754
895
  color="#000",
896
+ zorder=ZOrderEnum.LAYER_3 - 1,
755
897
  ),
756
- label=LabelStyle(font_size=7),
898
+ label=LabelStyle(),
757
899
  )
758
900
  """Styling for dark nebulas"""
759
901
 
760
902
  dso_hii_ionized_region: ObjectStyle = ObjectStyle(
761
903
  marker=MarkerStyle(
762
904
  symbol=MarkerSymbolEnum.SQUARE,
763
- size=7,
764
905
  fill=FillStyleEnum.TOP,
765
906
  color="#000",
907
+ zorder=ZOrderEnum.LAYER_3 - 1,
766
908
  ),
767
- label=LabelStyle(font_size=7),
909
+ label=LabelStyle(),
768
910
  )
769
911
  """Styling for HII Ionized regions"""
770
912
 
771
913
  dso_supernova_remnant: ObjectStyle = ObjectStyle(
772
914
  marker=MarkerStyle(
773
915
  symbol=MarkerSymbolEnum.SQUARE,
774
- size=7,
775
916
  fill=FillStyleEnum.TOP,
776
917
  color="#000",
918
+ zorder=ZOrderEnum.LAYER_3 - 1,
777
919
  ),
778
- label=LabelStyle(font_size=7),
920
+ label=LabelStyle(),
779
921
  )
780
922
  """Styling for supernova remnants"""
781
923
 
782
924
  dso_nova_star: ObjectStyle = ObjectStyle(
783
925
  marker=MarkerStyle(
784
926
  symbol=MarkerSymbolEnum.SQUARE,
785
- size=7,
786
927
  fill=FillStyleEnum.TOP,
787
928
  color="#000",
929
+ zorder=ZOrderEnum.LAYER_3 - 1,
788
930
  ),
789
- label=LabelStyle(font_size=7),
931
+ label=LabelStyle(),
790
932
  )
791
933
  """Styling for nova stars"""
792
934
 
793
935
  dso_nonexistant: ObjectStyle = ObjectStyle(
794
936
  marker=MarkerStyle(
795
937
  symbol=MarkerSymbolEnum.SQUARE,
796
- size=7,
797
938
  fill=FillStyleEnum.TOP,
798
939
  color="#000",
940
+ zorder=ZOrderEnum.LAYER_3 - 1,
799
941
  ),
800
- label=LabelStyle(font_size=7),
942
+ label=LabelStyle(),
801
943
  )
802
944
  """Styling for 'nonexistent' (as designated by OpenNGC) deep sky objects"""
803
945
 
804
946
  dso_unknown: ObjectStyle = ObjectStyle(
805
947
  marker=MarkerStyle(
806
948
  symbol=MarkerSymbolEnum.SQUARE,
807
- size=7,
808
949
  fill=FillStyleEnum.TOP,
809
950
  color="#000",
951
+ zorder=ZOrderEnum.LAYER_3 - 1,
810
952
  ),
811
- label=LabelStyle(font_size=7),
953
+ label=LabelStyle(),
812
954
  )
813
955
  """Styling for 'unknown' (as designated by OpenNGC) types of deep sky objects"""
814
956
 
815
957
  dso_duplicate: ObjectStyle = ObjectStyle(
816
958
  marker=MarkerStyle(
817
959
  symbol=MarkerSymbolEnum.SQUARE,
818
- size=7,
819
960
  fill=FillStyleEnum.TOP,
820
961
  color="#000",
962
+ zorder=ZOrderEnum.LAYER_3 - 1,
821
963
  ),
822
- label=LabelStyle(font_size=7),
964
+ label=LabelStyle(),
823
965
  )
824
966
  """Styling for 'duplicate record' (as designated by OpenNGC) types of deep sky objects"""
825
967
 
826
- # Constellations
827
- constellation: PathStyle = PathStyle(
828
- line=LineStyle(color="#c8c8c8"),
829
- label=LabelStyle(
830
- font_size=7,
831
- font_weight=FontWeightEnum.LIGHT,
832
- zorder=ZOrderEnum.LAYER_3,
833
- anchor_point=AnchorPointEnum.TOP_RIGHT,
834
- ),
835
- )
836
- """Styling for constellation lines and labels (only applies to map plots)"""
968
+ constellation_lines: LineStyle = LineStyle(color="#c8c8c8")
969
+ """Styling for constellation lines"""
837
970
 
838
971
  constellation_borders: LineStyle = LineStyle(
839
972
  color="#000",
840
- width=2,
973
+ width=1.5,
841
974
  style=LineStyleEnum.DASHED,
842
- alpha=0.2,
975
+ alpha=0.4,
976
+ zorder=ZOrderEnum.LAYER_3,
977
+ )
978
+ """Styling for constellation borders"""
979
+
980
+ constellation_labels: LabelStyle = LabelStyle(
981
+ font_size=21,
982
+ font_weight=FontWeightEnum.NORMAL,
843
983
  zorder=ZOrderEnum.LAYER_3,
984
+ anchor_point=AnchorPointEnum.CENTER,
844
985
  )
845
- """Styling for constellation borders (only applies to map plots)"""
986
+ """Styling for constellation labels"""
846
987
 
847
988
  # Milky Way
848
989
  milky_way: PolygonStyle = PolygonStyle(
849
990
  fill_color="#d9d9d9",
850
991
  alpha=0.36,
851
992
  edge_width=0,
852
- zorder=ZOrderEnum.LAYER_2,
993
+ zorder=ZOrderEnum.LAYER_1,
853
994
  )
854
995
  """Styling for the Milky Way (only applies to map plots)"""
855
996
 
@@ -867,9 +1008,8 @@ class PlotStyle(BaseStyle):
867
1008
  zorder=ZOrderEnum.LAYER_2,
868
1009
  ),
869
1010
  label=LabelStyle(
870
- font_size=9,
1011
+ font_size=20,
871
1012
  font_color="#000",
872
- font_weight=FontWeightEnum.LIGHT,
873
1013
  font_alpha=1,
874
1014
  anchor_point=AnchorPointEnum.BOTTOM_CENTER,
875
1015
  ),
@@ -880,16 +1020,15 @@ class PlotStyle(BaseStyle):
880
1020
  ecliptic: PathStyle = PathStyle(
881
1021
  line=LineStyle(
882
1022
  color="#777",
883
- width=2,
1023
+ width=3,
884
1024
  style=LineStyleEnum.DOTTED,
885
1025
  dash_capstyle=DashCapStyleEnum.ROUND,
886
- alpha=0.8,
887
- zorder=ZOrderEnum.LAYER_3,
1026
+ alpha=1,
1027
+ zorder=ZOrderEnum.LAYER_3 - 1,
888
1028
  ),
889
1029
  label=LabelStyle(
890
- font_size=6,
1030
+ font_size=22,
891
1031
  font_color="#777",
892
- font_weight=FontWeightEnum.LIGHT,
893
1032
  font_alpha=1,
894
1033
  zorder=ZOrderEnum.LAYER_3,
895
1034
  ),
@@ -900,13 +1039,13 @@ class PlotStyle(BaseStyle):
900
1039
  celestial_equator: PathStyle = PathStyle(
901
1040
  line=LineStyle(
902
1041
  color="#999",
903
- width=2,
1042
+ width=3,
904
1043
  style=LineStyleEnum.DASHED_DOTS,
905
1044
  alpha=0.65,
906
1045
  zorder=ZOrderEnum.LAYER_3,
907
1046
  ),
908
1047
  label=LabelStyle(
909
- font_size=6,
1048
+ font_size=22,
910
1049
  font_color="#999",
911
1050
  font_weight=FontWeightEnum.LIGHT,
912
1051
  font_alpha=0.65,
@@ -918,7 +1057,7 @@ class PlotStyle(BaseStyle):
918
1057
  horizon: PathStyle = PathStyle(
919
1058
  line=LineStyle(
920
1059
  color="#fff",
921
- width=64,
1060
+ width=80,
922
1061
  edge_width=4,
923
1062
  edge_color="#000",
924
1063
  style=LineStyleEnum.SOLID,
@@ -929,7 +1068,7 @@ class PlotStyle(BaseStyle):
929
1068
  label=LabelStyle(
930
1069
  anchor_point=AnchorPointEnum.CENTER,
931
1070
  font_color="#000",
932
- font_size=23,
1071
+ font_size=64,
933
1072
  font_weight=FontWeightEnum.BOLD,
934
1073
  zorder=ZOrderEnum.LAYER_5,
935
1074
  ),
@@ -961,7 +1100,7 @@ class PlotStyle(BaseStyle):
961
1100
  DsoType.GROUP_OF_GALAXIES: self.dso_galaxy,
962
1101
  # Nebulas ----------
963
1102
  DsoType.NEBULA: self.dso_nebula,
964
- DsoType.PLANETARY_NEBULA: self.dso_nebula,
1103
+ DsoType.PLANETARY_NEBULA: self.dso_planetary_nebula,
965
1104
  DsoType.EMISSION_NEBULA: self.dso_nebula,
966
1105
  DsoType.STAR_CLUSTER_NEBULA: self.dso_nebula,
967
1106
  DsoType.REFLECTION_NEBULA: self.dso_nebula,