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,294 @@
|
|
|
1
|
+
from typing import Callable, Mapping
|
|
2
|
+
|
|
3
|
+
from ibis import _
|
|
4
|
+
import numpy as np
|
|
5
|
+
|
|
6
|
+
from starplot.data.dsos import load
|
|
7
|
+
from starplot.data.catalogs import Catalog, OPEN_NGC
|
|
8
|
+
from starplot.data.translations import translate
|
|
9
|
+
from starplot.models.dso import (
|
|
10
|
+
DSO,
|
|
11
|
+
DsoType,
|
|
12
|
+
from_tuple,
|
|
13
|
+
ONGC_TYPE_MAP,
|
|
14
|
+
DSO_LEGEND_LABELS,
|
|
15
|
+
)
|
|
16
|
+
from starplot.styles import MarkerSymbolEnum
|
|
17
|
+
from starplot.profile import profile
|
|
18
|
+
from starplot.plotters.text import CollisionHandler
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class DsoPlotterMixin:
|
|
22
|
+
def _plot_dso_polygon(self, polygon, style):
|
|
23
|
+
coords = list(zip(*polygon.exterior.coords.xy))
|
|
24
|
+
# close the polygon - for some reason matplotlib needs the coord twice
|
|
25
|
+
coords.append(coords[0])
|
|
26
|
+
coords.append(coords[0])
|
|
27
|
+
self._polygon(coords, style.marker.to_polygon_style(), closed=False)
|
|
28
|
+
|
|
29
|
+
def messier(self, **kwargs):
|
|
30
|
+
"""
|
|
31
|
+
Plots Messier objects
|
|
32
|
+
|
|
33
|
+
This is just a small wrapper around the `dsos()` function, so any `kwargs` will be passed through.
|
|
34
|
+
"""
|
|
35
|
+
where = kwargs.pop("where", [])
|
|
36
|
+
where.append(_.m.notnull())
|
|
37
|
+
self.dsos(where=where, **kwargs)
|
|
38
|
+
|
|
39
|
+
def open_clusters(self, **kwargs):
|
|
40
|
+
"""
|
|
41
|
+
Plots open clusters
|
|
42
|
+
|
|
43
|
+
This is just a small wrapper around the `dsos()` function, so any `kwargs` will be passed through.
|
|
44
|
+
"""
|
|
45
|
+
where = kwargs.pop("where", [])
|
|
46
|
+
where.append(_.type == DsoType.OPEN_CLUSTER.value)
|
|
47
|
+
self.dsos(where=where, **kwargs)
|
|
48
|
+
|
|
49
|
+
def globular_clusters(self, **kwargs):
|
|
50
|
+
"""
|
|
51
|
+
Plots globular clusters
|
|
52
|
+
|
|
53
|
+
This is just a small wrapper around the `dsos()` function, so any `kwargs` will be passed through.
|
|
54
|
+
"""
|
|
55
|
+
where = kwargs.pop("where", [])
|
|
56
|
+
where.append(_.type == DsoType.GLOBULAR_CLUSTER.value)
|
|
57
|
+
self.dsos(where=where, **kwargs)
|
|
58
|
+
|
|
59
|
+
def galaxies(self, **kwargs):
|
|
60
|
+
"""
|
|
61
|
+
Plots galaxy DSO types:
|
|
62
|
+
|
|
63
|
+
- Galaxy
|
|
64
|
+
- Galaxy Pair
|
|
65
|
+
- Galaxy Triplet
|
|
66
|
+
|
|
67
|
+
This is just a small wrapper around the `dsos()` function, so any `kwargs` will be passed through.
|
|
68
|
+
"""
|
|
69
|
+
galaxy_types = [
|
|
70
|
+
DsoType.GALAXY.value,
|
|
71
|
+
DsoType.GALAXY_PAIR.value,
|
|
72
|
+
DsoType.GALAXY_TRIPLET.value,
|
|
73
|
+
]
|
|
74
|
+
where = kwargs.pop("where", [])
|
|
75
|
+
where.append(_.type.isin(galaxy_types))
|
|
76
|
+
self.dsos(where=where, **kwargs)
|
|
77
|
+
|
|
78
|
+
def nebula(self, **kwargs):
|
|
79
|
+
"""
|
|
80
|
+
Plots all nebula DSO types (except for dark nebulae):
|
|
81
|
+
|
|
82
|
+
- Nebula
|
|
83
|
+
- Emission Nebula
|
|
84
|
+
- Star Cluster Nebula
|
|
85
|
+
- Reflection Nebula
|
|
86
|
+
- HII Ionized Regions
|
|
87
|
+
- Planetary Nebula
|
|
88
|
+
|
|
89
|
+
This is just a small wrapper around the `dsos()` function, so any `kwargs` will be passed through.
|
|
90
|
+
"""
|
|
91
|
+
nebula_types = [
|
|
92
|
+
DsoType.NEBULA.value,
|
|
93
|
+
DsoType.EMISSION_NEBULA.value,
|
|
94
|
+
DsoType.STAR_CLUSTER_NEBULA.value,
|
|
95
|
+
DsoType.REFLECTION_NEBULA.value,
|
|
96
|
+
DsoType.HII_IONIZED_REGION.value,
|
|
97
|
+
DsoType.PLANETARY_NEBULA.value,
|
|
98
|
+
]
|
|
99
|
+
where = kwargs.pop("where", [])
|
|
100
|
+
where.append(_.type.isin(nebula_types))
|
|
101
|
+
self.dsos(where=where, **kwargs)
|
|
102
|
+
|
|
103
|
+
def bright_nebula(self, **kwargs):
|
|
104
|
+
"""
|
|
105
|
+
Plots the following nebula DSO types:
|
|
106
|
+
|
|
107
|
+
- Nebula
|
|
108
|
+
- Emission Nebula
|
|
109
|
+
- Star Cluster Nebula
|
|
110
|
+
- Reflection Nebula
|
|
111
|
+
- HII Ionized Regions
|
|
112
|
+
|
|
113
|
+
This is just a small wrapper around the `dsos()` function, so any `kwargs` will be passed through.
|
|
114
|
+
"""
|
|
115
|
+
nebula_types = [
|
|
116
|
+
DsoType.NEBULA.value,
|
|
117
|
+
DsoType.EMISSION_NEBULA.value,
|
|
118
|
+
DsoType.STAR_CLUSTER_NEBULA.value,
|
|
119
|
+
DsoType.REFLECTION_NEBULA.value,
|
|
120
|
+
DsoType.HII_IONIZED_REGION.value,
|
|
121
|
+
]
|
|
122
|
+
where = kwargs.pop("where", [])
|
|
123
|
+
where.append(_.type.isin(nebula_types))
|
|
124
|
+
self.dsos(where=where, **kwargs)
|
|
125
|
+
|
|
126
|
+
def planetary_nebula(self, **kwargs):
|
|
127
|
+
"""
|
|
128
|
+
Plots planetary nebula
|
|
129
|
+
|
|
130
|
+
This is just a small wrapper around the `dsos()` function, so any `kwargs` will be passed through.
|
|
131
|
+
"""
|
|
132
|
+
where = kwargs.pop("where", [])
|
|
133
|
+
where.append(_.type == DsoType.PLANETARY_NEBULA.value)
|
|
134
|
+
self.dsos(where=where, **kwargs)
|
|
135
|
+
|
|
136
|
+
def dark_nebula(self, **kwargs):
|
|
137
|
+
"""
|
|
138
|
+
Plots dark nebula
|
|
139
|
+
|
|
140
|
+
This is just a small wrapper around the `dsos()` function, so any `kwargs` will be passed through.
|
|
141
|
+
"""
|
|
142
|
+
where = kwargs.pop("where", [])
|
|
143
|
+
where.append(_.type == DsoType.DARK_NEBULA.value)
|
|
144
|
+
self.dsos(where=where, **kwargs)
|
|
145
|
+
|
|
146
|
+
@profile
|
|
147
|
+
def dsos(
|
|
148
|
+
self,
|
|
149
|
+
where: list = None,
|
|
150
|
+
where_labels: list = None,
|
|
151
|
+
where_true_size: list = None,
|
|
152
|
+
legend_labels: Mapping[DsoType, str] = DSO_LEGEND_LABELS,
|
|
153
|
+
alpha_fn: Callable[[DSO], float] = None,
|
|
154
|
+
label_fn: Callable[[DSO], str] = DSO.get_label,
|
|
155
|
+
sql: str = None,
|
|
156
|
+
sql_labels: str = None,
|
|
157
|
+
catalog: Catalog = OPEN_NGC,
|
|
158
|
+
collision_handler: CollisionHandler = None,
|
|
159
|
+
):
|
|
160
|
+
"""
|
|
161
|
+
Plots Deep Sky Objects (DSOs).
|
|
162
|
+
|
|
163
|
+
Args:
|
|
164
|
+
where: A list of expressions that determine which DSOs to plot. See [Selecting Objects](/reference-selecting-objects/) for details.
|
|
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.
|
|
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`.
|
|
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.
|
|
169
|
+
label_fn: Callable for determining the label of each DSO.
|
|
170
|
+
sql: SQL query for selecting DSOs (table name is `_`). This query will be applied _after_ any filters in the `where` kwarg.
|
|
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.
|
|
174
|
+
"""
|
|
175
|
+
|
|
176
|
+
# TODO: add kwarg styles
|
|
177
|
+
|
|
178
|
+
where = where or []
|
|
179
|
+
where_labels = where_labels or []
|
|
180
|
+
where_true_size = where_true_size or []
|
|
181
|
+
handler = collision_handler or self.point_label_handler
|
|
182
|
+
|
|
183
|
+
if legend_labels is None:
|
|
184
|
+
legend_labels = {}
|
|
185
|
+
else:
|
|
186
|
+
legend_labels = {**DSO_LEGEND_LABELS, **legend_labels}
|
|
187
|
+
|
|
188
|
+
extent = self._extent_mask()
|
|
189
|
+
dso_results = load(extent=extent, filters=where, sql=sql, catalog=catalog)
|
|
190
|
+
|
|
191
|
+
dsos_labeled = dso_results
|
|
192
|
+
for f in where_labels:
|
|
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)
|
|
198
|
+
|
|
199
|
+
if sql_labels:
|
|
200
|
+
result = dsos_labeled.alias("_").sql(sql_labels).select("pk").execute()
|
|
201
|
+
pks = result["pk"].to_list()
|
|
202
|
+
dsos_labeled = dsos_labeled.filter(_.pk.isin(pks))
|
|
203
|
+
|
|
204
|
+
label_pks = dsos_labeled.select("pk").to_pandas()["pk"].tolist()
|
|
205
|
+
true_size_pks = dsos_true_size.select("pk").to_pandas()["pk"].tolist()
|
|
206
|
+
|
|
207
|
+
results_df = dso_results.to_pandas().replace({np.nan: None})
|
|
208
|
+
|
|
209
|
+
for d in results_df.itertuples():
|
|
210
|
+
ra = d.ra
|
|
211
|
+
dec = d.dec
|
|
212
|
+
dso_type = ONGC_TYPE_MAP[d.type]
|
|
213
|
+
style = self.style.get_dso_style(dso_type)
|
|
214
|
+
maj_ax, min_ax, angle = d.maj_ax, d.min_ax, d.angle
|
|
215
|
+
legend_label = legend_labels.get(dso_type)
|
|
216
|
+
if legend_label:
|
|
217
|
+
legend_label = translate(legend_label, self.language) or legend_label
|
|
218
|
+
_dso = from_tuple(d)
|
|
219
|
+
|
|
220
|
+
label = label_fn(_dso)
|
|
221
|
+
|
|
222
|
+
if style is None:
|
|
223
|
+
continue
|
|
224
|
+
|
|
225
|
+
_alpha_fn = alpha_fn or (lambda d: style.marker.alpha)
|
|
226
|
+
style.marker.alpha = _alpha_fn(_dso)
|
|
227
|
+
|
|
228
|
+
if _dso.pk not in label_pks:
|
|
229
|
+
label = None
|
|
230
|
+
|
|
231
|
+
_true_size = _dso.pk in true_size_pks
|
|
232
|
+
|
|
233
|
+
if _true_size and d.size is not None:
|
|
234
|
+
if "Polygon" == str(d.geometry.geom_type):
|
|
235
|
+
self._plot_dso_polygon(d.geometry, style)
|
|
236
|
+
|
|
237
|
+
elif "MultiPolygon" == str(d.geometry.geom_type):
|
|
238
|
+
for polygon in d.geometry.geoms:
|
|
239
|
+
self._plot_dso_polygon(polygon, style)
|
|
240
|
+
elif maj_ax:
|
|
241
|
+
# if object has a major axis then plot its actual extent
|
|
242
|
+
maj_ax_degrees = (maj_ax / 60) / 2
|
|
243
|
+
|
|
244
|
+
if min_ax:
|
|
245
|
+
min_ax_degrees = (min_ax / 60) / 2
|
|
246
|
+
else:
|
|
247
|
+
min_ax_degrees = maj_ax_degrees
|
|
248
|
+
|
|
249
|
+
poly_style = style.marker.to_polygon_style()
|
|
250
|
+
|
|
251
|
+
if style.marker.symbol == MarkerSymbolEnum.SQUARE:
|
|
252
|
+
self.rectangle(
|
|
253
|
+
(ra, dec),
|
|
254
|
+
min_ax_degrees * 2,
|
|
255
|
+
maj_ax_degrees * 2,
|
|
256
|
+
style=poly_style,
|
|
257
|
+
angle=angle or 0,
|
|
258
|
+
)
|
|
259
|
+
else:
|
|
260
|
+
self.ellipse(
|
|
261
|
+
(ra, dec),
|
|
262
|
+
min_ax_degrees * 2,
|
|
263
|
+
maj_ax_degrees * 2,
|
|
264
|
+
style=poly_style,
|
|
265
|
+
angle=angle or 0,
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
if label and self.in_bounds(ra, dec):
|
|
269
|
+
self.text(
|
|
270
|
+
label,
|
|
271
|
+
ra,
|
|
272
|
+
dec,
|
|
273
|
+
style.label,
|
|
274
|
+
collision_handler=handler,
|
|
275
|
+
gid=f"dso-{d.type}-label",
|
|
276
|
+
)
|
|
277
|
+
|
|
278
|
+
self._add_legend_handle_marker(legend_label, style.marker)
|
|
279
|
+
|
|
280
|
+
else:
|
|
281
|
+
# if no major axis, then just plot as a marker
|
|
282
|
+
self.marker(
|
|
283
|
+
ra=ra,
|
|
284
|
+
dec=dec,
|
|
285
|
+
style=style,
|
|
286
|
+
label=label,
|
|
287
|
+
legend_label=legend_label,
|
|
288
|
+
collision_handler=handler,
|
|
289
|
+
# skip_bounds_check=True,
|
|
290
|
+
gid_marker=f"dso-{d.type}-marker",
|
|
291
|
+
gid_label=f"dso-{d.type}-label",
|
|
292
|
+
)
|
|
293
|
+
|
|
294
|
+
self._objects.dsos.append(_dso)
|