File:Colours and temperatures of main sequence stars 1.svg
Original file (SVG file, nominally 1,333 × 819 pixels, file size: 44 KB)
Captions
Summary
[edit]DescriptionColours and temperatures of main sequence stars 1.svg |
English: Colours and surface temperatures of main sequence stars |
Date | |
Source | Own work |
Author | Merikanto |
Source of main sequence data
https://en.wikipedia.org/wiki/Main_sequence
Source of CIE data
https://github.com/jrr1984/Prototipo0_S-D_SpectralGUI/blob/master/spectral_gui/cie-cmf.txt
Python code
- star spectral type and temperature interpolate
- view star colours in filled circles
- needs predefined table of staller tspectral types, masses, temperatures ...
- python 3 code
- 13.2.2023 v 0000.0002
import numpy as np
- import scipy as sp
import matplotlib.pyplot as plt
import math
import pandas as pd
from sklearn import metrics
from sklearn.linear_model import LinearRegression
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import r2_score
from pygam import GAM, s, te
from pygam import LinearGAM
from pygam import PoissonGAM
- from pygam import LogisticGAM
from scipy import interpolate
from scipy.constants import h, c, k
from matplotlib.patches import Circle
from colour_system import cs_hdtv
cs = cs_hdtv
def planck(lam, T):
lam_m = lam / 1.e9
fac = h*c/lam_m/k/T
B = 2*h*c**2/lam_m**5 / (np.exp(fac) - 1)
return B
def linear_log_predict1(x,y):
logx=np.log10(x).reshape(-1, 1)
logy=np.log10(y).reshape(-1, 1)
logmodel= LinearRegression().fit(logx, logy)
logk=logmodel.coef_
logb=logmodel.intercept_
#print(logmodel)
logpre=logmodel.predict(logx)
pre=np.power(10, logpre)
return(pre, logk, logb)
def linear_log_predict2(x,y, x2):
logx=np.log10(x).reshape(-1, 1)
logy=np.log10(y).reshape(-1, 1)
logx2=np.log10(x2).reshape(-1, 1)
logmodel= LinearRegression().fit(logx, logy)
logk=logmodel.coef_
logb=logmodel.intercept_
#print(loglums_model)
logpre=logmodel.predict(logx2)
pre=np.power(10, logpre)
return(pre)
def linear_log_predict_point(x,y, px):
logx=np.log10(x).reshape(-1, 1)
logy=np.log10(y).reshape(-1, 1)
logmodel= LinearRegression().fit(logx, logy)
logk=logmodel.coef_
logb=logmodel.intercept_
logpx=math.log10(px)
logpy=logb+logpx*logk
py=math.pow(10,logpy)
return(py)
def gamma_log_predict2(x,y, x2):
logx=np.log10(x).reshape(-1, 1)
logy=np.log10(y).reshape(-1, 1)
logx2=np.log10(x2).reshape(-1, 1)
gam = LinearGAM(s(0, n_splines=10)).fit(logx,logy)
#gam = PoissonGAM(s(0, n_splines=10)).fit(logx,logy)
logpre = gam.predict(logx2)
pre=np.power(10, logpre)
return(pre)
def gamma_predict3(x,y, x2):
ex=x.reshape(-1, 1)
ey=y.reshape(-1, 1)
ex2=x2.reshape(-1, 1)
gam = LogisticGAM(s(0, n_splines=10)).fit(ex,ey)
pre = gam.predict(ex2)
return(pre)
def rf_log_predict2(x,y, x2):
logx=np.log10(x).reshape(-1, 1)
logy=np.log10(y).reshape(-1, 1)
logx2=np.log10(x2).reshape(-1, 1)
regressor = RandomForestRegressor(n_estimators=10000, random_state=0)
regressor.fit(logx,logy)
logpre = regressor.predict(logx2)
pre=np.power(10, logpre)
return(pre)
def interpolate1(x,y, x2):
f = interpolate.interp1d(x, y)
y2 = f(x2)
return(y2)
def interpolate_point(x,y, px):
f = interpolate.interp1d(x, y)
y2 = f(px)
return(y2)
def interpolate2(x,y, x2):
logx=np.log10(x).reshape(-1, 1)
logy=np.log10(y).reshape(-1, 1)
logx2=np.log10(x2).reshape(-1, 1)
f = interpolate.interp1d(logx, logy)
y2 = f(logx2)
pre=np.power(10,y2)
return(y2)
def speknum(spt):
spe=spt
spe=spe.replace('O', '1')
spe=spe.replace('B', '2')
spe=spe.replace('A', '3')
spe=spe.replace('F', '4')
spe=spe.replace('G', '5')
spe=spe.replace('K', '6')
spe=spe.replace('M', '7')
spe=spe.replace('L', '8')
return(int(spe))
- load main sequence star data, edited from wiki 2023
- https://en.wikipedia.org/wiki/Main_sequence
arrname1="mainseq1.txt"
starr1 = np.loadtxt(arrname1,skiprows=1,dtype="float",delimiter=",",usecols =(1,2,3,4))
print(starr1)
masses1=starr1[:,1]
lums1=starr1[:,2]
temps1=starr1[:,3]
radiuses1=starr1[:,0]
print (masses1)
print (lums1)
print (temps1)
df00 = pd.read_csv(arrname1, sep=",")
- print(df00)
spek1=df00['spectral']
- print(spek1)
classes="OBAFGKML"
spek2=spek1.tolist()
- print(spek2)
spek3 = [sub.replace('O', '1') for sub in spek2]
spek3 = [sub.replace('B', '2') for sub in spek3]
spek3 = [sub.replace('A', '3') for sub in spek3]
spek3 = [sub.replace('F', '4') for sub in spek3]
spek3 = [sub.replace('G', '5') for sub in spek3]
spek3 = [sub.replace('K', '6') for sub in spek3]
spek3 = [sub.replace('M', '7') for sub in spek3]
spek3 = [sub.replace('L', '8') for sub in spek3]
- print(spek3)
spek4=np.array(spek3).astype(float)
- print(spek4)
speg1=np.arange(12,82,1)
- print(speg1)
speg2=speg1.astype(int)
- print(speg2)
speg3=speg2.tolist()
- print(speg3)
speg4 = [str(x) for x in speg3]
- print(speg4)
speg5=[]
first1=0
for sx in speg4:
sy=sx
print(sy)
chari1=sy[0]
if(sy[0]=='1'):
sy=sy.replace(sy[0],"O",1)
if(sy[0]=='2'):
sy=sy.replace(sy[0],"B",1)
if(sy[0]=='3'):
sy=sy.replace(sy[0],"A",1)
if(sy[0]=='4'):
sy=sy.replace(sy[0],"F",1)
if(sy[0]=='5'):
sy=sy.replace(sy[0],"G",1)
if(sy[0]=='6'):
sy=sy.replace(sy[0],"K",1)
if(sy[0]=='7'):
sy=sy.replace(sy[0],"M",1)
if(sy[0]=='8'):
sy=sy.replace(sy[0],"L",1)
speg5.append(sy)
- print("speg5")
- print(spek4)
- print(speg1)
- print(speg5)
spektr1=spek4
spektr2=speg1
sally1=spek2
sally2=speg5
print(sally1)
print(sally2)
print(spektr1)
print(spektr2)
masses2=interpolate1(spektr1, masses1, spektr2)
radiuses2=interpolate1(spektr1, radiuses1, spektr2)
lums2=interpolate1(spektr1, lums1, spektr2)
temps2=interpolate1(spektr1, temps1, spektr2)
spt1="G2"
spnum1=speknum(spt1)
teff1=interpolate_point(spektr1,temps1, spnum1)
print(spt1, spnum1,teff1)
- lum1=interpolate_point(masses1, lums1, m1)
- plt.xlim(0.1, 1.5)
- plt.ylim(0.0, 3)
font = {'family' : 'DejaVu Sans',
'weight' : 'normal',
'size' : 18}
- plt.rc('font', **font)
- plt.title ("Main sequence spectral class - surface temperature", size=20)
- plt.plot(spektr1, temps1, "o", lw=6)
- plt.plot(spektr2, temps2, "-", color="r", lw=10)
- plt.grid(color='b', linestyle=':', linewidth=1)
- plt.xticks(spektr1, sally1)
- plt.plot(spnum1, teff1, "x")
- plt.show()
fig, ax = plt.subplots()
- The grid of visible wavelengths corresponding to the grid of colour-matching
- functions used by the ColourSystem instance.
lam = np.arange(380., 781., 5)
for i in range(len(spektr1)):
# T = 500 to 12000 K
#T = 500*i + 500
T=int(temps1[i])
sp1=sally1[i]
# Calculate the black body spectrum and the HTML hex RGB colour string
# it looks like
spec = planck(lam, T)
html_rgb = cs.spec_to_rgb(spec, out_fmt='html')
# Place and label a circle with the colour of a black body at temperature T
x, y = i % 5, -(i // 5)
circle = Circle(xy=(x, y*1.2), radius=0.4, fc=html_rgb)
ax.add_patch(circle)
ax.annotate('{:4d} K'.format(T), xy=(x, y*1.2-0.6), va='center',
ha='center', color=html_rgb, fontsize=15)
ax.annotate('{:4s}'.format(sp1), xy=(x, y*1.2), va='center',
ha='center', color='k', fontsize=18)
- Set the limits and background colour; remove the ticks
ax.set_xlim(-0.5,5.0)
ax.set_ylim(-4.35, 0.5)
ax.set_xticks([])
ax.set_yticks([])
ax.set_facecolor('k')
- Make sure our circles are circular!
ax.set_aspect("equal")
plt.title("Colours and temperatures of main sequence stars", size=22)
plt.show()
CIE colour system code
- colour_system.py
import numpy as np
def xyz_from_xy(x, y):
"""Return the vector (x, y, 1-x-y)."""
return np.array((x, y, 1-x-y))
class ColourSystem:
"""A class representing a colour system.
A colour system defined by the CIE x, y and z=1-x-y coordinates of
its three primary illuminants and its "white point".
TODO: Implement gamma correction
"""
# The CIE colour matching function for 380 - 780 nm in 5 nm intervals
cmf = np.loadtxt('cie-cmf.txt', usecols=(1,2,3))
def __init__(self, red, green, blue, white):
"""Initialise the ColourSystem object.
Pass vectors (ie NumPy arrays of shape (3,)) for each of the
red, green, blue chromaticities and the white illuminant
defining the colour system.
"""
# Chromaticities
self.red, self.green, self.blue = red, green, blue
self.white = white
# The chromaticity matrix (rgb -> xyz) and its inverse
self.M = np.vstack((self.red, self.green, self.blue)).T
self.MI = np.linalg.inv(self.M)
# White scaling array
self.wscale = self.MI.dot(self.white)
# xyz -> rgb transformation matrix
self.T = self.MI / self.wscale[:, np.newaxis]
def xyz_to_rgb(self, xyz, out_fmt=None):
"""Transform from xyz to rgb representation of colour.
The output rgb components are normalized on their maximum
value. If xyz is out the rgb gamut, it is desaturated until it
comes into gamut.
By default, fractional rgb components are returned; if
out_fmt='html', the HTML hex string '#rrggbb' is returned.
"""
rgb = self.T.dot(xyz)
if np.any(rgb < 0):
# We're not in the RGB gamut: approximate by desaturating
w = - np.min(rgb)
rgb += w
if not np.all(rgb==0):
# Normalize the rgb vector
rgb /= np.max(rgb)
if out_fmt == 'html':
return self.rgb_to_hex(rgb)
return rgb
def rgb_to_hex(self, rgb):
"""Convert from fractional rgb values to HTML-style hex string."""
hex_rgb = (255 * rgb).astype(int)
return '#{:02x}{:02x}{:02x}'.format(*hex_rgb)
def spec_to_xyz(self, spec):
"""Convert a spectrum to an xyz point.
The spectrum must be on the same grid of points as the colour-matching
function, self.cmf: 380-780 nm in 5 nm steps.
"""
XYZ = np.sum(spec[:, np.newaxis] * self.cmf, axis=0)
den = np.sum(XYZ)
if den == 0.:
return XYZ
return XYZ / den
def spec_to_rgb(self, spec, out_fmt=None):
"""Convert a spectrum to an rgb value."""
xyz = self.spec_to_xyz(spec)
return self.xyz_to_rgb(xyz, out_fmt)
illuminant_D65 = xyz_from_xy(0.3127, 0.3291)
cs_hdtv = ColourSystem(red=xyz_from_xy(0.67, 0.33),
green=xyz_from_xy(0.21, 0.71),
blue=xyz_from_xy(0.15, 0.06),
white=illuminant_D65)
cs_smpte = ColourSystem(red=xyz_from_xy(0.63, 0.34),
green=xyz_from_xy(0.31, 0.595),
blue=xyz_from_xy(0.155, 0.070),
white=illuminant_D65)
cs_srgb = ColourSystem(red=xyz_from_xy(0.64, 0.33),
green=xyz_from_xy(0.30, 0.60),
blue=xyz_from_xy(0.15, 0.06),
white=illuminant_D65)
Stellar data
spectral,radius, mass, luminosity,teff
"O2",12,100,800000,50000
"O6",9.8,35,180000,38000
"B0",7.4,18,20000,30000
"B5",3.8,6.5,800,16400
"A0",2.5,3.2,80,10800
"A5",1.7,2.1,20,8620
"F0",1.3,1.7,6,7240
"F5",1.2,1.3,2.5,6540
"G0",1.05,1.10,1.26,5920
"G5",0.93,0.93,0.79,5610
"K0",0.85,0.78,0.40,5240
"K5",0.74,0.69,0.16,4410
"M0",0.51,0.60,0.072,3800
"M5",0.18,0.15,0.0027,3120
"M8",0.11,0.08,0.0004,2650
"L1",0.09,0.07,0.00017,2200
Cie colour system file
380 0.0014 0.0000 0.0065
385 0.0022 0.0001 0.0105
390 0.0042 0.0001 0.0201
395 0.0076 0.0002 0.0362
400 0.0143 0.0004 0.0679
405 0.0232 0.0006 0.1102
410 0.0435 0.0012 0.2074
415 0.0776 0.0022 0.3713
420 0.1344 0.0040 0.6456
425 0.2148 0.0073 1.0391
430 0.2839 0.0116 1.3856
435 0.3285 0.0168 1.6230
440 0.3483 0.0230 1.7471
445 0.3481 0.0298 1.7826
450 0.3362 0.0380 1.7721
455 0.3187 0.0480 1.7441
460 0.2908 0.0600 1.6692
465 0.2511 0.0739 1.5281
470 0.1954 0.0910 1.2876
475 0.1421 0.1126 1.0419
480 0.0956 0.1390 0.8130
485 0.0580 0.1693 0.6162
490 0.0320 0.2080 0.4652
495 0.0147 0.2586 0.3533
500 0.0049 0.3230 0.2720
505 0.0024 0.4073 0.2123
510 0.0093 0.5030 0.1582
515 0.0291 0.6082 0.1117
520 0.0633 0.7100 0.0782
525 0.1096 0.7932 0.0573
530 0.1655 0.8620 0.0422
535 0.2257 0.9149 0.0298
540 0.2904 0.9540 0.0203
545 0.3597 0.9803 0.0134
550 0.4334 0.9950 0.0087
555 0.5121 1.0000 0.0057
560 0.5945 0.9950 0.0039
565 0.6784 0.9786 0.0027
570 0.7621 0.9520 0.0021
575 0.8425 0.9154 0.0018
580 0.9163 0.8700 0.0017
585 0.9786 0.8163 0.0014
590 1.0263 0.7570 0.0011
595 1.0567 0.6949 0.0010
600 1.0622 0.6310 0.0008
605 1.0456 0.5668 0.0006
610 1.0026 0.5030 0.0003
615 0.9384 0.4412 0.0002
620 0.8544 0.3810 0.0002
625 0.7514 0.3210 0.0001
630 0.6424 0.2650 0.0000
635 0.5419 0.2170 0.0000
640 0.4479 0.1750 0.0000
645 0.3608 0.1382 0.0000
650 0.2835 0.1070 0.0000
655 0.2187 0.0816 0.0000
660 0.1649 0.0610 0.0000
665 0.1212 0.0446 0.0000
670 0.0874 0.0320 0.0000
675 0.0636 0.0232 0.0000
680 0.0468 0.0170 0.0000
685 0.0329 0.0119 0.0000
690 0.0227 0.0082 0.0000
695 0.0158 0.0057 0.0000
700 0.0114 0.0041 0.0000
705 0.0081 0.0029 0.0000
710 0.0058 0.0021 0.0000
715 0.0041 0.0015 0.0000
720 0.0029 0.0010 0.0000
725 0.0020 0.0007 0.0000
730 0.0014 0.0005 0.0000
735 0.0010 0.0004 0.0000
740 0.0007 0.0002 0.0000
745 0.0005 0.0002 0.0000
750 0.0003 0.0001 0.0000
755 0.0002 0.0001 0.0000
760 0.0002 0.0001 0.0000
765 0.0001 0.0000 0.0000
770 0.0001 0.0000 0.0000
775 0.0001 0.0000 0.0000
780 0.0000 0.0000 0.0000
Licensing
[edit]- You are free:
- to share – to copy, distribute and transmit the work
- to remix – to adapt the work
- Under the following conditions:
- attribution – You must give appropriate credit, provide a link to the license, and indicate if changes were made. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use.
- share alike – If you remix, transform, or build upon the material, you must distribute your contributions under the same or compatible license as the original.
File history
Click on a date/time to view the file as it appeared at that time.
Date/Time | Thumbnail | Dimensions | User | Comment | |
---|---|---|---|---|---|
current | 10:47, 13 February 2023 | 1,333 × 819 (44 KB) | Merikanto (talk | contribs) | Update | |
10:22, 13 February 2023 | 1,138 × 791 (44 KB) | Merikanto (talk | contribs) | Uploaded own work with UploadWizard |
You cannot overwrite this file.
File usage on Commons
There are no pages that use this file.
Metadata
This file contains additional information such as Exif metadata which may have been added by the digital camera, scanner, or software program used to create or digitize it. If the file has been modified from its original state, some details such as the timestamp may not fully reflect those of the original file. The timestamp is only as accurate as the clock in the camera, and it may be completely wrong.
Width | 1066.32pt |
---|---|
Height | 655.2pt |