starplot 0.10.2__py2.py3-none-any.whl → 0.11.1__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 +10 -2
- starplot/base.py +27 -6
- starplot/data/__init__.py +12 -1
- starplot/data/bigsky.py +97 -0
- starplot/data/library/{stars.tycho-1.gz.parquet → stars.bigsky.mag11.parquet} +0 -0
- starplot/data/stars.py +30 -16
- starplot/data/utils.py +27 -0
- starplot/map.py +210 -77
- starplot/models/__init__.py +1 -0
- starplot/models/base.py +17 -0
- starplot/models/constellation.py +72 -0
- starplot/models/star.py +8 -0
- starplot/optic.py +2 -2
- starplot/plotters/stars.py +25 -5
- starplot/projections.py +11 -0
- starplot/styles/base.py +71 -4
- starplot/styles/ext/antique.yml +16 -0
- starplot/styles/ext/blue_dark.yml +16 -1
- starplot/styles/ext/blue_light.yml +18 -0
- starplot/styles/ext/blue_medium.yml +18 -0
- starplot/styles/ext/cb_wong.yml +20 -1
- starplot/styles/ext/color_print.yml +108 -0
- starplot/styles/ext/grayscale.yml +18 -0
- starplot/styles/ext/grayscale_dark.yml +20 -4
- starplot/styles/ext/nord.yml +21 -4
- starplot/styles/ext/optic.yml +1 -1
- starplot/styles/extensions.py +1 -0
- {starplot-0.10.2.dist-info → starplot-0.11.1.dist-info}/METADATA +7 -3
- {starplot-0.10.2.dist-info → starplot-0.11.1.dist-info}/RECORD +31 -28
- starplot/data/library/readme.md +0 -9
- {starplot-0.10.2.dist-info → starplot-0.11.1.dist-info}/LICENSE +0 -0
- {starplot-0.10.2.dist-info → starplot-0.11.1.dist-info}/WHEEL +0 -0
starplot/__init__.py
CHANGED
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
"""Star charts and maps"""
|
|
2
2
|
|
|
3
|
-
__version__ = "0.
|
|
3
|
+
__version__ = "0.11.1"
|
|
4
4
|
|
|
5
5
|
from .base import BasePlot # noqa: F401
|
|
6
6
|
from .map import MapPlot, Projection # noqa: F401
|
|
7
|
-
from .models import
|
|
7
|
+
from .models import (
|
|
8
|
+
DSO, # noqa: F401
|
|
9
|
+
Star, # noqa: F401
|
|
10
|
+
Constellation, # noqa: F401
|
|
11
|
+
Planet, # noqa: F401
|
|
12
|
+
Moon, # noqa: F401
|
|
13
|
+
Sun, # noqa: F401
|
|
14
|
+
ObjectList, # noqa: F401
|
|
15
|
+
)
|
|
8
16
|
from .optic import OpticPlot # noqa: F401
|
|
9
17
|
from .styles import * # noqa: F401 F403
|
starplot/base.py
CHANGED
|
@@ -144,12 +144,20 @@ class BasePlot(ABC):
|
|
|
144
144
|
label=label,
|
|
145
145
|
)
|
|
146
146
|
|
|
147
|
-
def _text(
|
|
147
|
+
def _text(
|
|
148
|
+
self,
|
|
149
|
+
ra: float,
|
|
150
|
+
dec: float,
|
|
151
|
+
text: str,
|
|
152
|
+
hide_on_collision: bool = True,
|
|
153
|
+
*args,
|
|
154
|
+
**kwargs,
|
|
155
|
+
) -> None:
|
|
148
156
|
if not text:
|
|
149
157
|
return
|
|
150
158
|
|
|
151
159
|
x, y = self._prepare_coords(ra, dec)
|
|
152
|
-
kwargs["path_effects"] = kwargs.get("path_effects"
|
|
160
|
+
kwargs["path_effects"] = kwargs.get("path_effects", [self.text_border])
|
|
153
161
|
label = self.ax.annotate(
|
|
154
162
|
text,
|
|
155
163
|
(x, y),
|
|
@@ -157,13 +165,24 @@ class BasePlot(ABC):
|
|
|
157
165
|
**kwargs,
|
|
158
166
|
**self._plot_kwargs(),
|
|
159
167
|
)
|
|
168
|
+
if kwargs.get("clip_on") is False:
|
|
169
|
+
return
|
|
170
|
+
|
|
160
171
|
label.set_clip_on(True)
|
|
161
172
|
label.set_clip_path(self._background_clip_path)
|
|
162
173
|
|
|
163
|
-
|
|
174
|
+
if hide_on_collision:
|
|
175
|
+
self._maybe_remove_label(label)
|
|
164
176
|
|
|
165
177
|
@use_style(LabelStyle)
|
|
166
|
-
def text(
|
|
178
|
+
def text(
|
|
179
|
+
self,
|
|
180
|
+
text: str,
|
|
181
|
+
ra: float,
|
|
182
|
+
dec: float,
|
|
183
|
+
style: LabelStyle = None,
|
|
184
|
+
hide_on_collision: bool = True,
|
|
185
|
+
):
|
|
167
186
|
"""
|
|
168
187
|
Plots text
|
|
169
188
|
|
|
@@ -172,6 +191,7 @@ class BasePlot(ABC):
|
|
|
172
191
|
ra: Right ascension of text (0...24)
|
|
173
192
|
dec: Declination of text (-90...90)
|
|
174
193
|
style: Styling of the text
|
|
194
|
+
hide_on_collision: If True, then the text will not be plotted if it collides with another label
|
|
175
195
|
"""
|
|
176
196
|
style = style or LabelStyle()
|
|
177
197
|
self._text(
|
|
@@ -179,6 +199,7 @@ class BasePlot(ABC):
|
|
|
179
199
|
dec,
|
|
180
200
|
text,
|
|
181
201
|
**style.matplot_kwargs(self._size_multiplier),
|
|
202
|
+
hide_on_collision=hide_on_collision,
|
|
182
203
|
xytext=(style.offset_x, style.offset_y),
|
|
183
204
|
textcoords="offset pixels",
|
|
184
205
|
)
|
|
@@ -271,7 +292,7 @@ class BasePlot(ABC):
|
|
|
271
292
|
|
|
272
293
|
Args:
|
|
273
294
|
filename: Filename of exported file
|
|
274
|
-
format: Format of file
|
|
295
|
+
format: Format of file (options are "png", "jpeg", or "svg")
|
|
275
296
|
padding: Padding (in inches) around the image
|
|
276
297
|
**kwargs: Any keyword arguments to pass through to matplotlib's `savefig` method
|
|
277
298
|
|
|
@@ -480,7 +501,7 @@ class BasePlot(ABC):
|
|
|
480
501
|
"""Plots a polygon of points
|
|
481
502
|
|
|
482
503
|
Args:
|
|
483
|
-
points: List of polygon points `[(ra, dec), ...]`
|
|
504
|
+
points: List of polygon points `[(ra, dec), ...]` - **must be in counterclockwise order**
|
|
484
505
|
style: Style of polygon
|
|
485
506
|
"""
|
|
486
507
|
_points = [(ra * 15, dec) for ra, dec in points]
|
starplot/data/__init__.py
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
1
3
|
from enum import Enum
|
|
2
4
|
from pathlib import Path
|
|
3
5
|
|
|
@@ -9,12 +11,21 @@ DATA_PATH = HERE / "library"
|
|
|
9
11
|
load = Loader(DATA_PATH)
|
|
10
12
|
|
|
11
13
|
|
|
14
|
+
def env(name, default):
|
|
15
|
+
return os.environ.get(name) or default
|
|
16
|
+
|
|
17
|
+
|
|
12
18
|
class DataFiles(str, Enum):
|
|
19
|
+
# Built-In Files
|
|
13
20
|
CONSTELLATION_LINES = DATA_PATH / "constellation_lines_inv.gpkg"
|
|
14
21
|
CONSTELLATION_LINES_HIP = DATA_PATH / "constellation_lines_hips.json"
|
|
15
22
|
CONSTELLATION_BORDERS = DATA_PATH / "constellation_borders_inv.gpkg"
|
|
16
23
|
MILKY_WAY = DATA_PATH / "milkyway.gpkg"
|
|
17
24
|
HIPPARCOS = DATA_PATH / "stars.hipparcos.parquet"
|
|
18
|
-
|
|
25
|
+
BIG_SKY_MAG11 = DATA_PATH / "stars.bigsky.mag11.parquet"
|
|
19
26
|
ONGC = DATA_PATH / "ongc.gpkg.zip"
|
|
20
27
|
CONSTELLATIONS = DATA_PATH / "constellations.gpkg"
|
|
28
|
+
|
|
29
|
+
# Downloaded Files
|
|
30
|
+
_DOWNLOAD_PATH = Path(env("STARPLOT_DOWNLOAD_PATH", str(DATA_PATH)))
|
|
31
|
+
BIG_SKY = _DOWNLOAD_PATH / "stars.bigsky.parquet"
|
starplot/data/bigsky.py
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
3
|
+
import pandas as pd
|
|
4
|
+
|
|
5
|
+
from starplot.data import DATA_PATH, DataFiles, utils
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
BIG_SKY_VERSION = "0.1.0"
|
|
9
|
+
|
|
10
|
+
BIG_SKY_FILENAME = "bigsky.stars.csv.gz"
|
|
11
|
+
|
|
12
|
+
BIG_SKY_URL = f"https://github.com/steveberardi/bigsky/releases/download/v{BIG_SKY_VERSION}/{BIG_SKY_FILENAME}"
|
|
13
|
+
|
|
14
|
+
DOWNLOADED_PATH = DATA_PATH / BIG_SKY_FILENAME
|
|
15
|
+
|
|
16
|
+
DIGITS = 4
|
|
17
|
+
|
|
18
|
+
BIG_SKY_ASSETS = {
|
|
19
|
+
DataFiles.BIG_SKY: "bigsky.stars.csv.gz",
|
|
20
|
+
DataFiles.BIG_SKY_MAG11: "bigsky.stars.mag11.csv.gz",
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def url(filename: str, version: str):
|
|
25
|
+
return f"https://github.com/steveberardi/bigsky/releases/download/v{version}/{filename}"
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def download(
|
|
29
|
+
filename: str = BIG_SKY_FILENAME,
|
|
30
|
+
version: str = BIG_SKY_VERSION,
|
|
31
|
+
download_path: str = None,
|
|
32
|
+
digits: int = 4,
|
|
33
|
+
):
|
|
34
|
+
download_path = download_path or str(DATA_PATH / filename)
|
|
35
|
+
utils.download(
|
|
36
|
+
url(filename, version),
|
|
37
|
+
download_path,
|
|
38
|
+
"Big Sky Star Catalog",
|
|
39
|
+
)
|
|
40
|
+
to_parquet(
|
|
41
|
+
download_path,
|
|
42
|
+
DataFiles.BIG_SKY,
|
|
43
|
+
digits,
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def to_parquet(source_path: str, destination_path: str, digits: int = DIGITS):
|
|
48
|
+
print("Preparing Big Sky Catalog for Starplot...")
|
|
49
|
+
|
|
50
|
+
df = pd.read_csv(
|
|
51
|
+
source_path,
|
|
52
|
+
header=0,
|
|
53
|
+
names=[
|
|
54
|
+
"tyc_id",
|
|
55
|
+
"hip_id",
|
|
56
|
+
"ccdm",
|
|
57
|
+
"magnitude",
|
|
58
|
+
"bv",
|
|
59
|
+
"ra_degrees_j2000",
|
|
60
|
+
"dec_degrees_j2000",
|
|
61
|
+
"ra_mas_per_year",
|
|
62
|
+
"dec_mas_per_year",
|
|
63
|
+
"parallax_mas",
|
|
64
|
+
],
|
|
65
|
+
compression="gzip",
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
df["ra_hours"] = df.apply(
|
|
69
|
+
lambda row: round(row.ra_degrees_j2000 / 15, digits), axis=1
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
df = df.assign(epoch_year=2000)
|
|
73
|
+
|
|
74
|
+
df = df.rename(
|
|
75
|
+
columns={
|
|
76
|
+
"hip_id": "hip",
|
|
77
|
+
"ra_degrees_j2000": "ra_degrees",
|
|
78
|
+
"dec_degrees_j2000": "dec_degrees",
|
|
79
|
+
}
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
df.to_parquet(destination_path, compression="gzip")
|
|
83
|
+
|
|
84
|
+
print(f"Done! {destination_path.value}")
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def load(path):
|
|
88
|
+
if not exists(path):
|
|
89
|
+
download(filename=BIG_SKY_ASSETS.get(path))
|
|
90
|
+
|
|
91
|
+
df = pd.read_parquet(path)
|
|
92
|
+
|
|
93
|
+
return df.set_index("tyc_id")
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def exists(path) -> bool:
|
|
97
|
+
return os.path.isfile(path)
|
|
Binary file
|
starplot/data/stars.py
CHANGED
|
@@ -2,7 +2,7 @@ from enum import Enum
|
|
|
2
2
|
|
|
3
3
|
from pandas import read_parquet
|
|
4
4
|
|
|
5
|
-
from starplot.data import DataFiles
|
|
5
|
+
from starplot.data import bigsky, DataFiles
|
|
6
6
|
|
|
7
7
|
STAR_NAMES = {
|
|
8
8
|
7588: "Achernar",
|
|
@@ -117,27 +117,41 @@ class StarCatalog(str, Enum):
|
|
|
117
117
|
HIPPARCOS = "hipparcos"
|
|
118
118
|
"""Hipparcos Catalog = 118,218 stars"""
|
|
119
119
|
|
|
120
|
-
|
|
121
|
-
"""
|
|
120
|
+
BIG_SKY_MAG11 = "big-sky-mag11"
|
|
121
|
+
"""
|
|
122
|
+
[Big Sky Catalog](https://github.com/steveberardi/bigsky) ~ 900k stars up to magnitude 11
|
|
123
|
+
|
|
124
|
+
This is an _abridged_ version of the Big Sky Catalog, including stars up to a limiting magnitude of 11 (total = 981,852).
|
|
122
125
|
|
|
126
|
+
This catalog is included with Starplot, so does not require downloading any files.
|
|
127
|
+
"""
|
|
123
128
|
|
|
124
|
-
|
|
125
|
-
|
|
129
|
+
BIG_SKY = "big-sky"
|
|
130
|
+
"""
|
|
131
|
+
[Big Sky Catalog](https://github.com/steveberardi/bigsky) ~ 2.5M stars
|
|
126
132
|
|
|
133
|
+
This is the full version of the Big Sky Catalog, which includes 2,557,499 stars from Hipparcos, Tycho-1, and Tycho-2.
|
|
127
134
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
+
This catalog is very large (50+ MB), so it's not built-in to Starplot. When you plot stars and specify this catalog, the catalog
|
|
136
|
+
will be downloaded from the [Big Sky GitHub repository](https://github.com/steveberardi/bigsky) and saved to Starplot's data library
|
|
137
|
+
directory. You can override this download path with the environment variable `STARPLOT_DOWNLOAD_PATH`
|
|
138
|
+
|
|
139
|
+
"""
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def load_bigsky():
|
|
143
|
+
if not bigsky.exists():
|
|
144
|
+
bigsky.download()
|
|
145
|
+
|
|
146
|
+
return bigsky.load(DataFiles.BIG_SKY)
|
|
135
147
|
|
|
136
148
|
|
|
137
149
|
def load(catalog: StarCatalog = StarCatalog.HIPPARCOS):
|
|
138
|
-
if catalog == StarCatalog.
|
|
139
|
-
return
|
|
140
|
-
elif catalog == StarCatalog.
|
|
141
|
-
return
|
|
150
|
+
if catalog == StarCatalog.HIPPARCOS:
|
|
151
|
+
return read_parquet(DataFiles.HIPPARCOS)
|
|
152
|
+
elif catalog == StarCatalog.BIG_SKY_MAG11:
|
|
153
|
+
return bigsky.load(DataFiles.BIG_SKY_MAG11)
|
|
154
|
+
elif catalog == StarCatalog.BIG_SKY:
|
|
155
|
+
return bigsky.load(DataFiles.BIG_SKY)
|
|
142
156
|
else:
|
|
143
157
|
raise ValueError("Unrecognized star catalog.")
|
starplot/data/utils.py
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
|
|
3
|
+
import requests
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def download(url, download_path, description=""):
|
|
7
|
+
with open(download_path, "wb") as f:
|
|
8
|
+
print(f"Downloading {description}...")
|
|
9
|
+
|
|
10
|
+
response = requests.get(url, stream=True)
|
|
11
|
+
total_size = response.headers.get("content-length")
|
|
12
|
+
|
|
13
|
+
if total_size is None:
|
|
14
|
+
f.write(response.content)
|
|
15
|
+
return
|
|
16
|
+
|
|
17
|
+
bytes_written = 0
|
|
18
|
+
total_size = int(total_size)
|
|
19
|
+
for chunk in response.iter_content(chunk_size=4096):
|
|
20
|
+
bytes_written += len(chunk)
|
|
21
|
+
f.write(chunk)
|
|
22
|
+
|
|
23
|
+
progress = int(25 * bytes_written / total_size)
|
|
24
|
+
sys.stdout.write("\r[%s%s]" % ("=" * progress, " " * (25 - progress)))
|
|
25
|
+
sys.stdout.flush()
|
|
26
|
+
|
|
27
|
+
print("Download complete!")
|