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
starplot/plotters/dsos.py CHANGED
@@ -15,6 +15,7 @@ from starplot.models.dso import (
15
15
  )
16
16
  from starplot.styles import MarkerSymbolEnum
17
17
  from starplot.profile import profile
18
+ from starplot.plotters.text import CollisionHandler
18
19
 
19
20
 
20
21
  class DsoPlotterMixin:
@@ -147,33 +148,37 @@ class DsoPlotterMixin:
147
148
  self,
148
149
  where: list = None,
149
150
  where_labels: list = None,
150
- true_size: bool = True,
151
+ where_true_size: list = None,
151
152
  legend_labels: Mapping[DsoType, str] = DSO_LEGEND_LABELS,
152
153
  alpha_fn: Callable[[DSO], float] = None,
153
154
  label_fn: Callable[[DSO], str] = DSO.get_label,
154
155
  sql: str = None,
155
156
  sql_labels: str = None,
156
157
  catalog: Catalog = OPEN_NGC,
158
+ collision_handler: CollisionHandler = None,
157
159
  ):
158
160
  """
159
- Plots Deep Sky Objects (DSOs), from OpenNGC
161
+ Plots Deep Sky Objects (DSOs).
160
162
 
161
163
  Args:
162
164
  where: A list of expressions that determine which DSOs to plot. See [Selecting Objects](/reference-selecting-objects/) for details.
163
- where_labels: A list of expressions that determine which DSOs are labeled on the plot. See [Selecting Objects](/reference-selecting-objects/) for details.
164
- 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.
165
- 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`.
165
+ where_labels: A list of expressions that determine which DSOs are labeled on the plot. By default all DSOs are labeled. See [Selecting Objects](/reference-selecting-objects/) for details.
166
+ where_true_size: A list of expressions that determine which DSOs are plotted as their true apparent size in the sky. By default all DSOs are plotted as their true size.
166
167
  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`.
167
168
  alpha_fn: Callable for calculating the alpha value (aka "opacity") of each DSO. If `None`, then the marker style's alpha will be used.
168
169
  label_fn: Callable for determining the label of each DSO.
169
170
  sql: SQL query for selecting DSOs (table name is `_`). This query will be applied _after_ any filters in the `where` kwarg.
170
171
  sql_labels: SQL query for selecting DSOs that will be labeled (table name is `_`). Applied _after_ any filters in the `where_labels` kwarg.
172
+ catalog: The catalog of DSOs to use -- see [catalogs overview](/data/overview/) for details
173
+ collision_handler: An instance of [CollisionHandler][starplot.CollisionHandler] that describes what to do on label collisions with other labels, markers, etc. If `None`, then the collision handler of the plot will be used.
171
174
  """
172
175
 
173
176
  # TODO: add kwarg styles
174
177
 
175
178
  where = where or []
176
179
  where_labels = where_labels or []
180
+ where_true_size = where_true_size or []
181
+ handler = collision_handler or self.collision_handler
177
182
 
178
183
  if legend_labels is None:
179
184
  legend_labels = {}
@@ -183,21 +188,23 @@ class DsoPlotterMixin:
183
188
  extent = self._extent_mask()
184
189
  dso_results = load(extent=extent, filters=where, sql=sql, catalog=catalog)
185
190
 
186
- dso_results_labeled = dso_results
191
+ dsos_labeled = dso_results
187
192
  for f in where_labels:
188
- dso_results_labeled = dso_results_labeled.filter(f)
193
+ dsos_labeled = dsos_labeled.filter(f)
194
+
195
+ dsos_true_size = dso_results
196
+ for f in where_true_size:
197
+ dsos_true_size = dsos_true_size.filter(f)
189
198
 
190
199
  if sql_labels:
191
- result = (
192
- dso_results_labeled.alias("_").sql(sql_labels).select("pk").execute()
193
- )
200
+ result = dsos_labeled.alias("_").sql(sql_labels).select("pk").execute()
194
201
  pks = result["pk"].to_list()
195
- dso_results_labeled = dso_results_labeled.filter(_.pk.isin(pks))
202
+ dsos_labeled = dsos_labeled.filter(_.pk.isin(pks))
196
203
 
197
- label_pks = dso_results_labeled.to_pandas()["pk"].tolist()
204
+ label_pks = dsos_labeled.select("pk").to_pandas()["pk"].tolist()
205
+ true_size_pks = dsos_true_size.select("pk").to_pandas()["pk"].tolist()
198
206
 
199
- results_df = dso_results.to_pandas()
200
- results_df = results_df.replace({np.nan: None})
207
+ results_df = dso_results.to_pandas().replace({np.nan: None})
201
208
 
202
209
  for d in results_df.itertuples():
203
210
  ra = d.ra
@@ -221,7 +228,9 @@ class DsoPlotterMixin:
221
228
  if _dso.pk not in label_pks:
222
229
  label = None
223
230
 
224
- if true_size and d.size is not None:
231
+ _true_size = _dso.pk in true_size_pks
232
+
233
+ if _true_size and d.size is not None:
225
234
  if "Polygon" == str(d.geometry.geom_type):
226
235
  self._plot_dso_polygon(d.geometry, style)
227
236
 
@@ -257,7 +266,14 @@ class DsoPlotterMixin:
257
266
  )
258
267
 
259
268
  if label:
260
- self.text(label, ra, dec, style.label, gid=f"dso-{d.type}-label")
269
+ self.text(
270
+ label,
271
+ ra,
272
+ dec,
273
+ style.label,
274
+ collision_handler=handler,
275
+ gid=f"dso-{d.type}-label",
276
+ )
261
277
 
262
278
  self._add_legend_handle_marker(legend_label, style.marker)
263
279
 
@@ -269,6 +285,7 @@ class DsoPlotterMixin:
269
285
  style=style,
270
286
  label=label,
271
287
  legend_label=legend_label,
288
+ collision_handler=handler,
272
289
  skip_bounds_check=True,
273
290
  gid_marker=f"dso-{d.type}-marker",
274
291
  gid_label=f"dso-{d.type}-label",
@@ -716,7 +716,6 @@ class ExperimentalPlotterMixin:
716
716
  ra,
717
717
  dec,
718
718
  style,
719
- hide_on_collision=self.hide_colliding_labels,
720
719
  area=MultiPolygon(polygons_sorted[:3])
721
720
  if len(polygons_sorted)
722
721
  else constellation.boundary,
@@ -1,32 +1,41 @@
1
1
  from shapely.ops import unary_union
2
2
 
3
+ from ibis import _
4
+
3
5
  from starplot.data import db
6
+ from starplot.data.catalogs import Catalog, MILKY_WAY
4
7
  from starplot.styles import PolygonStyle
5
8
  from starplot.styles.helpers import use_style
6
9
  from starplot.geometry import split_polygon_at_zero
7
10
  from starplot.profile import profile
11
+ from starplot.models.milky_way import from_tuple
8
12
 
9
13
 
10
14
  class MilkyWayPlotterMixin:
11
15
  @profile
12
16
  @use_style(PolygonStyle, "milky_way")
13
- def milky_way(self, style: PolygonStyle = None):
17
+ def milky_way(self, style: PolygonStyle = None, catalog: Catalog = MILKY_WAY):
14
18
  """
15
19
  Plots the Milky Way
16
20
 
17
21
  Args:
18
22
  style: Styling of the Milky Way. If None, then the plot's style (specified when creating the plot) will be used
23
+ catalog: Catalog to use for Milky Way polygons
19
24
  """
20
25
  con = db.connect()
21
- mw = con.table("milky_way")
26
+ mw = catalog._load(connection=con, table_name="milky_way")
27
+ mw = mw.mutate(
28
+ geometry=_.geometry.cast("geometry"), # cast WKB to geometry type
29
+ )
22
30
 
23
31
  extent = self._extent_mask()
24
- result = mw.filter(mw.geometry.intersects(extent)).to_pandas()
32
+ df = mw.filter(_.geometry.intersects(extent)).to_pandas()
25
33
 
26
- polygons = []
34
+ milky_ways = [from_tuple(m) for m in df.itertuples()]
27
35
 
28
- for row in result.itertuples():
29
- polygons.extend(split_polygon_at_zero(row.geometry))
36
+ polygons = []
37
+ for milky_way in milky_ways:
38
+ polygons.extend(split_polygon_at_zero(milky_way.geometry))
30
39
 
31
40
  mw_union = unary_union(polygons)
32
41
 
@@ -4,7 +4,7 @@ from typing import Callable
4
4
  import rtree
5
5
  import numpy as np
6
6
  from ibis import _ as ibis_table
7
- from skyfield.api import Star as SkyfieldStar, wgs84
7
+ from skyfield.api import Star as SkyfieldStar
8
8
 
9
9
  from starplot import callables
10
10
  from starplot.data import stars
@@ -13,6 +13,7 @@ from starplot.data.translations import translate
13
13
  from starplot.models.star import Star, from_tuple
14
14
  from starplot.styles import ObjectStyle, use_style
15
15
  from starplot.profile import profile
16
+ from starplot.plotters.text import CollisionHandler
16
17
 
17
18
 
18
19
  class StarPlotterMixin:
@@ -65,6 +66,7 @@ class StarPlotterMixin:
65
66
  bayer_labels: bool,
66
67
  flamsteed_labels: bool,
67
68
  label_fn: Callable[[Star], str],
69
+ collision_handler: CollisionHandler,
68
70
  ):
69
71
  _bayer = []
70
72
  _flamsteed = []
@@ -100,7 +102,7 @@ class StarPlotterMixin:
100
102
  marker_size=star_sizes[i],
101
103
  scale=self.scale,
102
104
  ),
103
- hide_on_collision=self.hide_colliding_labels,
105
+ collision_handler=collision_handler,
104
106
  gid="stars-label-name",
105
107
  )
106
108
 
@@ -121,7 +123,7 @@ class StarPlotterMixin:
121
123
  marker_size=star_size,
122
124
  scale=self.scale,
123
125
  ),
124
- hide_on_collision=self.hide_colliding_labels,
126
+ collision_handler=collision_handler,
125
127
  gid="stars-label-bayer",
126
128
  )
127
129
 
@@ -135,7 +137,7 @@ class StarPlotterMixin:
135
137
  marker_size=star_size,
136
138
  scale=self.scale,
137
139
  ),
138
- hide_on_collision=self.hide_colliding_labels,
140
+ collision_handler=collision_handler,
139
141
  gid="stars-label-flamsteed",
140
142
  )
141
143
 
@@ -163,22 +165,15 @@ class StarPlotterMixin:
163
165
  flamsteed_labels: bool = False,
164
166
  sql: str = None,
165
167
  sql_labels: str = None,
166
- *args,
167
- **kwargs,
168
+ collision_handler: CollisionHandler = None,
168
169
  ):
169
170
  """
170
171
  Plots stars
171
172
 
172
- Labels for stars are determined in this order:
173
-
174
- 1. Return value from `label_fn`
175
- 2. Value for star's HIP id in `labels`
176
- 3. IAU-designated name, as listed in the [data reference](/data/star-designations/)
177
-
178
173
  Args:
179
174
  where: A list of expressions that determine which stars to plot. See [Selecting Objects](/reference-selecting-objects/) for details.
180
175
  where_labels: A list of expressions that determine which stars are labeled on the plot (this includes all labels: name, Bayer, and Flamsteed). If you want to hide **all** labels, then set this arg to `[False]`. See [Selecting Objects](/reference-selecting-objects/) for details.
181
- catalog: The catalog of stars to use: "big-sky-mag11", or "big-sky" -- see [star catalogs](/data/star-catalogs/) for details
176
+ catalog: The catalog of stars to use -- see [catalogs overview](/data/overview/) for details
182
177
  style: If `None`, then the plot's style for stars will be used
183
178
  size_fn: Callable for calculating the marker size of each star. If `None`, then the marker style's size will be used.
184
179
  alpha_fn: Callable for calculating the alpha value (aka "opacity") of each star. If `None`, then the marker style's alpha will be used.
@@ -189,6 +184,7 @@ class StarPlotterMixin:
189
184
  flamsteed_labels: If True, then Flamsteed number labels for stars will be plotted.
190
185
  sql: SQL query for selecting stars (table name is `_`). This query will be applied _after_ any filters in the `where` kwarg.
191
186
  sql_labels: SQL query for selecting stars that will be labeled (table name is `_`). Applied _after_ any filters in the `where_labels` kwarg.
187
+ collision_handler: An instance of [CollisionHandler][starplot.CollisionHandler] that describes what to do on label collisions with other labels, markers, etc. If `None`, then the collision handler of the plot will be used.
192
188
  """
193
189
 
194
190
  # fallback to style if callables are None
@@ -199,6 +195,7 @@ class StarPlotterMixin:
199
195
  alpha_fn = alpha_fn or (lambda d: style.marker.alpha)
200
196
  color_fn = color_fn or (lambda d: color_hex)
201
197
 
198
+ handler = collision_handler or self.collision_handler
202
199
  where = where or []
203
200
  where_labels = where_labels or []
204
201
  stars_to_index = []
@@ -221,30 +218,15 @@ class StarPlotterMixin:
221
218
  stars_df = star_results.to_pandas()
222
219
  stars_df["ra_hours"], stars_df["dec_degrees"] = (stars_df.ra / 15, stars_df.dec)
223
220
 
224
- if getattr(self, "projection", None) == "zenith":
225
- # filter stars for zenith plots to only include those above horizon
226
- self.location = self.earth + wgs84.latlon(
227
- self.observer.lat, self.observer.lon
228
- )
229
- stars_apparent = (
230
- self.location.at(self.observer.timescale)
231
- .observe(SkyfieldStar.from_dataframe(stars_df))
232
- .apparent()
233
- )
234
- # we only need altitude
235
- stars_alt, _, _ = stars_apparent.altaz()
236
- stars_df["alt"] = stars_alt.degrees
237
- stars_df = stars_df[stars_df["alt"] > 0]
238
- else:
239
- nearby_stars = SkyfieldStar.from_dataframe(stars_df)
240
- astrometric = self.earth.at(self.observer.timescale).observe(nearby_stars)
241
- stars_ra, stars_dec, _ = astrometric.radec()
242
- stars_df["ra"], stars_df["dec"] = (
243
- stars_ra.hours * 15,
244
- stars_dec.degrees,
245
- )
246
-
221
+ nearby_stars = SkyfieldStar.from_dataframe(stars_df)
222
+ astrometric = self.earth.at(self.observer.timescale).observe(nearby_stars)
223
+ stars_ra, stars_dec, _ = astrometric.radec()
224
+ stars_df["ra"], stars_df["dec"] = (
225
+ stars_ra.hours * 15,
226
+ stars_dec.degrees,
227
+ )
247
228
  stars_df = self._prepare_star_coords(stars_df)
229
+
248
230
  starz = []
249
231
  rtree_id = 1
250
232
 
@@ -330,4 +312,5 @@ class StarPlotterMixin:
330
312
  bayer_labels,
331
313
  flamsteed_labels,
332
314
  label_fn,
315
+ handler,
333
316
  )