starplot 0.14.0__py2.py3-none-any.whl → 0.15.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 (62) hide show
  1. starplot/__init__.py +3 -1
  2. starplot/base.py +149 -37
  3. starplot/cli.py +33 -0
  4. starplot/data/__init__.py +6 -24
  5. starplot/data/bigsky.py +58 -40
  6. starplot/data/constellation_lines.py +827 -0
  7. starplot/data/constellation_stars.py +1501 -0
  8. starplot/data/constellations.py +43 -32
  9. starplot/data/db.py +17 -0
  10. starplot/data/dsos.py +24 -141
  11. starplot/data/stars.py +45 -24
  12. starplot/geod.py +0 -6
  13. starplot/geometry.py +105 -6
  14. starplot/horizon.py +118 -107
  15. starplot/map.py +45 -96
  16. starplot/mixins.py +75 -14
  17. starplot/models/__init__.py +1 -1
  18. starplot/models/base.py +10 -128
  19. starplot/models/constellation.py +55 -32
  20. starplot/models/dso.py +132 -67
  21. starplot/models/moon.py +57 -78
  22. starplot/models/planet.py +44 -69
  23. starplot/models/star.py +91 -60
  24. starplot/models/sun.py +32 -53
  25. starplot/optic.py +14 -17
  26. starplot/plotters/constellations.py +81 -78
  27. starplot/plotters/dsos.py +49 -68
  28. starplot/plotters/experimental.py +1 -1
  29. starplot/plotters/milkyway.py +18 -20
  30. starplot/plotters/stars.py +91 -116
  31. starplot/profile.py +16 -0
  32. starplot/settings.py +26 -0
  33. starplot/styles/__init__.py +2 -0
  34. starplot/styles/base.py +7 -17
  35. starplot/styles/ext/blue_gold.yml +135 -0
  36. starplot/styles/ext/blue_light.yml +5 -4
  37. starplot/styles/ext/blue_medium.yml +11 -7
  38. starplot/styles/extensions.py +1 -0
  39. starplot/warnings.py +5 -0
  40. {starplot-0.14.0.dist-info → starplot-0.15.0.dist-info}/METADATA +11 -11
  41. {starplot-0.14.0.dist-info → starplot-0.15.0.dist-info}/RECORD +44 -54
  42. starplot-0.15.0.dist-info/entry_points.txt +3 -0
  43. starplot/data/bayer.py +0 -3499
  44. starplot/data/flamsteed.py +0 -2682
  45. starplot/data/library/constellation_borders_inv.gpkg +0 -0
  46. starplot/data/library/constellation_lines_hips.json +0 -709
  47. starplot/data/library/constellation_lines_inv.gpkg +0 -0
  48. starplot/data/library/constellations.gpkg +0 -0
  49. starplot/data/library/constellations_hip.fab +0 -88
  50. starplot/data/library/milkyway.gpkg +0 -0
  51. starplot/data/library/milkyway_inv.gpkg +0 -0
  52. starplot/data/library/ongc.gpkg.zip +0 -0
  53. starplot/data/library/stars.bigsky.mag11.parquet +0 -0
  54. starplot/data/library/stars.hipparcos.parquet +0 -0
  55. starplot/data/messier.py +0 -111
  56. starplot/data/prep/__init__.py +0 -0
  57. starplot/data/prep/constellations.py +0 -108
  58. starplot/data/prep/dsos.py +0 -299
  59. starplot/data/prep/utils.py +0 -16
  60. starplot/models/geometry.py +0 -44
  61. {starplot-0.14.0.dist-info → starplot-0.15.0.dist-info}/LICENSE +0 -0
  62. {starplot-0.14.0.dist-info → starplot-0.15.0.dist-info}/WHEEL +0 -0
@@ -1,4 +1,3 @@
1
- import geopandas as gpd
2
1
  import numpy as np
3
2
 
4
3
  import rtree
@@ -6,33 +5,61 @@ from shapely import (
6
5
  MultiPoint,
7
6
  )
8
7
  from matplotlib.collections import LineCollection
8
+ from ibis import _
9
9
 
10
10
  from starplot.coordinates import CoordinateSystem
11
- from starplot.data import DataFiles, constellations as condata, stars
11
+ from starplot.data import constellations as condata, constellation_lines as conlines
12
+ from starplot.data.stars import load as load_stars, StarCatalog
12
13
  from starplot.data.constellations import (
13
14
  CONSTELLATIONS_FULL_NAMES,
14
15
  CONSTELLATION_HIP_IDS,
15
16
  )
17
+ from starplot.data.constellation_stars import CONSTELLATION_HIPS
16
18
  from starplot.models.constellation import from_tuple as constellation_from_tuple
17
19
  from starplot.projections import Projection
20
+ from starplot.profile import profile
18
21
  from starplot.styles import PathStyle, LineStyle, LabelStyle
19
22
  from starplot.styles.helpers import use_style
20
23
  from starplot.utils import points_on_line
21
- from starplot.geometry import wrapped_polygon_adjustment
24
+ from starplot.geometry import is_wrapped_polygon
22
25
 
23
26
  DEFAULT_AUTO_ADJUST_SETTINGS = {
24
27
  "avoid_constellation_lines": False,
25
- "point_generation_max_iterations": 500,
26
- "distance_step_size": 1,
27
- "max_distance": 300,
28
- "label_padding": 9,
29
- "buffer": 0.05,
28
+ "point_generation_max_iterations": 10,
29
+ "distance_step_size": 2,
30
+ "max_distance": 3_000,
31
+ "label_padding": 6,
32
+ "buffer": 0.3,
30
33
  "seed": None,
31
34
  }
32
35
  """Default settings for auto-adjusting constellation labels"""
33
36
 
34
37
 
35
38
  class ConstellationPlotterMixin:
39
+ def inbounds_temp(self, x, y):
40
+ data_x, data_y = self._proj.transform_point(x, y, self._geodetic)
41
+ display_x, display_y = self.ax.transData.transform((data_x, data_y))
42
+ return display_x > 0 and display_y > 0
43
+
44
+ @profile
45
+ def _prepare_constellation_stars(self) -> dict[int, tuple[float, float]]:
46
+ """
47
+ Returns dictionary of stars and their position:
48
+
49
+ {hip: (x,y)}
50
+
51
+ Where (x, y) is the plotted coordinate system (RA/DEC or AZ/ALT)
52
+ """
53
+ results = load_stars(
54
+ catalog=StarCatalog.BIG_SKY_MAG11,
55
+ filters=[_.hip.isin(CONSTELLATION_HIPS)],
56
+ )
57
+ df = results.to_pandas()
58
+ df = self._prepare_star_coords(df, limit_by_altaz=False)
59
+
60
+ return {star.hip: (star.x, star.y) for star in df.itertuples()}
61
+
62
+ @profile
36
63
  @use_style(LineStyle, "constellation_lines")
37
64
  def constellations(
38
65
  self,
@@ -52,15 +79,11 @@ class ConstellationPlotterMixin:
52
79
  where = where or []
53
80
  ctr = 0
54
81
 
55
- constellations_gdf = gpd.read_file(
56
- DataFiles.CONSTELLATIONS.value,
57
- engine="pyogrio",
58
- use_arrow=True,
59
- bbox=self._extent_mask(),
60
- )
61
- stars_df = stars.load("hipparcos")
82
+ extent = self._extent_mask()
83
+ results = condata.load(extent=extent, filters=where)
84
+ constellations_df = results.to_pandas()
62
85
 
63
- if constellations_gdf.empty:
86
+ if constellations_df.empty:
64
87
  return
65
88
 
66
89
  if getattr(self, "projection", None) in [
@@ -71,49 +94,38 @@ class ConstellationPlotterMixin:
71
94
  else:
72
95
  transform = self._geodetic
73
96
 
74
- conline_hips = condata.lines()
75
97
  style_kwargs = style.matplot_kwargs(self.scale)
76
98
  constellation_points_to_index = []
77
99
  lines = []
100
+ constars = self._prepare_constellation_stars()
78
101
 
79
- for c in constellations_gdf.itertuples():
80
- obj = constellation_from_tuple(c)
81
-
82
- if not all([e.evaluate(obj) for e in where]):
83
- continue
84
-
85
- hiplines = conline_hips[c.iau_id]
102
+ for c in constellations_df.itertuples():
103
+ hiplines = conlines.hips[c.iau_id]
86
104
  inbounds = False
87
105
 
88
106
  for s1_hip, s2_hip in hiplines:
89
- s1 = stars_df.loc[s1_hip]
90
- s2 = stars_df.loc[s2_hip]
91
-
92
- s1_ra = s1.ra_hours * 15
93
- s2_ra = s2.ra_hours * 15
94
-
95
- s1_dec = s1.dec_degrees
96
- s2_dec = s2.dec_degrees
107
+ if not constars.get(s2_hip):
108
+ continue
109
+ s1_ra, s1_dec = constars.get(s1_hip)
110
+ s2_ra, s2_dec = constars.get(s2_hip)
97
111
 
98
112
  if s1_ra - s2_ra > 60:
99
113
  s2_ra += 360
100
-
101
114
  elif s2_ra - s1_ra > 60:
102
115
  s1_ra += 360
103
116
 
104
- if not inbounds and self.in_bounds(s1.ra_hours, s1_dec):
117
+ x1, x2 = s1_ra, s2_ra
118
+ y1, y2 = s1_dec, s2_dec
119
+ if not inbounds and (
120
+ self._in_bounds_xy(x1, y1) or self._in_bounds_xy(x2, y2)
121
+ ):
105
122
  inbounds = True
123
+ elif not inbounds:
124
+ continue
106
125
 
107
126
  if self._coordinate_system == CoordinateSystem.RA_DEC:
108
- s1_ra *= -1
109
- s2_ra *= -1
110
- x1, x2 = s1_ra, s2_ra
111
- y1, y2 = s1_dec, s2_dec
112
- elif self._coordinate_system == CoordinateSystem.AZ_ALT:
113
- x1, y1 = self._prepare_coords(s1_ra / 15, s1_dec)
114
- x2, y2 = self._prepare_coords(s2_ra / 15, s2_dec)
115
- else:
116
- raise ValueError("Unrecognized coordinate system")
127
+ x1 *= -1
128
+ x2 *= -1
117
129
 
118
130
  lines.append([(x1, y1), (x2, y2)])
119
131
 
@@ -143,6 +155,7 @@ class ConstellationPlotterMixin:
143
155
  ctr += 1
144
156
 
145
157
  if inbounds:
158
+ obj = constellation_from_tuple(c)
146
159
  self._objects.constellations.append(obj)
147
160
 
148
161
  style_kwargs = style.matplot_line_collection_kwargs(self.scale)
@@ -169,8 +182,6 @@ class ConstellationPlotterMixin:
169
182
  bbox,
170
183
  None,
171
184
  )
172
- # self._plot_constellation_labels(style.label, labels_to_plot)
173
- # self._plot_constellation_labels_experimental(style.label, labels_to_plot)
174
185
 
175
186
  def _plot_constellation_labels(
176
187
  self,
@@ -206,6 +217,7 @@ class ConstellationPlotterMixin:
206
217
  if label is not None:
207
218
  self._constellation_labels.append(label)
208
219
 
220
+ @profile
209
221
  @use_style(LineStyle, "constellation_borders")
210
222
  def constellation_borders(self, style: LineStyle = None):
211
223
  """Plots the constellation borders
@@ -213,49 +225,40 @@ class ConstellationPlotterMixin:
213
225
  Args:
214
226
  style: Styling of the constellation borders. If None, then the plot's style (specified when creating the plot) will be used
215
227
  """
216
- constellation_borders = self._read_geo_package(
217
- DataFiles.CONSTELLATION_BORDERS.value
218
- )
228
+ extent = self._extent_mask()
229
+ results = condata.load_borders(extent=extent)
230
+ borders_df = results.to_pandas()
219
231
 
220
- if constellation_borders.empty:
232
+ if borders_df.empty:
221
233
  return
222
234
 
223
- geometries = []
224
235
  border_lines = []
225
- transform = self._plate_carree
226
-
227
- for _, c in constellation_borders.iterrows():
228
- for ls in c.geometry.geoms:
229
- geometries.append(ls)
236
+ geometries = [line.geometry for line in borders_df.itertuples()]
230
237
 
231
238
  for ls in geometries:
232
- x, y = ls.xy
233
- x = list(x)
234
- y = list(y)
239
+ if ls.length < 80:
240
+ ls = ls.segmentize(1)
241
+
242
+ xy = [c for c in ls.coords]
235
243
 
236
244
  if self._coordinate_system == CoordinateSystem.RA_DEC:
237
- border_lines.append(list(zip(x, y)))
245
+ border_lines.append(xy)
238
246
 
239
247
  elif self._coordinate_system == CoordinateSystem.AZ_ALT:
240
- x = [24 - (x0 / 15) for x0 in x]
241
- coords = [self._prepare_coords(*p) for p in list(zip(x, y))]
248
+ coords = [self._prepare_coords(*p) for p in xy]
242
249
  border_lines.append(coords)
243
- transform = self._crs
244
250
 
245
251
  else:
246
252
  raise ValueError("Unrecognized coordinate system")
247
253
 
248
- style_kwargs = style.matplot_line_collection_kwargs(self.scale)
249
-
250
254
  line_collection = LineCollection(
251
255
  border_lines,
252
- **style_kwargs,
253
- transform=transform,
256
+ **style.matplot_line_collection_kwargs(self.scale),
257
+ transform=self._crs,
254
258
  clip_on=True,
255
259
  clip_path=self._background_clip_path,
256
260
  gid="constellations-border",
257
261
  )
258
-
259
262
  self.ax.add_collection(line_collection)
260
263
 
261
264
  def _constellation_labels_auto(self, style, labels, settings):
@@ -268,23 +271,23 @@ class ConstellationPlotterMixin:
268
271
  if not constellation_line_stars:
269
272
  continue
270
273
 
271
- points_line = MultiPoint([(s.ra, s.dec) for s in constellation_line_stars])
272
- centroid = points_line.centroid
273
-
274
- adjustment = wrapped_polygon_adjustment(constellation.boundary)
274
+ if is_wrapped_polygon(constellation.boundary):
275
+ starpoints = []
276
+ ra, dec = zip(*[(s.ra, s.dec) for s in constellation_line_stars])
277
+ new_ra = [r - 360 if r > 300 else r for r in ra]
278
+ starpoints = list(zip(new_ra, dec))
275
279
 
276
- if (adjustment > 0 and centroid.x < 12) or (
277
- adjustment < 0 and centroid.x > 12
278
- ):
279
- x = centroid.x + adjustment
280
280
  else:
281
- x = centroid.x
281
+ ra, dec = zip(*[(s.ra, s.dec) for s in constellation_line_stars])
282
+ starpoints = list(zip(ra, dec))
282
283
 
284
+ points_line = MultiPoint(starpoints)
285
+ centroid = points_line.centroid
283
286
  text = labels.get(constellation.iau_id)
284
287
 
285
288
  self.text(
286
289
  text,
287
- x,
290
+ centroid.x,
288
291
  centroid.y,
289
292
  style,
290
293
  hide_on_collision=self.hide_colliding_labels,
@@ -306,6 +309,7 @@ class ConstellationPlotterMixin:
306
309
  gid="constellations-label-name",
307
310
  )
308
311
 
312
+ @profile
309
313
  @use_style(LabelStyle, "constellation_labels")
310
314
  def constellation_labels(
311
315
  self,
@@ -329,7 +333,6 @@ class ConstellationPlotterMixin:
329
333
  make this work without plotting constellations first
330
334
 
331
335
  """
332
- self.logger.debug("Plotting constellation labels...")
333
336
 
334
337
  if auto_adjust:
335
338
  settings = DEFAULT_AUTO_ADJUST_SETTINGS
starplot/plotters/dsos.py CHANGED
@@ -1,24 +1,22 @@
1
- from functools import cache
2
1
  from typing import Callable, Mapping
3
2
 
3
+ from ibis import _
4
+ import numpy as np
5
+
4
6
  from starplot.data.dsos import (
7
+ DSO_LABELS_DEFAULT,
8
+ DsoLabelMaker,
9
+ load,
10
+ )
11
+ from starplot.models.dso import (
12
+ DSO,
5
13
  DsoType,
14
+ from_tuple,
6
15
  ONGC_TYPE_MAP,
7
16
  DSO_LEGEND_LABELS,
8
- DSO_LABELS_DEFAULT,
9
- DsoLabelMaker,
10
- load_ongc,
11
17
  )
12
- from starplot.models.dso import DSO, from_tuple
13
18
  from starplot.styles import MarkerSymbolEnum
14
-
15
-
16
- def _where(*args, **kwargs):
17
- where = kwargs.pop("where", [])
18
-
19
- if mag := kwargs.pop("mag", None):
20
- where.append(DSO.magnitude.is_null() | (DSO.magnitude <= mag))
21
- return where
19
+ from starplot.profile import profile
22
20
 
23
21
 
24
22
  class DsoPlotterMixin:
@@ -29,40 +27,37 @@ class DsoPlotterMixin:
29
27
  coords.append(coords[0])
30
28
  self._polygon(coords, style.marker.to_polygon_style(), closed=False)
31
29
 
32
- def messier(self, *args, **kwargs):
30
+ def messier(self, **kwargs):
33
31
  """
34
32
  Plots Messier objects
35
33
 
36
34
  This is just a small wrapper around the `dsos()` function, so any `kwargs` will be passed through.
37
35
  """
38
- where = _where(**kwargs)
39
- where.append(DSO.m.is_not_null())
40
- kwargs.pop("where", None)
36
+ where = kwargs.pop("where", [])
37
+ where.append(_.m.notnull())
41
38
  self.dsos(where=where, **kwargs)
42
39
 
43
- def open_clusters(self, *args, **kwargs):
40
+ def open_clusters(self, **kwargs):
44
41
  """
45
42
  Plots open clusters
46
43
 
47
44
  This is just a small wrapper around the `dsos()` function, so any `kwargs` will be passed through.
48
45
  """
49
- where = _where(**kwargs)
50
- where.append(DSO.type == DsoType.OPEN_CLUSTER)
51
- kwargs.pop("where", None)
46
+ where = kwargs.pop("where", [])
47
+ where.append(_.type == DsoType.OPEN_CLUSTER)
52
48
  self.dsos(where=where, **kwargs)
53
49
 
54
- def globular_clusters(self, *args, **kwargs):
50
+ def globular_clusters(self, **kwargs):
55
51
  """
56
52
  Plots globular clusters
57
53
 
58
54
  This is just a small wrapper around the `dsos()` function, so any `kwargs` will be passed through.
59
55
  """
60
- where = _where(**kwargs)
61
- where.append(DSO.type == DsoType.GLOBULAR_CLUSTER)
62
- kwargs.pop("where", None)
56
+ where = kwargs.pop("where", [])
57
+ where.append(_.type == DsoType.GLOBULAR_CLUSTER)
63
58
  self.dsos(where=where, **kwargs)
64
59
 
65
- def galaxies(self, *args, **kwargs):
60
+ def galaxies(self, **kwargs):
66
61
  """
67
62
  Plots galaxy DSO types:
68
63
 
@@ -77,12 +72,11 @@ class DsoPlotterMixin:
77
72
  DsoType.GALAXY_PAIR,
78
73
  DsoType.GALAXY_TRIPLET,
79
74
  ]
80
- where = _where(**kwargs)
81
- where.append(DSO.type.is_in(galaxy_types))
82
- kwargs.pop("where", None)
75
+ where = kwargs.pop("where", [])
76
+ where.append(_.type.isin(galaxy_types))
83
77
  self.dsos(where=where, **kwargs)
84
78
 
85
- def nebula(self, *args, **kwargs):
79
+ def nebula(self, **kwargs):
86
80
  """
87
81
  Plots nebula DSO types:
88
82
 
@@ -101,50 +95,39 @@ class DsoPlotterMixin:
101
95
  DsoType.STAR_CLUSTER_NEBULA,
102
96
  DsoType.REFLECTION_NEBULA,
103
97
  ]
104
- where = _where(**kwargs)
105
- where.append(DSO.type.is_in(nebula_types))
106
- kwargs.pop("where", None)
98
+ where = kwargs.pop("where", [])
99
+ where.append(_.type.isin(nebula_types))
107
100
  self.dsos(where=where, **kwargs)
108
101
 
109
- @cache
110
- def _load_dsos(self):
111
- return load_ongc(bbox=self._extent_mask())
112
-
102
+ @profile
113
103
  def dsos(
114
104
  self,
115
- mag: float = 8.0,
105
+ where: list = None,
106
+ where_labels: list = None,
116
107
  true_size: bool = True,
117
108
  labels: Mapping[str, str] = DSO_LABELS_DEFAULT,
118
109
  legend_labels: Mapping[DsoType, str] = DSO_LEGEND_LABELS,
119
110
  alpha_fn: Callable[[DSO], float] = None,
120
111
  label_fn: Callable[[DSO], str] = None,
121
- where: list = None,
122
- where_labels: list = None,
123
112
  ):
124
113
  """
125
114
  Plots Deep Sky Objects (DSOs), from OpenNGC
126
115
 
127
116
  Args:
128
- mag: Limiting magnitude of DSOs to plot. For more control of what DSOs to plot, use the `where` kwarg. **Note:** if you pass `mag` and `where` then `mag` will be ignored
117
+ where: A list of expressions that determine which DSOs to plot. See [Selecting Objects](/reference-selecting-objects/) for details.
118
+ where_labels: A list of expressions that determine which DSOs are labeled on the plot. See [Selecting Objects](/reference-selecting-objects/) for details.
129
119
  true_size: If True, then each DSO will be plotted as its true apparent size in the sky (note: this increases plotting time). If False, then the style's marker size will be used. Also, keep in mind not all DSOs have a defined size (according to OpenNGC) -- so these will use the style's marker size.
130
120
  labels: A dictionary that maps DSO names (as specified in OpenNGC) to the label that'll be plotted for that object. By default, the DSO's name in OpenNGC will be used as the label. If you want to hide all labels, then set this arg to `None`.
131
121
  legend_labels: A dictionary that maps a `DsoType` to the legend label that'll be plotted for that type of DSO. If you want to hide all DSO legend labels, then set this arg to `None`.
132
122
  alpha_fn: Callable for calculating the alpha value (aka "opacity") of each DSO. If `None`, then the marker style's alpha will be used.
133
123
  label_fn: Callable for determining the label of each DSO. If `None`, then the names in the `labels` kwarg will be used.
134
- where: A list of expressions that determine which DSOs to plot. See [Selecting Objects](/reference-selecting-objects/) for details.
135
- where_labels: A list of expressions that determine which DSOs are labeled on the plot. See [Selecting Objects](/reference-selecting-objects/) for details.
136
124
  """
137
125
 
138
126
  # TODO: add kwarg styles
139
127
 
140
- self.logger.debug("Plotting DSOs...")
141
-
142
128
  where = where or []
143
129
  where_labels = where_labels or []
144
130
 
145
- if not where:
146
- where = [DSO.magnitude.is_null() | (DSO.magnitude <= mag)]
147
-
148
131
  if labels is None:
149
132
  labels = {}
150
133
  elif type(labels) != DsoLabelMaker:
@@ -155,35 +138,35 @@ class DsoPlotterMixin:
155
138
  else:
156
139
  legend_labels = {**DSO_LEGEND_LABELS, **legend_labels}
157
140
 
158
- nearby_dsos = self._load_dsos() # load_ongc(bbox=self._extent_mask())
159
- # dso_types = [ONGC_TYPE[dtype] for dtype in types]
160
- # nearby_dsos = nearby_dsos[nearby_dsos["type"].isin(dso_types)]
141
+ extent = self._extent_mask()
142
+ dso_results = load(extent=extent, filters=where)
143
+
144
+ dso_results_labeled = dso_results
145
+ for f in where_labels:
146
+ dso_results_labeled = dso_results_labeled.filter(f)
147
+
148
+ label_row_ids = dso_results_labeled.to_pandas()["rowid"].tolist()
149
+
150
+ results_df = dso_results.to_pandas()
151
+ results_df = results_df.replace({np.nan: None})
161
152
 
162
- for d in nearby_dsos.itertuples():
153
+ for d in results_df.itertuples():
163
154
  ra = d.ra_degrees
164
155
  dec = d.dec_degrees
165
156
  dso_type = ONGC_TYPE_MAP[d.type]
166
157
  style = self.style.get_dso_style(dso_type)
167
158
  maj_ax, min_ax, angle = d.maj_ax, d.min_ax, d.angle
168
159
  legend_label = legend_labels.get(dso_type)
169
- magnitude = d.mag_v or d.mag_b or None
170
- magnitude = float(magnitude) if magnitude else None
171
160
  _dso = from_tuple(d)
172
161
  label = labels.get(d.name) if label_fn is None else label_fn(_dso)
173
162
 
174
- if any(
175
- [
176
- style is None,
177
- not all([e.evaluate(_dso) for e in where]),
178
- # not self.in_bounds(ra / 15, dec),
179
- ]
180
- ):
163
+ if style is None:
181
164
  continue
182
165
 
183
166
  _alpha_fn = alpha_fn or (lambda d: style.marker.alpha)
184
167
  style.marker.alpha = _alpha_fn(_dso)
185
168
 
186
- if where_labels and not all([e.evaluate(_dso) for e in where_labels]):
169
+ if _dso._row_id not in label_row_ids:
187
170
  label = None
188
171
 
189
172
  if true_size and d.size_deg2 is not None:
@@ -206,7 +189,7 @@ class DsoPlotterMixin:
206
189
 
207
190
  if style.marker.symbol == MarkerSymbolEnum.SQUARE:
208
191
  self.rectangle(
209
- (ra / 15, dec),
192
+ (ra, dec),
210
193
  min_ax_degrees * 2,
211
194
  maj_ax_degrees * 2,
212
195
  style=poly_style,
@@ -214,7 +197,7 @@ class DsoPlotterMixin:
214
197
  )
215
198
  else:
216
199
  self.ellipse(
217
- (ra / 15, dec),
200
+ (ra, dec),
218
201
  min_ax_degrees * 2,
219
202
  maj_ax_degrees * 2,
220
203
  style=poly_style,
@@ -222,14 +205,12 @@ class DsoPlotterMixin:
222
205
  )
223
206
 
224
207
  if label:
225
- self.text(
226
- label, ra / 15, dec, style.label, gid=f"dso-{d.type}-label"
227
- )
208
+ self.text(label, ra, dec, style.label, gid=f"dso-{d.type}-label")
228
209
 
229
210
  else:
230
211
  # if no major axis, then just plot as a marker
231
212
  self.marker(
232
- ra=ra / 15,
213
+ ra=ra,
233
214
  dec=dec,
234
215
  style=style,
235
216
  label=label,
@@ -22,7 +22,7 @@ class ExperimentalPlotterMixin:
22
22
  from shapely.ops import unary_union
23
23
 
24
24
  constellation_borders = gpd.read_file(
25
- DataFiles.CONSTELLATIONS.value,
25
+ DataFiles.CONSTELLATIONS,
26
26
  engine="pyogrio",
27
27
  use_arrow=True,
28
28
  bbox=self._extent_mask(),
@@ -1,10 +1,14 @@
1
- from starplot.data import DataFiles
1
+ from shapely.ops import unary_union
2
+
3
+ from starplot.data import db
2
4
  from starplot.styles import PolygonStyle
3
5
  from starplot.styles.helpers import use_style
4
- from starplot.utils import lon_to_ra
6
+ from starplot.geometry import unwrap_polygon_360
7
+ from starplot.profile import profile
5
8
 
6
9
 
7
10
  class MilkyWayPlotterMixin:
11
+ @profile
8
12
  @use_style(PolygonStyle, "milky_way")
9
13
  def milky_way(self, style: PolygonStyle = None):
10
14
  """
@@ -13,29 +17,23 @@ class MilkyWayPlotterMixin:
13
17
  Args:
14
18
  style: Styling of the Milky Way. If None, then the plot's style (specified when creating the plot) will be used
15
19
  """
20
+ con = db.connect()
21
+ mw = con.table("milky_way")
16
22
 
17
- mw = self._read_geo_package(DataFiles.MILKY_WAY.value)
18
-
19
- if mw.empty:
20
- return
21
-
22
- def _prepare_polygon(p):
23
- points = list(zip(*p.boundary.coords.xy))
24
- # convert lon to RA and reverse so the coordinates are counterclockwise order
25
- return [(lon_to_ra(lon) * 15, dec) for lon, dec in reversed(points)]
23
+ extent = self._extent_mask()
24
+ result = mw.filter(mw.geometry.intersects(extent)).to_pandas()
26
25
 
27
- # create union of all Milky Way patches
28
- gs = mw.geometry.to_crs(self._plate_carree)
29
- mw_union = gs.buffer(0.1).unary_union.buffer(-0.1)
30
- polygons = []
26
+ mw_union = unary_union(
27
+ [unwrap_polygon_360(row.geometry) for row in result.itertuples()]
28
+ )
31
29
 
32
30
  if mw_union.geom_type == "MultiPolygon":
33
- polygons.extend([_prepare_polygon(polygon) for polygon in mw_union.geoms])
31
+ polygons = mw_union.geoms
34
32
  else:
35
- polygons.append(_prepare_polygon(mw_union))
33
+ polygons = [mw_union]
36
34
 
37
- for polygon_points in polygons:
38
- self._polygon(
39
- points=polygon_points,
35
+ for p in polygons:
36
+ self.polygon(
37
+ geometry=p,
40
38
  style=style,
41
39
  )