starplot 0.20.5__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.
- starplot/__init__.py +59 -0
- starplot/callables.py +176 -0
- starplot/cli.py +29 -0
- starplot/config.py +80 -0
- starplot/coordinates.py +7 -0
- starplot/data/__init__.py +22 -0
- starplot/data/catalogs.py +356 -0
- starplot/data/constellations.py +71 -0
- starplot/data/db.py +33 -0
- starplot/data/dsos.py +85 -0
- starplot/data/ecliptic.py +201 -0
- starplot/data/library/constellation_names.parquet +0 -0
- starplot/data/library/dso_names.parquet +0 -0
- starplot/data/library/readme.md +1 -0
- starplot/data/library/star_designations.parquet +0 -0
- starplot/data/stars.py +79 -0
- starplot/data/translations.py +408 -0
- starplot/data/utils.py +35 -0
- starplot/geometry.py +319 -0
- starplot/mixins.py +360 -0
- starplot/models/__init__.py +21 -0
- starplot/models/base.py +77 -0
- starplot/models/comet.py +302 -0
- starplot/models/constellation.py +151 -0
- starplot/models/dso.py +317 -0
- starplot/models/milky_way.py +30 -0
- starplot/models/moon.py +130 -0
- starplot/models/objects.py +29 -0
- starplot/models/observer.py +125 -0
- starplot/models/optics.py +342 -0
- starplot/models/planet.py +137 -0
- starplot/models/satellite.py +138 -0
- starplot/models/star.py +253 -0
- starplot/models/sun.py +62 -0
- starplot/plots/__init__.py +7 -0
- starplot/plots/base.py +1023 -0
- starplot/plots/galaxy.py +372 -0
- starplot/plots/horizon.py +543 -0
- starplot/plots/map.py +515 -0
- starplot/plots/optic.py +469 -0
- starplot/plots/zenith.py +217 -0
- starplot/plotters/__init__.py +9 -0
- starplot/plotters/arrow.py +174 -0
- starplot/plotters/constellations.py +298 -0
- starplot/plotters/debug.py +21 -0
- starplot/plotters/dsos.py +294 -0
- starplot/plotters/experimental.py +722 -0
- starplot/plotters/gradients.py +153 -0
- starplot/plotters/legend.py +253 -0
- starplot/plotters/milkyway.py +51 -0
- starplot/plotters/stars.py +319 -0
- starplot/plotters/text.py +802 -0
- starplot/profile.py +16 -0
- starplot/projections.py +184 -0
- starplot/styles/__init__.py +6 -0
- starplot/styles/base.py +1344 -0
- starplot/styles/ext/antique.yml +175 -0
- starplot/styles/ext/blue_dark.yml +163 -0
- starplot/styles/ext/blue_gold.yml +147 -0
- starplot/styles/ext/blue_light.yml +123 -0
- starplot/styles/ext/blue_medium.yml +142 -0
- starplot/styles/ext/blue_night.yml +185 -0
- starplot/styles/ext/cb_wong.yml +124 -0
- starplot/styles/ext/color_print.yml +111 -0
- starplot/styles/ext/gradient_presets.yml +158 -0
- starplot/styles/ext/grayscale.yml +94 -0
- starplot/styles/ext/grayscale_dark.yml +136 -0
- starplot/styles/ext/map.yml +12 -0
- starplot/styles/ext/nord.yml +158 -0
- starplot/styles/ext/optic.yml +20 -0
- starplot/styles/ext/publication.yml +8 -0
- starplot/styles/extensions.py +129 -0
- starplot/styles/fonts-library/gfs-didot/DESCRIPTION.en_us.html +9 -0
- starplot/styles/fonts-library/gfs-didot/GFSDidot-Regular.ttf +0 -0
- starplot/styles/fonts-library/gfs-didot/METADATA.pb +16 -0
- starplot/styles/fonts-library/gfs-didot/OFL.txt +94 -0
- starplot/styles/fonts-library/inter/Inter-Bold.ttf +0 -0
- starplot/styles/fonts-library/inter/Inter-BoldItalic.ttf +0 -0
- starplot/styles/fonts-library/inter/Inter-ExtraBold.ttf +0 -0
- starplot/styles/fonts-library/inter/Inter-ExtraLight.ttf +0 -0
- starplot/styles/fonts-library/inter/Inter-ExtraLightItalic.ttf +0 -0
- starplot/styles/fonts-library/inter/Inter-Italic.ttf +0 -0
- starplot/styles/fonts-library/inter/Inter-Light.ttf +0 -0
- starplot/styles/fonts-library/inter/Inter-LightItalic.ttf +0 -0
- starplot/styles/fonts-library/inter/Inter-Regular.ttf +0 -0
- starplot/styles/fonts-library/inter/Inter-SemiBold.ttf +0 -0
- starplot/styles/fonts-library/inter/Inter-SemiBoldItalic.ttf +0 -0
- starplot/styles/fonts-library/inter/LICENSE.txt +92 -0
- starplot/styles/fonts.py +15 -0
- starplot/styles/helpers.py +93 -0
- starplot/styles/markers.py +308 -0
- starplot/utils.py +169 -0
- starplot/warnings.py +21 -0
- starplot-0.20.5.dist-info/METADATA +146 -0
- starplot-0.20.5.dist-info/RECORD +98 -0
- starplot-0.20.5.dist-info/WHEEL +4 -0
- starplot-0.20.5.dist-info/entry_points.txt +3 -0
- starplot-0.20.5.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from typing import Callable
|
|
3
|
+
|
|
4
|
+
import rtree
|
|
5
|
+
import numpy as np
|
|
6
|
+
from ibis import _ as ibis_table
|
|
7
|
+
from skyfield.api import Star as SkyfieldStar
|
|
8
|
+
|
|
9
|
+
from starplot import callables
|
|
10
|
+
from starplot.data import stars
|
|
11
|
+
from starplot.data.catalogs import Catalog, BIG_SKY_MAG11
|
|
12
|
+
from starplot.data.translations import translate
|
|
13
|
+
from starplot.models.star import Star, from_tuple
|
|
14
|
+
from starplot.styles import ObjectStyle, use_style
|
|
15
|
+
from starplot.profile import profile
|
|
16
|
+
from starplot.plotters.text import CollisionHandler
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class StarPlotterMixin:
|
|
20
|
+
def _load_stars(self, catalog, filters=None, sql=None):
|
|
21
|
+
extent = self._extent_mask()
|
|
22
|
+
|
|
23
|
+
return stars.load(
|
|
24
|
+
extent=extent,
|
|
25
|
+
catalog=catalog,
|
|
26
|
+
filters=filters,
|
|
27
|
+
sql=sql,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
def _scatter_stars(self, ras, decs, sizes, alphas, colors, style=None, **kwargs):
|
|
31
|
+
style = style or self.style.star
|
|
32
|
+
edge_colors = kwargs.pop("edgecolors", None)
|
|
33
|
+
|
|
34
|
+
if not edge_colors:
|
|
35
|
+
if style.marker.edge_color:
|
|
36
|
+
edge_colors = style.marker.edge_color.as_hex()
|
|
37
|
+
else:
|
|
38
|
+
edge_colors = "none"
|
|
39
|
+
|
|
40
|
+
plotted = self.ax.scatter(
|
|
41
|
+
ras,
|
|
42
|
+
decs,
|
|
43
|
+
s=sizes,
|
|
44
|
+
c=colors,
|
|
45
|
+
marker=kwargs.pop("symbol", None) or style.marker.symbol_matplot,
|
|
46
|
+
zorder=kwargs.pop("zorder", None) or style.marker.zorder,
|
|
47
|
+
edgecolors=edge_colors,
|
|
48
|
+
alpha=alphas,
|
|
49
|
+
gid="stars",
|
|
50
|
+
**self._plot_kwargs(),
|
|
51
|
+
**kwargs,
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
if self._background_clip_path is not None:
|
|
55
|
+
plotted.set_clip_on(True)
|
|
56
|
+
plotted.set_clip_path(self._background_clip_path)
|
|
57
|
+
|
|
58
|
+
return plotted
|
|
59
|
+
|
|
60
|
+
def _star_labels(
|
|
61
|
+
self,
|
|
62
|
+
star_objects: list[Star],
|
|
63
|
+
star_sizes: list[float],
|
|
64
|
+
label_pks: list,
|
|
65
|
+
style: ObjectStyle,
|
|
66
|
+
bayer_labels: bool,
|
|
67
|
+
flamsteed_labels: bool,
|
|
68
|
+
label_fn: Callable[[Star], str],
|
|
69
|
+
collision_handler: CollisionHandler,
|
|
70
|
+
):
|
|
71
|
+
_bayer = []
|
|
72
|
+
_flamsteed = []
|
|
73
|
+
|
|
74
|
+
# Plot all star common names first
|
|
75
|
+
for i, s in enumerate(star_objects):
|
|
76
|
+
if s.pk not in label_pks:
|
|
77
|
+
continue
|
|
78
|
+
|
|
79
|
+
if (
|
|
80
|
+
s.hip
|
|
81
|
+
and s.hip in self._labeled_stars
|
|
82
|
+
or s.tyc
|
|
83
|
+
and s.tyc in self._labeled_stars
|
|
84
|
+
):
|
|
85
|
+
continue
|
|
86
|
+
elif s.hip:
|
|
87
|
+
self._labeled_stars.append(s.hip)
|
|
88
|
+
elif s.tyc:
|
|
89
|
+
self._labeled_stars.append(s.tyc)
|
|
90
|
+
|
|
91
|
+
label = label_fn(s)
|
|
92
|
+
bayer_desig = s.bayer
|
|
93
|
+
flamsteed_num = s.flamsteed
|
|
94
|
+
|
|
95
|
+
if label:
|
|
96
|
+
self.text(
|
|
97
|
+
label,
|
|
98
|
+
s.ra,
|
|
99
|
+
s.dec,
|
|
100
|
+
style=style.label.offset_from_marker(
|
|
101
|
+
marker_symbol=style.marker.symbol,
|
|
102
|
+
marker_size=star_sizes[i],
|
|
103
|
+
scale=self.scale,
|
|
104
|
+
),
|
|
105
|
+
collision_handler=collision_handler,
|
|
106
|
+
gid="stars-label-name",
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
if bayer_labels and bayer_desig and s.is_primary:
|
|
110
|
+
_bayer.append((bayer_desig, s.ra, s.dec, star_sizes[i]))
|
|
111
|
+
|
|
112
|
+
if flamsteed_labels and flamsteed_num and not bayer_desig and s.is_primary:
|
|
113
|
+
_flamsteed.append((flamsteed_num, s.ra, s.dec, star_sizes[i]))
|
|
114
|
+
|
|
115
|
+
# Plot bayer/flamsteed
|
|
116
|
+
for bayer_desig, ra, dec, star_size in _bayer:
|
|
117
|
+
self.text(
|
|
118
|
+
bayer_desig,
|
|
119
|
+
ra,
|
|
120
|
+
dec,
|
|
121
|
+
style=self.style.bayer_labels.offset_from_marker(
|
|
122
|
+
marker_symbol=style.marker.symbol,
|
|
123
|
+
marker_size=star_size,
|
|
124
|
+
scale=self.scale,
|
|
125
|
+
),
|
|
126
|
+
collision_handler=collision_handler,
|
|
127
|
+
gid="stars-label-bayer",
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
for flamsteed_num, ra, dec, star_size in _flamsteed:
|
|
131
|
+
self.text(
|
|
132
|
+
flamsteed_num,
|
|
133
|
+
ra,
|
|
134
|
+
dec,
|
|
135
|
+
style=self.style.flamsteed_labels.offset_from_marker(
|
|
136
|
+
marker_symbol=style.marker.symbol,
|
|
137
|
+
marker_size=star_size,
|
|
138
|
+
scale=self.scale,
|
|
139
|
+
),
|
|
140
|
+
collision_handler=collision_handler,
|
|
141
|
+
gid="stars-label-flamsteed",
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
def _prepare_star_coords(self, df, limit_by_altaz=False):
|
|
145
|
+
df["x"], df["y"] = (
|
|
146
|
+
df["ra"],
|
|
147
|
+
df["dec"],
|
|
148
|
+
)
|
|
149
|
+
return df
|
|
150
|
+
|
|
151
|
+
@profile
|
|
152
|
+
@use_style(ObjectStyle, "star")
|
|
153
|
+
def stars(
|
|
154
|
+
self,
|
|
155
|
+
where: list = None,
|
|
156
|
+
where_labels: list = None,
|
|
157
|
+
catalog: Catalog | Path | str = BIG_SKY_MAG11,
|
|
158
|
+
style: ObjectStyle = None,
|
|
159
|
+
size_fn: Callable[[Star], float] = callables.size_by_magnitude,
|
|
160
|
+
alpha_fn: Callable[[Star], float] = None,
|
|
161
|
+
color_fn: Callable[[Star], str] = None,
|
|
162
|
+
label_fn: Callable[[Star], str] = Star.get_label,
|
|
163
|
+
legend_label: str = "Star",
|
|
164
|
+
bayer_labels: bool = False,
|
|
165
|
+
flamsteed_labels: bool = False,
|
|
166
|
+
sql: str = None,
|
|
167
|
+
sql_labels: str = None,
|
|
168
|
+
collision_handler: CollisionHandler = None,
|
|
169
|
+
):
|
|
170
|
+
"""
|
|
171
|
+
Plots stars
|
|
172
|
+
|
|
173
|
+
Args:
|
|
174
|
+
where: A list of expressions that determine which stars to plot. See [Selecting Objects](/reference-selecting-objects/) for details.
|
|
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.
|
|
176
|
+
catalog: The catalog of stars to use -- see [catalogs overview](/data/overview/) for details
|
|
177
|
+
style: If `None`, then the plot's style for stars will be used
|
|
178
|
+
size_fn: Callable for calculating the marker size of each star. If `None`, then the marker style's size will be used.
|
|
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.
|
|
180
|
+
color_fn: Callable for calculating the color of each star. If `None`, then the marker style's color will be used.
|
|
181
|
+
label_fn: Callable for determining the label of each star.
|
|
182
|
+
legend_label: Label for stars in the legend. If `None`, then they will not be in the legend.
|
|
183
|
+
bayer_labels: If True, then Bayer labels for stars will be plotted.
|
|
184
|
+
flamsteed_labels: If True, then Flamsteed number labels for stars will be plotted.
|
|
185
|
+
sql: SQL query for selecting stars (table name is `_`). This query will be applied _after_ any filters in the `where` kwarg.
|
|
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.
|
|
188
|
+
"""
|
|
189
|
+
|
|
190
|
+
# fallback to style if callables are None
|
|
191
|
+
color_hex = (
|
|
192
|
+
style.marker.color.as_hex()
|
|
193
|
+
) # calculate color hex once here to avoid repeated calls in color_fn()
|
|
194
|
+
size_fn = size_fn or (lambda d: style.marker.size)
|
|
195
|
+
alpha_fn = alpha_fn or (lambda d: style.marker.alpha)
|
|
196
|
+
color_fn = color_fn or (lambda d: color_hex)
|
|
197
|
+
|
|
198
|
+
handler = collision_handler or self.point_label_handler
|
|
199
|
+
where = where or []
|
|
200
|
+
where_labels = where_labels or []
|
|
201
|
+
stars_to_index = []
|
|
202
|
+
|
|
203
|
+
star_results = self._load_stars(catalog, filters=where, sql=sql)
|
|
204
|
+
|
|
205
|
+
star_results_labeled = star_results
|
|
206
|
+
for f in where_labels:
|
|
207
|
+
star_results_labeled = star_results_labeled.filter(f)
|
|
208
|
+
|
|
209
|
+
if sql_labels:
|
|
210
|
+
result = (
|
|
211
|
+
star_results_labeled.alias("_").sql(sql_labels).select("pk").execute()
|
|
212
|
+
)
|
|
213
|
+
pks = result["pk"].to_list()
|
|
214
|
+
star_results_labeled = star_results_labeled.filter(ibis_table.pk.isin(pks))
|
|
215
|
+
|
|
216
|
+
label_pks = star_results_labeled.to_pandas()["pk"].tolist()
|
|
217
|
+
|
|
218
|
+
stars_df = star_results.to_pandas()
|
|
219
|
+
stars_df["ra_hours"], stars_df["dec_degrees"] = (stars_df.ra / 15, stars_df.dec)
|
|
220
|
+
|
|
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
|
+
)
|
|
228
|
+
stars_df = self._prepare_star_coords(stars_df)
|
|
229
|
+
|
|
230
|
+
starz = []
|
|
231
|
+
rtree_id = 1
|
|
232
|
+
|
|
233
|
+
transformed = self._proj.transform_points(
|
|
234
|
+
self._crs,
|
|
235
|
+
stars_df["x"].to_numpy(),
|
|
236
|
+
stars_df["y"].to_numpy(),
|
|
237
|
+
)
|
|
238
|
+
stars_df["data_x"] = transformed[:, 0]
|
|
239
|
+
stars_df["data_y"] = transformed[:, 1]
|
|
240
|
+
stars_df[["display_x", "display_y"]] = self.ax.transData.transform(
|
|
241
|
+
stars_df[["data_x", "data_y"]].to_numpy()
|
|
242
|
+
)
|
|
243
|
+
stars_df = stars_df[(stars_df["display_x"] >= 0) & (stars_df["display_y"] >= 0)]
|
|
244
|
+
|
|
245
|
+
for star in stars_df.itertuples():
|
|
246
|
+
display_x, display_y = star.display_x, star.display_y
|
|
247
|
+
|
|
248
|
+
obj = from_tuple(star)
|
|
249
|
+
size = size_fn(obj) * self.scale**2
|
|
250
|
+
alpha = alpha_fn(obj)
|
|
251
|
+
color = color_fn(obj) or style.marker.color.as_hex()
|
|
252
|
+
|
|
253
|
+
if obj.magnitude < 5:
|
|
254
|
+
rtree_id += 1
|
|
255
|
+
radius = size**0.5 / 5
|
|
256
|
+
bbox = np.array(
|
|
257
|
+
(
|
|
258
|
+
display_x - radius,
|
|
259
|
+
display_y - radius,
|
|
260
|
+
display_x + radius,
|
|
261
|
+
display_y + radius,
|
|
262
|
+
)
|
|
263
|
+
)
|
|
264
|
+
if self.debug_text:
|
|
265
|
+
self._debug_bbox(bbox, color="#39FF14", width=1)
|
|
266
|
+
if self._stars_rtree.get_size() > 0:
|
|
267
|
+
self._stars_rtree.insert(
|
|
268
|
+
0,
|
|
269
|
+
bbox,
|
|
270
|
+
None,
|
|
271
|
+
)
|
|
272
|
+
else:
|
|
273
|
+
# if the index has no stars yet, then wait until end to load for better performance
|
|
274
|
+
stars_to_index.append((rtree_id, bbox, None))
|
|
275
|
+
|
|
276
|
+
starz.append((star.x, star.y, size, alpha, color, obj))
|
|
277
|
+
|
|
278
|
+
starz.sort(key=lambda s: s[2], reverse=True) # sort by descending size
|
|
279
|
+
|
|
280
|
+
if not starz:
|
|
281
|
+
self.logger.debug(f"Star count = {len(starz)}")
|
|
282
|
+
return
|
|
283
|
+
|
|
284
|
+
x, y, sizes, alphas, colors, star_objects = zip(*starz)
|
|
285
|
+
|
|
286
|
+
self._objects.stars.extend(star_objects)
|
|
287
|
+
|
|
288
|
+
self.logger.debug(f"Star count = {len(star_objects)}")
|
|
289
|
+
|
|
290
|
+
# Plot Stars
|
|
291
|
+
self._scatter_stars(
|
|
292
|
+
x,
|
|
293
|
+
y,
|
|
294
|
+
sizes,
|
|
295
|
+
alphas,
|
|
296
|
+
colors,
|
|
297
|
+
style=style,
|
|
298
|
+
zorder=style.marker.zorder,
|
|
299
|
+
edgecolors=style.marker.edge_color.as_hex()
|
|
300
|
+
if style.marker.edge_color
|
|
301
|
+
else "none",
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
_legend_label = translate(legend_label, self.language) or legend_label
|
|
305
|
+
self._add_legend_handle_marker(_legend_label, style.marker)
|
|
306
|
+
|
|
307
|
+
if stars_to_index:
|
|
308
|
+
self._stars_rtree = rtree.index.Index(stars_to_index)
|
|
309
|
+
|
|
310
|
+
self._star_labels(
|
|
311
|
+
star_objects,
|
|
312
|
+
sizes,
|
|
313
|
+
label_pks,
|
|
314
|
+
style,
|
|
315
|
+
bayer_labels,
|
|
316
|
+
flamsteed_labels,
|
|
317
|
+
label_fn,
|
|
318
|
+
handler,
|
|
319
|
+
)
|