starplot 0.16.1__py2.py3-none-any.whl → 0.17.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.
Files changed (40) hide show
  1. starplot/__init__.py +28 -2
  2. starplot/base.py +42 -60
  3. starplot/config.py +41 -9
  4. starplot/data/bigsky.py +1 -1
  5. starplot/data/constellations.py +9 -681
  6. starplot/data/db.py +2 -2
  7. starplot/data/dsos.py +11 -28
  8. starplot/data/library/bigsky.0.4.0.stars.mag11.parquet +0 -0
  9. starplot/data/library/sky.db +0 -0
  10. starplot/data/stars.py +15 -433
  11. starplot/data/translations.py +161 -0
  12. starplot/geometry.py +52 -6
  13. starplot/horizon.py +18 -12
  14. starplot/map.py +1 -5
  15. starplot/mixins.py +283 -0
  16. starplot/models/__init__.py +19 -7
  17. starplot/models/base.py +1 -1
  18. starplot/models/comet.py +332 -0
  19. starplot/models/constellation.py +10 -0
  20. starplot/models/dso.py +24 -0
  21. starplot/{optics.py → models/optics.py} +4 -4
  22. starplot/models/satellite.py +158 -0
  23. starplot/models/star.py +10 -0
  24. starplot/optic.py +24 -13
  25. starplot/plotters/__init__.py +1 -0
  26. starplot/plotters/arrow.py +162 -0
  27. starplot/plotters/constellations.py +34 -56
  28. starplot/plotters/dsos.py +8 -14
  29. starplot/plotters/experimental.py +560 -8
  30. starplot/plotters/legend.py +5 -0
  31. starplot/plotters/stars.py +7 -16
  32. starplot/styles/base.py +20 -1
  33. starplot/styles/extensions.py +10 -1
  34. starplot/zenith.py +4 -1
  35. {starplot-0.16.1.dist-info → starplot-0.17.0.dist-info}/METADATA +20 -17
  36. {starplot-0.16.1.dist-info → starplot-0.17.0.dist-info}/RECORD +40 -36
  37. /starplot/{observer.py → models/observer.py} +0 -0
  38. {starplot-0.16.1.dist-info → starplot-0.17.0.dist-info}/WHEEL +0 -0
  39. {starplot-0.16.1.dist-info → starplot-0.17.0.dist-info}/entry_points.txt +0 -0
  40. {starplot-0.16.1.dist-info → starplot-0.17.0.dist-info}/licenses/LICENSE +0 -0
starplot/__init__.py CHANGED
@@ -1,6 +1,6 @@
1
1
  """Star charts and maps of the sky"""
2
2
 
3
- __version__ = "0.16.1"
3
+ __version__ = "0.17.0"
4
4
 
5
5
  from .base import BasePlot # noqa: F401
6
6
  from .map import MapPlot # noqa: F401
@@ -12,14 +12,40 @@ from .models import (
12
12
  DsoType, # noqa: F401
13
13
  Star, # noqa: F401
14
14
  Constellation, # noqa: F401
15
+ Comet, # noqa: F401
15
16
  Planet, # noqa: F401
16
17
  Moon, # noqa: F401
17
18
  Sun, # noqa: F401
18
19
  ObjectList, # noqa: F401
20
+ Scope, # noqa: F401
21
+ Binoculars, # noqa: F401
22
+ Reflector, # noqa: F401
23
+ Refractor, # noqa: F401
24
+ Camera, # noqa: F401
25
+ Satellite, # noqa: F401
26
+ Observer, # noqa: F401
19
27
  )
20
28
  from .styles import * # noqa: F401 F403
21
- from .observer import Observer # noqa: F401
22
29
  from .projections import * # noqa: F401 F403
23
30
  from .config import settings # noqa: F401
24
31
 
25
32
  from ibis import _ # noqa: F401 F403
33
+
34
+
35
+ import contextlib
36
+
37
+
38
+ @contextlib.contextmanager
39
+ def override_settings(**kwargs):
40
+ original = {}
41
+
42
+ for key, value in kwargs.items():
43
+ original[key] = getattr(settings, key, None)
44
+ setattr(settings, key, value)
45
+
46
+ try:
47
+ yield
48
+
49
+ finally:
50
+ for key, value in original.items():
51
+ setattr(settings, key, value)
starplot/base.py CHANGED
@@ -14,11 +14,13 @@ from shapely import Polygon, Point
14
14
 
15
15
  from starplot.coordinates import CoordinateSystem
16
16
  from starplot import geod, models, warnings
17
- from starplot.config import settings, SvgTextType
17
+ from starplot.config import settings as StarplotSettings, SvgTextType
18
18
  from starplot.data import load, ecliptic
19
+ from starplot.data.translations import translate
19
20
  from starplot.models.planet import PlanetName, PLANET_LABELS_DEFAULT
20
21
  from starplot.models.moon import MoonPhase
21
- from starplot.observer import Observer
22
+ from starplot.models.optics import Optic, Camera
23
+ from starplot.models.observer import Observer
22
24
  from starplot.styles import (
23
25
  AnchorPointEnum,
24
26
  PlotStyle,
@@ -47,16 +49,6 @@ LOG_FORMATTER = logging.Formatter(
47
49
  LOG_HANDLER.setFormatter(LOG_FORMATTER)
48
50
  LOGGER.addHandler(LOG_HANDLER)
49
51
 
50
-
51
- DEFAULT_FOV_STYLE = PolygonStyle(
52
- fill_color=None,
53
- edge_color="red",
54
- line_style=[1, [2, 3]],
55
- edge_width=3,
56
- zorder=-1000,
57
- )
58
- """Default style for plotting scope and bino field of view circles"""
59
-
60
52
  DEFAULT_STYLE = PlotStyle()
61
53
 
62
54
  DEFAULT_RESOLUTION = 4096
@@ -100,7 +92,7 @@ class BasePlot(ABC):
100
92
  *args,
101
93
  **kwargs,
102
94
  ):
103
- if settings.svg_text_type == SvgTextType.PATH:
95
+ if StarplotSettings.svg_text_type == SvgTextType.PATH:
104
96
  plt.rcParams["svg.fonttype"] = "path"
105
97
  else:
106
98
  plt.rcParams["svg.fonttype"] = "none"
@@ -108,6 +100,8 @@ class BasePlot(ABC):
108
100
  px = 1 / DPI # plt.rcParams["figure.dpi"] # pixel in inches
109
101
  self.pixels_per_point = DPI / 72
110
102
 
103
+ self.language = StarplotSettings.language
104
+
111
105
  self.style = style
112
106
  self.figure_size = resolution * px
113
107
  self.resolution = resolution
@@ -383,7 +377,7 @@ class BasePlot(ABC):
383
377
 
384
378
  x, y = self._prepare_coords(ra, dec)
385
379
 
386
- if settings.svg_text_type == SvgTextType.PATH:
380
+ if StarplotSettings.svg_text_type == SvgTextType.PATH:
387
381
  kwargs["path_effects"] = kwargs.get("path_effects", [self.text_border])
388
382
 
389
383
  remove_on_constellation_collision = kwargs.pop(
@@ -437,10 +431,12 @@ class BasePlot(ABC):
437
431
  settings: dict = None,
438
432
  **kwargs,
439
433
  ) -> None:
440
- kwargs["path_effects"] = kwargs.get("path_effects", [self.text_border])
441
434
  kwargs["va"] = "center"
442
435
  kwargs["ha"] = "center"
443
436
 
437
+ if StarplotSettings.svg_text_type == SvgTextType.PATH:
438
+ kwargs["path_effects"] = kwargs.get("path_effects", [self.text_border])
439
+
444
440
  avoid_constellation_lines = settings.get("avoid_constellation_lines", False)
445
441
  padding = settings.get("label_padding", 3)
446
442
  settings.get("buffer", 0.1)
@@ -737,8 +733,11 @@ class BasePlot(ABC):
737
733
  self.observer.dt, self.observer.lat, self.observer.lon, self._ephemeris_name
738
734
  )
739
735
 
736
+ legend_label = translate(legend_label, self.language)
737
+
740
738
  for p in planets:
741
739
  label = labels.get(p.name)
740
+ label = translate(label, self.language)
742
741
 
743
742
  if self.in_bounds(p.ra, p.dec):
744
743
  self._objects.planets.append(p)
@@ -794,6 +793,8 @@ class BasePlot(ABC):
794
793
  lon=self.observer.lon,
795
794
  ephemeris=self._ephemeris_name,
796
795
  )
796
+ label = translate(label, self.language)
797
+ legend_label = translate(legend_label, self.language)
797
798
  s.name = label or s.name
798
799
 
799
800
  if not self.in_bounds(s.ra, s.dec):
@@ -1072,6 +1073,8 @@ class BasePlot(ABC):
1072
1073
  lon=self.observer.lon,
1073
1074
  ephemeris=self._ephemeris_name,
1074
1075
  )
1076
+ label = translate(label, self.language)
1077
+ legend_label = translate(legend_label, self.language)
1075
1078
  m.name = label or m.name
1076
1079
 
1077
1080
  if not self.in_bounds(m.ra, m.dec):
@@ -1205,61 +1208,36 @@ class BasePlot(ABC):
1205
1208
  gid="moon-marker",
1206
1209
  )
1207
1210
 
1208
- def _fov_circle(
1209
- self, ra, dec, fov, magnification, style: PolygonStyle = DEFAULT_FOV_STYLE
1210
- ):
1211
- # FOV (degrees) = FOV eyepiece / magnification
1212
- fov_degrees = fov / magnification
1213
- fov_radius = fov_degrees / 2
1214
- self.circle(
1215
- (ra, dec),
1216
- fov_radius,
1217
- style=style,
1218
- )
1219
-
1220
- @use_style(PolygonStyle)
1221
- def scope_fov(
1222
- self,
1223
- ra: float,
1224
- dec: float,
1225
- scope_focal_length: float,
1226
- eyepiece_focal_length: float,
1227
- eyepiece_fov: float,
1228
- style: PolygonStyle = DEFAULT_FOV_STYLE,
1229
- ):
1230
- """Draws a circle representing the field of view for a telescope and eyepiece.
1231
-
1232
- Args:
1233
- ra: Right ascension of the center of view
1234
- dec: Declination of the center of view
1235
- scope_focal_length: focal length (mm) of the scope
1236
- eyepiece_focal_length: focal length (mm) of the eyepiece
1237
- eyepiece_fov: field of view (degrees) of the eyepiece
1238
- style: style of the polygon
1239
- """
1240
- # FOV (degrees) = FOV eyepiece / magnification
1241
- magnification = scope_focal_length / eyepiece_focal_length
1242
- self._fov_circle(ra, dec, eyepiece_fov, magnification, style)
1243
-
1244
- @use_style(PolygonStyle)
1245
- def bino_fov(
1211
+ @use_style(PolygonStyle, "optic_fov")
1212
+ def optic_fov(
1246
1213
  self,
1247
1214
  ra: float,
1248
1215
  dec: float,
1249
- fov: float,
1250
- magnification: float,
1251
- style: PolygonStyle = DEFAULT_FOV_STYLE,
1216
+ optic: Optic,
1217
+ style: PolygonStyle = None,
1252
1218
  ):
1253
- """Draws a circle representing the field of view for binoculars.
1219
+ """Draws a polygon representing the field of view for an optic, centered at a specific point.
1254
1220
 
1255
1221
  Args:
1256
1222
  ra: Right ascension of the center of view
1257
1223
  dec: Declination of the center of view
1258
- fov: field of view (degrees) of the binoculars
1259
- magnification: magnification of the binoculars
1224
+ optic: Instance of an [Optic][starplot.models.Optic]
1260
1225
  style: style of the polygon
1261
1226
  """
1262
- self._fov_circle(ra, dec, fov, magnification, style)
1227
+ if isinstance(optic, Camera):
1228
+ self.rectangle(
1229
+ center=(ra, dec),
1230
+ height_degrees=optic.true_fov_y,
1231
+ width_degrees=optic.true_fov_x,
1232
+ angle=optic.rotation,
1233
+ style=style,
1234
+ )
1235
+ else:
1236
+ self.circle(
1237
+ center=(ra, dec),
1238
+ radius_degrees=optic.true_fov / 2,
1239
+ style=style,
1240
+ )
1263
1241
 
1264
1242
  @use_style(PathStyle, "ecliptic")
1265
1243
  def ecliptic(self, style: PathStyle = None, label: str = "ECLIPTIC"):
@@ -1273,6 +1251,8 @@ class BasePlot(ABC):
1273
1251
  y = []
1274
1252
  inbounds = []
1275
1253
 
1254
+ label = translate(label, self.language)
1255
+
1276
1256
  for ra, dec in ecliptic.RA_DECS:
1277
1257
  x0, y0 = self._prepare_coords(ra * 15, dec)
1278
1258
  x.append(x0)
@@ -1312,6 +1292,8 @@ class BasePlot(ABC):
1312
1292
 
1313
1293
  # TODO : handle wrapping
1314
1294
 
1295
+ label = translate(label, self.language)
1296
+
1315
1297
  for ra in range(25):
1316
1298
  x0, y0 = self._prepare_coords(ra * 15, 0)
1317
1299
  x.append(x0)
starplot/config.py CHANGED
@@ -1,7 +1,8 @@
1
+ import os
2
+
1
3
  from enum import Enum
2
4
  from pathlib import Path
3
-
4
- from pydantic_settings import BaseSettings, SettingsConfigDict
5
+ from dataclasses import dataclass, field
5
6
 
6
7
 
7
8
  STARPLOT_PATH = Path(__file__).resolve().parent
@@ -15,30 +16,46 @@ RAW_DATA_PATH = STARPLOT_PATH.parent.parent / "raw"
15
16
  BUILD_PATH = STARPLOT_PATH.parent.parent / "build"
16
17
 
17
18
 
19
+ def _get_path(var_name, default) -> Path:
20
+ def _get():
21
+ value = os.environ.get(var_name, default)
22
+ return Path(value)
23
+
24
+ return _get
25
+
26
+
18
27
  class SvgTextType(str, Enum):
19
28
  PATH = "path"
20
29
  ELEMENT = "element"
21
30
 
22
31
 
23
- class Settings(BaseSettings):
24
- model_config = SettingsConfigDict(env_prefix="STARPLOT_")
25
- """Configuration for the Pydantic settings model. Do not change."""
26
-
27
- download_path: Path = DATA_PATH / "downloads"
32
+ @dataclass
33
+ class Settings:
34
+ download_path: Path = field(
35
+ default_factory=_get_path("STARPLOT_DOWNLOAD_PATH", DATA_PATH / "downloads")
36
+ )
28
37
  """
29
38
  Path for downloaded data, including the Big Sky catalog, ephemeris files, etc.
30
39
 
31
40
  Default = `<starplot_source_path>/data/library/downloads/`
32
41
  """
33
42
 
34
- duckdb_extension_path: Path = DATA_PATH / "duckdb-extensions"
43
+ duckdb_extension_path: Path = field(
44
+ default_factory=_get_path(
45
+ "STARPLOT_DUCKDB_EXTENSION_PATH", DATA_PATH / "duckdb-extensions"
46
+ )
47
+ )
35
48
  """
36
49
  Path for the DuckDB spatial extension, which is required for the data backend.
37
50
 
38
51
  Default = `<starplot_source_path>/data/library/duckdb-extensions/`
39
52
  """
40
53
 
41
- svg_text_type: SvgTextType = SvgTextType.PATH
54
+ svg_text_type: SvgTextType = field(
55
+ default_factory=lambda: os.environ.get(
56
+ "STARPLOT_SVG_TEXT_TYPE", SvgTextType.PATH
57
+ )
58
+ )
42
59
  """
43
60
  Method for rendering text in SVG exports:
44
61
 
@@ -52,5 +69,20 @@ class Settings(BaseSettings):
52
69
 
53
70
  """
54
71
 
72
+ language: str = field(
73
+ default_factory=lambda: os.environ.get("STARPLOT_LANGUAGE", "en-US")
74
+ )
75
+ """
76
+ Default language for plotted labels, as an ISO-639 code. Case insensitive.
77
+
78
+ Supported values:
79
+
80
+ - `en-US` = English
81
+ - `fr` = French
82
+ - `zh-CN` = Chinese. Make sure you have a good Chinese font installed (such as [Noto Sans SC](https://fonts.google.com/noto/specimen/Noto+Sans+SC)) and you'll also need to set that as the font in your plot's style.
83
+
84
+ **🌐 Want to see another language available? Please help us add it! [Details here](https://github.com/steveberardi/starplot/tree/main/data/raw/translations).**
85
+ """
86
+
55
87
 
56
88
  settings = Settings()
starplot/data/bigsky.py CHANGED
@@ -1,7 +1,6 @@
1
1
  import os
2
2
  from pathlib import Path
3
3
 
4
- import pandas as pd
5
4
 
6
5
  from starplot.config import settings
7
6
  from starplot.data import DataFiles, utils
@@ -46,6 +45,7 @@ def download(
46
45
  def to_parquet(source_path: str, destination_path: str):
47
46
  import pyarrow as pa
48
47
  import pyarrow.parquet as pq
48
+ import pandas as pd
49
49
 
50
50
  print("Preparing Big Sky Catalog for Starplot...")
51
51