This notebook processes data from the Gaia Catalog of Nearby Stars into a format that's usable with the godot-starlight addon, for rendering stars in games.

GCNS can be downloaded from VizieR here: https://cdsarc.cds.unistra.fr/viz-bin/cat/J/A+A/649/A6

It comes in FITS format, which can be read using astropy, and then the parsed tables can be used with pandas.

The fields that are relevant for this are:

`BPmag`

(blue half of spectrum) and`RPmag`

(red half of spectrum), which can be used to calculate effective temperature (`Teff`

).`Gmag`

(G band apparent magnitude) and`Dist50`

(50th percentile distance, in kiloparsecs), which can be used to calculate absolute magnitude, which in turn can be used to calculate luminosity in solar units.`xcoord50`

,`yxcoord50`

,`zcoord50`

, for position relative to the galactic plane in cartesian coordinates. Distance from origin is derived from`Dist50`

, hence the name.

```
from astropy.io import fits
import pandas as pd
import numpy as np
table1c = pd.DataFrame(fits.open('table1c.fits.gz')[1].data)
```

Calculations for `Teff`

are based on the formula Gaia Sky uses.

Some stars don't have correct measurements for BPmag and result in
`Teff`

of infinity. These are replaced with NA values so they will be
excluded from the final CSV. Most of these seem to be extremely dim
stars. There are about 6000 such sources.

```
def lint(x, x0, x1, y0, y1):
interp = y0 + (y1 - y0) * (x - x0) / (x1 - x0)
return interp.where(x > x0, y0).where(x < x1, y1)
def xp_to_teff(xp):
pow_teff = (3.999 - 0.654 * xp + 0.709 * xp.pow(2.0) - 0.316 * xp.pow(3.0)).rpow(10.0)
lint_teff = lint(xp, 1.5, 15.0, 3521.6, 3000.0)
return lint_teff.where(xp >= 1.5, pow_teff)
xp = table1c['BPmag'] - table1c['RPmag']
teff = xp_to_teff(xp)
teff = teff.where(table1c['BPmag'] != 0.0)
teff.loc[teff < 8000].plot.hist(bins=200, logy=True, label="Teff")
```

<Axes: ylabel='Frequency'>

Absolute magnitude ($M$) can be computed from apparent magnitude ($m$) and distance in parsecs ($d_{pc}$) if they are known. They are related by the equation:

$$ M = m - 5 log_{10}\left(d_{pc}\right) + 5 $$

Absolute magnitude is related to luminosity ($L$) relative to the Sun ($L_\odot$) with this equation:

$$ log_{10}\left(\frac{L}{L_\odot}\right) = \frac{M_\odot - M}{2.5} $$

where $M_\odot$ (absolute magnitude of the Sun) is 4.74.

```
def absmag(app: pd.Series, dist_kpc: pd.Series):
return app - 5 * np.log10(dist_kpc * 1000) + 5
def luminosity(abs: pd.Series):
return ((4.74 - abs) / 2.5).rpow(10)
Gabs = absmag(table1c['Gmag'], table1c['Dist50'])
lum = luminosity(Gabs)
Gabs.hist(bins=200)
```

<Axes: >

Now the final CSV file can be generated. `xcoord50`

is shortened to just `x`

and the columns that were just calculated are exported as well. NA values are dropped so that only stars with valid data will be included.

```
tab = table1c.filter(['xcoord50', 'ycoord50', 'zcoord50'])
tab.insert(0, 'temperature', teff.round(0))
tab.insert(0, 'magnitude', Gabs.round(2))
tab = tab.rename(columns={'xcoord50': 'x', 'ycoord50': 'y', 'zcoord50': 'z'})
tab = tab.dropna()
tab.to_csv('stars.csv', index=False)
```