starplot 0.15.5__py2.py3-none-any.whl → 0.15.7__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.
- starplot/__init__.py +1 -1
- starplot/base.py +12 -3
- starplot/data/constellations.py +19 -5
- starplot/data/dsos.py +17 -4
- starplot/data/library/sky.db +0 -0
- starplot/data/stars.py +15 -4
- starplot/models/base.py +60 -14
- starplot/models/constellation.py +14 -26
- starplot/models/dso.py +54 -41
- starplot/models/moon.py +6 -28
- starplot/models/planet.py +2 -18
- starplot/models/star.py +25 -36
- starplot/models/sun.py +2 -18
- starplot/optic.py +3 -1
- starplot/optics.py +81 -40
- starplot/plotters/constellations.py +15 -10
- starplot/plotters/dsos.py +26 -11
- starplot/plotters/stars.py +18 -3
- {starplot-0.15.5.dist-info → starplot-0.15.7.dist-info}/METADATA +3 -2
- {starplot-0.15.5.dist-info → starplot-0.15.7.dist-info}/RECORD +23 -23
- {starplot-0.15.5.dist-info → starplot-0.15.7.dist-info}/WHEEL +1 -1
- {starplot-0.15.5.dist-info → starplot-0.15.7.dist-info}/entry_points.txt +0 -0
- {starplot-0.15.5.dist-info → starplot-0.15.7.dist-info/licenses}/LICENSE +0 -0
starplot/__init__.py
CHANGED
starplot/base.py
CHANGED
|
@@ -360,6 +360,9 @@ class BasePlot(ABC):
|
|
|
360
360
|
|
|
361
361
|
x, y = self._prepare_coords(ra, dec)
|
|
362
362
|
kwargs["path_effects"] = kwargs.get("path_effects", [self.text_border])
|
|
363
|
+
remove_on_constellation_collision = kwargs.pop(
|
|
364
|
+
"remove_on_constellation_collision", True
|
|
365
|
+
)
|
|
363
366
|
|
|
364
367
|
original_va = kwargs.pop("va", None)
|
|
365
368
|
original_ha = kwargs.pop("ha", None)
|
|
@@ -386,7 +389,10 @@ class BasePlot(ABC):
|
|
|
386
389
|
x, y, text, **kwargs, va=va, ha=ha, xytext=(offset_x, offset_y)
|
|
387
390
|
)
|
|
388
391
|
removed = self._maybe_remove_label(
|
|
389
|
-
label,
|
|
392
|
+
label,
|
|
393
|
+
remove_on_collision=hide_on_collision,
|
|
394
|
+
remove_on_clipped=clip_on,
|
|
395
|
+
remove_on_constellation_collision=remove_on_constellation_collision,
|
|
390
396
|
)
|
|
391
397
|
|
|
392
398
|
if force or not removed:
|
|
@@ -868,10 +874,13 @@ class BasePlot(ABC):
|
|
|
868
874
|
# closed=False, # needs to be false for circles at poles?
|
|
869
875
|
**style.matplot_kwargs(self.scale),
|
|
870
876
|
**kwargs,
|
|
871
|
-
clip_on=True,
|
|
872
|
-
clip_path=self._background_clip_path,
|
|
877
|
+
# clip_on=True,
|
|
878
|
+
# clip_path=self._background_clip_path,
|
|
873
879
|
)
|
|
874
880
|
self.ax.add_patch(patch)
|
|
881
|
+
# Need to set clip path AFTER adding patch
|
|
882
|
+
patch.set_clip_on(True)
|
|
883
|
+
patch.set_clip_path(self._background_clip_path)
|
|
875
884
|
|
|
876
885
|
@use_style(PolygonStyle)
|
|
877
886
|
def polygon(
|
starplot/data/constellations.py
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
from functools import cache
|
|
2
|
+
|
|
1
3
|
import ibis
|
|
2
4
|
from ibis import _
|
|
3
5
|
|
|
@@ -669,23 +671,35 @@ CONSTELLATION_HIP_IDS = {
|
|
|
669
671
|
}
|
|
670
672
|
|
|
671
673
|
|
|
672
|
-
|
|
673
|
-
|
|
674
|
+
@cache
|
|
675
|
+
def table():
|
|
674
676
|
con = db.connect()
|
|
675
677
|
c = con.table("constellations")
|
|
676
|
-
|
|
678
|
+
|
|
679
|
+
return c.mutate(
|
|
677
680
|
ra=_.center_ra,
|
|
678
681
|
dec=_.center_dec,
|
|
679
682
|
constellation_id=_.iau_id,
|
|
680
|
-
rowid=ibis.row_number(),
|
|
681
683
|
boundary=_.geometry,
|
|
684
|
+
rowid=ibis.row_number(),
|
|
685
|
+
sk=ibis.row_number(),
|
|
682
686
|
)
|
|
683
687
|
|
|
688
|
+
|
|
689
|
+
def load(extent=None, filters=None, sql=None):
|
|
690
|
+
filters = filters or []
|
|
691
|
+
c = table()
|
|
692
|
+
|
|
684
693
|
if extent:
|
|
685
694
|
filters.append(_.geometry.intersects(extent))
|
|
686
695
|
|
|
687
696
|
if filters:
|
|
688
|
-
|
|
697
|
+
c = c.filter(*filters)
|
|
698
|
+
|
|
699
|
+
if sql:
|
|
700
|
+
result = c.alias("_").sql(sql).select("sk").execute()
|
|
701
|
+
skids = result["sk"].to_list()
|
|
702
|
+
c = c.filter(_.sk.isin(skids))
|
|
689
703
|
|
|
690
704
|
return c
|
|
691
705
|
|
starplot/data/dsos.py
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
from functools import cache
|
|
2
|
+
|
|
1
3
|
import ibis
|
|
2
4
|
from ibis import _
|
|
3
5
|
|
|
@@ -25,26 +27,37 @@ class DsoLabelMaker(dict):
|
|
|
25
27
|
DSO_LABELS_DEFAULT = DsoLabelMaker()
|
|
26
28
|
|
|
27
29
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
+
@cache
|
|
31
|
+
def table():
|
|
30
32
|
con = db.connect()
|
|
31
33
|
dsos = con.table("deep_sky_objects")
|
|
32
34
|
|
|
33
|
-
|
|
35
|
+
return dsos.mutate(
|
|
34
36
|
ra=_.ra_degrees,
|
|
35
37
|
dec=_.dec_degrees,
|
|
36
38
|
constellation_id=_.constellation,
|
|
37
39
|
magnitude=ibis.coalesce(_.mag_v, _.mag_b, None),
|
|
38
40
|
size=_.size_deg2,
|
|
39
41
|
rowid=ibis.row_number(),
|
|
42
|
+
sk=ibis.row_number(),
|
|
40
43
|
)
|
|
41
44
|
|
|
45
|
+
|
|
46
|
+
def load(extent=None, filters=None, sql=None):
|
|
47
|
+
filters = filters or []
|
|
48
|
+
dsos = table()
|
|
49
|
+
|
|
42
50
|
if extent:
|
|
43
51
|
dsos = dsos.filter(_.geometry.intersects(extent))
|
|
44
52
|
|
|
45
53
|
filters.extend([_.ra_degrees.notnull() & _.dec_degrees.notnull()])
|
|
46
54
|
|
|
47
55
|
if filters:
|
|
48
|
-
|
|
56
|
+
dsos = dsos.filter(*filters)
|
|
57
|
+
|
|
58
|
+
if sql:
|
|
59
|
+
result = dsos.alias("_").sql(sql).select("sk").execute()
|
|
60
|
+
skids = result["sk"].to_list()
|
|
61
|
+
dsos = dsos.filter(_.sk.isin(skids))
|
|
49
62
|
|
|
50
63
|
return dsos
|
starplot/data/library/sky.db
CHANGED
|
Binary file
|
starplot/data/stars.py
CHANGED
|
@@ -459,7 +459,7 @@ class StarCatalog:
|
|
|
459
459
|
|
|
460
460
|
|
|
461
461
|
@cache
|
|
462
|
-
def
|
|
462
|
+
def table(catalog: StarCatalog = StarCatalog.BIG_SKY_MAG11, table_name="stars"):
|
|
463
463
|
con = db.connect()
|
|
464
464
|
|
|
465
465
|
if catalog == StarCatalog.BIG_SKY_MAG11:
|
|
@@ -481,6 +481,7 @@ def read_catalog(catalog: StarCatalog = StarCatalog.BIG_SKY_MAG11, table_name="s
|
|
|
481
481
|
# stars parquet does not have geometry field
|
|
482
482
|
geometry=_.ra_degrees.point(_.dec_degrees),
|
|
483
483
|
rowid=ibis.row_number(),
|
|
484
|
+
sk=ibis.row_number(),
|
|
484
485
|
)
|
|
485
486
|
|
|
486
487
|
stars = stars.join(
|
|
@@ -495,14 +496,24 @@ def read_catalog(catalog: StarCatalog = StarCatalog.BIG_SKY_MAG11, table_name="s
|
|
|
495
496
|
return stars
|
|
496
497
|
|
|
497
498
|
|
|
498
|
-
def load(
|
|
499
|
+
def load(
|
|
500
|
+
extent=None,
|
|
501
|
+
catalog: StarCatalog = StarCatalog.BIG_SKY_MAG11,
|
|
502
|
+
filters=None,
|
|
503
|
+
sql=None,
|
|
504
|
+
):
|
|
499
505
|
filters = filters or []
|
|
500
|
-
stars =
|
|
506
|
+
stars = table(catalog)
|
|
501
507
|
|
|
502
508
|
if extent:
|
|
503
509
|
stars = stars.filter(stars.geometry.intersects(extent))
|
|
504
510
|
|
|
505
511
|
if filters:
|
|
506
|
-
|
|
512
|
+
stars = stars.filter(*filters)
|
|
513
|
+
|
|
514
|
+
if sql:
|
|
515
|
+
result = stars.alias("_").sql(sql).select("sk").execute()
|
|
516
|
+
skids = result["sk"].to_list()
|
|
517
|
+
stars = stars.filter(_.sk.isin(skids))
|
|
507
518
|
|
|
508
519
|
return stars
|
starplot/models/base.py
CHANGED
|
@@ -1,40 +1,86 @@
|
|
|
1
|
+
import json
|
|
2
|
+
|
|
1
3
|
from functools import cache
|
|
2
4
|
from typing import Optional
|
|
3
5
|
|
|
6
|
+
from shapely import to_geojson, from_geojson, Geometry
|
|
7
|
+
from shapely.geometry import Polygon, MultiPolygon, Point
|
|
8
|
+
|
|
9
|
+
from pydantic_core import core_schema
|
|
10
|
+
|
|
11
|
+
from pydantic import (
|
|
12
|
+
BaseModel,
|
|
13
|
+
computed_field,
|
|
14
|
+
)
|
|
4
15
|
from skyfield.api import position_of_radec, load_constellation_map
|
|
5
16
|
|
|
6
17
|
from starplot.mixins import CreateMapMixin, CreateOpticMixin
|
|
7
18
|
|
|
8
19
|
|
|
20
|
+
class ShapelyPydantic:
|
|
21
|
+
@classmethod
|
|
22
|
+
def validate(cls, field_value, info):
|
|
23
|
+
return field_value.is_valid
|
|
24
|
+
|
|
25
|
+
@classmethod
|
|
26
|
+
def __get_pydantic_core_schema__(cls, source, handler) -> core_schema.CoreSchema:
|
|
27
|
+
def validate_from_geojson(value: dict) -> Geometry:
|
|
28
|
+
return from_geojson(json.loads(value))
|
|
29
|
+
|
|
30
|
+
from_dict_schema = core_schema.chain_schema(
|
|
31
|
+
[
|
|
32
|
+
core_schema.dict_schema(),
|
|
33
|
+
core_schema.no_info_plain_validator_function(validate_from_geojson),
|
|
34
|
+
]
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
return core_schema.json_or_python_schema(
|
|
38
|
+
json_schema=from_dict_schema,
|
|
39
|
+
python_schema=core_schema.union_schema(
|
|
40
|
+
[
|
|
41
|
+
core_schema.is_instance_schema(Geometry),
|
|
42
|
+
from_dict_schema,
|
|
43
|
+
]
|
|
44
|
+
),
|
|
45
|
+
serialization=core_schema.plain_serializer_function_ser_schema(
|
|
46
|
+
lambda instance: json.loads(to_geojson(instance))
|
|
47
|
+
),
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class ShapelyPolygon(ShapelyPydantic, Polygon):
|
|
52
|
+
pass
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class ShapelyMultiPolygon(ShapelyPydantic, MultiPolygon):
|
|
56
|
+
pass
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class ShapelyPoint(ShapelyPydantic, Point):
|
|
60
|
+
pass
|
|
61
|
+
|
|
62
|
+
|
|
9
63
|
@cache
|
|
10
64
|
def constellation_at():
|
|
11
65
|
return load_constellation_map()
|
|
12
66
|
|
|
13
67
|
|
|
14
|
-
class SkyObject(CreateMapMixin, CreateOpticMixin):
|
|
68
|
+
class SkyObject(BaseModel, CreateMapMixin, CreateOpticMixin):
|
|
15
69
|
"""
|
|
16
70
|
Basic sky object model.
|
|
17
71
|
"""
|
|
18
72
|
|
|
19
73
|
ra: float
|
|
20
|
-
"""Right Ascension, in degrees (0
|
|
74
|
+
"""Right Ascension, in degrees (0 to 360)"""
|
|
21
75
|
|
|
22
76
|
dec: float
|
|
23
|
-
"""Declination, in degrees (-90
|
|
24
|
-
|
|
25
|
-
_constellation_id = None
|
|
26
|
-
|
|
27
|
-
constellation_id: Optional[str] = None
|
|
28
|
-
"""Identifier of the constellation that contains this object. The ID is the three-letter (all lowercase) abbreviation from the International Astronomical Union (IAU)."""
|
|
77
|
+
"""Declination, in degrees (-90 to 90)"""
|
|
29
78
|
|
|
30
|
-
|
|
31
|
-
self.ra = ra
|
|
32
|
-
self.dec = dec
|
|
33
|
-
if constellation_id:
|
|
34
|
-
self._constellation_id = constellation_id
|
|
79
|
+
_constellation_id: Optional[str] = None
|
|
35
80
|
|
|
81
|
+
@computed_field
|
|
36
82
|
@property
|
|
37
|
-
def constellation_id(self):
|
|
83
|
+
def constellation_id(self) -> str | None:
|
|
38
84
|
"""Identifier of the constellation that contains this object. The ID is the three-letter (all lowercase) abbreviation from the International Astronomical Union (IAU)."""
|
|
39
85
|
if not self._constellation_id:
|
|
40
86
|
pos = position_of_radec(self.ra, self.dec)
|
starplot/models/constellation.py
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
from typing import
|
|
1
|
+
from typing import Iterator
|
|
2
2
|
|
|
3
3
|
from ibis import _
|
|
4
|
-
from shapely import Polygon, MultiPolygon
|
|
5
4
|
|
|
6
|
-
from starplot.models.base import SkyObject
|
|
5
|
+
from starplot.models.base import SkyObject, ShapelyPolygon, ShapelyMultiPolygon
|
|
7
6
|
from starplot.data import constellations
|
|
8
7
|
|
|
9
8
|
|
|
@@ -21,29 +20,14 @@ class Constellation(SkyObject):
|
|
|
21
20
|
"""
|
|
22
21
|
|
|
23
22
|
name: str = None
|
|
24
|
-
"""Name"""
|
|
23
|
+
"""Name of constellation"""
|
|
25
24
|
|
|
26
25
|
star_hip_ids: list[int] = None
|
|
27
26
|
"""List of HIP ids for stars that are part of the _lines_ for this constellation."""
|
|
28
27
|
|
|
29
|
-
boundary:
|
|
28
|
+
boundary: ShapelyPolygon | ShapelyMultiPolygon = None
|
|
30
29
|
"""Shapely Polygon of the constellation's boundary. Right ascension coordinates are in degrees (0...360)."""
|
|
31
30
|
|
|
32
|
-
def __init__(
|
|
33
|
-
self,
|
|
34
|
-
ra: float,
|
|
35
|
-
dec: float,
|
|
36
|
-
iau_id: str,
|
|
37
|
-
name: str = None,
|
|
38
|
-
star_hip_ids: list[int] = None,
|
|
39
|
-
boundary: Polygon = None,
|
|
40
|
-
) -> None:
|
|
41
|
-
super().__init__(ra, dec, constellation_id=iau_id.lower())
|
|
42
|
-
self.iau_id = iau_id.lower()
|
|
43
|
-
self.name = name
|
|
44
|
-
self.star_hip_ids = star_hip_ids
|
|
45
|
-
self.boundary = boundary
|
|
46
|
-
|
|
47
31
|
def __repr__(self) -> str:
|
|
48
32
|
return f"Constellation(iau_id={self.iau_id}, name={self.name}, ra={self.ra}, dec={self.dec})"
|
|
49
33
|
|
|
@@ -55,7 +39,7 @@ class Constellation(SkyObject):
|
|
|
55
39
|
yield from_tuple(c)
|
|
56
40
|
|
|
57
41
|
@classmethod
|
|
58
|
-
def get(cls, **kwargs) -> "Constellation":
|
|
42
|
+
def get(cls, sql: str = None, **kwargs) -> "Constellation":
|
|
59
43
|
"""
|
|
60
44
|
Get a Constellation, by matching its attributes.
|
|
61
45
|
|
|
@@ -64,6 +48,7 @@ class Constellation(SkyObject):
|
|
|
64
48
|
hercules = Constellation.get(name="Hercules")
|
|
65
49
|
|
|
66
50
|
Args:
|
|
51
|
+
sql: SQL query for selecting constellation (table name is "_")
|
|
67
52
|
**kwargs: Attributes on the constellation you want to match
|
|
68
53
|
|
|
69
54
|
Raises: `ValueError` if more than one constellation is matched
|
|
@@ -73,7 +58,7 @@ class Constellation(SkyObject):
|
|
|
73
58
|
for k, v in kwargs.items():
|
|
74
59
|
filters.append(getattr(_, k) == v)
|
|
75
60
|
|
|
76
|
-
df = constellations.load(filters=filters).to_pandas()
|
|
61
|
+
df = constellations.load(filters=filters, sql=sql).to_pandas()
|
|
77
62
|
results = [from_tuple(c) for c in df.itertuples()]
|
|
78
63
|
|
|
79
64
|
if len(results) == 1:
|
|
@@ -87,18 +72,19 @@ class Constellation(SkyObject):
|
|
|
87
72
|
return None
|
|
88
73
|
|
|
89
74
|
@classmethod
|
|
90
|
-
def find(cls, where: list) -> list["Constellation"]:
|
|
75
|
+
def find(cls, where: list = None, sql: str = None) -> list["Constellation"]:
|
|
91
76
|
"""
|
|
92
77
|
Find Constellations
|
|
93
78
|
|
|
94
79
|
Args:
|
|
95
80
|
where: A list of expressions that determine which constellations to find. See [Selecting Objects](/reference-selecting-objects/) for details.
|
|
81
|
+
sql: SQL query for selecting constellations (table name is "_")
|
|
96
82
|
|
|
97
83
|
Returns:
|
|
98
84
|
List of Constellations that match all `where` expressions
|
|
99
85
|
|
|
100
86
|
"""
|
|
101
|
-
df = constellations.load(filters=where).to_pandas()
|
|
87
|
+
df = constellations.load(filters=where, sql=sql).to_pandas()
|
|
102
88
|
|
|
103
89
|
return [from_tuple(c) for c in df.itertuples()]
|
|
104
90
|
|
|
@@ -108,11 +94,13 @@ class Constellation(SkyObject):
|
|
|
108
94
|
|
|
109
95
|
|
|
110
96
|
def from_tuple(c: tuple) -> Constellation:
|
|
111
|
-
|
|
97
|
+
c = Constellation(
|
|
112
98
|
ra=c.ra,
|
|
113
99
|
dec=c.dec,
|
|
114
|
-
iau_id=c.iau_id,
|
|
100
|
+
iau_id=c.iau_id.lower(),
|
|
115
101
|
name=c.name,
|
|
116
102
|
star_hip_ids=c.star_hip_ids,
|
|
117
103
|
boundary=c.geometry,
|
|
118
104
|
)
|
|
105
|
+
c._constellation_id = c.iau_id
|
|
106
|
+
return c
|
starplot/models/dso.py
CHANGED
|
@@ -1,39 +1,80 @@
|
|
|
1
|
-
from typing import Optional,
|
|
1
|
+
from typing import Optional, Iterator
|
|
2
|
+
from enum import Enum
|
|
2
3
|
|
|
3
4
|
from ibis import _
|
|
4
|
-
from shapely.geometry import Polygon, MultiPolygon
|
|
5
5
|
|
|
6
6
|
from starplot.data.dsos import load
|
|
7
7
|
from starplot.mixins import CreateMapMixin, CreateOpticMixin
|
|
8
|
-
from starplot.models.base import SkyObject
|
|
8
|
+
from starplot.models.base import SkyObject, ShapelyPolygon, ShapelyMultiPolygon
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
class DsoType:
|
|
11
|
+
class DsoType(str, Enum):
|
|
12
12
|
"""
|
|
13
|
-
Type of deep sky object (
|
|
13
|
+
Type of deep sky object (DSO), as designated in OpenNGC
|
|
14
14
|
"""
|
|
15
15
|
|
|
16
16
|
STAR = "*"
|
|
17
|
+
"""Star"""
|
|
18
|
+
|
|
17
19
|
DOUBLE_STAR = "**"
|
|
20
|
+
"""Double star or multiple star system"""
|
|
21
|
+
|
|
18
22
|
ASSOCIATION_OF_STARS = "*Ass"
|
|
23
|
+
"""Association of stars"""
|
|
24
|
+
|
|
19
25
|
OPEN_CLUSTER = "OCl"
|
|
26
|
+
"""Open cluster of stars"""
|
|
27
|
+
|
|
20
28
|
GLOBULAR_CLUSTER = "GCl"
|
|
29
|
+
"""Globular cluster of stars"""
|
|
30
|
+
|
|
21
31
|
GALAXY = "G"
|
|
32
|
+
"""Galaxy"""
|
|
33
|
+
|
|
22
34
|
GALAXY_PAIR = "GPair"
|
|
35
|
+
"""Group of two galaxies"""
|
|
36
|
+
|
|
23
37
|
GALAXY_TRIPLET = "GTrpl"
|
|
38
|
+
"""Group of three galaxies"""
|
|
39
|
+
|
|
24
40
|
GROUP_OF_GALAXIES = "GGroup"
|
|
41
|
+
"""Group of more than three galaxies"""
|
|
42
|
+
|
|
25
43
|
NEBULA = "Neb"
|
|
44
|
+
"""Nebula"""
|
|
45
|
+
|
|
26
46
|
PLANETARY_NEBULA = "PN"
|
|
47
|
+
"""Planetary nebula"""
|
|
48
|
+
|
|
27
49
|
EMISSION_NEBULA = "EmN"
|
|
50
|
+
"""Emission Nebula"""
|
|
51
|
+
|
|
28
52
|
STAR_CLUSTER_NEBULA = "Cl+N"
|
|
53
|
+
"""Star cluster with nebulosity"""
|
|
54
|
+
|
|
29
55
|
REFLECTION_NEBULA = "RfN"
|
|
56
|
+
"""Reflection nebula"""
|
|
57
|
+
|
|
30
58
|
DARK_NEBULA = "DrkN"
|
|
59
|
+
"""Dark nebula"""
|
|
60
|
+
|
|
31
61
|
HII_IONIZED_REGION = "HII"
|
|
62
|
+
"""Hydrogen ionized region"""
|
|
63
|
+
|
|
32
64
|
SUPERNOVA_REMNANT = "SNR"
|
|
65
|
+
"""Supernova remnant"""
|
|
66
|
+
|
|
33
67
|
NOVA_STAR = "Nova"
|
|
68
|
+
"""Nova star"""
|
|
69
|
+
|
|
34
70
|
NONEXISTENT = "NonEx"
|
|
71
|
+
"""Non-existant object"""
|
|
72
|
+
|
|
35
73
|
UNKNOWN = "Other"
|
|
74
|
+
"""Unknown type of object"""
|
|
75
|
+
|
|
36
76
|
DUPLICATE_RECORD = "Dup"
|
|
77
|
+
"""Duplicate record of another object"""
|
|
37
78
|
|
|
38
79
|
|
|
39
80
|
class DSO(SkyObject, CreateMapMixin, CreateOpticMixin):
|
|
@@ -78,39 +119,9 @@ class DSO(SkyObject, CreateMapMixin, CreateOpticMixin):
|
|
|
78
119
|
Index Catalogue (IC) identifier. *Note that this field is a string, to support objects like '4974 NED01'.*
|
|
79
120
|
"""
|
|
80
121
|
|
|
81
|
-
geometry:
|
|
122
|
+
geometry: ShapelyPolygon | ShapelyMultiPolygon = None
|
|
82
123
|
"""Shapely Polygon of the DSO's extent. Right ascension coordinates are in degrees (0...360)."""
|
|
83
124
|
|
|
84
|
-
def __init__(
|
|
85
|
-
self,
|
|
86
|
-
ra: float,
|
|
87
|
-
dec: float,
|
|
88
|
-
name: str,
|
|
89
|
-
type: DsoType,
|
|
90
|
-
magnitude: float = None,
|
|
91
|
-
maj_ax: float = None,
|
|
92
|
-
min_ax: float = None,
|
|
93
|
-
angle: float = None,
|
|
94
|
-
size: float = None,
|
|
95
|
-
m: str = None,
|
|
96
|
-
ngc: str = None,
|
|
97
|
-
ic: str = None,
|
|
98
|
-
geometry: Union[Polygon, MultiPolygon] = None,
|
|
99
|
-
constellation_id: str = None,
|
|
100
|
-
) -> None:
|
|
101
|
-
super().__init__(ra, dec, constellation_id)
|
|
102
|
-
self.name = name
|
|
103
|
-
self.type = type
|
|
104
|
-
self.magnitude = magnitude
|
|
105
|
-
self.maj_ax = maj_ax
|
|
106
|
-
self.min_ax = min_ax
|
|
107
|
-
self.angle = angle
|
|
108
|
-
self.size = size
|
|
109
|
-
self.m = m
|
|
110
|
-
self.ngc = ngc
|
|
111
|
-
self.ic = ic
|
|
112
|
-
self.geometry = geometry
|
|
113
|
-
|
|
114
125
|
def __repr__(self) -> str:
|
|
115
126
|
return f"DSO(name={self.name}, magnitude={self.magnitude})"
|
|
116
127
|
|
|
@@ -122,7 +133,7 @@ class DSO(SkyObject, CreateMapMixin, CreateOpticMixin):
|
|
|
122
133
|
yield from_tuple(d)
|
|
123
134
|
|
|
124
135
|
@classmethod
|
|
125
|
-
def get(cls, **kwargs) -> "DSO":
|
|
136
|
+
def get(cls, sql: str = None, **kwargs) -> "DSO":
|
|
126
137
|
"""
|
|
127
138
|
Get a DSO, by matching its attributes.
|
|
128
139
|
|
|
@@ -131,6 +142,7 @@ class DSO(SkyObject, CreateMapMixin, CreateOpticMixin):
|
|
|
131
142
|
d = DSO.get(m=13)
|
|
132
143
|
|
|
133
144
|
Args:
|
|
145
|
+
sql: SQL query for selecting DSO (table name is "_")
|
|
134
146
|
**kwargs: Attributes on the DSO you want to match
|
|
135
147
|
|
|
136
148
|
Raises: `ValueError` if more than one DSO is matched
|
|
@@ -140,7 +152,7 @@ class DSO(SkyObject, CreateMapMixin, CreateOpticMixin):
|
|
|
140
152
|
for k, v in kwargs.items():
|
|
141
153
|
filters.append(getattr(_, k) == v)
|
|
142
154
|
|
|
143
|
-
df = load(filters=filters).to_pandas()
|
|
155
|
+
df = load(filters=filters, sql=sql).to_pandas()
|
|
144
156
|
|
|
145
157
|
results = [from_tuple(d) for d in df.itertuples()]
|
|
146
158
|
|
|
@@ -155,18 +167,19 @@ class DSO(SkyObject, CreateMapMixin, CreateOpticMixin):
|
|
|
155
167
|
return None
|
|
156
168
|
|
|
157
169
|
@classmethod
|
|
158
|
-
def find(cls, where: list) -> list["DSO"]:
|
|
170
|
+
def find(cls, where: list = None, sql: str = None) -> list["DSO"]:
|
|
159
171
|
"""
|
|
160
172
|
Find DSOs
|
|
161
173
|
|
|
162
174
|
Args:
|
|
163
175
|
where: A list of expressions that determine which DSOs to find. See [Selecting Objects](/reference-selecting-objects/) for details.
|
|
176
|
+
sql: SQL query for selecting DSOs (table name is "_")
|
|
164
177
|
|
|
165
178
|
Returns:
|
|
166
179
|
List of DSOs that match all `where` expressions
|
|
167
180
|
|
|
168
181
|
"""
|
|
169
|
-
df = load(filters=where).to_pandas()
|
|
182
|
+
df = load(filters=where, sql=sql).to_pandas()
|
|
170
183
|
return [from_tuple(d) for d in df.itertuples()]
|
|
171
184
|
|
|
172
185
|
|
|
@@ -185,8 +198,8 @@ def from_tuple(d: tuple) -> DSO:
|
|
|
185
198
|
ngc=d.ngc,
|
|
186
199
|
ic=d.ic,
|
|
187
200
|
geometry=d.geometry,
|
|
188
|
-
constellation_id=d.constellation_id,
|
|
189
201
|
)
|
|
202
|
+
dso._constellation_id = d.constellation_id
|
|
190
203
|
dso._row_id = getattr(d, "rowid", None)
|
|
191
204
|
return dso
|
|
192
205
|
|
starplot/models/moon.py
CHANGED
|
@@ -4,10 +4,9 @@ from enum import Enum
|
|
|
4
4
|
import numpy as np
|
|
5
5
|
from skyfield.api import Angle, wgs84
|
|
6
6
|
from skyfield import almanac
|
|
7
|
-
from shapely import Polygon
|
|
8
7
|
|
|
9
8
|
from starplot.data import load
|
|
10
|
-
from starplot.models.base import SkyObject
|
|
9
|
+
from starplot.models.base import SkyObject, ShapelyPolygon
|
|
11
10
|
from starplot.geometry import circle
|
|
12
11
|
from starplot.utils import dt_or_now
|
|
13
12
|
|
|
@@ -35,7 +34,7 @@ class Moon(SkyObject):
|
|
|
35
34
|
"""Date/time of moon's position"""
|
|
36
35
|
|
|
37
36
|
apparent_size: float
|
|
38
|
-
"""Apparent size (degrees)"""
|
|
37
|
+
"""Apparent size in the sky (degrees)"""
|
|
39
38
|
|
|
40
39
|
phase_angle: float
|
|
41
40
|
"""Angle of the moon from the Sun (degrees)"""
|
|
@@ -44,31 +43,10 @@ class Moon(SkyObject):
|
|
|
44
43
|
"""Description of the moon's phase. The Moon will be considered New/Full/Quarter if it's within 12 hours of that precise phase."""
|
|
45
44
|
|
|
46
45
|
illumination: float
|
|
47
|
-
"""Percent of illumination (0
|
|
48
|
-
|
|
49
|
-
geometry:
|
|
50
|
-
"""Shapely Polygon of the moon's extent. Right ascension coordinates are in degrees (0
|
|
51
|
-
|
|
52
|
-
def __init__(
|
|
53
|
-
self,
|
|
54
|
-
ra: float,
|
|
55
|
-
dec: float,
|
|
56
|
-
name: str,
|
|
57
|
-
dt: datetime,
|
|
58
|
-
apparent_size: float,
|
|
59
|
-
phase_angle: float,
|
|
60
|
-
phase_description: str,
|
|
61
|
-
illumination: str,
|
|
62
|
-
geometry: Polygon = None,
|
|
63
|
-
) -> None:
|
|
64
|
-
super().__init__(ra, dec)
|
|
65
|
-
self.name = name
|
|
66
|
-
self.dt = dt
|
|
67
|
-
self.apparent_size = apparent_size
|
|
68
|
-
self.phase_angle = phase_angle
|
|
69
|
-
self.phase_description = phase_description
|
|
70
|
-
self.illumination = illumination
|
|
71
|
-
self.geometry = geometry
|
|
46
|
+
"""Percent of illumination (0 to 1)"""
|
|
47
|
+
|
|
48
|
+
geometry: ShapelyPolygon = None
|
|
49
|
+
"""Shapely Polygon of the moon's extent. Right ascension coordinates are in degrees (0 to 360)."""
|
|
72
50
|
|
|
73
51
|
@classmethod
|
|
74
52
|
def get(
|
starplot/models/planet.py
CHANGED
|
@@ -5,10 +5,9 @@ from typing import Iterator
|
|
|
5
5
|
import numpy as np
|
|
6
6
|
|
|
7
7
|
from skyfield.api import Angle, wgs84
|
|
8
|
-
from shapely import Polygon
|
|
9
8
|
|
|
10
9
|
from starplot.data import load
|
|
11
|
-
from starplot.models.base import SkyObject
|
|
10
|
+
from starplot.models.base import SkyObject, ShapelyPolygon
|
|
12
11
|
from starplot.geometry import circle
|
|
13
12
|
from starplot.utils import dt_or_now
|
|
14
13
|
|
|
@@ -72,24 +71,9 @@ class Planet(SkyObject):
|
|
|
72
71
|
apparent_size: float
|
|
73
72
|
"""Apparent size (degrees)"""
|
|
74
73
|
|
|
75
|
-
geometry:
|
|
74
|
+
geometry: ShapelyPolygon = None
|
|
76
75
|
"""Shapely Polygon of the planet's extent. Right ascension coordinates are in degrees (0...360)."""
|
|
77
76
|
|
|
78
|
-
def __init__(
|
|
79
|
-
self,
|
|
80
|
-
ra: float,
|
|
81
|
-
dec: float,
|
|
82
|
-
name: str,
|
|
83
|
-
dt: datetime,
|
|
84
|
-
apparent_size: float,
|
|
85
|
-
geometry: Polygon = None,
|
|
86
|
-
) -> None:
|
|
87
|
-
super().__init__(ra, dec)
|
|
88
|
-
self.name = name
|
|
89
|
-
self.dt = dt
|
|
90
|
-
self.apparent_size = apparent_size
|
|
91
|
-
self.geometry = geometry
|
|
92
|
-
|
|
93
77
|
@classmethod
|
|
94
78
|
def all(
|
|
95
79
|
cls,
|