Triangulating stars on the night sky
In a previous notebook, I have shown properties of the distribution of stars in the sky. Here, I would like to use the existing database of stars' positions and display them as a triangulation
Let's first initialize the notebook:
import numpy as np
np.set_printoptions(precision=6, suppress=True)
%matplotlib inline
%config InlineBackend.figure_format = 'retina'
import matplotlib.pyplot as plt
phi = (np.sqrt(5)+1)/2
fig_width = 10
figsize = (fig_width, fig_width/phi)
importing data¶
Importing all stars' position is as simple as invoking the HYG database:
import pandas as pd
url = "https://github.com/astronexus/HYG-Database/raw/master/hygdata_v30.csv"
url = "https://raw.githubusercontent.com/astronexus/HYG-Database/main/hyg/v3/hyg_v30.csv"
space = pd.read_csv(url, index_col=0)
print(f'Columns in the database: {space.columns=}')
print(f'Number of stars in the catalog = {len(space)=}')
extracting ra, dec and mag¶
For which we may extract what interests us: position (right ascension and declination) and visual magnitude:
space_pos = space[['ra', 'dec', 'mag']]
space_pos
First, right ascension is "the angular distance of a particular point measured eastward along the celestial equator from the Sun at the March equinox to the (hour circle of the) point in question above the earth." It is given in hours:
ra_min, ra_max = 0, 24
print(f"RA: {space_pos['ra'].min()=}, {space_pos['ra'].max()=}")
normalizing ra into az¶
Let's convert this in visual angle, that is in an azimuth:
space_norm = space_pos[['dec', 'mag']].copy()
space_norm
az_min, az_max = 0, 360
def ra2az(ra):
return az_max - ra / ra_max * az_max
space_norm["az"] = ra2az(space_pos['ra'])
print(f"AZ: {space_norm['az'].min()=}, {space_norm['az'].max()=}")
Then, declination is "comparable to geographic latitude, projected onto the celestial sphere" and is given here in degrees:
dec_min, dec_max = -90, 90
print(f"DEC: {space_norm['dec'].min()=}, {space_norm['dec'].max()=}")
The magnitude varies a lot (the less the value, the more it is visible - "The apparent magnitudes of known objects range from the Sun at −26.7 to objects in deep Hubble Space Telescope images of magnitude +31.5"):
print(f"mag: {space_norm['mag'].min()=}, {space_norm['mag'].max()=}")
Let's normalize the lower bound:
space_norm['mag'] = space_pos['mag'] - space_pos['mag'].min()
print(f"mag: {space_norm['mag'].min()=}, {space_norm['mag'].max()=}")
Let's define a threshold using the quantile function:
print(f"{space_norm['mag'].quantile(q=0.01)=}")
Which leaves only a limited number of stars
space_bright = space_norm[space_norm['mag']<space_norm['mag'].quantile(q=0.05)]
#space_bright = space_pos[space_pos['mag']<6]
print(f'Number of bright stars = {len(space_bright)=}')
print(f"MAG: {space_bright['mag'].min()=}, {space_bright['mag'].max()=}")
scatter plots¶
From these elements, we may plot the stars on these coordinates:
stars_color = np.array([255., 235., 220.])
stars_color /= 255.
fig, ax = plt.subplots(figsize=(fig_width, fig_width/phi))
ax.set_facecolor('black')
ax.scatter(space_bright['az'], space_bright['dec'], c=stars_color[None, :], ec='none', s=.4 * (space_bright['mag'].max()-space_bright['mag']))
ax.set_xlabel('Azimuth')
ax.set_ylabel('Declination')
ax.set_xlim(az_min, az_max)
ax.set_ylim(dec_min, dec_max);
do you see the Milky way?
Orion¶
We may want to focus on the Orion constellation:
orion_az_max, orion_az_min = ra2az(4.8), ra2az(6.25)
orion_dec_min, orion_dec_max = -13.0, 22.
space_orion = space_bright[(orion_az_min < space_bright['az']) * (space_bright['az'] < orion_az_max) *
(orion_dec_min < space_bright['dec']) * (space_bright['dec'] < orion_dec_max)]
print(f'Number of bright stars in orion = {len(space_orion)=}')
print(f"MAG: {space_orion['mag'].min()=}, {space_orion['mag'].max()=}")
fig, ax = plt.subplots(figsize=(fig_width, fig_width))
ax.set_facecolor('black')
ax.scatter(space_orion['az'], space_orion['dec'], c=stars_color[None, :], s= 10 * (space_orion['mag'].max()-space_orion['mag']))
ax.set_aspect('equal')
ax.set_xlabel('Azimuth')
ax.set_ylabel('Declination')
ax.set_xlim(orion_az_min, orion_az_max)
ax.set_ylim(orion_dec_min, orion_dec_max);
Which is to be compared to this image:
from IPython.display import display, SVG, Image
display(SVG('https://upload.wikimedia.org/wikipedia/commons/f/ff/Orion_IAU.svg'))
Triangulation¶
Following work with Etienne Rey, we have developped visualization based on triangulation of an optimal packing of point clouds.
display(Image('https://laurentperrinet.github.io/post/2021-10-04_interstices/featured.jpg'))
The idea here is to apply such a visualization to the stars position. IT is based on
import matplotlib.tri as tri
triang = tri.Triangulation(space_bright['az'], space_bright['dec'])
fig, ax = plt.subplots(figsize=(fig_width, fig_width))
ax.set_facecolor('black')
ax.triplot(triang, lw=0.1, color=stars_color[None, :])
ax.set_aspect('equal')
ax.set_xlabel('Azimuth')
ax.set_ylabel('Declination')
border_ratio = .95
ax.set_xlim(az_min+(az_max-az_min)*(1-border_ratio), az_min+(az_max-az_min)*border_ratio)
ax.set_ylim(dec_min+(dec_max-dec_min)*(1-border_ratio), dec_min+(dec_max-dec_min)*border_ratio);
fig, ax = plt.subplots(figsize=(fig_width, fig_width))
ax.set_facecolor('black')
ax.triplot(triang, lw=0.3, c=stars_color)
ax.scatter(space_orion['az'], space_orion['dec'], c=stars_color[None, :], ec='none', alpha=.5, s= 40 * (space_orion['mag'].max()-space_orion['mag']))
ax.set_aspect('equal')
ax.set_xlabel('Azimuth')
ax.set_ylabel('Declination')
ax.set_xlim(orion_az_min+(orion_az_max-orion_az_min)*(1-border_ratio), orion_az_min+(orion_az_max-orion_az_min)*border_ratio)
ax.set_ylim(orion_dec_min+(orion_dec_max-orion_dec_min)*(1-border_ratio), orion_dec_min+(orion_dec_max-orion_dec_min)*border_ratio);
q = 0.01
space_norm['mag'].quantile(q=q)
space_orion = space_norm[space_norm['mag']<space_norm['mag'].quantile(q=q)]
space_orion = space_orion[(orion_az_min < space_orion['az']) * (space_orion['az'] < orion_az_max) *
(orion_dec_min < space_orion['dec']) * (space_orion['dec'] < orion_dec_max)]
Let's now super-impose different triangulations at different magnitudes:
fig, ax = plt.subplots(figsize=(fig_width, fig_width))
ax.set_facecolor('black')
for mag in range(2, 8):
#q = 1 - 0.8**mag
#print (q)
space_orion = space_norm.copy()
#space_orion = space_norm[space_norm['mag']<mag]
space_orion = space_orion[(orion_az_min < space_orion['az']) * (space_orion['az'] < orion_az_max) *
(orion_dec_min < space_orion['dec']) * (space_orion['dec'] < orion_dec_max)]
space_orion = space_orion[space_orion['mag'] > space_orion['mag'].max()-mag]
print(f'{mag=:.3f}, Number of bright stars = {len(space_orion)=}')
triang = tri.Triangulation(space_orion['az'], space_orion['dec'])
ax.triplot(triang, lw=9/mag**2, color=stars_color, alpha=.4)
#ax.scatter(space_orion['az'], space_orion['dec'], s= 40 * (space_orion['mag'].max()-space_orion['mag']))
ax.set_aspect('equal')
ax.set_xlabel('Azimuth')
ax.set_ylabel('Declination')
ax.set_xlim(orion_az_min+(orion_az_max-orion_az_min)*(1-border_ratio), orion_az_min+(orion_az_max-orion_az_min)*border_ratio)
ax.set_ylim(orion_dec_min+(orion_dec_max-orion_dec_min)*(1-border_ratio), orion_dec_min+(orion_dec_max-orion_dec_min)*border_ratio);
some book keeping for the notebook¶
%load_ext watermark
%watermark -i -h -m -v -p numpy,matplotlib,scipy,pillow,imageio -r -g -b