starplot 0.14.0__py2.py3-none-any.whl → 0.15.1__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.
- starplot/__init__.py +3 -1
- starplot/base.py +149 -37
- starplot/cli.py +33 -0
- starplot/data/__init__.py +6 -24
- starplot/data/bigsky.py +58 -40
- starplot/data/constellation_lines.py +827 -0
- starplot/data/constellation_stars.py +1501 -0
- starplot/data/constellations.py +43 -32
- starplot/data/db.py +17 -0
- starplot/data/dsos.py +24 -141
- starplot/data/library/{stars.bigsky.mag11.parquet → bigsky.0.4.0.stars.mag11.parquet} +0 -0
- starplot/data/library/sky.db +0 -0
- starplot/data/stars.py +45 -24
- starplot/geod.py +0 -6
- starplot/geometry.py +105 -6
- starplot/horizon.py +118 -107
- starplot/map.py +45 -96
- starplot/mixins.py +75 -14
- starplot/models/__init__.py +1 -1
- starplot/models/base.py +10 -128
- starplot/models/constellation.py +55 -32
- starplot/models/dso.py +132 -67
- starplot/models/moon.py +57 -78
- starplot/models/planet.py +44 -69
- starplot/models/star.py +91 -60
- starplot/models/sun.py +32 -53
- starplot/optic.py +14 -17
- starplot/plotters/constellations.py +81 -78
- starplot/plotters/dsos.py +49 -68
- starplot/plotters/experimental.py +1 -1
- starplot/plotters/milkyway.py +18 -20
- starplot/plotters/stars.py +91 -116
- starplot/profile.py +16 -0
- starplot/settings.py +26 -0
- starplot/styles/__init__.py +2 -0
- starplot/styles/base.py +7 -17
- starplot/styles/ext/blue_gold.yml +135 -0
- starplot/styles/ext/blue_light.yml +5 -4
- starplot/styles/ext/blue_medium.yml +11 -7
- starplot/styles/extensions.py +1 -0
- starplot/warnings.py +5 -0
- {starplot-0.14.0.dist-info → starplot-0.15.1.dist-info}/METADATA +11 -11
- {starplot-0.14.0.dist-info → starplot-0.15.1.dist-info}/RECORD +46 -54
- starplot-0.15.1.dist-info/entry_points.txt +3 -0
- starplot/data/bayer.py +0 -3499
- starplot/data/flamsteed.py +0 -2682
- starplot/data/library/constellation_borders_inv.gpkg +0 -0
- starplot/data/library/constellation_lines_hips.json +0 -709
- starplot/data/library/constellation_lines_inv.gpkg +0 -0
- starplot/data/library/constellations.gpkg +0 -0
- starplot/data/library/constellations_hip.fab +0 -88
- starplot/data/library/milkyway.gpkg +0 -0
- starplot/data/library/milkyway_inv.gpkg +0 -0
- starplot/data/library/ongc.gpkg.zip +0 -0
- starplot/data/library/stars.hipparcos.parquet +0 -0
- starplot/data/messier.py +0 -111
- starplot/data/prep/__init__.py +0 -0
- starplot/data/prep/constellations.py +0 -108
- starplot/data/prep/dsos.py +0 -299
- starplot/data/prep/utils.py +0 -16
- starplot/models/geometry.py +0 -44
- {starplot-0.14.0.dist-info → starplot-0.15.1.dist-info}/LICENSE +0 -0
- {starplot-0.14.0.dist-info → starplot-0.15.1.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
|
|
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
|
|
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":
|
|
26
|
-
"distance_step_size":
|
|
27
|
-
"max_distance":
|
|
28
|
-
"label_padding":
|
|
29
|
-
"buffer": 0.
|
|
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
|
-
|
|
56
|
-
|
|
57
|
-
|
|
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
|
|
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
|
|
80
|
-
|
|
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
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
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
|
-
|
|
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
|
-
|
|
109
|
-
|
|
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
|
-
|
|
217
|
-
|
|
218
|
-
)
|
|
228
|
+
extent = self._extent_mask()
|
|
229
|
+
results = condata.load_borders(extent=extent)
|
|
230
|
+
borders_df = results.to_pandas()
|
|
219
231
|
|
|
220
|
-
if
|
|
232
|
+
if borders_df.empty:
|
|
221
233
|
return
|
|
222
234
|
|
|
223
|
-
geometries = []
|
|
224
235
|
border_lines = []
|
|
225
|
-
|
|
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
|
-
|
|
233
|
-
|
|
234
|
-
|
|
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(
|
|
245
|
+
border_lines.append(xy)
|
|
238
246
|
|
|
239
247
|
elif self._coordinate_system == CoordinateSystem.AZ_ALT:
|
|
240
|
-
|
|
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
|
-
**
|
|
253
|
-
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
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
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
|
-
|
|
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,
|
|
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 =
|
|
39
|
-
where.append(
|
|
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,
|
|
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 =
|
|
50
|
-
where.append(
|
|
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,
|
|
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 =
|
|
61
|
-
where.append(
|
|
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,
|
|
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 =
|
|
81
|
-
where.append(
|
|
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,
|
|
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 =
|
|
105
|
-
where.append(
|
|
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
|
-
@
|
|
110
|
-
def _load_dsos(self):
|
|
111
|
-
return load_ongc(bbox=self._extent_mask())
|
|
112
|
-
|
|
102
|
+
@profile
|
|
113
103
|
def dsos(
|
|
114
104
|
self,
|
|
115
|
-
|
|
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
|
-
|
|
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
|
-
|
|
159
|
-
|
|
160
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
213
|
+
ra=ra,
|
|
233
214
|
dec=dec,
|
|
234
215
|
style=style,
|
|
235
216
|
label=label,
|
starplot/plotters/milkyway.py
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
|
-
from
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
|
31
|
+
polygons = mw_union.geoms
|
|
34
32
|
else:
|
|
35
|
-
polygons
|
|
33
|
+
polygons = [mw_union]
|
|
36
34
|
|
|
37
|
-
for
|
|
38
|
-
self.
|
|
39
|
-
|
|
35
|
+
for p in polygons:
|
|
36
|
+
self.polygon(
|
|
37
|
+
geometry=p,
|
|
40
38
|
style=style,
|
|
41
39
|
)
|