starplot 0.18.3__py2.py3-none-any.whl → 0.19.2__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 (38) hide show
  1. starplot/__init__.py +33 -27
  2. starplot/config.py +11 -0
  3. starplot/data/__init__.py +3 -5
  4. starplot/data/catalogs.py +24 -12
  5. starplot/data/constellations.py +1 -0
  6. starplot/data/db.py +1 -7
  7. starplot/geod.py +3 -4
  8. starplot/geometry.py +17 -1
  9. starplot/mixins.py +11 -0
  10. starplot/models/__init__.py +3 -1
  11. starplot/models/constellation.py +20 -3
  12. starplot/models/milky_way.py +30 -0
  13. starplot/models/moon.py +1 -1
  14. starplot/models/observer.py +11 -2
  15. starplot/models/planet.py +1 -1
  16. starplot/models/sun.py +1 -1
  17. starplot/plots/__init__.py +6 -0
  18. starplot/{base.py → plots/base.py} +107 -456
  19. starplot/{horizon.py → plots/horizon.py} +12 -10
  20. starplot/{map.py → plots/map.py} +11 -7
  21. starplot/{optic.py → plots/optic.py} +21 -30
  22. starplot/{zenith.py → plots/zenith.py} +37 -8
  23. starplot/plotters/__init__.py +9 -7
  24. starplot/plotters/arrow.py +1 -1
  25. starplot/plotters/constellations.py +46 -61
  26. starplot/plotters/dsos.py +33 -16
  27. starplot/plotters/experimental.py +0 -1
  28. starplot/plotters/milkyway.py +15 -6
  29. starplot/plotters/stars.py +19 -36
  30. starplot/plotters/text.py +524 -0
  31. starplot/styles/__init__.py +4 -4
  32. starplot/styles/base.py +1 -13
  33. {starplot-0.18.3.dist-info → starplot-0.19.2.dist-info}/METADATA +2 -1
  34. {starplot-0.18.3.dist-info → starplot-0.19.2.dist-info}/RECORD +37 -35
  35. starplot/data/library/sky.db +0 -0
  36. {starplot-0.18.3.dist-info → starplot-0.19.2.dist-info}/WHEEL +0 -0
  37. {starplot-0.18.3.dist-info → starplot-0.19.2.dist-info}/entry_points.txt +0 -0
  38. {starplot-0.18.3.dist-info → starplot-0.19.2.dist-info}/licenses/LICENSE +0 -0
@@ -9,7 +9,7 @@ from matplotlib.ticker import FixedLocator, FuncFormatter
9
9
  from skyfield.api import wgs84, Star as SkyfieldStar
10
10
  from shapely import Point, Polygon, MultiPolygon
11
11
  from starplot.coordinates import CoordinateSystem
12
- from starplot.base import BasePlot, DPI
12
+ from starplot.plots.base import BasePlot, DPI
13
13
  from starplot.mixins import ExtentMaskMixin
14
14
  from starplot.models.observer import Observer
15
15
  from starplot.plotters import (
@@ -21,6 +21,7 @@ from starplot.plotters import (
21
21
  LegendPlotterMixin,
22
22
  ArrowPlotterMixin,
23
23
  )
24
+ from starplot.plotters.text import CollisionHandler
24
25
  from starplot.styles import (
25
26
  PlotStyle,
26
27
  extensions,
@@ -58,15 +59,14 @@ class HorizonPlot(
58
59
  """Creates a new horizon plot.
59
60
 
60
61
  Args:
61
- lat: Latitude of observer's location
62
- lon: Longitude of observer's location
62
+
63
63
  altitude: Tuple of altitude range to plot (min, max)
64
64
  azimuth: Tuple of azimuth range to plot (min, max)
65
- dt: Date/time of observation (*must be timezone-aware*). Default = current UTC time.
65
+ observer: Observer instance which specifies a time and place. Defaults to `Observer()`
66
66
  ephemeris: Ephemeris to use for calculating planet positions (see [Skyfield's documentation](https://rhodesmill.org/skyfield/planets.html) for details)
67
- style: Styling for the plot (colors, sizes, fonts, etc)
67
+ style: Styling for the plot (colors, sizes, fonts, etc). If `None`, it defaults to `PlotStyle()`
68
68
  resolution: Size (in pixels) of largest dimension of the map
69
- hide_colliding_labels: If True, then labels will not be plotted if they collide with another existing label
69
+ collision_handler: Default [CollisionHandler][starplot.CollisionHandler] for the plot that describes what to do on label collisions with other labels, markers, etc.
70
70
  scale: Scaling factor that will be applied to all relevant sizes in styles (e.g. font size, marker size, line widths, etc). For example, if you want to make everything 2x bigger, then set scale to 2.
71
71
  autoscale: If True, then the scale will be automatically set based on resolution
72
72
  suppress_warnings: If True (the default), then all warnings will be suppressed
@@ -85,23 +85,25 @@ class HorizonPlot(
85
85
  self,
86
86
  altitude: tuple[float, float],
87
87
  azimuth: tuple[float, float],
88
- observer: Observer = Observer(),
88
+ observer: Observer = None,
89
89
  ephemeris: str = "de421.bsp",
90
90
  style: PlotStyle = DEFAULT_HORIZON_STYLE,
91
91
  resolution: int = 4096,
92
- hide_colliding_labels: bool = True,
92
+ collision_handler: CollisionHandler = None,
93
93
  scale: float = 1.0,
94
94
  autoscale: bool = False,
95
95
  suppress_warnings: bool = True,
96
96
  *args,
97
97
  **kwargs,
98
98
  ) -> "HorizonPlot":
99
+ observer = observer or Observer()
100
+
99
101
  super().__init__(
100
102
  observer,
101
103
  ephemeris,
102
104
  style,
103
105
  resolution,
104
- hide_colliding_labels,
106
+ collision_handler=collision_handler,
105
107
  scale=scale,
106
108
  autoscale=autoscale,
107
109
  suppress_warnings=suppress_warnings,
@@ -160,7 +162,7 @@ class HorizonPlot(
160
162
  # import geopandas as gpd
161
163
 
162
164
  # Skyfield needs these columns
163
- df["ra_hours"], df["dec_degrees"] = (df.ra / 15, df.dec)
165
+ # df["ra_hours"], df["dec_degrees"] = (df.ra / 15, df.dec)
164
166
 
165
167
  stars_apparent = self.observe(SkyfieldStar.from_dataframe(df)).apparent()
166
168
  nearby_stars_alt, nearby_stars_az, _ = stars_apparent.altaz()
@@ -12,7 +12,7 @@ import numpy as np
12
12
 
13
13
  from starplot.coordinates import CoordinateSystem
14
14
  from starplot import geod
15
- from starplot.base import BasePlot, DPI
15
+ from starplot.plots.base import BasePlot, DPI
16
16
  from starplot.mixins import ExtentMaskMixin
17
17
  from starplot.models.observer import Observer
18
18
  from starplot.plotters import (
@@ -24,6 +24,7 @@ from starplot.plotters import (
24
24
  GradientBackgroundMixin,
25
25
  ArrowPlotterMixin,
26
26
  )
27
+ from starplot.plotters.text import CollisionHandler
27
28
  from starplot.projections import StereoNorth, StereoSouth, ProjectionBase
28
29
  from starplot.styles import (
29
30
  ObjectStyle,
@@ -57,11 +58,11 @@ class MapPlot(
57
58
  ra_max: Maximum right ascension of the map's extent, in degrees (0...360)
58
59
  dec_min: Minimum declination of the map's extent, in degrees (-90...90)
59
60
  dec_max: Maximum declination of the map's extent, in degrees (-90...90)
60
- observer: Observer instance which specifies a time and place
61
+ observer: Observer instance which specifies a time and place. Defaults to an observer at epoch J2000
61
62
  ephemeris: Ephemeris to use for calculating planet positions (see [Skyfield's documentation](https://rhodesmill.org/skyfield/planets.html) for details)
62
- style: Styling for the plot (colors, sizes, fonts, etc)
63
+ style: Styling for the plot (colors, sizes, fonts, etc). If `None`, it defaults to `PlotStyle()`
63
64
  resolution: Size (in pixels) of largest dimension of the map
64
- hide_colliding_labels: If True, then labels will not be plotted if they collide with another existing label
65
+ collision_handler: Default [CollisionHandler][starplot.CollisionHandler] for the plot that describes what to do on label collisions with other labels, markers, etc.
65
66
  clip_path: An optional Shapely Polygon that specifies the clip path of the plot -- only objects inside the polygon will be plotted. If `None` (the default), then the clip path will be the extent of the map you specified with the RA/DEC parameters.
66
67
  scale: Scaling factor that will be applied to all sizes in styles (e.g. font size, marker size, line widths, etc). For example, if you want to make everything 2x bigger, then set the scale to 2. At `scale=1` and `resolution=4096` (the default), all sizes are optimized visually for a map that covers 1-3 constellations. So, if you're creating a plot of a _larger_ extent, then it'd probably be good to decrease the scale (i.e. make everything smaller) -- and _increase_ the scale if you're plotting a very small area.
67
68
  autoscale: If True, then the scale will be set automatically based on resolution.
@@ -82,11 +83,11 @@ class MapPlot(
82
83
  ra_max: float = 360,
83
84
  dec_min: float = -90,
84
85
  dec_max: float = 90,
85
- observer: Observer = Observer(),
86
+ observer: Observer = None,
86
87
  ephemeris: str = "de421.bsp",
87
88
  style: PlotStyle = DEFAULT_MAP_STYLE,
88
89
  resolution: int = 4096,
89
- hide_colliding_labels: bool = True,
90
+ collision_handler: CollisionHandler = None,
90
91
  clip_path: Polygon = None,
91
92
  scale: float = 1.0,
92
93
  autoscale: bool = False,
@@ -94,12 +95,14 @@ class MapPlot(
94
95
  *args,
95
96
  **kwargs,
96
97
  ) -> "MapPlot":
98
+ observer = observer or Observer.at_epoch(2000)
99
+
97
100
  super().__init__(
98
101
  observer,
99
102
  ephemeris,
100
103
  style,
101
104
  resolution,
102
- hide_colliding_labels,
105
+ collision_handler=collision_handler,
103
106
  scale=scale,
104
107
  autoscale=autoscale,
105
108
  suppress_warnings=suppress_warnings,
@@ -120,6 +123,7 @@ class MapPlot(
120
123
  self.ra_max = ra_max
121
124
  self.dec_min = dec_min
122
125
  self.dec_max = dec_max
126
+
123
127
  self.clip_path = clip_path
124
128
 
125
129
  self._geodetic = ccrs.Geodetic()
@@ -1,12 +1,13 @@
1
- from typing import Callable, Mapping
1
+ from typing import Callable
2
2
 
3
3
  from cartopy import crs as ccrs
4
4
  from matplotlib import pyplot as plt, patches, path
5
5
  from skyfield.api import wgs84, Star as SkyfieldStar
6
6
 
7
- from starplot.coordinates import CoordinateSystem
7
+
8
8
  from starplot import callables, geod
9
- from starplot.base import BasePlot, DPI
9
+ from starplot.coordinates import CoordinateSystem
10
+ from starplot.plots.base import BasePlot, DPI
10
11
  from starplot.data.catalogs import Catalog, BIG_SKY_MAG11
11
12
  from starplot.mixins import ExtentMaskMixin
12
13
  from starplot.models import Star, Optic, Camera
@@ -27,6 +28,7 @@ from starplot.styles import (
27
28
  GradientDirection,
28
29
  )
29
30
  from starplot.utils import azimuth_to_string
31
+ from starplot.plotters.text import CollisionHandler
30
32
 
31
33
  DEFAULT_OPTIC_STYLE = PlotStyle().extend(extensions.OPTIC)
32
34
 
@@ -42,16 +44,14 @@ class OpticPlot(
42
44
  """Creates a new optic plot.
43
45
 
44
46
  Args:
45
- optic: Optic instance that defines optical parameters
46
47
  ra: Right ascension of target center, in degrees (0...360)
47
48
  dec: Declination of target center, in degrees (-90...90)
48
- lat: Latitude of observer's location
49
- lon: Longitude of observer's location
50
- dt: Date/time of observation (*must be timezone-aware*). Default = current UTC time.
49
+ optic: Optic instance that defines optical parameters
50
+ observer: Observer instance which specifies a time and place. Defaults to `Observer()`
51
51
  ephemeris: Ephemeris to use for calculating planet positions (see [Skyfield's documentation](https://rhodesmill.org/skyfield/planets.html) for details)
52
- style: Styling for the plot (colors, sizes, fonts, etc)
52
+ style: Styling for the plot (colors, sizes, fonts, etc). If `None`, it defaults to `PlotStyle()`
53
53
  resolution: Size (in pixels) of largest dimension of the map
54
- hide_colliding_labels: If True, then labels will not be plotted if they collide with another existing label
54
+ collision_handler: Default [CollisionHandler][starplot.CollisionHandler] for the plot that describes what to do on label collisions with other labels, markers, etc.
55
55
  raise_on_below_horizon: If True, then a ValueError will be raised if the target is below the horizon at the observing time/location
56
56
  scale: Scaling factor that will be applied to all sizes in styles (e.g. font size, marker size, line widths, etc). For example, if you want to make everything 2x bigger, then set the scale to 2. At `scale=1` and `resolution=4096` (the default), all sizes are optimized visually for a map that covers 1-3 constellations. So, if you're creating a plot of a _larger_ extent, then it'd probably be good to decrease the scale (i.e. make everything smaller) -- and _increase_ the scale if you're plotting a very small area.
57
57
  autoscale: If True, then the scale will be set automatically based on resolution.
@@ -72,11 +72,11 @@ class OpticPlot(
72
72
  ra: float,
73
73
  dec: float,
74
74
  optic: Optic,
75
- observer: Observer = Observer(),
75
+ observer: Observer = None,
76
76
  ephemeris: str = "de421.bsp",
77
77
  style: PlotStyle = DEFAULT_OPTIC_STYLE,
78
78
  resolution: int = 4096,
79
- hide_colliding_labels: bool = True,
79
+ collision_handler: CollisionHandler = None,
80
80
  raise_on_below_horizon: bool = True,
81
81
  scale: float = 1.0,
82
82
  autoscale: bool = False,
@@ -84,12 +84,13 @@ class OpticPlot(
84
84
  *args,
85
85
  **kwargs,
86
86
  ) -> "OpticPlot":
87
+ observer = observer or Observer()
87
88
  super().__init__(
88
89
  observer,
89
90
  ephemeris,
90
91
  style,
91
92
  resolution,
92
- hide_colliding_labels,
93
+ collision_handler=collision_handler,
93
94
  scale=scale,
94
95
  autoscale=autoscale,
95
96
  suppress_warnings=suppress_warnings,
@@ -251,43 +252,35 @@ class OpticPlot(
251
252
  where_labels: list = None,
252
253
  catalog: Catalog = BIG_SKY_MAG11,
253
254
  style: ObjectStyle = None,
254
- rasterize: bool = False,
255
255
  size_fn: Callable[[Star], float] = callables.size_by_magnitude_for_optic,
256
256
  alpha_fn: Callable[[Star], float] = callables.alpha_by_magnitude,
257
257
  color_fn: Callable[[Star], str] = None,
258
258
  label_fn: Callable[[Star], str] = Star.get_label,
259
- labels: Mapping[int, str] = None,
260
259
  legend_label: str = "Star",
261
260
  bayer_labels: bool = False,
262
261
  flamsteed_labels: bool = False,
263
262
  sql: str = None,
264
- *args,
265
- **kwargs,
263
+ sql_labels: str = None,
264
+ collision_handler: CollisionHandler = None,
266
265
  ):
267
266
  """
268
267
  Plots stars
269
268
 
270
- Labels for stars are determined in this order:
271
-
272
- 1. Return value from `label_fn`
273
- 2. Value for star's HIP id in `labels`
274
- 3. IAU-designated name, as listed in the [data reference](/data/star-designations/)
275
-
276
269
  Args:
277
270
  where: A list of expressions that determine which stars to plot. See [Selecting Objects](/reference-selecting-objects/) for details.
278
271
  where_labels: A list of expressions that determine which stars are labeled on the plot. See [Selecting Objects](/reference-selecting-objects/) for details.
279
- catalog: The catalog of stars to use: "big-sky-mag11", or "big-sky" -- see [star catalogs](/data/star-catalogs/) for details
272
+ catalog: The catalog of stars to use -- see [catalogs overview](/data/overview/) for details
280
273
  style: If `None`, then the plot's style for stars will be used
281
- rasterize: If True, then the stars will be rasterized when plotted, which can speed up exporting to SVG and reduce the file size but with a loss of image quality
282
274
  size_fn: Callable for calculating the marker size of each star. If `None`, then the marker style's size will be used.
283
275
  alpha_fn: Callable for calculating the alpha value (aka "opacity") of each star. If `None`, then the marker style's alpha will be used.
284
276
  color_fn: Callable for calculating the color of each star. If `None`, then the marker style's color will be used.
285
- label_fn: Callable for determining the label of each star. If `None`, then the names in the `labels` kwarg will be used.
286
- labels: A dictionary that maps a star's HIP id to the label that'll be plotted for that star. If `None`, then the star's IAU-designated name will be used.
277
+ label_fn: Callable for determining the label of each star.
287
278
  legend_label: Label for stars in the legend. If `None`, then they will not be in the legend.
288
279
  bayer_labels: If True, then Bayer labels for stars will be plotted.
289
280
  flamsteed_labels: If True, then Flamsteed number labels for stars will be plotted.
290
281
  sql: SQL query for selecting stars (table name is `_`). This query will be applied _after_ any filters in the `where` kwarg.
282
+ sql_labels: SQL query for selecting stars that will be labeled (table name is `_`). Applied _after_ any filters in the `where_labels` kwarg.
283
+ collision_handler: An instance of [CollisionHandler][starplot.CollisionHandler] that describes what to do on collisions with other labels, markers, etc. If `None`, then the collision handler of the plot will be used.
291
284
  """
292
285
  optic_star_multiplier = self.FIELD_OF_VIEW_MAX / self.optic.true_fov
293
286
  size_fn_mx = None
@@ -302,18 +295,16 @@ class OpticPlot(
302
295
  where_labels=where_labels,
303
296
  catalog=catalog,
304
297
  style=style,
305
- rasterize=rasterize,
306
298
  size_fn=size_fn_mx,
307
299
  alpha_fn=alpha_fn,
308
300
  color_fn=color_fn,
309
301
  label_fn=label_fn,
310
- labels=labels,
311
302
  legend_label=legend_label,
312
303
  bayer_labels=bayer_labels,
313
304
  flamsteed_labels=flamsteed_labels,
314
305
  sql=sql,
315
- *args,
316
- **kwargs,
306
+ sql_labels=sql_labels,
307
+ collision_handler=collision_handler,
317
308
  )
318
309
 
319
310
  @use_style(LabelStyle, "info_text")
@@ -3,12 +3,12 @@ from matplotlib import path, patches
3
3
 
4
4
  from starplot.coordinates import CoordinateSystem
5
5
  from starplot.data.translations import translate
6
- from starplot.map import MapPlot
6
+ from starplot.plots.map import MapPlot
7
7
  from starplot.models.observer import Observer
8
8
  from starplot.projections import Stereographic
9
9
  from starplot.styles import LabelStyle, PlotStyle, PathStyle, GradientDirection
10
10
  from starplot.styles.helpers import use_style
11
-
11
+ from starplot.plotters.text import CollisionHandler
12
12
 
13
13
  DEFAULT_MAP_STYLE = PlotStyle() # .extend(extensions.MAP)
14
14
 
@@ -17,11 +17,11 @@ class ZenithPlot(MapPlot):
17
17
  """Creates a new zenith plot.
18
18
 
19
19
  Args:
20
- observer: Observer instance which specifies a time and place
20
+ observer: Observer instance which specifies a time and place. Defaults to `Observer()`
21
21
  ephemeris: Ephemeris to use for calculating planet positions (see [Skyfield's documentation](https://rhodesmill.org/skyfield/planets.html) for details)
22
- style: Styling for the plot (colors, sizes, fonts, etc)
22
+ style: Styling for the plot (colors, sizes, fonts, etc). If `None`, it defaults to `PlotStyle()`
23
23
  resolution: Size (in pixels) of largest dimension of the map
24
- hide_colliding_labels: If True, then labels will not be plotted if they collide with another existing label
24
+ collision_handler: Default [CollisionHandler][starplot.CollisionHandler] for the plot that describes what to do on label collisions with other labels, markers, etc.
25
25
  scale: Scaling factor that will be applied to all sizes in styles (e.g. font size, marker size, line widths, etc). For example, if you want to make everything 2x bigger, then set the scale to 2. At `scale=1` and `resolution=4096` (the default), all sizes are optimized visually for a map that covers 1-3 constellations. So, if you're creating a plot of a _larger_ extent, then it'd probably be good to decrease the scale (i.e. make everything smaller) -- and _increase_ the scale if you're plotting a very small area.
26
26
  autoscale: If True, then the scale will be set automatically based on resolution.
27
27
  suppress_warnings: If True (the default), then all warnings will be suppressed
@@ -36,17 +36,18 @@ class ZenithPlot(MapPlot):
36
36
 
37
37
  def __init__(
38
38
  self,
39
- observer: Observer = Observer(),
39
+ observer: Observer = None,
40
40
  ephemeris: str = "de421.bsp",
41
41
  style: PlotStyle = DEFAULT_MAP_STYLE,
42
42
  resolution: int = 4096,
43
- hide_colliding_labels: bool = True,
43
+ collision_handler: CollisionHandler = None,
44
44
  scale: float = 1.0,
45
45
  autoscale: bool = False,
46
46
  suppress_warnings: bool = True,
47
47
  *args,
48
48
  **kwargs,
49
49
  ) -> "ZenithPlot":
50
+ observer = observer or Observer()
50
51
  projection = Stereographic(
51
52
  center_ra=observer.lst,
52
53
  center_dec=observer.lat,
@@ -62,7 +63,7 @@ class ZenithPlot(MapPlot):
62
63
  ephemeris,
63
64
  style,
64
65
  resolution,
65
- hide_colliding_labels,
66
+ collision_handler=collision_handler,
66
67
  clip_path=None,
67
68
  scale=scale,
68
69
  autoscale=autoscale,
@@ -127,6 +128,12 @@ class ZenithPlot(MapPlot):
127
128
  **style.label.matplot_kwargs(self.scale),
128
129
  )
129
130
 
131
+ def _adjust_radec_minmax(self):
132
+ self.ra_min = 0
133
+ self.ra_max = 360
134
+ self.dec_min = -90
135
+ self.dec_max = 90
136
+
130
137
  def _set_extent(self):
131
138
  theta = np.linspace(0, 2 * np.pi, 100)
132
139
  center, radius = [0.5, 0.5], 0.45
@@ -175,3 +182,25 @@ class ZenithPlot(MapPlot):
175
182
 
176
183
  self.ax.add_patch(self._background_clip_path)
177
184
  self._update_clip_path_polygon()
185
+
186
+ def _prepare_star_coords(self, df, limit_by_altaz=False):
187
+ # TODO : reconcile this commented code
188
+ # self.location = self.earth + wgs84.latlon(
189
+ # self.observer.lat, self.observer.lon
190
+ # )
191
+ # df["ra_hours"], df["dec_degrees"] = (df.ra / 15, df.dec)
192
+ # stars_apparent = (
193
+ # self.location.at(self.observer.timescale)
194
+ # .observe(SkyfieldStar.from_dataframe(df))
195
+ # .apparent()
196
+ # )
197
+ # # we only need altitude
198
+ # stars_alt, _, _ = stars_apparent.altaz()
199
+ # df["alt"] = stars_alt.degrees
200
+ # df = df[df["alt"] > 0]
201
+
202
+ df["x"], df["y"] = (
203
+ df["ra"],
204
+ df["dec"],
205
+ )
206
+ return df
@@ -1,7 +1,9 @@
1
- from .constellations import ConstellationPlotterMixin # noqa: F401
2
- from .stars import StarPlotterMixin # noqa: F401
3
- from .dsos import DsoPlotterMixin # noqa: F401
4
- from .milkyway import MilkyWayPlotterMixin # noqa: F401
5
- from .legend import LegendPlotterMixin # noqa: F401
6
- from .gradients import GradientBackgroundMixin # noqa: F401
7
- from .arrow import ArrowPlotterMixin # noqa: F401
1
+ # ruff: noqa: F401,F403
2
+
3
+ from .constellations import ConstellationPlotterMixin
4
+ from .stars import StarPlotterMixin
5
+ from .dsos import DsoPlotterMixin
6
+ from .milkyway import MilkyWayPlotterMixin
7
+ from .legend import LegendPlotterMixin
8
+ from .gradients import GradientBackgroundMixin
9
+ from .arrow import ArrowPlotterMixin
@@ -52,7 +52,7 @@ class ArrowPlotterMixin:
52
52
  max_attempts: int = 100,
53
53
  ):
54
54
  """
55
- Plots an arrow from one point to another.
55
+ Plots an arrow from one point to another if you specify both `origin` and `target`. If you only specify a `target`, then the arrow will serve as a "pointer" to that target.
56
56
 
57
57
  Args:
58
58
  origin: Starting point (ra, dec)
@@ -10,8 +10,13 @@ from matplotlib.collections import LineCollection
10
10
  from ibis import _
11
11
 
12
12
  from starplot.coordinates import CoordinateSystem
13
- from starplot.data import constellations as condata
14
- from starplot.data.catalogs import Catalog, CONSTELLATIONS_IAU, BIG_SKY_MAG11
13
+ from starplot.data import db, constellations as condata
14
+ from starplot.data.catalogs import (
15
+ Catalog,
16
+ CONSTELLATIONS_IAU,
17
+ CONSTELLATION_BORDERS,
18
+ BIG_SKY_MAG11,
19
+ )
15
20
  from starplot.data.stars import load as load_stars
16
21
  from starplot.models import Star, Constellation
17
22
  from starplot.models.constellation import from_tuple
@@ -27,17 +32,7 @@ from starplot.styles import LineStyle, LabelStyle
27
32
  from starplot.styles.helpers import use_style
28
33
  from starplot.utils import points_on_line
29
34
  from starplot.geometry import is_wrapped_polygon
30
-
31
- DEFAULT_AUTO_ADJUST_SETTINGS = {
32
- "avoid_constellation_lines": False,
33
- "point_generation_max_iterations": 10,
34
- "distance_step_size": 2,
35
- "max_distance": 3_000,
36
- "label_padding": 6,
37
- "buffer": 0.3,
38
- "seed": None,
39
- }
40
- """Default settings for auto-adjusting constellation labels"""
35
+ from starplot.plotters.text import CollisionHandler
41
36
 
42
37
  GEODETIC_PROJECTIONS = (
43
38
  Equidistant,
@@ -74,6 +69,7 @@ class ConstellationPlotterMixin:
74
69
  filters=[_.hip.isin(hips)],
75
70
  )
76
71
  df = results.to_pandas()
72
+ df["ra_hours"], df["dec_degrees"] = (df.ra / 15, df.dec)
77
73
  df = self._prepare_star_coords(df, limit_by_altaz=False)
78
74
 
79
75
  return {star.hip: (star.x, star.y) for star in df.itertuples()}
@@ -95,6 +91,7 @@ class ConstellationPlotterMixin:
95
91
  style: Styling of the constellations. If None, then the plot's style (specified when creating the plot) will be used
96
92
  where: A list of expressions that determine which constellations to plot. See [Selecting Objects](/reference-selecting-objects/) for details.
97
93
  sql: SQL query for selecting constellations (table name is `_`). This query will be applied _after_ any filters in the `where` kwarg.
94
+ catalog: The catalog of constellations to use -- see [catalogs overview](/data/overview/) for details
98
95
  """
99
96
  self.logger.debug("Plotting constellation lines...")
100
97
 
@@ -126,7 +123,7 @@ class ConstellationPlotterMixin:
126
123
  inbounds = False
127
124
 
128
125
  for s1_hip, s2_hip in hiplines:
129
- if not constars.get(s2_hip):
126
+ if not constars.get(s1_hip) or not constars.get(s2_hip):
130
127
  continue
131
128
  s1_ra, s1_dec = constars.get(s1_hip)
132
129
  s2_ra, s2_dec = constars.get(s2_hip)
@@ -206,15 +203,23 @@ class ConstellationPlotterMixin:
206
203
 
207
204
  @profile
208
205
  @use_style(LineStyle, "constellation_borders")
209
- def constellation_borders(self, style: LineStyle = None):
206
+ def constellation_borders(
207
+ self, style: LineStyle = None, catalog: Catalog = CONSTELLATION_BORDERS
208
+ ):
210
209
  """Plots the constellation borders
211
210
 
212
211
  Args:
213
212
  style: Styling of the constellation borders. If None, then the plot's style (specified when creating the plot) will be used
213
+ catalog: Catalog to use for constellation borders
214
214
  """
215
+ con = db.connect()
216
+ borders = catalog._load(connection=con, table_name="constellation_borders")
217
+ borders = borders.mutate(
218
+ geometry=_.geometry.cast("geometry"), # cast WKB to geometry type
219
+ )
220
+
215
221
  extent = self._extent_mask()
216
- results = condata.load_borders(extent=extent)
217
- borders_df = results.to_pandas()
222
+ borders_df = borders.filter(_.geometry.intersects(extent)).to_pandas()
218
223
 
219
224
  if borders_df.empty:
220
225
  return
@@ -248,7 +253,29 @@ class ConstellationPlotterMixin:
248
253
  )
249
254
  self.ax.add_collection(line_collection)
250
255
 
251
- def _constellation_labels_auto(self, style, label_fn, settings):
256
+ @profile
257
+ @use_style(LabelStyle, "constellation_labels")
258
+ def constellation_labels(
259
+ self,
260
+ style: LabelStyle = None,
261
+ label_fn: Callable[[Constellation], str] = Constellation.get_label,
262
+ collision_handler: CollisionHandler = None,
263
+ ):
264
+ """
265
+ Plots constellation labels for all constellations that have been plotted. This means you must plot the constellations before plotting their labels.
266
+
267
+ It's good to plot these last because they're area-based labels (vs point-based, like for star names), and area-based labels have more freedom to move around. If you plot area-based labels first, then it would limit the available space for point-based labels.
268
+
269
+ Args:
270
+ style: Styling of the constellation labels. If None, then the plot's style (specified when creating the plot) will be used
271
+ label_fn: Callable for determining the label for each constellation. The default function returns the constellation's name in uppercase.
272
+ collision_handler: An instance of [CollisionHandler][starplot.CollisionHandler] that describes what to do on collisions with other labels, markers, etc. If `None`, then `CollisionHandler(allow_constellation_line_collisions=True)` will be used (**Important: this function does NOT default to the plot's collision handler, since it's the only area-based label function and collisions should be handled differently**).
273
+ """
274
+
275
+ collision_handler = collision_handler or CollisionHandler(
276
+ allow_constellation_line_collisions=True
277
+ )
278
+
252
279
  hips = []
253
280
  for c in self.objects.constellations:
254
281
  hips.extend(c.star_hip_ids)
@@ -283,49 +310,7 @@ class ConstellationPlotterMixin:
283
310
  centroid.x,
284
311
  centroid.y,
285
312
  style,
286
- hide_on_collision=self.hide_colliding_labels,
287
313
  area=constellation.boundary, # TODO : make this intersection with clip path
288
- auto_adjust_settings=settings,
314
+ collision_handler=collision_handler,
289
315
  gid="constellations-label-name",
290
316
  )
291
-
292
- def _constellation_labels_static(self, style, label_fn):
293
- for constellation in self.objects.constellations:
294
- text = label_fn(constellation)
295
- self.text(
296
- text,
297
- constellation.ra,
298
- constellation.dec,
299
- style,
300
- hide_on_collision=self.hide_colliding_labels,
301
- remove_on_constellation_collision=False,
302
- gid="constellations-label-name",
303
- )
304
-
305
- @profile
306
- @use_style(LabelStyle, "constellation_labels")
307
- def constellation_labels(
308
- self,
309
- style: LabelStyle = None,
310
- label_fn: Callable[[Constellation], str] = Constellation.get_label,
311
- auto_adjust: bool = True,
312
- auto_adjust_settings: dict = DEFAULT_AUTO_ADJUST_SETTINGS,
313
- ):
314
- """
315
- Plots constellation labels for all constellations that have been plotted. This means you must plot the constellations before plotting their labels.
316
-
317
- It's good to plot these last because they're area-based labels (vs point-based, like for star names), and area-based labels have more freedom to move around. If you plot area-based labels first, then it would limit the available space for point-based labels.
318
-
319
- Args:
320
- style: Styling of the constellation labels. If None, then the plot's style (specified when creating the plot) will be used
321
- label_fn: Callable for determining the label for each constellation. The default function returns the constellation's name in uppercase.
322
- auto_adjust: If True (the default), then labels will be automatically adjusted to avoid collisions with other labels and stars **Important: you must plot stars and constellations first for this to work**. This uses a fairly simple method: for each constellation it finds the centroid of all plotted constellation stars with lines and then generates random points in the constellation boundary starting at the centroid and then progressively increasing the distance from the centroid.
323
- auto_adjust_settings: Optional settings for the auto adjustment algorithm.
324
- """
325
-
326
- if auto_adjust:
327
- settings = DEFAULT_AUTO_ADJUST_SETTINGS
328
- settings.update(auto_adjust_settings)
329
- self._constellation_labels_auto(style, label_fn, settings=settings)
330
- else:
331
- self._constellation_labels_static(style, label_fn)