starplot 0.13.0__py2.py3-none-any.whl → 0.14.0__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/map.py CHANGED
@@ -1,40 +1,37 @@
1
1
  import datetime
2
2
  import math
3
- import warnings
4
3
  from typing import Callable
4
+ from functools import cache
5
5
 
6
6
  from cartopy import crs as ccrs
7
7
  from matplotlib import pyplot as plt
8
8
  from matplotlib import path, patches, ticker
9
9
  from matplotlib.ticker import FuncFormatter, FixedLocator
10
- from shapely import LineString, MultiLineString, Polygon
11
- from shapely.ops import unary_union
10
+ from shapely import Polygon
12
11
  from skyfield.api import Star as SkyfieldStar, wgs84
13
12
  import geopandas as gpd
14
13
  import numpy as np
15
14
 
15
+ from starplot.coordinates import CoordinateSystem
16
16
  from starplot import geod
17
17
  from starplot.base import BasePlot, DPI
18
- from starplot.data import DataFiles, constellations as condata, stars
19
- from starplot.data.constellations import CONSTELLATIONS_FULL_NAMES
20
18
  from starplot.mixins import ExtentMaskMixin
21
- from starplot.models.constellation import from_tuple as constellation_from_tuple
22
- from starplot.plotters import StarPlotterMixin, DsoPlotterMixin
19
+ from starplot.plotters import (
20
+ ConstellationPlotterMixin,
21
+ StarPlotterMixin,
22
+ DsoPlotterMixin,
23
+ MilkyWayPlotterMixin,
24
+ )
23
25
  from starplot.projections import Projection
24
26
  from starplot.styles import (
25
27
  ObjectStyle,
26
28
  LabelStyle,
27
- LineStyle,
28
29
  PlotStyle,
29
- PolygonStyle,
30
30
  PathStyle,
31
31
  )
32
32
  from starplot.styles.helpers import use_style
33
33
  from starplot.utils import lon_to_ra, ra_to_lon
34
34
 
35
- # Silence noisy cartopy warnings
36
- warnings.filterwarnings("ignore", module="cartopy")
37
- warnings.filterwarnings("ignore", module="shapely")
38
35
 
39
36
  DEFAULT_MAP_STYLE = PlotStyle() # .extend(extensions.MAP)
40
37
 
@@ -57,7 +54,14 @@ def points(start, end, num_points=100):
57
54
  return list(zip(x_coords, y_coords))
58
55
 
59
56
 
60
- class MapPlot(BasePlot, ExtentMaskMixin, StarPlotterMixin, DsoPlotterMixin):
57
+ class MapPlot(
58
+ BasePlot,
59
+ ExtentMaskMixin,
60
+ StarPlotterMixin,
61
+ DsoPlotterMixin,
62
+ MilkyWayPlotterMixin,
63
+ ConstellationPlotterMixin,
64
+ ):
61
65
  """Creates a new map plot.
62
66
 
63
67
  !!! star "Note"
@@ -79,12 +83,15 @@ class MapPlot(BasePlot, ExtentMaskMixin, StarPlotterMixin, DsoPlotterMixin):
79
83
  clip_path: An optional Shapely Polygon that specifies the clip path of the plot -- only objects inside the polygon will be plotted. If `None` (the default), then the clip path will be the extent of the map you specified with the RA/DEC parameters.
80
84
  scale: Scaling factor that will be applied to all sizes in styles (e.g. font size, marker size, line widths, etc). For example, if you want to make everything 2x bigger, then set the scale to 2. At `scale=1` and `resolution=4096` (the default), all sizes are optimized visually for a map that covers 1-3 constellations. So, if you're creating a plot of a _larger_ extent, then it'd probably be good to decrease the scale (i.e. make everything smaller) -- and _increase_ the scale if you're plotting a very small area.
81
85
  autoscale: If True, then the scale will be set automatically based on resolution.
86
+ suppress_warnings: If True (the default), then all warnings will be suppressed
82
87
 
83
88
  Returns:
84
89
  MapPlot: A new instance of a MapPlot
85
90
 
86
91
  """
87
92
 
93
+ _coordinate_system = CoordinateSystem.RA_DEC
94
+
88
95
  def __init__(
89
96
  self,
90
97
  projection: Projection,
@@ -102,6 +109,7 @@ class MapPlot(BasePlot, ExtentMaskMixin, StarPlotterMixin, DsoPlotterMixin):
102
109
  clip_path: Polygon = None,
103
110
  scale: float = 1.0,
104
111
  autoscale: bool = False,
112
+ suppress_warnings: bool = True,
105
113
  *args,
106
114
  **kwargs,
107
115
  ) -> "MapPlot":
@@ -113,6 +121,7 @@ class MapPlot(BasePlot, ExtentMaskMixin, StarPlotterMixin, DsoPlotterMixin):
113
121
  hide_colliding_labels,
114
122
  scale=scale,
115
123
  autoscale=autoscale,
124
+ suppress_warnings=suppress_warnings,
116
125
  *args,
117
126
  **kwargs,
118
127
  )
@@ -166,6 +175,7 @@ class MapPlot(BasePlot, ExtentMaskMixin, StarPlotterMixin, DsoPlotterMixin):
166
175
  def _prepare_coords(self, ra: float, dec: float) -> (float, float):
167
176
  return ra * 15, dec
168
177
 
178
+ @cache
169
179
  def in_bounds(self, ra: float, dec: float) -> bool:
170
180
  """Determine if a coordinate is within the bounds of the plot.
171
181
 
@@ -258,342 +268,6 @@ class MapPlot(BasePlot, ExtentMaskMixin, StarPlotterMixin, DsoPlotterMixin):
258
268
 
259
269
  return df
260
270
 
261
- @use_style(LineStyle, "constellation_borders")
262
- def constellation_borders(self, style: LineStyle = None):
263
- """Plots the constellation borders
264
-
265
- Args:
266
- style: Styling of the constellation borders. If None, then the plot's style (specified when creating the plot) will be used
267
- """
268
- constellation_borders = self._read_geo_package(
269
- DataFiles.CONSTELLATION_BORDERS.value
270
- )
271
-
272
- if constellation_borders.empty:
273
- return
274
-
275
- style_kwargs = style.matplot_kwargs(self.scale)
276
-
277
- geometries = []
278
-
279
- for _, c in constellation_borders.iterrows():
280
- for ls in c.geometry.geoms:
281
- geometries.append(ls)
282
-
283
- for ls in geometries:
284
- x, y = ls.xy
285
- self.ax.plot(
286
- list(x),
287
- list(y),
288
- transform=self._plate_carree,
289
- clip_on=True,
290
- clip_path=self._background_clip_path,
291
- gid="constellations-border",
292
- **style_kwargs,
293
- )
294
-
295
- def _plot_constellation_borders(self):
296
- """work in progress"""
297
- constellation_borders = gpd.read_file(
298
- DataFiles.CONSTELLATIONS.value,
299
- engine="pyogrio",
300
- use_arrow=True,
301
- bbox=self._extent_mask(),
302
- )
303
-
304
- if constellation_borders.empty:
305
- return
306
-
307
- geometries = []
308
-
309
- for i, constellation in constellation_borders.iterrows():
310
- geometry_types = constellation.geometry.geom_type
311
-
312
- # equinox = LineString([[0, 90], [0, -90]])
313
- """
314
- Problems:
315
- - Need to handle multipolygon borders too (SER)
316
- - Shapely's union doesn't handle geodesy (e.g. TRI + AND)
317
- - ^^ TRI is plotted with ra < 360, but AND has ra > 360
318
- - ^^ idea: create union first and then remove duplicate lines?
319
-
320
- TODO: create new static data file of constellation border lines
321
- """
322
-
323
- if "Polygon" in geometry_types and "MultiPolygon" not in geometry_types:
324
- polygons = [constellation.geometry]
325
-
326
- elif "MultiPolygon" in geometry_types:
327
- polygons = constellation.geometry.geoms
328
-
329
- for p in polygons:
330
- coords = list(zip(*p.exterior.coords.xy))
331
- # coords = [(ra * -1, dec) for ra, dec in coords]
332
-
333
- new_coords = []
334
-
335
- for i, c in enumerate(coords):
336
- ra, dec = c
337
- if i > 0:
338
- if new_coords[i - 1][0] - ra > 60:
339
- ra += 360
340
-
341
- elif ra - new_coords[i - 1][0] > 60:
342
- new_coords[i - 1][0] += 360
343
-
344
- new_coords.append([ra, dec])
345
-
346
- ls = LineString(new_coords)
347
- geometries.append(ls)
348
-
349
- mls = MultiLineString(geometries)
350
- geometries = unary_union(mls)
351
-
352
- style_kwargs = self.style.constellation_borders.matplot_kwargs(self.scale)
353
-
354
- for ls in list(geometries.geoms):
355
- # print(ls)
356
- x, y = ls.xy
357
- newx = [xx * -1 for xx in list(x)]
358
- self.ax.plot(
359
- # list(x),
360
- newx,
361
- list(y),
362
- # **self._plot_kwargs(),
363
- # transform=self._geodetic,
364
- transform=self._plate_carree,
365
- **style_kwargs,
366
- )
367
-
368
- @use_style(PathStyle, "constellation")
369
- def constellations(
370
- self,
371
- style: PathStyle = None,
372
- labels: dict[str, str] = CONSTELLATIONS_FULL_NAMES,
373
- where: list = None,
374
- ):
375
- """Plots the constellation lines and/or labels.
376
-
377
- **Important:** If you're plotting the constellation lines, then it's good to plot them _first_, because Starplot will use the constellation lines to determine where to place labels that are plotted afterwards (labels will look better if they're not crossing a constellation line).
378
-
379
- Args:
380
- style: Styling of the constellations. If None, then the plot's style (specified when creating the plot) will be used
381
- labels: A dictionary where the keys are each constellation's 3-letter abbreviation, and the values are how the constellation will be labeled on the plot.
382
- where: A list of expressions that determine which constellations to plot. See [Selecting Objects](/reference-selecting-objects/) for details.
383
- """
384
- self.logger.debug("Plotting constellations...")
385
-
386
- labels = labels or {}
387
- where = where or []
388
-
389
- constellations_gdf = gpd.read_file(
390
- DataFiles.CONSTELLATIONS.value,
391
- engine="pyogrio",
392
- use_arrow=True,
393
- bbox=self._extent_mask(),
394
- )
395
- stars_df = stars.load("hipparcos")
396
-
397
- if constellations_gdf.empty:
398
- return
399
-
400
- if self.projection in [Projection.MERCATOR, Projection.MILLER]:
401
- transform = self._plate_carree
402
- else:
403
- transform = self._geodetic
404
-
405
- conline_hips = condata.lines()
406
- style_kwargs = style.line.matplot_kwargs(self.scale)
407
-
408
- for c in constellations_gdf.itertuples():
409
- obj = constellation_from_tuple(c)
410
-
411
- if not all([e.evaluate(obj) for e in where]):
412
- continue
413
-
414
- hiplines = conline_hips[c.iau_id]
415
- inbounds = False
416
-
417
- for s1_hip, s2_hip in hiplines:
418
- s1 = stars_df.loc[s1_hip]
419
- s2 = stars_df.loc[s2_hip]
420
-
421
- s1_ra = s1.ra_hours * 15
422
- s2_ra = s2.ra_hours * 15
423
-
424
- s1_dec = s1.dec_degrees
425
- s2_dec = s2.dec_degrees
426
-
427
- if s1_ra - s2_ra > 60:
428
- s2_ra += 360
429
-
430
- elif s2_ra - s1_ra > 60:
431
- s1_ra += 360
432
-
433
- if self.in_bounds(s1_ra / 15, s1_dec):
434
- inbounds = True
435
-
436
- s1_ra *= -1
437
- s2_ra *= -1
438
-
439
- # make lines straight
440
- # s1_ra, s1_dec = self._proj.transform_point(s1_ra, s1.dec_degrees, self._geodetic)
441
- # s2_ra, s2_dec = self._proj.transform_point(s2_ra, s2.dec_degrees, self._geodetic)
442
-
443
- constellation_line = self.ax.plot(
444
- [s1_ra, s2_ra],
445
- [s1_dec, s2_dec],
446
- transform=transform,
447
- **style_kwargs,
448
- clip_on=True,
449
- clip_path=self._background_clip_path,
450
- gid="constellations-line",
451
- )[0]
452
-
453
- extent = constellation_line.get_window_extent(
454
- renderer=self.fig.canvas.get_renderer()
455
- )
456
-
457
- if extent.xmin < 0:
458
- continue
459
-
460
- start = self._proj.transform_point(s1_ra, s1_dec, self._geodetic)
461
- end = self._proj.transform_point(s2_ra, s2_dec, self._geodetic)
462
- radius = style_kwargs.get("linewidth") or 1
463
-
464
- if any([np.isnan(n) for n in start + end]):
465
- continue
466
-
467
- for x, y in points(start, end, 25):
468
- x0, y0 = self.ax.transData.transform((x, y))
469
- if x0 < 0 or y0 < 0:
470
- continue
471
- self._constellations_rtree.insert(
472
- 0,
473
- np.array((x0 - radius, y0 - radius, x0 + radius, y0 + radius)),
474
- obj=obj.name,
475
- )
476
-
477
- if inbounds:
478
- self._objects.constellations.append(obj)
479
-
480
- self._plot_constellation_labels(style.label, labels)
481
- # self._plot_constellation_labels_experimental(style.label, labels)
482
-
483
- def _plot_constellation_labels(
484
- self,
485
- style: PathStyle = None,
486
- labels: dict[str, str] = CONSTELLATIONS_FULL_NAMES,
487
- ):
488
- style = style or self.style.constellation.label
489
-
490
- for con in condata.iterator():
491
- _, ra, dec = condata.get(con)
492
- text = labels.get(con.lower())
493
- self.text(
494
- text,
495
- ra,
496
- dec,
497
- style,
498
- hide_on_collision=False,
499
- gid="constellations-label-name",
500
- )
501
-
502
- def _plot_constellation_labels_experimental(
503
- self,
504
- style: PathStyle = None,
505
- labels: dict[str, str] = CONSTELLATIONS_FULL_NAMES,
506
- ):
507
- from shapely import (
508
- MultiPoint,
509
- intersection,
510
- delaunay_triangles,
511
- distance,
512
- )
513
-
514
- def sorter(g):
515
- d = distance(g.centroid, points.centroid)
516
- # d = distance(g.centroid, constellation.boundary.centroid)
517
- extent = abs(g.bounds[2] - g.bounds[0])
518
- area = g.area / constellation.boundary.area
519
- return (extent**2 + area) - (d**2)
520
-
521
- for constellation in self.objects.constellations:
522
- constellation_stars = [
523
- s
524
- for s in self.objects.stars
525
- if s.constellation_id == constellation.iau_id
526
- ]
527
- points = MultiPoint([(s.ra, s.dec) for s in constellation_stars])
528
-
529
- triangles = delaunay_triangles(
530
- geometry=points,
531
- # tolerance=2,
532
- )
533
-
534
- polygons = []
535
- for t in triangles.geoms:
536
- try:
537
- inter = intersection(t, constellation.boundary)
538
- except Exception:
539
- continue
540
- if (
541
- inter.geom_type == "Polygon"
542
- and len(list(zip(*inter.exterior.coords.xy))) > 2
543
- ):
544
- polygons.append(inter)
545
-
546
- p_by_area = {pg.area: pg for pg in polygons}
547
- polygons_sorted = [
548
- p_by_area[k] for k in sorted(p_by_area.keys(), reverse=True)
549
- ]
550
-
551
- # sort by combination of horizontal extent and area
552
- polygons_sorted = sorted(polygons_sorted, key=sorter, reverse=True)
553
-
554
- if len(polygons_sorted) > 0:
555
- i = 0
556
- ra, dec = polygons_sorted[i].centroid.x, polygons_sorted[i].centroid.y
557
- else:
558
- ra, dec = constellation.ra, constellation.dec
559
-
560
- text = labels.get(constellation.iau_id)
561
- style = style or self.style.constellation.label
562
- self.text(text, ra, dec, style)
563
-
564
- @use_style(PolygonStyle, "milky_way")
565
- def milky_way(self, style: PolygonStyle = None):
566
- """Plots the Milky Way
567
-
568
- Args:
569
- style: Styling of the Milky Way. If None, then the plot's style (specified when creating the plot) will be used
570
- """
571
- mw = self._read_geo_package(DataFiles.MILKY_WAY.value)
572
-
573
- if mw.empty:
574
- return
575
-
576
- def _prepare_polygon(p):
577
- points = list(zip(*p.boundary.coords.xy))
578
- # convert lon to RA and reverse so the coordinates are counterclockwise order
579
- return [(lon_to_ra(lon) * 15, dec) for lon, dec in reversed(points)]
580
-
581
- # create union of all Milky Way patches
582
- gs = mw.geometry.to_crs(self._plate_carree)
583
- mw_union = gs.buffer(0.1).unary_union.buffer(-0.1)
584
- polygons = []
585
-
586
- if mw_union.geom_type == "MultiPolygon":
587
- polygons.extend([_prepare_polygon(polygon) for polygon in mw_union.geoms])
588
- else:
589
- polygons.append(_prepare_polygon(mw_union))
590
-
591
- for polygon_points in polygons:
592
- self._polygon(
593
- polygon_points,
594
- style=style,
595
- )
596
-
597
271
  @use_style(ObjectStyle, "zenith")
598
272
  def zenith(
599
273
  self,
@@ -654,37 +328,51 @@ class MapPlot(BasePlot, ExtentMaskMixin, StarPlotterMixin, DsoPlotterMixin):
654
328
  )
655
329
  x = []
656
330
  y = []
657
- verts = []
658
-
659
- # TODO : handle map edges better
660
331
 
661
332
  for ra, dec in points:
662
333
  ra = ra / 15
663
334
  x0, y0 = self._prepare_coords(ra, dec)
664
335
  x.append(x0)
665
336
  y.append(y0)
666
- verts.append((x0, y0))
667
337
 
668
338
  style_kwargs = {}
669
339
  if self.projection == Projection.ZENITH:
670
340
  """
671
- For zenith projections, we plot the horizon as a patch because
672
- plottting as a line results in extra pixels on bottom.
673
-
674
- TODO : investigate why line is extra thick on bottom when plotting line
341
+ For zenith projections, we plot the horizon as a patch to make a more perfect circle
675
342
  """
676
343
  style_kwargs = style.line.matplot_kwargs(self.scale)
677
344
  style_kwargs["clip_on"] = False
678
345
  style_kwargs["edgecolor"] = style_kwargs.pop("color")
679
-
680
- patch = patches.Polygon(
681
- verts,
346
+ patch = patches.Circle(
347
+ (0.50, 0.50),
348
+ radius=0.454,
682
349
  facecolor=None,
683
350
  fill=False,
684
- transform=self._crs,
351
+ transform=self.ax.transAxes,
685
352
  **style_kwargs,
686
353
  )
687
354
  self.ax.add_patch(patch)
355
+ self._background_clip_path = patch
356
+
357
+ if not labels:
358
+ return
359
+
360
+ label_ax_coords = [
361
+ (0.5, 0.95), # north
362
+ (0.045, 0.5), # east
363
+ (0.5, 0.045), # south
364
+ (0.954, 0.5), # west
365
+ ]
366
+ for label, coords in zip(labels, label_ax_coords):
367
+ self.ax.annotate(
368
+ label,
369
+ coords,
370
+ xycoords=self.ax.transAxes,
371
+ clip_on=False,
372
+ **style.label.matplot_kwargs(self.scale),
373
+ )
374
+
375
+ return
688
376
 
689
377
  else:
690
378
  style_kwargs["clip_on"] = True
@@ -698,13 +386,6 @@ class MapPlot(BasePlot, ExtentMaskMixin, StarPlotterMixin, DsoPlotterMixin):
698
386
  **self._plot_kwargs(),
699
387
  )
700
388
 
701
- # self.circle(
702
- # (ra.hours, dec.degrees),
703
- # 90,
704
- # style,
705
- # num_pts=200,
706
- # )
707
-
708
389
  if not labels:
709
390
  return
710
391
 
@@ -731,7 +412,8 @@ class MapPlot(BasePlot, ExtentMaskMixin, StarPlotterMixin, DsoPlotterMixin):
731
412
 
732
413
  for i, position in enumerate(cardinal_directions):
733
414
  ra, dec, _ = position.radec()
734
- self._text(ra.hours, dec.degrees, labels[i], force=True, **text_kwargs)
415
+ x, y = self._prepare_coords(ra, dec)
416
+ self._text(x, y, labels[i], **text_kwargs)
735
417
 
736
418
  @use_style(PathStyle, "gridlines")
737
419
  def gridlines(
@@ -928,6 +610,12 @@ class MapPlot(BasePlot, ExtentMaskMixin, StarPlotterMixin, DsoPlotterMixin):
928
610
  **style.matplot_kwargs(self.scale),
929
611
  )
930
612
 
613
+ def _ax_to_radec(self, x, y):
614
+ trans = self.ax.transAxes + self.ax.transData.inverted()
615
+ x_projected, y_projected = trans.transform((x, y)) # axes to data
616
+ x_ra, y_ra = self._crs.transform_point(x_projected, y_projected, self._proj)
617
+ return (x_ra + 360) / 15, y_ra
618
+
931
619
  def _plot_background_clip_path(self):
932
620
  def to_axes(points):
933
621
  ax_points = []
starplot/models/base.py CHANGED
@@ -113,6 +113,8 @@ class SkyObject(CreateMapMixin, CreateOpticMixin, metaclass=Meta):
113
113
  dec: float
114
114
  """Declination, in degrees (-90...90)"""
115
115
 
116
+ _constellation_id = None
117
+
116
118
  constellation_id: Optional[str] = None
117
119
  """Identifier of the constellation that contains this object. The ID is the three-letter (all lowercase) abbreviation from the International Astronomical Union (IAU)."""
118
120
 
@@ -120,8 +122,13 @@ class SkyObject(CreateMapMixin, CreateOpticMixin, metaclass=Meta):
120
122
  self.ra = ra
121
123
  self.dec = dec
122
124
 
123
- pos = position_of_radec(ra, dec)
124
- self.constellation_id = constellation_at(pos).lower()
125
+ @property
126
+ def constellation_id(self):
127
+ """Identifier of the constellation that contains this object. The ID is the three-letter (all lowercase) abbreviation from the International Astronomical Union (IAU)."""
128
+ if not self._constellation_id:
129
+ pos = position_of_radec(self.ra, self.dec)
130
+ self._constellation_id = constellation_at(pos).lower()
131
+ return self._constellation_id
125
132
 
126
133
  def constellation(self):
127
134
  """Returns an instance of the [`Constellation`][starplot.models.Constellation] that contains this object"""
@@ -39,7 +39,7 @@ class Constellation(SkyObject):
39
39
  ) -> None:
40
40
  super().__init__(ra, dec)
41
41
  self.iau_id = iau_id.lower()
42
- self.constellation_id = self.iau_id # override from super()
42
+ self._constellation_id = self.iau_id # override from super()
43
43
  self.name = name
44
44
  self.boundary = boundary
45
45
 
starplot/optic.py CHANGED
@@ -7,6 +7,7 @@ from cartopy import crs as ccrs
7
7
  from matplotlib import pyplot as plt, patches, path
8
8
  from skyfield.api import wgs84, Star as SkyfieldStar
9
9
 
10
+ from starplot.coordinates import CoordinateSystem
10
11
  from starplot import callables
11
12
  from starplot.base import BasePlot, DPI
12
13
  from starplot.data.stars import StarCatalog, STAR_NAMES
@@ -46,12 +47,15 @@ class OpticPlot(BasePlot, ExtentMaskMixin, StarPlotterMixin, DsoPlotterMixin):
46
47
  raise_on_below_horizon: If True, then a ValueError will be raised if the target is below the horizon at the observing time/location
47
48
  scale: Scaling factor that will be applied to all sizes in styles (e.g. font size, marker size, line widths, etc). For example, if you want to make everything 2x bigger, then set the scale to 2. At `scale=1` and `resolution=4096` (the default), all sizes are optimized visually for a map that covers 1-3 constellations. So, if you're creating a plot of a _larger_ extent, then it'd probably be good to decrease the scale (i.e. make everything smaller) -- and _increase_ the scale if you're plotting a very small area.
48
49
  autoscale: If True, then the scale will be set automatically based on resolution.
50
+ suppress_warnings: If True (the default), then all warnings will be suppressed
49
51
 
50
52
  Returns:
51
53
  OpticPlot: A new instance of an OpticPlot
52
54
 
53
55
  """
54
56
 
57
+ _coordinate_system = CoordinateSystem.AZ_ALT
58
+
55
59
  FIELD_OF_VIEW_MAX = 9.0
56
60
 
57
61
  def __init__(
@@ -69,6 +73,7 @@ class OpticPlot(BasePlot, ExtentMaskMixin, StarPlotterMixin, DsoPlotterMixin):
69
73
  raise_on_below_horizon: bool = True,
70
74
  scale: float = 1.0,
71
75
  autoscale: bool = False,
76
+ suppress_warnings: bool = True,
72
77
  *args,
73
78
  **kwargs,
74
79
  ) -> "OpticPlot":
@@ -80,6 +85,7 @@ class OpticPlot(BasePlot, ExtentMaskMixin, StarPlotterMixin, DsoPlotterMixin):
80
85
  hide_colliding_labels,
81
86
  scale=scale,
82
87
  autoscale=autoscale,
88
+ suppress_warnings=suppress_warnings,
83
89
  *args,
84
90
  **kwargs,
85
91
  )
@@ -242,7 +248,7 @@ class OpticPlot(BasePlot, ExtentMaskMixin, StarPlotterMixin, DsoPlotterMixin):
242
248
  if size_fn is not None:
243
249
 
244
250
  def size_fn_mx(s):
245
- return size_fn(s) * optic_star_multiplier
251
+ return size_fn(s) * optic_star_multiplier * 0.68
246
252
 
247
253
  super().stars(
248
254
  mag=mag,
@@ -1,2 +1,4 @@
1
+ from .constellations import ConstellationPlotterMixin # noqa: F401
1
2
  from .stars import StarPlotterMixin # noqa: F401
2
3
  from .dsos import DsoPlotterMixin # noqa: F401
4
+ from .milkyway import MilkyWayPlotterMixin # noqa: F401