starplot 0.18.3__py2.py3-none-any.whl → 0.19.2__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.
Files changed (38) hide show
  1. starplot/__init__.py +33 -27
  2. starplot/config.py +11 -0
  3. starplot/data/__init__.py +3 -5
  4. starplot/data/catalogs.py +24 -12
  5. starplot/data/constellations.py +1 -0
  6. starplot/data/db.py +1 -7
  7. starplot/geod.py +3 -4
  8. starplot/geometry.py +17 -1
  9. starplot/mixins.py +11 -0
  10. starplot/models/__init__.py +3 -1
  11. starplot/models/constellation.py +20 -3
  12. starplot/models/milky_way.py +30 -0
  13. starplot/models/moon.py +1 -1
  14. starplot/models/observer.py +11 -2
  15. starplot/models/planet.py +1 -1
  16. starplot/models/sun.py +1 -1
  17. starplot/plots/__init__.py +6 -0
  18. starplot/{base.py → plots/base.py} +107 -456
  19. starplot/{horizon.py → plots/horizon.py} +12 -10
  20. starplot/{map.py → plots/map.py} +11 -7
  21. starplot/{optic.py → plots/optic.py} +21 -30
  22. starplot/{zenith.py → plots/zenith.py} +37 -8
  23. starplot/plotters/__init__.py +9 -7
  24. starplot/plotters/arrow.py +1 -1
  25. starplot/plotters/constellations.py +46 -61
  26. starplot/plotters/dsos.py +33 -16
  27. starplot/plotters/experimental.py +0 -1
  28. starplot/plotters/milkyway.py +15 -6
  29. starplot/plotters/stars.py +19 -36
  30. starplot/plotters/text.py +524 -0
  31. starplot/styles/__init__.py +4 -4
  32. starplot/styles/base.py +1 -13
  33. {starplot-0.18.3.dist-info → starplot-0.19.2.dist-info}/METADATA +2 -1
  34. {starplot-0.18.3.dist-info → starplot-0.19.2.dist-info}/RECORD +37 -35
  35. starplot/data/library/sky.db +0 -0
  36. {starplot-0.18.3.dist-info → starplot-0.19.2.dist-info}/WHEEL +0 -0
  37. {starplot-0.18.3.dist-info → starplot-0.19.2.dist-info}/entry_points.txt +0 -0
  38. {starplot-0.18.3.dist-info → starplot-0.19.2.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,524 @@
1
+ from dataclasses import dataclass
2
+
3
+ import numpy as np
4
+ import rtree
5
+ from shapely import Point
6
+ from shapely.errors import GEOSException
7
+ from matplotlib.text import Text
8
+
9
+ from starplot.config import settings as StarplotSettings, SvgTextType
10
+ from starplot.styles import AnchorPointEnum, LabelStyle
11
+ from starplot.styles.helpers import use_style
12
+ from starplot.geometry import (
13
+ random_point_in_polygon_at_distance,
14
+ union_at_zero,
15
+ )
16
+
17
+ """
18
+ Long term strategy:
19
+
20
+ - plot all markers FIRST (but keep track of labels)
21
+ - on export, find best positions for labels
22
+ - introduce some "priority" for labels (e.g. order by)
23
+
24
+ """
25
+
26
+ BBox = tuple[float, float, float, float]
27
+
28
+
29
+ @dataclass
30
+ class CollisionHandler:
31
+ """
32
+ Dataclass that describes how to handle label collisions with other objects, like text, markers, constellation lines, etc.
33
+ """
34
+
35
+ allow_clipped: bool = False
36
+ """If True, then labels will be plotted if they're clipped (i.e. part of the label is outside the plot area)"""
37
+
38
+ allow_label_collisions: bool = False
39
+ """If True, then labels will be plotted if they collide with another label"""
40
+
41
+ allow_marker_collisions: bool = False
42
+ """If True, then labels will be plotted if they collide with another marker"""
43
+
44
+ allow_constellation_line_collisions: bool = False
45
+ """If True, then labels will be plotted if they collide with a constellation line"""
46
+
47
+ plot_on_fail: bool = False
48
+ """If True, then labels will be plotted even if no allowed position is found. They will be plotted at their last attempted position."""
49
+
50
+ attempts: int = 500
51
+ """Max attempts to find a good label position"""
52
+
53
+ seed: int = None
54
+ """Random seed for randomly generating points"""
55
+
56
+ anchor_fallbacks: list[AnchorPointEnum] = None
57
+ """
58
+ If a point-based label's preferred anchor point results in a collision, then these fallbacks will be tried in
59
+ sequence until a collision-free position is found.
60
+
61
+ Default:
62
+ ```python
63
+ [
64
+ AnchorPointEnum.BOTTOM_RIGHT,
65
+ AnchorPointEnum.TOP_LEFT,
66
+ AnchorPointEnum.TOP_RIGHT,
67
+ AnchorPointEnum.BOTTOM_LEFT,
68
+ AnchorPointEnum.BOTTOM_CENTER,
69
+ AnchorPointEnum.TOP_CENTER,
70
+ AnchorPointEnum.RIGHT_CENTER,
71
+ AnchorPointEnum.LEFT_CENTER,
72
+ ]
73
+ ```
74
+ """
75
+
76
+ def __post_init__(self):
77
+ self.anchor_fallbacks = self.anchor_fallbacks or [
78
+ AnchorPointEnum.BOTTOM_RIGHT,
79
+ AnchorPointEnum.TOP_LEFT,
80
+ AnchorPointEnum.TOP_RIGHT,
81
+ AnchorPointEnum.BOTTOM_LEFT,
82
+ AnchorPointEnum.BOTTOM_CENTER,
83
+ AnchorPointEnum.TOP_CENTER,
84
+ AnchorPointEnum.RIGHT_CENTER,
85
+ AnchorPointEnum.LEFT_CENTER,
86
+ ]
87
+
88
+
89
+ class TextPlotterMixin:
90
+ def __init__(self, *args, **kwargs):
91
+ self.labels = []
92
+ self._labels_rtree = rtree.index.Index()
93
+ self._constellations_rtree = rtree.index.Index()
94
+ self._stars_rtree = rtree.index.Index()
95
+ self._markers_rtree = rtree.index.Index()
96
+ self.collision_handler = kwargs.pop("collision_handler", CollisionHandler())
97
+
98
+ def _is_label_collision(self, bbox: BBox) -> bool:
99
+ ix = list(self._labels_rtree.intersection(bbox))
100
+ return len(ix) > 0
101
+
102
+ def _is_constellation_collision(self, bbox: BBox) -> bool:
103
+ ix = list(self._constellations_rtree.intersection(bbox))
104
+ return len(ix) > 0
105
+
106
+ def _is_star_collision(self, bbox: BBox) -> bool:
107
+ ix = list(self._stars_rtree.intersection(bbox))
108
+ return len(ix) > 0
109
+
110
+ def _is_marker_collision(self, bbox: BBox) -> bool:
111
+ ix = list(self._markers_rtree.intersection(bbox))
112
+ return len(ix) > 0
113
+
114
+ def _is_clipped(self, points) -> bool:
115
+ p = self._clip_path_polygon
116
+
117
+ for x, y in points:
118
+ if not p.contains(Point(x, y)):
119
+ return True
120
+
121
+ return False
122
+
123
+ def _add_label_to_rtree(self, label: Text, extent=None):
124
+ extent = extent or label.get_window_extent(
125
+ renderer=self.fig.canvas.get_renderer()
126
+ )
127
+ self.labels.append(label)
128
+ self._labels_rtree.insert(
129
+ 0, (extent.x0 - 1, extent.y0 - 1, extent.x1 + 1, extent.y1 + 1)
130
+ )
131
+
132
+ def _is_open_space(
133
+ self,
134
+ bbox: BBox,
135
+ padding=0,
136
+ avoid_clipped=True,
137
+ avoid_label_collisions=True,
138
+ avoid_marker_collisions=True,
139
+ avoid_constellation_collision=True,
140
+ ) -> bool:
141
+ """
142
+ Returns true if the boox covers an open space (i.e. no collisions)
143
+
144
+ Args:
145
+ bbox: 4-element tuple of lower left and upper right coordinates
146
+ """
147
+ x0, y0, x1, y1 = bbox
148
+ points = [(x0, y0), (x1, y1)]
149
+ bbox = (
150
+ x0 - padding,
151
+ y0 - padding,
152
+ x1 + padding,
153
+ y1 + padding,
154
+ )
155
+
156
+ if any([np.isnan(c) for c in (x0, y0, x1, y1)]):
157
+ return False
158
+
159
+ if avoid_clipped and self._is_clipped(points):
160
+ return False
161
+
162
+ if avoid_label_collisions and self._is_label_collision(bbox):
163
+ return False
164
+
165
+ if avoid_marker_collisions and (
166
+ self._is_star_collision(bbox) or self._is_marker_collision(bbox)
167
+ ):
168
+ return False
169
+
170
+ if avoid_constellation_collision and self._is_constellation_collision(bbox):
171
+ return False
172
+
173
+ return True
174
+
175
+ def _get_label_bbox(self, label: Text) -> BBox:
176
+ extent = label.get_window_extent(renderer=self.fig.canvas.get_renderer())
177
+ return (float(extent.x0), float(extent.y0), float(extent.x1), float(extent.y1))
178
+
179
+ def _maybe_remove_label(
180
+ self,
181
+ label: Text,
182
+ collision_handler: CollisionHandler,
183
+ ) -> bool:
184
+ """Returns true if the label is removed, else false"""
185
+ extent = label.get_window_extent(renderer=self.fig.canvas.get_renderer())
186
+ bbox = (float(extent.x0), float(extent.y0), float(extent.x1), float(extent.y1))
187
+ points = [(extent.x0, extent.y0), (extent.x1, extent.y1)]
188
+
189
+ if any([np.isnan(c) for c in bbox]):
190
+ label.remove()
191
+ return True
192
+
193
+ if not collision_handler.allow_clipped and self._is_clipped(points):
194
+ label.remove()
195
+ return True
196
+
197
+ if not collision_handler.allow_label_collisions and self._is_label_collision(
198
+ bbox
199
+ ):
200
+ label.remove()
201
+ return True
202
+
203
+ if not collision_handler.allow_marker_collisions and (
204
+ self._is_star_collision(bbox) or self._is_marker_collision(bbox)
205
+ ):
206
+ label.remove()
207
+ return True
208
+
209
+ if (
210
+ not collision_handler.allow_constellation_line_collisions
211
+ and self._is_constellation_collision(bbox)
212
+ ):
213
+ label.remove()
214
+ return True
215
+
216
+ return False
217
+
218
+ def _text(self, x, y, text, **kwargs) -> Text:
219
+ """Plots text at (x, y)"""
220
+ label = self.ax.annotate(
221
+ text,
222
+ (x, y),
223
+ **kwargs,
224
+ **self._plot_kwargs(),
225
+ )
226
+ if kwargs.get("clip_on"):
227
+ label.set_clip_on(True)
228
+ label.set_clip_path(self._background_clip_path)
229
+ return label
230
+
231
+ def _text_point(
232
+ self,
233
+ ra: float,
234
+ dec: float,
235
+ text: str,
236
+ collision_handler: CollisionHandler,
237
+ **kwargs,
238
+ ) -> Text | None:
239
+ if not text:
240
+ return None
241
+
242
+ x, y = self._prepare_coords(ra, dec)
243
+
244
+ if StarplotSettings.svg_text_type == SvgTextType.PATH:
245
+ kwargs["path_effects"] = kwargs.get("path_effects", [self.text_border])
246
+
247
+ original_va = kwargs.pop("va", None)
248
+ original_ha = kwargs.pop("ha", None)
249
+ original_offset_x, original_offset_y = kwargs.pop("xytext", (0, 0))
250
+ attempts = 0
251
+
252
+ anchors = [(original_va, original_ha)]
253
+ for a in collision_handler.anchor_fallbacks:
254
+ d = AnchorPointEnum.from_str(a).as_matplot()
255
+ anchors.append((d["va"], d["ha"]))
256
+
257
+ for va, ha in anchors:
258
+ attempts += 1
259
+ offset_x, offset_y = original_offset_x, original_offset_y
260
+ if original_ha != ha:
261
+ offset_x *= -1
262
+
263
+ if original_va != va:
264
+ offset_y *= -1
265
+
266
+ if ha == "center":
267
+ offset_x = 0
268
+ offset_y = 0
269
+
270
+ label = self._text(
271
+ x, y, text, va=va, ha=ha, xytext=(offset_x, offset_y), **kwargs
272
+ )
273
+
274
+ if (
275
+ collision_handler.plot_on_fail
276
+ and label
277
+ and (attempts == collision_handler.attempts or attempts == len(anchors))
278
+ ):
279
+ self._add_label_to_rtree(label)
280
+ return label
281
+
282
+ removed = self._maybe_remove_label(label, collision_handler)
283
+
284
+ if not removed:
285
+ self._add_label_to_rtree(label)
286
+ return label
287
+ elif attempts == collision_handler.attempts or attempts == len(anchors):
288
+ return None
289
+
290
+ # from matplotlib.patches import Rectangle
291
+ # bbox = label.get_window_extent(renderer=self.fig.canvas.get_renderer())
292
+ # bbox = bbox.transformed(self.ax.transAxes.inverted())
293
+ # # bbox = bbox.padded(1)
294
+ # # bbox = bbox.expanded(1, 2)
295
+ # rect = Rectangle(
296
+ # # Bbox(x0=0.19034844035799406, y0=0.8351746595026188, x1=0.20519408725358892, y1=0.8615984521601776)
297
+ # (bbox.x0, bbox.y0), # (x, y) position in display pixels
298
+ # width=bbox.width,
299
+ # height=bbox.height,
300
+ # transform=self.ax.transAxes,
301
+ # fill=False,
302
+ # facecolor='none',
303
+ # edgecolor='red',
304
+ # linewidth=1,
305
+ # alpha=1,
306
+ # zorder=100_000,
307
+ # )
308
+ # self.ax.add_patch(rect)
309
+
310
+ def _text_area(
311
+ self,
312
+ ra: float,
313
+ dec: float,
314
+ text: str,
315
+ area,
316
+ collision_handler: CollisionHandler,
317
+ **kwargs,
318
+ ) -> Text | None:
319
+ kwargs["va"] = "center"
320
+ kwargs["ha"] = "center"
321
+
322
+ if StarplotSettings.svg_text_type == SvgTextType.PATH:
323
+ kwargs["path_effects"] = kwargs.get("path_effects", [self.text_border])
324
+
325
+ padding = 0
326
+ max_distance = 2_000
327
+ distance_step_size = 2
328
+ attempts = 0
329
+ height = None
330
+ width = None
331
+ bbox = None
332
+
333
+ origin = Point(ra, dec)
334
+
335
+ total_area = (
336
+ area
337
+ if area.geom_type != "MultiPolygon"
338
+ else union_at_zero(area.geoms[0], area.geoms[1])
339
+ )
340
+ original_size = total_area.area
341
+ buffer = -0.05 if original_size < 400 else -1
342
+
343
+ # Intersect with extent
344
+ extent = self._extent_mask()
345
+
346
+ try:
347
+ area = area.intersection(extent)
348
+ except GEOSException:
349
+ # TODO : handle this better
350
+ pass
351
+
352
+ area = (
353
+ area
354
+ if area.geom_type != "MultiPolygon"
355
+ else union_at_zero(area.geoms[0], area.geoms[1])
356
+ )
357
+ area = area.buffer(buffer, cap_style="square", join_style="mitre")
358
+
359
+ if not area.contains(origin) or area.area < (original_size * 0.9):
360
+ origin = area.centroid
361
+
362
+ if self.debug_text and area.is_valid and not origin.is_empty:
363
+ """Plots marker at origin and polygon of area"""
364
+ self.marker(
365
+ origin.x,
366
+ origin.y,
367
+ style={
368
+ "marker": {
369
+ "symbol": "triangle",
370
+ "color": "red",
371
+ }
372
+ },
373
+ )
374
+ self.polygon(
375
+ geometry=area,
376
+ style={
377
+ "edge_color": "red",
378
+ "edge_width": 2,
379
+ },
380
+ )
381
+
382
+ for d in range(0, max_distance, distance_step_size):
383
+ if not area.contains(origin):
384
+ continue
385
+ distance = d / 25
386
+ point = random_point_in_polygon_at_distance(
387
+ area,
388
+ origin_point=origin,
389
+ distance=distance,
390
+ max_iterations=10,
391
+ seed=collision_handler.seed,
392
+ )
393
+
394
+ if point is None:
395
+ continue
396
+
397
+ x, y = self._prepare_coords(point.x, point.y)
398
+
399
+ if height and width:
400
+ data_xy = self._proj.transform_point(x, y, self._crs)
401
+ display_x, display_y = self.ax.transData.transform(data_xy)
402
+ bbox = (
403
+ display_x - width / 2,
404
+ display_y - height / 2,
405
+ display_x + width / 2,
406
+ display_y + height / 2,
407
+ )
408
+ label = None
409
+
410
+ else:
411
+ label = self._text(x, y, text, **kwargs)
412
+ bbox = self._get_label_bbox(label)
413
+ height = bbox[3] - bbox[1]
414
+ width = bbox[2] - bbox[0]
415
+
416
+ is_open = self._is_open_space(
417
+ bbox,
418
+ padding=padding,
419
+ avoid_clipped=not collision_handler.allow_clipped,
420
+ avoid_constellation_collision=not collision_handler.allow_constellation_line_collisions,
421
+ avoid_marker_collisions=not collision_handler.allow_marker_collisions,
422
+ avoid_label_collisions=not collision_handler.allow_label_collisions,
423
+ )
424
+
425
+ # # TODO : remove label if not fully inside area?
426
+
427
+ attempts += 1
428
+
429
+ if is_open and label is None:
430
+ label = self._text(x, y, text, **kwargs)
431
+
432
+ if is_open or (
433
+ collision_handler.plot_on_fail
434
+ and attempts == collision_handler.attempts
435
+ ):
436
+ self._add_label_to_rtree(label)
437
+ return label
438
+
439
+ elif label is not None:
440
+ label.remove()
441
+
442
+ elif attempts == collision_handler.attempts:
443
+ return None
444
+
445
+ @use_style(LabelStyle)
446
+ def text(
447
+ self,
448
+ text: str,
449
+ ra: float,
450
+ dec: float,
451
+ style: LabelStyle = None,
452
+ collision_handler: CollisionHandler = None,
453
+ **kwargs,
454
+ ):
455
+ """
456
+ Plots text
457
+
458
+ Args:
459
+ text: Text to plot
460
+ ra: Right ascension of text (0...360)
461
+ dec: Declination of text (-90...90)
462
+ style: Styling of the text
463
+ collision_handler: An instance of [CollisionHandler][starplot.CollisionHandler] that describes what to do on collisions with other labels, markers, etc. If `None`, then the collision handler of the plot will be used.
464
+ """
465
+ if not text:
466
+ return
467
+
468
+ style = style.model_copy() # need a copy because we possibly mutate it below
469
+
470
+ collision_handler = collision_handler or self.collision_handler
471
+
472
+ if style.offset_x == "auto":
473
+ style.offset_x = 0
474
+
475
+ if style.offset_y == "auto":
476
+ style.offset_y = 0
477
+
478
+ if kwargs.get("area"):
479
+ label = self._text_area(
480
+ ra,
481
+ dec,
482
+ text,
483
+ **style.matplot_kwargs(self.scale),
484
+ area=kwargs.pop("area"),
485
+ collision_handler=collision_handler,
486
+ xycoords="data",
487
+ xytext=(style.offset_x * self.scale, style.offset_y * self.scale),
488
+ textcoords="offset points",
489
+ **kwargs,
490
+ )
491
+ else:
492
+ label = self._text_point(
493
+ ra,
494
+ dec,
495
+ text,
496
+ **style.matplot_kwargs(self.scale),
497
+ collision_handler=collision_handler,
498
+ xycoords="data",
499
+ xytext=(style.offset_x * self.scale, style.offset_y * self.scale),
500
+ textcoords="offset points",
501
+ **kwargs,
502
+ )
503
+
504
+ if self.debug_text and label:
505
+ """Plots bounding box around label"""
506
+ from matplotlib.patches import Rectangle
507
+
508
+ bbox = label.get_window_extent(renderer=self.fig.canvas.get_renderer())
509
+ bbox = bbox.transformed(self.ax.transAxes.inverted())
510
+ rect = Rectangle(
511
+ (bbox.x0, bbox.y0), # (x, y) position in display pixels
512
+ width=bbox.width,
513
+ height=bbox.height,
514
+ transform=self.ax.transAxes,
515
+ fill=False,
516
+ facecolor="none",
517
+ edgecolor="red",
518
+ linewidth=1,
519
+ alpha=1,
520
+ zorder=100_000,
521
+ )
522
+ self.ax.add_patch(rect)
523
+
524
+ return label
@@ -1,6 +1,6 @@
1
- from .base import * # noqa: F401,F403
2
- from .helpers import * # noqa: F401,F403
1
+ # ruff: noqa: F401,F403
3
2
 
4
- # from .extensions import * # noqa: F401
3
+ from .base import *
4
+ from .helpers import *
5
5
 
6
- import starplot.styles.extensions as style_extensions # noqa: F401
6
+ import starplot.styles.extensions as style_extensions
starplot/styles/base.py CHANGED
@@ -2,7 +2,7 @@ import json
2
2
 
3
3
  from enum import Enum
4
4
  from pathlib import Path
5
- from typing import Optional, Union, List
5
+ from typing import Optional, Union
6
6
 
7
7
  import yaml
8
8
 
@@ -813,18 +813,6 @@ class PlotStyle(BaseStyle):
813
813
 
814
814
  text_border_color: ColorStr = ColorStr("#fff")
815
815
 
816
- text_anchor_fallbacks: List[AnchorPointEnum] = [
817
- AnchorPointEnum.BOTTOM_RIGHT,
818
- AnchorPointEnum.TOP_LEFT,
819
- AnchorPointEnum.TOP_RIGHT,
820
- AnchorPointEnum.BOTTOM_LEFT,
821
- AnchorPointEnum.BOTTOM_CENTER,
822
- AnchorPointEnum.TOP_CENTER,
823
- AnchorPointEnum.RIGHT_CENTER,
824
- AnchorPointEnum.LEFT_CENTER,
825
- ]
826
- """If a label's preferred anchor point results in a collision, then these fallbacks will be tried in sequence until a collision-free position is found."""
827
-
828
816
  # Borders
829
817
  border_font_size: int = 18
830
818
  border_font_weight: FontWeightEnum = FontWeightEnum.BOLD
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: starplot
3
- Version: 0.18.3
3
+ Version: 0.19.2
4
4
  Summary: Star charts and maps of the sky
5
5
  Keywords: astronomy,stars,charts,maps,constellations,sky,plotting
6
6
  Author-email: Steve Berardi <hello@steveberardi.com>
@@ -136,6 +136,7 @@ See more details on the [Public Roadmap](https://trello.com/b/sUksygn4/starplot-
136
136
  - [starplot-hyg](https://github.com/steveberardi/starplot-hyg)
137
137
  - [starplot-gaia-dr3](https://github.com/steveberardi/starplot-gaia-dr3)
138
138
  - [starplot-hyperleda](https://github.com/steveberardi/starplot-hyperleda)
139
+ - [starplot-milkyway](https://github.com/steveberardi/starplot-milkyway)
139
140
 
140
141
  ## License
141
142
  [MIT License](https://github.com/steveberardi/starplot/blob/main/LICENSE)
@@ -1,24 +1,19 @@
1
- starplot/__init__.py,sha256=c3-3p6r1LF5cA64d6gUrrCDY16acOzy0Of3peyD3o3k,1301
2
- starplot/base.py,sha256=dR6rhNT8AUvPlbRKzKiL0n4YA59QDS7ZnZcAW6e9PjM,42538
1
+ starplot/__init__.py,sha256=bHPp8kjV-1kjqngkE4G5ms_NgLCgpD1Vr1NvkpD8sg8,964
3
2
  starplot/callables.py,sha256=k8Ra0nmNfc8vjOpNPdQfAqpNaM2ajCPB3XkgzCqrcQ0,4039
4
3
  starplot/cli.py,sha256=Tjkc_5khvb1mL_Ai_met__zViINvtL4SgbYc0_mB2_U,622
5
- starplot/config.py,sha256=Rz2USH1ETFi61USSuxTFSh-K-u_8-vOn6bL97Nbzde8,2500
4
+ starplot/config.py,sha256=8IbQTlQP-e7Yvv63zS9z5Ifcumr696MvdGT3JDvV-ik,2919
6
5
  starplot/coordinates.py,sha256=7LDz32VTKa8H-4F67-XvzmjpcTVojZwYVJzXZkBaZ3U,136
7
- starplot/geod.py,sha256=pVnDr-yxGjOIXwKCknbtCZiRle5IqRnqpY43s0PMnmA,2574
8
- starplot/geometry.py,sha256=qU8OVIchzGe7-F7X6cynVaZFknOuPeYRAjRfaZjRc1Y,6715
9
- starplot/horizon.py,sha256=1dTA0VEFUkZvIEcxwVyzpeXUZMsLRDeMKjQyAJ9SRYk,20245
10
- starplot/map.py,sha256=2rxnAgJYfHcgdFL1__1MXyg_R7ynN2RACNF_edD-PkA,19185
11
- starplot/mixins.py,sha256=ZZBVg1Ad3xnbyLskCEhpDcd9Jmb_2_jT8hUiiCbU658,12268
12
- starplot/optic.py,sha256=wi2ZMBC09Due_YBAh6IRAsYR2wk-vQRSeWfNNymrQOc,17518
6
+ starplot/geod.py,sha256=au25V21-sexxIPXUbN02nfd9pxOzwjdCxyUXDDsUIZc,2611
7
+ starplot/geometry.py,sha256=NYhfaNJtl-Cbtyq1IfrQimaqKChm9ZNQNsRdpYLR0PU,7248
8
+ starplot/mixins.py,sha256=PoSn8QfLS-P8dUF8rNrFOvhs9yb4D-ZRV2R1-1DSiaA,12536
13
9
  starplot/profile.py,sha256=V5LOZFDdnGo-P8ikWvV3jmUVJIKO3gd4H2bjBlk7aUM,300
14
10
  starplot/projections.py,sha256=6mj8uJkWE-79giXF-OVS8ixUbbojOHuwI51C-ovHyIo,5101
15
11
  starplot/utils.py,sha256=49m8QXJl188Pgpef_82gyykly7ZjfAuHVEcSA5QFITA,3720
16
12
  starplot/warnings.py,sha256=uKvGSAVpWKZIHMKxxegO5owFJnKvBYLyq3pJatD0qQ4,594
17
- starplot/zenith.py,sha256=JvlMxHOzc2b-2C1Z3p6I8Qux-Z05FLWNxPL6WrLteaY,6680
18
- starplot/data/__init__.py,sha256=QLsNozY78tnwjktLuFHFuBt7DZ-r38i2oJ_obGzBsXo,587
19
- starplot/data/catalogs.py,sha256=3n1_hQqIQCMJJ12ZTXGxsugEnljBgxlxN0EukUerFMc,11478
20
- starplot/data/constellations.py,sha256=MrRiTA_pJhJEV_D1SnLO8lsVq1MJkHjuW99KA-vCimw,2259
21
- starplot/data/db.py,sha256=AZ-q_bqnxs1i2NacLWBbqam6M5JYa3Ie2tXeMIOEKY8,778
13
+ starplot/data/__init__.py,sha256=GBJw579v-5ZNsKk1RxE7Fdnjf4hDIW2gevQJAZ7-6b0,550
14
+ starplot/data/catalogs.py,sha256=Izf2XjKDIcLA-sM9TEL8Csg5CSizYxmvhHq_UXSHMt0,12010
15
+ starplot/data/constellations.py,sha256=-fjneGcLTIxZMxrTQRRoHaMKWy1taW6rQQ3RQ7LWgnE,2330
16
+ starplot/data/db.py,sha256=8SMDx6IkWqhnS2QobL5bp6qD0yze7P05C7b0ls_dbXk,669
22
17
  starplot/data/dsos.py,sha256=8rp_Heme3bYFFWUuAPlWMHlfzsMsZ2W_Lq2jwgSWlQ8,2377
23
18
  starplot/data/ecliptic.py,sha256=Qre9YdFbTC9mAx-vd2C0Ou4CsnRehIScnTpmEUDDYcM,4638
24
19
  starplot/data/stars.py,sha256=C8U29m6pW8L6jwyFqDU1mQgfzeBZjme7OrgYCQ-8ghU,2390
@@ -27,32 +22,39 @@ starplot/data/utils.py,sha256=W2Su63PA_tKbpCkKAAdjwhBpgiq6hYkCEAVz4cC1y7k,978
27
22
  starplot/data/library/constellation_names.parquet,sha256=ol_pv7FJTbDzsac-gWrXH3URijlDbCBgZrREmmDrn9w,13412
28
23
  starplot/data/library/dso_names.parquet,sha256=BRHfI9HTJW1jiOkPnVkvj7EJejZKaTgUp22uU__0Ee8,24541
29
24
  starplot/data/library/readme.md,sha256=sJyJ1EkC5lcwLbvhTF96XlVa8tC6HyuXWWRooMyRNLA,68
30
- starplot/data/library/sky.db,sha256=E4uB7NLPGF3wrOgHbBuWMlVZ7qvox70Yd3yhytJqlQA,1585152
31
25
  starplot/data/library/star_designations.parquet,sha256=WJLiv73VoVfptWT1oK1zzgio5UdGd_ebuy2Ew1-M9xQ,70170
32
- starplot/models/__init__.py,sha256=qQqlYH5vJQrs017gd7hOg4J1EDCav73cLUJWn72ooBM,414
26
+ starplot/models/__init__.py,sha256=jypNZ_41BtVbV4xS7QDAwwey7rTxUTXNKuXIAV3HhE8,468
33
27
  starplot/models/base.py,sha256=wIoxP96wPc8glIFUgFhSeCtzU_pz597vWBdveqSoBNY,2175
34
28
  starplot/models/comet.py,sha256=pG_yNVmWCNCaAEZGhAoeRtDe8FaDKWmsqt9-6BCicUo,11210
35
- starplot/models/constellation.py,sha256=SbdFrZtBuYC0eUoyvprb0xVpTMHTkpO8CheQrvj7qow,4222
29
+ starplot/models/constellation.py,sha256=aDoh1wWB4za92gHSCwxl86aVhOtXZdcrYblVSAVhrog,4908
36
30
  starplot/models/dso.py,sha256=Iehc1VGkpQsZDEVIft7KZyjXUevesg3FgBUsWU_Gc3E,9019
37
- starplot/models/moon.py,sha256=rnKL8tafxtd2x-K-CGAloMpHKJUcIrWFCX4exWyocDs,4624
31
+ starplot/models/milky_way.py,sha256=8ll-JV_PH9J0xOUL7R-t3vdcHTrynU0fuZD-R8LiVWI,889
32
+ starplot/models/moon.py,sha256=QLzANZ59ghG0fK0RJXjg8vdegJHPcAA8DgQPUBpHBUw,4628
38
33
  starplot/models/objects.py,sha256=BXwUMT-zPiOYBWYV7L-TRDfPo6lsx_AIk3yxJ3qi0ck,683
39
- starplot/models/observer.py,sha256=R15X0DZhDSFQ06mf4Tv-q7Qf-o1GR3CSz-9H_CBDFg8,1825
34
+ starplot/models/observer.py,sha256=x55ZaW4sSRtdM1prNo2bCiAfM4mdAlTf-xh00GVnKAE,2048
40
35
  starplot/models/optics.py,sha256=6quf3Cxga5pjTunchtGe2OKCU6hgsm5yg7NfYWIfoNA,9314
41
- starplot/models/planet.py,sha256=wKjuKClcTHRxpCwdVk4f8roN7yatQD3pkGOli7fEaK8,4745
36
+ starplot/models/planet.py,sha256=G-MpJGydmakCqSnXu6G3MdjyFXNtfWI51ST8ewYJh6w,4749
42
37
  starplot/models/satellite.py,sha256=X5StTyVjpWQ94FT21OU8ArzxrdIDGB581bstWFNvT3k,5228
43
38
  starplot/models/star.py,sha256=0EkqS-i2ErLVPFY7GYqEWWIqhaiZU0RwDDJiIVABua4,6970
44
- starplot/models/sun.py,sha256=AMWQ6N6y3xjkB6YavAtxxdpq-nQgXQnMhIvsdQswq08,2410
45
- starplot/plotters/__init__.py,sha256=JoFv2TG0-l9lDK5KD-xMSp0B0taMPgJCToK6Ap0yov4,388
46
- starplot/plotters/arrow.py,sha256=GtPDaaHw2ooJmM0bG-G1fR-aGLxxamf3-iOU1Ety1f4,6452
47
- starplot/plotters/constellations.py,sha256=siPahtGrIPxqlaKldh1B2DOceOwFfLfNFJlC2xjdG8U,12406
48
- starplot/plotters/dsos.py,sha256=D08cfRZtYZ9YG3bBwil6KxjY7GAzv4-gksWXd9woHS0,10414
49
- starplot/plotters/experimental.py,sha256=sO-wR_YcEuLQ28V2ej4W4-BI2kZIWiBkqoYtSH6j550,16004
39
+ starplot/models/sun.py,sha256=L93DKFFgfzVuwESA-8C6g7-gUC4D5tix41SabZ-WP84,2414
40
+ starplot/plots/__init__.py,sha256=YtvBn2ClaGrmnOfFKdXs9duOZNBmRDvZwNJYF_7TTPU,143
41
+ starplot/plots/base.py,sha256=ZabMdrdoiSQ08KlzwHileWaFv1PRCD9RZBPm5vVU9qo,33606
42
+ starplot/plots/horizon.py,sha256=a2a78DPnlmnYyp1xucsQdAR7SepPp2Q6SCPAlu2ygsk,20374
43
+ starplot/plots/map.py,sha256=gyCU5mIm_prUg7gtsKjKO7ppBuwhJNwQoJ1vIEK93TQ,19454
44
+ starplot/plots/optic.py,sha256=0kgj6UC_MouoG5hrywW9zseCR5TtpYlPsoT-XGoqwyo,17305
45
+ starplot/plots/zenith.py,sha256=i_83cXpNk2KB81hFhqUw6ConLzUKyrzb2NxoWxjZCwk,7792
46
+ starplot/plotters/__init__.py,sha256=RzsH2t4PbdsEMBjcgIhQ_ng7fIgjW4CobQcwtGo9oTc,315
47
+ starplot/plotters/arrow.py,sha256=hI2-WGSWjMwK5rax4cMDsjorX2ILylnn1RbWNHbPq5g,6583
48
+ starplot/plotters/constellations.py,sha256=xT_QXHIbUvRKztLe1tjju5BWjfE9ro3Mi5YilHgTQtc,11787
49
+ starplot/plotters/dsos.py,sha256=xhQIXgDiQ0FdiOSC5mJybFkYeiDwPlkwRAaV70Sfl9c,11007
50
+ starplot/plotters/experimental.py,sha256=wDNhPUbmK61xkZvTiwTh3ChpCkwzQmUQ0cY4DqDFH7U,15942
50
51
  starplot/plotters/gradients.py,sha256=ZonNeIEmbcZZWjFtlPahGtGCgeTCeimp84PZnqj8dXY,5781
51
52
  starplot/plotters/legend.py,sha256=PwqhSQkYsxPNLMabL0Ox5eo0F3jMS4Ekhm2aHaHS3W4,8761
52
- starplot/plotters/milkyway.py,sha256=WpWwHefSHE2bDI_vTve-tbma31kk1CIGOp1ukLy-BiE,1189
53
- starplot/plotters/stars.py,sha256=_J1xLEc7huRkN-sur4IMq_dPLc0iH67QjGJGcG78wKk,12215
54
- starplot/styles/__init__.py,sha256=rtwzAylENUGIYGDPl106RGjU6e89yNURoxmPD3I_HM0,193
55
- starplot/styles/base.py,sha256=O1A-gDWH5pnZwx4dAPZCF2nGuKNm_pUIzL0Jg_U7G_Y,41400
53
+ starplot/plotters/milkyway.py,sha256=U5uRE4teoWk2v65RC2SkMKPX1LurR6zw7vzLK5mVxJE,1605
54
+ starplot/plotters/stars.py,sha256=rM8LJxCC1mwZjKr-OpcH6g4SlOwUlm-8yI1DSzaLbCQ,11660
55
+ starplot/plotters/text.py,sha256=r1_G4Oe487RxEl0Tjv_8964YfD644H-sdIvqPbK1Eck,16907
56
+ starplot/styles/__init__.py,sha256=HmIDU0cFu4ar8zKet_FEJoNdButQHJMprHnL_4JE2Mc,123
57
+ starplot/styles/base.py,sha256=9xeU0lhTO3eaqVMz1QmS7HMtRQ-OdtUwBP96kzQ7cO4,40881
56
58
  starplot/styles/extensions.py,sha256=qVNE9DaSvG8BPr6vPfT8v5vyZNBYB0AjkR-e9oPMk1I,2707
57
59
  starplot/styles/fonts.py,sha256=wC3cHuFkBUaZM5fKpT_ExV7anrRKMJX46mjEfcSRQMU,379
58
60
  starplot/styles/helpers.py,sha256=AGgHWaHLzJZ6jicvwPzY-p5oSHE0H8gDk1raCmeRFtg,3032
@@ -88,8 +90,8 @@ starplot/styles/fonts-library/inter/Inter-Regular.ttf,sha256=ZPi-blXDfjLvA9qZcUv
88
90
  starplot/styles/fonts-library/inter/Inter-SemiBold.ttf,sha256=DcmOiqWVhTlIgPJauJ5tkVrVE0Ui6WGwRspR-tOhglU,413976
89
91
  starplot/styles/fonts-library/inter/Inter-SemiBoldItalic.ttf,sha256=HhKJRT16iVz7c1adSFFjTIsOSdFQxN1S1Ev10gaQgnI,418520
90
92
  starplot/styles/fonts-library/inter/LICENSE.txt,sha256=JiSB6ERSGzJvXs0FPlm5jIstp4yO4b27boF0MF5Uk1o,4380
91
- starplot-0.18.3.dist-info/entry_points.txt,sha256=Sm6jC6h_RcaMGC8saLnYmT0SdhcF9_rMeQIiHneLHyc,46
92
- starplot-0.18.3.dist-info/licenses/LICENSE,sha256=jcjClHF4BQwhz-kDgia-KphO9Zxu0rCa2BbiA7j1jeU,1070
93
- starplot-0.18.3.dist-info/WHEEL,sha256=Dyt6SBfaasWElUrURkknVFAZDHSTwxg3PaTza7RSbkY,100
94
- starplot-0.18.3.dist-info/METADATA,sha256=-4kp-tfk2Mn_uFXz8cwNC6h3ZnO-h2WYHQFzoNV0d0A,5424
95
- starplot-0.18.3.dist-info/RECORD,,
93
+ starplot-0.19.2.dist-info/entry_points.txt,sha256=Sm6jC6h_RcaMGC8saLnYmT0SdhcF9_rMeQIiHneLHyc,46
94
+ starplot-0.19.2.dist-info/licenses/LICENSE,sha256=jcjClHF4BQwhz-kDgia-KphO9Zxu0rCa2BbiA7j1jeU,1070
95
+ starplot-0.19.2.dist-info/WHEEL,sha256=Dyt6SBfaasWElUrURkknVFAZDHSTwxg3PaTza7RSbkY,100
96
+ starplot-0.19.2.dist-info/METADATA,sha256=RiagUiM6UY4PQd2kYrSEOqDjURoTlV6z04vJbJYvwu4,5497
97
+ starplot-0.19.2.dist-info/RECORD,,
Binary file