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.
Files changed (98) hide show
  1. starplot/__init__.py +59 -0
  2. starplot/callables.py +176 -0
  3. starplot/cli.py +29 -0
  4. starplot/config.py +80 -0
  5. starplot/coordinates.py +7 -0
  6. starplot/data/__init__.py +22 -0
  7. starplot/data/catalogs.py +356 -0
  8. starplot/data/constellations.py +71 -0
  9. starplot/data/db.py +33 -0
  10. starplot/data/dsos.py +85 -0
  11. starplot/data/ecliptic.py +201 -0
  12. starplot/data/library/constellation_names.parquet +0 -0
  13. starplot/data/library/dso_names.parquet +0 -0
  14. starplot/data/library/readme.md +1 -0
  15. starplot/data/library/star_designations.parquet +0 -0
  16. starplot/data/stars.py +79 -0
  17. starplot/data/translations.py +408 -0
  18. starplot/data/utils.py +35 -0
  19. starplot/geometry.py +319 -0
  20. starplot/mixins.py +360 -0
  21. starplot/models/__init__.py +21 -0
  22. starplot/models/base.py +77 -0
  23. starplot/models/comet.py +302 -0
  24. starplot/models/constellation.py +151 -0
  25. starplot/models/dso.py +317 -0
  26. starplot/models/milky_way.py +30 -0
  27. starplot/models/moon.py +130 -0
  28. starplot/models/objects.py +29 -0
  29. starplot/models/observer.py +125 -0
  30. starplot/models/optics.py +342 -0
  31. starplot/models/planet.py +137 -0
  32. starplot/models/satellite.py +138 -0
  33. starplot/models/star.py +253 -0
  34. starplot/models/sun.py +62 -0
  35. starplot/plots/__init__.py +7 -0
  36. starplot/plots/base.py +1023 -0
  37. starplot/plots/galaxy.py +372 -0
  38. starplot/plots/horizon.py +543 -0
  39. starplot/plots/map.py +515 -0
  40. starplot/plots/optic.py +469 -0
  41. starplot/plots/zenith.py +217 -0
  42. starplot/plotters/__init__.py +9 -0
  43. starplot/plotters/arrow.py +174 -0
  44. starplot/plotters/constellations.py +298 -0
  45. starplot/plotters/debug.py +21 -0
  46. starplot/plotters/dsos.py +294 -0
  47. starplot/plotters/experimental.py +722 -0
  48. starplot/plotters/gradients.py +153 -0
  49. starplot/plotters/legend.py +253 -0
  50. starplot/plotters/milkyway.py +51 -0
  51. starplot/plotters/stars.py +319 -0
  52. starplot/plotters/text.py +802 -0
  53. starplot/profile.py +16 -0
  54. starplot/projections.py +184 -0
  55. starplot/styles/__init__.py +6 -0
  56. starplot/styles/base.py +1344 -0
  57. starplot/styles/ext/antique.yml +175 -0
  58. starplot/styles/ext/blue_dark.yml +163 -0
  59. starplot/styles/ext/blue_gold.yml +147 -0
  60. starplot/styles/ext/blue_light.yml +123 -0
  61. starplot/styles/ext/blue_medium.yml +142 -0
  62. starplot/styles/ext/blue_night.yml +185 -0
  63. starplot/styles/ext/cb_wong.yml +124 -0
  64. starplot/styles/ext/color_print.yml +111 -0
  65. starplot/styles/ext/gradient_presets.yml +158 -0
  66. starplot/styles/ext/grayscale.yml +94 -0
  67. starplot/styles/ext/grayscale_dark.yml +136 -0
  68. starplot/styles/ext/map.yml +12 -0
  69. starplot/styles/ext/nord.yml +158 -0
  70. starplot/styles/ext/optic.yml +20 -0
  71. starplot/styles/ext/publication.yml +8 -0
  72. starplot/styles/extensions.py +129 -0
  73. starplot/styles/fonts-library/gfs-didot/DESCRIPTION.en_us.html +9 -0
  74. starplot/styles/fonts-library/gfs-didot/GFSDidot-Regular.ttf +0 -0
  75. starplot/styles/fonts-library/gfs-didot/METADATA.pb +16 -0
  76. starplot/styles/fonts-library/gfs-didot/OFL.txt +94 -0
  77. starplot/styles/fonts-library/inter/Inter-Bold.ttf +0 -0
  78. starplot/styles/fonts-library/inter/Inter-BoldItalic.ttf +0 -0
  79. starplot/styles/fonts-library/inter/Inter-ExtraBold.ttf +0 -0
  80. starplot/styles/fonts-library/inter/Inter-ExtraLight.ttf +0 -0
  81. starplot/styles/fonts-library/inter/Inter-ExtraLightItalic.ttf +0 -0
  82. starplot/styles/fonts-library/inter/Inter-Italic.ttf +0 -0
  83. starplot/styles/fonts-library/inter/Inter-Light.ttf +0 -0
  84. starplot/styles/fonts-library/inter/Inter-LightItalic.ttf +0 -0
  85. starplot/styles/fonts-library/inter/Inter-Regular.ttf +0 -0
  86. starplot/styles/fonts-library/inter/Inter-SemiBold.ttf +0 -0
  87. starplot/styles/fonts-library/inter/Inter-SemiBoldItalic.ttf +0 -0
  88. starplot/styles/fonts-library/inter/LICENSE.txt +92 -0
  89. starplot/styles/fonts.py +15 -0
  90. starplot/styles/helpers.py +93 -0
  91. starplot/styles/markers.py +308 -0
  92. starplot/utils.py +169 -0
  93. starplot/warnings.py +21 -0
  94. starplot-0.20.5.dist-info/METADATA +146 -0
  95. starplot-0.20.5.dist-info/RECORD +98 -0
  96. starplot-0.20.5.dist-info/WHEEL +4 -0
  97. starplot-0.20.5.dist-info/entry_points.txt +3 -0
  98. 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)