starplot 0.15.6__py2.py3-none-any.whl → 0.15.8__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 +1 -1
- 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 +2 -0
- starplot/optics.py +81 -40
- starplot/plotters/constellations.py +3 -1
- starplot/plotters/dsos.py +23 -12
- starplot/plotters/stars.py +17 -2
- starplot/styles/base.py +1 -0
- {starplot-0.15.6.dist-info → starplot-0.15.8.dist-info}/METADATA +1 -1
- {starplot-0.15.6.dist-info → starplot-0.15.8.dist-info}/RECORD +23 -23
- {starplot-0.15.6.dist-info → starplot-0.15.8.dist-info}/WHEEL +0 -0
- {starplot-0.15.6.dist-info → starplot-0.15.8.dist-info}/entry_points.txt +0 -0
- {starplot-0.15.6.dist-info → starplot-0.15.8.dist-info}/licenses/LICENSE +0 -0
starplot/__init__.py
CHANGED
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,
|
starplot/models/star.py
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import math
|
|
2
|
-
from typing import Optional, Union, Iterator
|
|
2
|
+
from typing import Optional, Union, Iterator, Any
|
|
3
3
|
|
|
4
4
|
import numpy as np
|
|
5
|
-
from shapely import Point
|
|
6
5
|
from ibis import _
|
|
6
|
+
from pydantic import field_validator
|
|
7
7
|
|
|
8
|
-
from starplot.models.base import SkyObject
|
|
8
|
+
from starplot.models.base import SkyObject, ShapelyPoint
|
|
9
9
|
from starplot.data.stars import StarCatalog, load as _load_stars
|
|
10
10
|
|
|
11
11
|
|
|
@@ -38,38 +38,20 @@ class Star(SkyObject):
|
|
|
38
38
|
flamsteed: Optional[int] = None
|
|
39
39
|
"""Flamsteed number, if available"""
|
|
40
40
|
|
|
41
|
-
geometry:
|
|
41
|
+
geometry: ShapelyPoint = None
|
|
42
42
|
"""Shapely Point of the star's position. Right ascension coordinates are in degrees (0...360)."""
|
|
43
43
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
constellation_id: str = None,
|
|
56
|
-
bayer: str = None,
|
|
57
|
-
flamsteed: int = None,
|
|
58
|
-
) -> None:
|
|
59
|
-
super().__init__(ra, dec, constellation_id)
|
|
60
|
-
self.magnitude = magnitude
|
|
61
|
-
self.bv = bv
|
|
62
|
-
self.hip = hip if hip is not None and np.isfinite(hip) else None
|
|
63
|
-
self.name = name
|
|
64
|
-
self.tyc = tyc
|
|
65
|
-
self.ccdm = ccdm
|
|
66
|
-
self.geometry = geometry
|
|
67
|
-
|
|
68
|
-
if bayer:
|
|
69
|
-
self.bayer = bayer
|
|
70
|
-
|
|
71
|
-
if flamsteed and not math.isnan(flamsteed):
|
|
72
|
-
self.flamsteed = int(flamsteed)
|
|
44
|
+
@field_validator("flamsteed", "hip", mode="before")
|
|
45
|
+
@classmethod
|
|
46
|
+
def nan(cls, value: int) -> int:
|
|
47
|
+
if not value or math.isnan(value):
|
|
48
|
+
return None
|
|
49
|
+
|
|
50
|
+
return int(value)
|
|
51
|
+
|
|
52
|
+
def model_post_init(self, context: Any) -> None:
|
|
53
|
+
self.bayer = self.bayer or None
|
|
54
|
+
self.hip = self.hip if self.hip is not None and np.isfinite(self.hip) else None
|
|
73
55
|
|
|
74
56
|
def __repr__(self) -> str:
|
|
75
57
|
return f"Star(hip={self.hip}, tyc={self.tyc}, magnitude={self.magnitude}, ra={self.ra}, dec={self.dec})"
|
|
@@ -83,7 +65,7 @@ class Star(SkyObject):
|
|
|
83
65
|
|
|
84
66
|
@classmethod
|
|
85
67
|
def get(
|
|
86
|
-
cls, catalog: StarCatalog = StarCatalog.BIG_SKY_MAG11, **kwargs
|
|
68
|
+
cls, catalog: StarCatalog = StarCatalog.BIG_SKY_MAG11, sql: str = None, **kwargs
|
|
87
69
|
) -> Union["Star", None]:
|
|
88
70
|
"""
|
|
89
71
|
Get a Star, by matching its attributes as specified in `**kwargs`
|
|
@@ -94,6 +76,7 @@ class Star(SkyObject):
|
|
|
94
76
|
|
|
95
77
|
Args:
|
|
96
78
|
catalog: The catalog of stars to use: "big-sky-mag11", or "big-sky" -- see [`StarCatalog`](/reference-data/#starplot.data.stars.StarCatalog) for details
|
|
79
|
+
sql: SQL query for selecting star (table name is "_")
|
|
97
80
|
**kwargs: Attributes on the star you want to match
|
|
98
81
|
|
|
99
82
|
Raises: `ValueError` if more than one star is matched
|
|
@@ -109,6 +92,7 @@ class Star(SkyObject):
|
|
|
109
92
|
df = _load_stars(
|
|
110
93
|
catalog=catalog,
|
|
111
94
|
filters=filters,
|
|
95
|
+
sql=sql,
|
|
112
96
|
).to_pandas()
|
|
113
97
|
|
|
114
98
|
results = [from_tuple(s) for s in df.itertuples()]
|
|
@@ -125,13 +109,17 @@ class Star(SkyObject):
|
|
|
125
109
|
|
|
126
110
|
@classmethod
|
|
127
111
|
def find(
|
|
128
|
-
cls,
|
|
112
|
+
cls,
|
|
113
|
+
where: list = None,
|
|
114
|
+
sql: str = None,
|
|
115
|
+
catalog: StarCatalog = StarCatalog.BIG_SKY_MAG11,
|
|
129
116
|
) -> list["Star"]:
|
|
130
117
|
"""
|
|
131
118
|
Find Stars
|
|
132
119
|
|
|
133
120
|
Args:
|
|
134
121
|
where: A list of expressions that determine which stars to find. See [Selecting Objects](/reference-selecting-objects/) for details.
|
|
122
|
+
sql: SQL query for selecting stars (table name is "_")
|
|
135
123
|
catalog: The catalog of stars to use: "big-sky-mag11", or "big-sky" -- see [`StarCatalog`](/reference-data/#starplot.data.stars.StarCatalog) for details
|
|
136
124
|
|
|
137
125
|
Returns:
|
|
@@ -141,6 +129,7 @@ class Star(SkyObject):
|
|
|
141
129
|
df = _load_stars(
|
|
142
130
|
catalog=catalog,
|
|
143
131
|
filters=where,
|
|
132
|
+
sql=sql,
|
|
144
133
|
).to_pandas()
|
|
145
134
|
|
|
146
135
|
return [from_tuple(s) for s in df.itertuples()]
|
|
@@ -157,10 +146,10 @@ def from_tuple(star: tuple) -> Star:
|
|
|
157
146
|
ccdm=getattr(star, "ccdm", None),
|
|
158
147
|
name=getattr(star, "name", None),
|
|
159
148
|
geometry=star.geometry,
|
|
160
|
-
constellation_id=getattr(star, "constellation", None),
|
|
161
149
|
bayer=getattr(star, "bayer", None),
|
|
162
150
|
flamsteed=getattr(star, "flamsteed", None),
|
|
163
151
|
)
|
|
152
|
+
s._constellation_id = getattr(star, "constellation", None)
|
|
164
153
|
s._row_id = getattr(star, "rowid", None)
|
|
165
154
|
|
|
166
155
|
return s
|
starplot/models/sun.py
CHANGED
|
@@ -2,10 +2,9 @@ from datetime import datetime
|
|
|
2
2
|
|
|
3
3
|
import numpy as np
|
|
4
4
|
from skyfield.api import Angle, wgs84
|
|
5
|
-
from shapely import Polygon
|
|
6
5
|
|
|
7
6
|
from starplot.data import load
|
|
8
|
-
from starplot.models.base import SkyObject
|
|
7
|
+
from starplot.models.base import SkyObject, ShapelyPolygon
|
|
9
8
|
from starplot.geometry import circle
|
|
10
9
|
from starplot.utils import dt_or_now
|
|
11
10
|
|
|
@@ -22,24 +21,9 @@ class Sun(SkyObject):
|
|
|
22
21
|
apparent_size: float
|
|
23
22
|
"""Apparent size (degrees)"""
|
|
24
23
|
|
|
25
|
-
geometry:
|
|
24
|
+
geometry: ShapelyPolygon = None
|
|
26
25
|
"""Shapely Polygon of the Sun's extent. Right ascension coordinates are in degrees (0...360)."""
|
|
27
26
|
|
|
28
|
-
def __init__(
|
|
29
|
-
self,
|
|
30
|
-
ra: float,
|
|
31
|
-
dec: float,
|
|
32
|
-
name: str,
|
|
33
|
-
dt: datetime,
|
|
34
|
-
apparent_size: float,
|
|
35
|
-
geometry: Polygon = None,
|
|
36
|
-
) -> None:
|
|
37
|
-
super().__init__(ra, dec)
|
|
38
|
-
self.name = name
|
|
39
|
-
self.dt = dt
|
|
40
|
-
self.apparent_size = apparent_size
|
|
41
|
-
self.geometry = geometry
|
|
42
|
-
|
|
43
27
|
@classmethod
|
|
44
28
|
def get(
|
|
45
29
|
cls,
|
starplot/optic.py
CHANGED
|
@@ -220,6 +220,7 @@ class OpticPlot(BasePlot, ExtentMaskMixin, StarPlotterMixin, DsoPlotterMixin):
|
|
|
220
220
|
legend_label: str = "Star",
|
|
221
221
|
bayer_labels: bool = False,
|
|
222
222
|
flamsteed_labels: bool = False,
|
|
223
|
+
sql: str = None,
|
|
223
224
|
*args,
|
|
224
225
|
**kwargs,
|
|
225
226
|
):
|
|
@@ -239,6 +240,7 @@ class OpticPlot(BasePlot, ExtentMaskMixin, StarPlotterMixin, DsoPlotterMixin):
|
|
|
239
240
|
legend_label: Label for stars in the legend. If `None`, then they will not be in the legend.
|
|
240
241
|
bayer_labels: If True, then Bayer labels for stars will be plotted.
|
|
241
242
|
flamsteed_labels: If True, then Flamsteed number labels for stars will be plotted.
|
|
243
|
+
sql: SQL query for selecting stars (table name is `_`). This query will be applied _after_ any filters in the `where` kwarg.
|
|
242
244
|
"""
|
|
243
245
|
optic_star_multiplier = self.FIELD_OF_VIEW_MAX / self.optic.true_fov
|
|
244
246
|
size_fn_mx = None
|
starplot/optics.py
CHANGED
|
@@ -3,18 +3,15 @@ import math
|
|
|
3
3
|
from abc import ABC, abstractmethod
|
|
4
4
|
|
|
5
5
|
import pyproj
|
|
6
|
-
|
|
7
6
|
from matplotlib import patches
|
|
7
|
+
from pydantic import BaseModel, computed_field
|
|
8
8
|
|
|
9
9
|
from starplot.utils import in_circle
|
|
10
10
|
|
|
11
11
|
|
|
12
|
-
class Optic(ABC):
|
|
12
|
+
class Optic(BaseModel, ABC):
|
|
13
13
|
"""Abstract class for defining Optics."""
|
|
14
14
|
|
|
15
|
-
def __init__(self) -> "Optic":
|
|
16
|
-
pass
|
|
17
|
-
|
|
18
15
|
def __str__(self):
|
|
19
16
|
return "Optic"
|
|
20
17
|
|
|
@@ -70,18 +67,34 @@ class Scope(Optic):
|
|
|
70
67
|
Scope: A new instance of a Scope optic
|
|
71
68
|
"""
|
|
72
69
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
70
|
+
focal_length: float
|
|
71
|
+
"""Focal length (mm) of the telescope"""
|
|
72
|
+
|
|
73
|
+
eyepiece_focal_length: float
|
|
74
|
+
"""Focal length (mm) of the eyepiece"""
|
|
75
|
+
|
|
76
|
+
eyepiece_fov: float
|
|
77
|
+
"""Field of view (degrees) of the eyepiece"""
|
|
78
|
+
|
|
79
|
+
@computed_field
|
|
80
|
+
@property
|
|
81
|
+
def magnification(self) -> float:
|
|
82
|
+
"""Magnification calculated from the telescope's focal length and eyepiece focal length"""
|
|
83
|
+
return self.focal_length / self.eyepiece_focal_length
|
|
84
|
+
|
|
85
|
+
@computed_field
|
|
86
|
+
@property
|
|
87
|
+
def true_fov(self) -> float:
|
|
88
|
+
"""True field of view of telescope"""
|
|
89
|
+
return self.eyepiece_fov / self.magnification
|
|
90
|
+
|
|
91
|
+
@computed_field
|
|
92
|
+
@property
|
|
93
|
+
def radius(self) -> float:
|
|
94
|
+
return self._compute_radius(self.true_fov / 2)
|
|
82
95
|
|
|
83
96
|
def __str__(self):
|
|
84
|
-
return f"{self.focal_length}mm w/ {self.eyepiece_focal_length}mm ({self.magnification:.0f}x) @ {self.eyepiece_fov:.0f}\N{DEGREE SIGN} = {self.true_fov:.2f}\N{DEGREE SIGN} TFOV"
|
|
97
|
+
return f"{self.focal_length:.0f}mm w/ {self.eyepiece_focal_length:.0f}mm ({self.magnification:.0f}x) @ {self.eyepiece_fov:.0f}\N{DEGREE SIGN} = {self.true_fov:.2f}\N{DEGREE SIGN} TFOV"
|
|
85
98
|
|
|
86
99
|
@property
|
|
87
100
|
def xlim(self):
|
|
@@ -172,14 +185,25 @@ class Binoculars(Optic):
|
|
|
172
185
|
|
|
173
186
|
"""
|
|
174
187
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
188
|
+
magnification: float
|
|
189
|
+
"""Magnification of the binoculars"""
|
|
190
|
+
|
|
191
|
+
fov: float
|
|
192
|
+
"""Apparent field of view of the binoculars"""
|
|
193
|
+
|
|
194
|
+
@computed_field
|
|
195
|
+
@property
|
|
196
|
+
def true_fov(self) -> float:
|
|
197
|
+
"""True field of view of binoculars"""
|
|
198
|
+
return self.fov / self.magnification
|
|
199
|
+
|
|
200
|
+
@computed_field
|
|
201
|
+
@property
|
|
202
|
+
def radius(self) -> float:
|
|
203
|
+
return self._compute_radius(self.true_fov / 2)
|
|
180
204
|
|
|
181
205
|
def __str__(self):
|
|
182
|
-
return f"{self.magnification}x @ {self.
|
|
206
|
+
return f"{self.magnification:.0f}x @ {self.fov:.0f}\N{DEGREE SIGN} = {self.true_fov}\N{DEGREE SIGN}"
|
|
183
207
|
|
|
184
208
|
@property
|
|
185
209
|
def xlim(self):
|
|
@@ -225,39 +249,56 @@ class Camera(Optic):
|
|
|
225
249
|
sensor_height: Height of camera sensor (mm)
|
|
226
250
|
sensor_width: Width of camera sensor (mm)
|
|
227
251
|
lens_focal_length: Focal length of camera lens (mm)
|
|
228
|
-
rotation: Angle (degrees) to rotate camera
|
|
252
|
+
rotation: Angle (degrees) to rotate camera, defaults to 0
|
|
229
253
|
|
|
230
254
|
Returns:
|
|
231
255
|
Camera: A new instance of a Camera optic
|
|
232
256
|
|
|
233
257
|
"""
|
|
234
258
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
259
|
+
sensor_height: float
|
|
260
|
+
"""Height (mm) of camera's sensor"""
|
|
261
|
+
|
|
262
|
+
sensor_width: float
|
|
263
|
+
"""Width (mm) of camera's sensor"""
|
|
264
|
+
|
|
265
|
+
lens_focal_length: float
|
|
266
|
+
"""Focal length (mm) of the camera's lens"""
|
|
267
|
+
|
|
268
|
+
rotation: float = 0
|
|
269
|
+
"""Angle (degrees) to rotate the camera"""
|
|
270
|
+
|
|
271
|
+
@computed_field
|
|
272
|
+
@property
|
|
273
|
+
def true_fov_x(self) -> float:
|
|
274
|
+
return 2 * math.degrees(
|
|
247
275
|
math.atan(self.sensor_width / (2 * self.lens_focal_length))
|
|
248
276
|
)
|
|
249
|
-
|
|
277
|
+
|
|
278
|
+
@computed_field
|
|
279
|
+
@property
|
|
280
|
+
def true_fov_y(self) -> float:
|
|
281
|
+
return 2 * math.degrees(
|
|
250
282
|
math.atan(self.sensor_height / (2 * self.lens_focal_length))
|
|
251
283
|
)
|
|
252
|
-
self.true_fov = max(self.true_fov_x, self.true_fov_y)
|
|
253
284
|
|
|
254
|
-
|
|
255
|
-
|
|
285
|
+
@computed_field
|
|
286
|
+
@property
|
|
287
|
+
def true_fov(self) -> float:
|
|
288
|
+
return max(self.true_fov_x, self.true_fov_y)
|
|
289
|
+
|
|
290
|
+
@computed_field
|
|
291
|
+
@property
|
|
292
|
+
def radius_x(self) -> float:
|
|
293
|
+
return self._compute_radius(self.true_fov_x / 2)
|
|
256
294
|
|
|
257
|
-
|
|
295
|
+
@computed_field
|
|
296
|
+
@property
|
|
297
|
+
def radius_y(self) -> float:
|
|
298
|
+
return self._compute_radius(self.true_fov_y / 2)
|
|
258
299
|
|
|
259
300
|
def __str__(self):
|
|
260
|
-
return f"{self.sensor_width}x{self.sensor_height} w/ {self.lens_focal_length}mm lens = {self.true_fov_x:.2f}\N{DEGREE SIGN} x {self.true_fov_y:.2f}\N{DEGREE SIGN}"
|
|
301
|
+
return f"{self.sensor_width}x{self.sensor_height} w/ {self.lens_focal_length:.0f}mm lens = {self.true_fov_x:.2f}\N{DEGREE SIGN} x {self.true_fov_y:.2f}\N{DEGREE SIGN}"
|
|
261
302
|
|
|
262
303
|
@property
|
|
263
304
|
def xlim(self):
|
|
@@ -65,6 +65,7 @@ class ConstellationPlotterMixin:
|
|
|
65
65
|
self,
|
|
66
66
|
style: LineStyle = None,
|
|
67
67
|
where: list = None,
|
|
68
|
+
sql: str = None,
|
|
68
69
|
):
|
|
69
70
|
"""Plots the constellation lines **only**. To plot constellation borders and/or labels, see separate functions for them.
|
|
70
71
|
|
|
@@ -73,6 +74,7 @@ class ConstellationPlotterMixin:
|
|
|
73
74
|
Args:
|
|
74
75
|
style: Styling of the constellations. If None, then the plot's style (specified when creating the plot) will be used
|
|
75
76
|
where: A list of expressions that determine which constellations to plot. See [Selecting Objects](/reference-selecting-objects/) for details.
|
|
77
|
+
sql: SQL query for selecting constellations (table name is `_`). This query will be applied _after_ any filters in the `where` kwarg.
|
|
76
78
|
"""
|
|
77
79
|
self.logger.debug("Plotting constellation lines...")
|
|
78
80
|
|
|
@@ -80,7 +82,7 @@ class ConstellationPlotterMixin:
|
|
|
80
82
|
ctr = 0
|
|
81
83
|
|
|
82
84
|
extent = self._extent_mask()
|
|
83
|
-
results = condata.load(extent=extent, filters=where)
|
|
85
|
+
results = condata.load(extent=extent, filters=where, sql=sql)
|
|
84
86
|
constellations_df = results.to_pandas()
|
|
85
87
|
|
|
86
88
|
if constellations_df.empty:
|
starplot/plotters/dsos.py
CHANGED
|
@@ -44,7 +44,7 @@ class DsoPlotterMixin:
|
|
|
44
44
|
This is just a small wrapper around the `dsos()` function, so any `kwargs` will be passed through.
|
|
45
45
|
"""
|
|
46
46
|
where = kwargs.pop("where", [])
|
|
47
|
-
where.append(_.type == DsoType.OPEN_CLUSTER)
|
|
47
|
+
where.append(_.type == DsoType.OPEN_CLUSTER.value)
|
|
48
48
|
self.dsos(where=where, **kwargs)
|
|
49
49
|
|
|
50
50
|
def globular_clusters(self, **kwargs):
|
|
@@ -54,7 +54,7 @@ class DsoPlotterMixin:
|
|
|
54
54
|
This is just a small wrapper around the `dsos()` function, so any `kwargs` will be passed through.
|
|
55
55
|
"""
|
|
56
56
|
where = kwargs.pop("where", [])
|
|
57
|
-
where.append(_.type == DsoType.GLOBULAR_CLUSTER)
|
|
57
|
+
where.append(_.type == DsoType.GLOBULAR_CLUSTER.value)
|
|
58
58
|
self.dsos(where=where, **kwargs)
|
|
59
59
|
|
|
60
60
|
def galaxies(self, **kwargs):
|
|
@@ -68,9 +68,9 @@ class DsoPlotterMixin:
|
|
|
68
68
|
This is just a small wrapper around the `dsos()` function, so any `kwargs` will be passed through.
|
|
69
69
|
"""
|
|
70
70
|
galaxy_types = [
|
|
71
|
-
DsoType.GALAXY,
|
|
72
|
-
DsoType.GALAXY_PAIR,
|
|
73
|
-
DsoType.GALAXY_TRIPLET,
|
|
71
|
+
DsoType.GALAXY.value,
|
|
72
|
+
DsoType.GALAXY_PAIR.value,
|
|
73
|
+
DsoType.GALAXY_TRIPLET.value,
|
|
74
74
|
]
|
|
75
75
|
where = kwargs.pop("where", [])
|
|
76
76
|
where.append(_.type.isin(galaxy_types))
|
|
@@ -92,12 +92,12 @@ class DsoPlotterMixin:
|
|
|
92
92
|
This is just a small wrapper around the `dsos()` function, so any `kwargs` will be passed through.
|
|
93
93
|
"""
|
|
94
94
|
nebula_types = [
|
|
95
|
-
DsoType.NEBULA,
|
|
96
|
-
DsoType.PLANETARY_NEBULA,
|
|
97
|
-
DsoType.EMISSION_NEBULA,
|
|
98
|
-
DsoType.STAR_CLUSTER_NEBULA,
|
|
99
|
-
DsoType.REFLECTION_NEBULA,
|
|
100
|
-
DsoType.HII_IONIZED_REGION,
|
|
95
|
+
DsoType.NEBULA.value,
|
|
96
|
+
DsoType.PLANETARY_NEBULA.value,
|
|
97
|
+
DsoType.EMISSION_NEBULA.value,
|
|
98
|
+
DsoType.STAR_CLUSTER_NEBULA.value,
|
|
99
|
+
DsoType.REFLECTION_NEBULA.value,
|
|
100
|
+
DsoType.HII_IONIZED_REGION.value,
|
|
101
101
|
]
|
|
102
102
|
where = kwargs.pop("where", [])
|
|
103
103
|
where.append(_.type.isin(nebula_types))
|
|
@@ -113,6 +113,8 @@ class DsoPlotterMixin:
|
|
|
113
113
|
legend_labels: Mapping[DsoType, str] = DSO_LEGEND_LABELS,
|
|
114
114
|
alpha_fn: Callable[[DSO], float] = None,
|
|
115
115
|
label_fn: Callable[[DSO], str] = None,
|
|
116
|
+
sql: str = None,
|
|
117
|
+
sql_labels: str = None,
|
|
116
118
|
):
|
|
117
119
|
"""
|
|
118
120
|
Plots Deep Sky Objects (DSOs), from OpenNGC
|
|
@@ -125,6 +127,8 @@ class DsoPlotterMixin:
|
|
|
125
127
|
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`.
|
|
126
128
|
alpha_fn: Callable for calculating the alpha value (aka "opacity") of each DSO. If `None`, then the marker style's alpha will be used.
|
|
127
129
|
label_fn: Callable for determining the label of each DSO. If `None`, then the names in the `labels` kwarg will be used.
|
|
130
|
+
sql: SQL query for selecting DSOs (table name is `_`). This query will be applied _after_ any filters in the `where` kwarg.
|
|
131
|
+
sql_labels: SQL query for selecting DSOs that will be labeled (table name is `_`). Applied _after_ any filters in the `where_labels` kwarg.
|
|
128
132
|
"""
|
|
129
133
|
|
|
130
134
|
# TODO: add kwarg styles
|
|
@@ -143,12 +147,19 @@ class DsoPlotterMixin:
|
|
|
143
147
|
legend_labels = {**DSO_LEGEND_LABELS, **legend_labels}
|
|
144
148
|
|
|
145
149
|
extent = self._extent_mask()
|
|
146
|
-
dso_results = load(extent=extent, filters=where)
|
|
150
|
+
dso_results = load(extent=extent, filters=where, sql=sql)
|
|
147
151
|
|
|
148
152
|
dso_results_labeled = dso_results
|
|
149
153
|
for f in where_labels:
|
|
150
154
|
dso_results_labeled = dso_results_labeled.filter(f)
|
|
151
155
|
|
|
156
|
+
if sql_labels:
|
|
157
|
+
result = (
|
|
158
|
+
dso_results_labeled.alias("_").sql(sql_labels).select("sk").execute()
|
|
159
|
+
)
|
|
160
|
+
skids = result["sk"].to_list()
|
|
161
|
+
dso_results_labeled = dso_results_labeled.filter(_.sk.isin(skids))
|
|
162
|
+
|
|
152
163
|
label_row_ids = dso_results_labeled.to_pandas()["rowid"].tolist()
|
|
153
164
|
|
|
154
165
|
results_df = dso_results.to_pandas()
|
starplot/plotters/stars.py
CHANGED
|
@@ -2,6 +2,7 @@ from typing import Callable, Mapping
|
|
|
2
2
|
|
|
3
3
|
import rtree
|
|
4
4
|
import numpy as np
|
|
5
|
+
from ibis import _ as ibis_table
|
|
5
6
|
from skyfield.api import Star as SkyfieldStar, wgs84
|
|
6
7
|
|
|
7
8
|
from starplot import callables
|
|
@@ -13,13 +14,14 @@ from starplot.profile import profile
|
|
|
13
14
|
|
|
14
15
|
|
|
15
16
|
class StarPlotterMixin:
|
|
16
|
-
def _load_stars(self, catalog, filters=None):
|
|
17
|
+
def _load_stars(self, catalog, filters=None, sql=None):
|
|
17
18
|
extent = self._extent_mask()
|
|
18
19
|
|
|
19
20
|
return stars.load(
|
|
20
21
|
extent=extent,
|
|
21
22
|
catalog=catalog,
|
|
22
23
|
filters=filters,
|
|
24
|
+
sql=sql,
|
|
23
25
|
)
|
|
24
26
|
|
|
25
27
|
def _scatter_stars(self, ras, decs, sizes, alphas, colors, style=None, **kwargs):
|
|
@@ -165,6 +167,8 @@ class StarPlotterMixin:
|
|
|
165
167
|
legend_label: str = "Star",
|
|
166
168
|
bayer_labels: bool = False,
|
|
167
169
|
flamsteed_labels: bool = False,
|
|
170
|
+
sql: str = None,
|
|
171
|
+
sql_labels: str = None,
|
|
168
172
|
*args,
|
|
169
173
|
**kwargs,
|
|
170
174
|
):
|
|
@@ -190,6 +194,8 @@ class StarPlotterMixin:
|
|
|
190
194
|
legend_label: Label for stars in the legend. If `None`, then they will not be in the legend.
|
|
191
195
|
bayer_labels: If True, then Bayer labels for stars will be plotted.
|
|
192
196
|
flamsteed_labels: If True, then Flamsteed number labels for stars will be plotted.
|
|
197
|
+
sql: SQL query for selecting stars (table name is `_`). This query will be applied _after_ any filters in the `where` kwarg.
|
|
198
|
+
sql_labels: SQL query for selecting stars that will be labeled (table name is `_`). Applied _after_ any filters in the `where_labels` kwarg.
|
|
193
199
|
"""
|
|
194
200
|
|
|
195
201
|
# fallback to style if callables are None
|
|
@@ -205,12 +211,21 @@ class StarPlotterMixin:
|
|
|
205
211
|
stars_to_index = []
|
|
206
212
|
labels = labels or {}
|
|
207
213
|
|
|
208
|
-
star_results = self._load_stars(catalog, filters=where)
|
|
214
|
+
star_results = self._load_stars(catalog, filters=where, sql=sql)
|
|
209
215
|
|
|
210
216
|
star_results_labeled = star_results
|
|
211
217
|
for f in where_labels:
|
|
212
218
|
star_results_labeled = star_results_labeled.filter(f)
|
|
213
219
|
|
|
220
|
+
if sql_labels:
|
|
221
|
+
result = (
|
|
222
|
+
star_results_labeled.alias("_").sql(sql_labels).select("sk").execute()
|
|
223
|
+
)
|
|
224
|
+
skids = result["sk"].to_list()
|
|
225
|
+
star_results_labeled = star_results_labeled.filter(
|
|
226
|
+
ibis_table.sk.isin(skids)
|
|
227
|
+
)
|
|
228
|
+
|
|
214
229
|
label_row_ids = star_results_labeled.to_pandas()["rowid"].tolist()
|
|
215
230
|
|
|
216
231
|
stars_df = star_results.to_pandas()
|
starplot/styles/base.py
CHANGED
|
@@ -169,6 +169,7 @@ class MarkerSymbolEnum(str, Enum):
|
|
|
169
169
|
MarkerSymbolEnum.CIRCLE_DOTTED_RINGS: circle_dotted_rings(),
|
|
170
170
|
MarkerSymbolEnum.CIRCLE_LINE: circle_line(),
|
|
171
171
|
MarkerSymbolEnum.COMET: "$\u2604$",
|
|
172
|
+
MarkerSymbolEnum.STAR_4: "$\u2726$",
|
|
172
173
|
MarkerSymbolEnum.STAR_8: "$\u2734$",
|
|
173
174
|
MarkerSymbolEnum.ELLIPSE: ellipse(),
|
|
174
175
|
}[self.value]
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
starplot/__init__.py,sha256=
|
|
1
|
+
starplot/__init__.py,sha256=vOqisTpc-0yKEJR9jKWJKoQC__x8vg_PRaKi8MT9Cgc,558
|
|
2
2
|
starplot/base.py,sha256=s-mixdIBeT5QcKYuGXy52oBrg7wJO2rpmHmXqorex1c,43223
|
|
3
3
|
starplot/callables.py,sha256=_zDGCAJTqqNLvCtcIt4PVEe2L0Ggvl6pj-7ZFI-0zqI,4043
|
|
4
4
|
starplot/cli.py,sha256=W-V-h1DeD8zwzdhYuQ-i26LSZWYcS_NJ0zRXa-dmy1o,711
|
|
@@ -8,8 +8,8 @@ starplot/geometry.py,sha256=wr1vJo-WWP51bfblVC2CAR7288yWrG31dZg9ks9vfYg,4359
|
|
|
8
8
|
starplot/horizon.py,sha256=vsJCsJE5VJEe0vlx6A-L70LAGjbey9xMjgUcRSj1F4Y,15808
|
|
9
9
|
starplot/map.py,sha256=CIJC2CoAhH4SlV-dgLC4xDqCoyqXl7DOGegZafRIoqU,23441
|
|
10
10
|
starplot/mixins.py,sha256=8X-LhFbsVNBZN1PKIjlftknppRpcQMOMYE15gdNC-sE,4857
|
|
11
|
-
starplot/optic.py,sha256=
|
|
12
|
-
starplot/optics.py,sha256=
|
|
11
|
+
starplot/optic.py,sha256=aj7Ks8np6f6aefqGtNHbxk3mwcUydhNAsZAo5qO2OBU,15568
|
|
12
|
+
starplot/optics.py,sha256=v94Ff8bIruVBrME7lzwORlayadpoFIGQsAK0sFlx43Y,9314
|
|
13
13
|
starplot/profile.py,sha256=V5LOZFDdnGo-P8ikWvV3jmUVJIKO3gd4H2bjBlk7aUM,300
|
|
14
14
|
starplot/projections.py,sha256=o5wHLoaU8o0s0Z2kkWKxeNbOrskvWG88ULAXDoLOGeA,3423
|
|
15
15
|
starplot/settings.py,sha256=DCylQwkrgUki1yHrelMF483t98NIDQ1bivCeWfeknJw,627
|
|
@@ -19,32 +19,32 @@ starplot/data/__init__.py,sha256=3M_uHlwyIsc9cyfabnOp-6CoXoMteYAaWuj4St9_1BE,308
|
|
|
19
19
|
starplot/data/bigsky.py,sha256=SiHzzhoy-DAZpJ-Q_-lmJqHRLwTKgosaVOEXYWQ94PI,2820
|
|
20
20
|
starplot/data/constellation_lines.py,sha256=RLyFSoxGRL7kj9gGT4DDUubClKZEDu5wGUMG3PlpYfY,19344
|
|
21
21
|
starplot/data/constellation_stars.py,sha256=l2GeyJWuVtzH-MIw1oGR6jeMBvfqX-q-S2V_ilcEZG8,38221
|
|
22
|
-
starplot/data/constellations.py,sha256=
|
|
22
|
+
starplot/data/constellations.py,sha256=05fjaLy5gBDQYyxMV_Etq2O2OMzOh0ozYWT_BwNmfMc,15745
|
|
23
23
|
starplot/data/db.py,sha256=77oWr2HkZ95K_mG4vLc-ivP_SOFIiFYwoqrtTw-YWtk,384
|
|
24
|
-
starplot/data/dsos.py,sha256=
|
|
24
|
+
starplot/data/dsos.py,sha256=Tc264aSA3J8eVmVTUhjrMYMkijP870dqaleMk7xr3hE,1509
|
|
25
25
|
starplot/data/ecliptic.py,sha256=Qre9YdFbTC9mAx-vd2C0Ou4CsnRehIScnTpmEUDDYcM,4638
|
|
26
|
-
starplot/data/stars.py,sha256=
|
|
26
|
+
starplot/data/stars.py,sha256=ImcD0lwGgnOlVICQyM62nXVHoSvkS82x1TNIldFprCU,12288
|
|
27
27
|
starplot/data/utils.py,sha256=RPk3bnfL-KtjMk1VQygDD27INz_gEya_B1hu7X4K8hU,772
|
|
28
28
|
starplot/data/library/bigsky.0.4.0.stars.mag11.parquet,sha256=-_D6bghArUh1cmOKktxmmBFQNThiCWjVleI0wduP1GI,38884673
|
|
29
29
|
starplot/data/library/de421_2001.bsp,sha256=ymkZigAd8Vgscq_DYkdR4nZ1VGD5wwPd-sxe6HiiTns,5341104
|
|
30
|
-
starplot/data/library/sky.db,sha256=
|
|
30
|
+
starplot/data/library/sky.db,sha256=yl-pokiPUgHvlek7HhAbURwz4NFQ8N7WgX0b1oYjYrk,38023168
|
|
31
31
|
starplot/models/__init__.py,sha256=qi4arVatzEcR9TAbHadSbhq8xRhSb1_Br3UKNv4FP7o,330
|
|
32
|
-
starplot/models/base.py,sha256=
|
|
33
|
-
starplot/models/constellation.py,sha256=
|
|
34
|
-
starplot/models/dso.py,sha256=
|
|
35
|
-
starplot/models/moon.py,sha256=
|
|
32
|
+
starplot/models/base.py,sha256=sQ_qTUOUfGxtgLdJVnSbMG328_d_AO5GSIcnC-e0m80,2681
|
|
33
|
+
starplot/models/constellation.py,sha256=ayIGfafFs2eymWHlFdDgZPJkx115x_avPC1egqVZWnI,3220
|
|
34
|
+
starplot/models/dso.py,sha256=ZcAlMn5-y3A_IxfCjhMxmmQzSBeXbxb_P-Jw8T4DQPI,7022
|
|
35
|
+
starplot/models/moon.py,sha256=dW0N70DFx4yO9Zawfo96Z3LZxzLTMZDDpBHrP9rqfa0,4546
|
|
36
36
|
starplot/models/objects.py,sha256=BXwUMT-zPiOYBWYV7L-TRDfPo6lsx_AIk3yxJ3qi0ck,683
|
|
37
|
-
starplot/models/planet.py,sha256=
|
|
38
|
-
starplot/models/star.py,sha256=
|
|
39
|
-
starplot/models/sun.py,sha256=
|
|
37
|
+
starplot/models/planet.py,sha256=TyPGMQnlq4NwMXNSRrIgbpL4rAWTdKyNeo5jpSR0Crg,4661
|
|
38
|
+
starplot/models/star.py,sha256=gw36P1BB9qq4IfvS4TqcZsmltKeNWvcnw87wSDxmE1w,4555
|
|
39
|
+
starplot/models/sun.py,sha256=3EaRJclmYX-jhSJav5nGCazH-9_YHT6Qr2irDSsC63I,2342
|
|
40
40
|
starplot/plotters/__init__.py,sha256=p2wpyY_jK5_zOWWbGtokw4tcHBTuILjAhuobghDvdvM,223
|
|
41
|
-
starplot/plotters/constellations.py,sha256=
|
|
42
|
-
starplot/plotters/dsos.py,sha256=
|
|
41
|
+
starplot/plotters/constellations.py,sha256=ZkI3VfbI7yZfuzg3vG8de4AdxzolXgRj8gBDzwfiHo0,13274
|
|
42
|
+
starplot/plotters/dsos.py,sha256=u_V6b9ADk2YnqwXM6YNayju4SWxe1kLKKT-cMLJva5Y,9095
|
|
43
43
|
starplot/plotters/experimental.py,sha256=P4T9jJyAnViv6k2RJpmYEY8uI-0dyd-E6NeIRUWbu6c,5909
|
|
44
44
|
starplot/plotters/milkyway.py,sha256=ofenSqpqeeg7_LlWnH1PJiiHstzD-qQL7Lk6-WlEv2M,1122
|
|
45
|
-
starplot/plotters/stars.py,sha256=
|
|
45
|
+
starplot/plotters/stars.py,sha256=4k_OUMiNuGT28cMZfm-R9kMzUptPgtW55iqB9vH9WBo,12441
|
|
46
46
|
starplot/styles/__init__.py,sha256=rtwzAylENUGIYGDPl106RGjU6e89yNURoxmPD3I_HM0,193
|
|
47
|
-
starplot/styles/base.py,sha256=
|
|
47
|
+
starplot/styles/base.py,sha256=eSVITtg_dGp8ChI4pm4g3glpiW_Pd0irwNGQp9HND3g,36454
|
|
48
48
|
starplot/styles/extensions.py,sha256=Mv9FTSbwEtB4IFuo_5MFDlHRYQsKdC-19uLYtmJSUuE,649
|
|
49
49
|
starplot/styles/fonts.py,sha256=wC3cHuFkBUaZM5fKpT_ExV7anrRKMJX46mjEfcSRQMU,379
|
|
50
50
|
starplot/styles/helpers.py,sha256=AGgHWaHLzJZ6jicvwPzY-p5oSHE0H8gDk1raCmeRFtg,3032
|
|
@@ -92,8 +92,8 @@ starplot/styles/fonts-library/inter/Inter-SemiBoldItalic.ttf,sha256=HhKJRT16iVz7
|
|
|
92
92
|
starplot/styles/fonts-library/inter/Inter-Thin.ttf,sha256=TDktzIrZFvD533VZq1VjsB3ZT587LbNGF_45LgAGAzk,403404
|
|
93
93
|
starplot/styles/fonts-library/inter/Inter-ThinItalic.ttf,sha256=X8Ca-UpEf65vgsAPFd-u-ernxWDmy-RtPoRSQBmldKo,410232
|
|
94
94
|
starplot/styles/fonts-library/inter/LICENSE.txt,sha256=JiSB6ERSGzJvXs0FPlm5jIstp4yO4b27boF0MF5Uk1o,4380
|
|
95
|
-
starplot-0.15.
|
|
96
|
-
starplot-0.15.
|
|
97
|
-
starplot-0.15.
|
|
98
|
-
starplot-0.15.
|
|
99
|
-
starplot-0.15.
|
|
95
|
+
starplot-0.15.8.dist-info/entry_points.txt,sha256=Sm6jC6h_RcaMGC8saLnYmT0SdhcF9_rMeQIiHneLHyc,46
|
|
96
|
+
starplot-0.15.8.dist-info/licenses/LICENSE,sha256=jcjClHF4BQwhz-kDgia-KphO9Zxu0rCa2BbiA7j1jeU,1070
|
|
97
|
+
starplot-0.15.8.dist-info/WHEEL,sha256=Dyt6SBfaasWElUrURkknVFAZDHSTwxg3PaTza7RSbkY,100
|
|
98
|
+
starplot-0.15.8.dist-info/METADATA,sha256=w1KjXfQySDtPeNVmkQRP2HZsQD8TxlQwtSWVGW4wK3w,4276
|
|
99
|
+
starplot-0.15.8.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|