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
@@ -0,0 +1,41 @@
1
+ from starplot.data import DataFiles
2
+ from starplot.styles import PolygonStyle
3
+ from starplot.styles.helpers import use_style
4
+ from starplot.utils import lon_to_ra
5
+
6
+
7
+ class MilkyWayPlotterMixin:
8
+ @use_style(PolygonStyle, "milky_way")
9
+ def milky_way(self, style: PolygonStyle = None):
10
+ """
11
+ Plots the Milky Way
12
+
13
+ Args:
14
+ style: Styling of the Milky Way. If None, then the plot's style (specified when creating the plot) will be used
15
+ """
16
+
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)]
26
+
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 = []
31
+
32
+ if mw_union.geom_type == "MultiPolygon":
33
+ polygons.extend([_prepare_polygon(polygon) for polygon in mw_union.geoms])
34
+ else:
35
+ polygons.append(_prepare_polygon(mw_union))
36
+
37
+ for polygon_points in polygons:
38
+ self._polygon(
39
+ points=polygon_points,
40
+ style=style,
41
+ )
@@ -1,13 +1,17 @@
1
1
  from typing import Callable, Mapping
2
2
  from functools import cache
3
3
 
4
+ import rtree
4
5
  from skyfield.api import Star as SkyfieldStar
5
6
 
7
+ import numpy as np
8
+
6
9
  from starplot import callables
7
- from starplot.data import bayer, stars
10
+ from starplot.coordinates import CoordinateSystem
11
+ from starplot.data import bayer, stars, flamsteed
8
12
  from starplot.data.stars import StarCatalog, STAR_NAMES
9
13
  from starplot.models.star import Star, from_tuple
10
- from starplot.styles import ObjectStyle, LabelStyle, use_style
14
+ from starplot.styles import ObjectStyle, use_style
11
15
 
12
16
 
13
17
  class StarPlotterMixin:
@@ -64,6 +68,7 @@ class StarPlotterMixin:
64
68
  zorder=kwargs.pop("zorder", None) or style.marker.zorder,
65
69
  edgecolors=edge_colors,
66
70
  alpha=alphas,
71
+ gid="stars",
67
72
  **self._plot_kwargs(),
68
73
  **kwargs,
69
74
  )
@@ -77,24 +82,88 @@ class StarPlotterMixin:
77
82
  def _star_labels(
78
83
  self,
79
84
  star_objects: list[Star],
85
+ star_sizes: list[float],
80
86
  where_labels: list,
81
- style: LabelStyle,
87
+ style: ObjectStyle,
82
88
  labels: Mapping[str, str],
83
89
  bayer_labels: bool,
90
+ flamsteed_labels: bool,
84
91
  label_fn: Callable[[Star], str],
85
92
  ):
86
- for s in star_objects:
93
+ _bayer = []
94
+ _flamsteed = []
95
+
96
+ # Plot all star common names first
97
+ for i, s in enumerate(star_objects):
87
98
  if where_labels and not all([e.evaluate(s) for e in where_labels]):
88
99
  continue
89
100
 
101
+ if (
102
+ s.hip
103
+ and s.hip in self._labeled_stars
104
+ or s.tyc
105
+ and s.tyc in self._labeled_stars
106
+ ):
107
+ continue
108
+ elif s.hip:
109
+ self._labeled_stars.append(s.hip)
110
+ elif s.tyc:
111
+ self._labeled_stars.append(s.tyc)
112
+
90
113
  label = labels.get(s.hip) if label_fn is None else label_fn(s)
91
114
  bayer_desig = bayer.hip.get(s.hip)
115
+ flamsteed_num = flamsteed.hip.get(s.hip)
92
116
 
93
117
  if label:
94
- self.text(label, s.ra, s.dec, style)
118
+ self.text(
119
+ label,
120
+ s.ra,
121
+ s.dec,
122
+ style=style.label.offset_from_marker(
123
+ marker_symbol=style.marker.symbol,
124
+ marker_size=star_sizes[i],
125
+ scale=self.scale,
126
+ ),
127
+ hide_on_collision=self.hide_colliding_labels,
128
+ gid="stars-label-name",
129
+ )
95
130
 
96
131
  if bayer_labels and bayer_desig:
97
- self.text(bayer_desig, s.ra, s.dec, self.style.bayer_labels)
132
+ _bayer.append((bayer_desig, s.ra, s.dec, star_sizes[i], s.hip))
133
+
134
+ if flamsteed_labels and flamsteed_num:
135
+ _flamsteed.append((flamsteed_num, s.ra, s.dec, star_sizes[i], s.hip))
136
+
137
+ # Plot bayer/flamsteed
138
+ for bayer_desig, ra, dec, star_size, _ in _bayer:
139
+ self.text(
140
+ bayer_desig,
141
+ ra,
142
+ dec,
143
+ style=self.style.bayer_labels.offset_from_marker(
144
+ marker_symbol=style.marker.symbol,
145
+ marker_size=star_size,
146
+ scale=self.scale,
147
+ ),
148
+ hide_on_collision=self.hide_colliding_labels,
149
+ gid="stars-label-bayer",
150
+ )
151
+
152
+ for flamsteed_num, ra, dec, star_size, hip in _flamsteed:
153
+ if hip in bayer.hip:
154
+ continue
155
+ self.text(
156
+ flamsteed_num,
157
+ ra,
158
+ dec,
159
+ style=self.style.flamsteed_labels.offset_from_marker(
160
+ marker_symbol=style.marker.symbol,
161
+ marker_size=star_size,
162
+ scale=self.scale,
163
+ ),
164
+ hide_on_collision=self.hide_colliding_labels,
165
+ gid="stars-label-flamsteed",
166
+ )
98
167
 
99
168
  def _prepare_star_coords(self, df):
100
169
  df["x"], df["y"] = (
@@ -119,6 +188,7 @@ class StarPlotterMixin:
119
188
  labels: Mapping[int, str] = STAR_NAMES,
120
189
  legend_label: str = "Star",
121
190
  bayer_labels: bool = False,
191
+ flamsteed_labels: bool = False,
122
192
  *args,
123
193
  **kwargs,
124
194
  ):
@@ -138,7 +208,8 @@ class StarPlotterMixin:
138
208
  where_labels: A list of expressions that determine which stars are labeled on the plot. See [Selecting Objects](/reference-selecting-objects/) for details.
139
209
  labels: A dictionary that maps a star's HIP id to the label that'll be plotted for that star. If you want to hide name labels, then set this arg to `None`.
140
210
  legend_label: Label for stars in the legend. If `None`, then they will not be in the legend.
141
- bayer_labels: If True, then Bayer labels for stars will be plotted. Set this to False if you want to hide Bayer labels.
211
+ bayer_labels: If True, then Bayer labels for stars will be plotted.
212
+ flamsteed_labels: If True, then Flamsteed number labels for stars will be plotted.
142
213
  """
143
214
  self.logger.debug("Plotting stars...")
144
215
 
@@ -151,6 +222,7 @@ class StarPlotterMixin:
151
222
  color_fn = color_fn or (lambda d: color_hex)
152
223
 
153
224
  where = where or []
225
+ stars_to_index = []
154
226
 
155
227
  if where:
156
228
  mag = None
@@ -160,8 +232,6 @@ class StarPlotterMixin:
160
232
  else:
161
233
  labels = {**STAR_NAMES, **labels}
162
234
 
163
- star_size_multiplier = self._size_multiplier * style.marker.size / 5
164
-
165
235
  nearby_stars_df = self._load_stars(catalog, mag)
166
236
  nearby_stars = SkyfieldStar.from_dataframe(nearby_stars_df)
167
237
  astrometric = self.ephemeris["earth"].at(self.timescale).observe(nearby_stars)
@@ -173,17 +243,66 @@ class StarPlotterMixin:
173
243
  self._prepare_star_coords(nearby_stars_df)
174
244
 
175
245
  starz = []
246
+ ctr = 0
176
247
 
177
248
  for star in nearby_stars_df.itertuples():
178
249
  obj = from_tuple(star, catalog)
250
+ ctr += 1
179
251
 
180
252
  if not all([e.evaluate(obj) for e in where]):
181
253
  continue
182
254
 
183
- size = size_fn(obj) * star_size_multiplier
255
+ if self._coordinate_system == CoordinateSystem.RA_DEC:
256
+ data_xy = self._proj.transform_point(
257
+ star.ra * -1, star.dec, self._geodetic
258
+ )
259
+ elif self._coordinate_system == CoordinateSystem.AZ_ALT:
260
+ data_xy = self._proj.transform_point(star.x, star.y, self._crs)
261
+ else:
262
+ raise ValueError("Unrecognized coordinate system")
263
+
264
+ display_x, display_y = self.ax.transData.transform(data_xy)
265
+
266
+ if (
267
+ display_x < 0
268
+ or display_y < 0
269
+ or np.isnan(display_x)
270
+ or np.isnan(display_y)
271
+ or self._is_clipped([(display_x, display_y)])
272
+ ):
273
+ continue
274
+
275
+ size = size_fn(obj) * self.scale**2
184
276
  alpha = alpha_fn(obj)
185
277
  color = color_fn(obj) or style.marker.color.as_hex()
186
278
 
279
+ if obj.magnitude < 5:
280
+ # radius = ((size**0.5 / 2) / self.scale) #/ 3.14
281
+ radius = size**0.5 / 5
282
+
283
+ bbox = np.array(
284
+ (
285
+ display_x - radius,
286
+ display_y - radius,
287
+ display_x + radius,
288
+ display_y + radius,
289
+ )
290
+ )
291
+ # if obj.name == "Sirius":
292
+ # print(bbox)
293
+ # if obj.name == "Electra":
294
+ # print(bbox)
295
+
296
+ if self._stars_rtree.get_size() > 0:
297
+ self._stars_rtree.insert(
298
+ 0,
299
+ bbox,
300
+ None,
301
+ )
302
+ else:
303
+ # if the index has no stars yet, then wait until end to load for better performance
304
+ stars_to_index.append((ctr, bbox, None))
305
+
187
306
  starz.append((star.x, star.y, size, alpha, color, obj))
188
307
 
189
308
  starz.sort(key=lambda s: s[2], reverse=True) # sort by descending size
@@ -215,6 +334,17 @@ class StarPlotterMixin:
215
334
 
216
335
  self._add_legend_handle_marker(legend_label, style.marker)
217
336
 
218
- self._star_labels(
219
- star_objects, where_labels, style.label, labels, bayer_labels, label_fn
220
- )
337
+ if stars_to_index:
338
+ self._stars_rtree = rtree.index.Index(stars_to_index)
339
+
340
+ if labels:
341
+ self._star_labels(
342
+ star_objects,
343
+ sizes,
344
+ where_labels,
345
+ style,
346
+ labels,
347
+ bayer_labels,
348
+ flamsteed_labels,
349
+ label_fn,
350
+ )