The Hertzsprung-Russell Diagram.

Siria Sadeddin

Introduction

One of the most useful and powerful plots in astrophysics is the Hertzsprung-Russell diagram. It originated in 1911 when the Danish astronomer, Ejnar Hertzsprung, plotted the absolute magnitude of stars against their colour. Independently in 1913 the American astronomer Henry Norris Russell used spectral class against absolute magnitude. Their resultant plots showed that the relationship between temperature and luminosity of a star was not random but instead appeared to fall into distinct groups.[1] We will reproduce this diagram using the data provided in this course, this data consist in "txt" and "csv" files that contain information for each of the star classes:

  • Duarfs: dwarfs.csv
  • Giants: giants.txt
  • Main Sequence: ms.csv
  • Supergiants: supergiants.txt

Each of these files have the following information:

  • lum: Luminosity
  • temp: temperature in Kelvin
  • radius: radius of the star in

[1] https://www.atnf.csiro.au/outreach/education/senior/astrophysics/stellarevolution_hrintro.html

picture

Data preparation

Our strategy will be reading this files and join them, so we will have a unique dataframe of data for the stars. We will use pandas python library for this task.

In [8]:
#import pandas and numpy
import pandas as pd
import numpy as np
In [9]:
# define data directory
dir="./data"
In [10]:
# read files
dwarfs=pd.read_csv(dir+"/dwarfs.csv")
giants=pd.read_csv(dir+"/giants.txt", sep=" ")
ms=pd.read_csv(dir+"/ms.csv")
supergiants=pd.read_csv(dir+"/supergiants.txt", sep=" ")
In [11]:
# create new column "type" for identifying the star class in dataframe
dwarfs['type']='dwarfs'
giants['type']='giants'
ms['type']='ms'
supergiants['type']='supergiants'
In [12]:
# join datasets
df=pd.concat([dwarfs,giants,ms,supergiants],ignore_index=True)

#create new star class "blue giant" for the hottest supergiant available in data 
df.loc[(df.temp==np.max(df[(df.type=='supergiants')].temp)) & (df.type=='supergiants'),'type']='blue giant'

#take the log base 10 of the luminosity, radius and temperature. This will help on distinguish between data points, since some of them are
# orders of magnitude appart
df['log_lum']=np.log10(df.lum)
df['log_radius']=np.log10(df.radius)
df['log_temp']=np.log10(df.temp)

# sort values by temperature and reset row index numbers
df=df.sort_values('temp')
df = df.reset_index(drop=True)
df.head()
Out[12]:
lum temp radius type log_lum log_radius log_temp
0 0.000776 3577.003926 0.814703 ms -3.1104 -0.089001 3.553519
1 304.228573 3654.601099 145.483474 giants 2.4832 2.162814 3.562840
2 0.002638 3691.168543 1.209778 ms -2.5788 0.082706 3.567164
3 0.006823 3793.506494 1.630027 ms -2.1660 0.212195 3.579041
4 359749.335156 3801.042587 278.055832 supergiants 5.5560 2.444132 3.579903

Diagram plotting

We will use seaborn and matplotlib python libraries to make a visualization of the diagram. Seaborn helps on setting the point sizes and color easily. For the cluster names labeling (star clases), we will take the mean of the temperature and log10(luminosity), this gives the cluster centroid positions for each star class.

In [13]:
#libaries import
import seaborn as sns
import matplotlib
import matplotlib.pyplot as plt
In [14]:
#cluster means
means=df.groupby('type').mean()
means
Out[14]:
lum temp radius log_lum log_radius log_temp
type
blue giant 779830.110523 10200.701561 19.604244 5.892000 1.292350 4.008630
dwarfs 0.000304 6851.165387 4.312305 -3.600667 0.617061 3.829688
giants 92.579808 4009.110946 64.770748 1.698400 1.731200 3.602071
ms 27.658464 6834.153632 4.479883 0.605920 0.604103 3.817994
supergiants 674267.072595 5375.640867 163.832724 5.785000 2.134169 3.713757

Hertzsprung-Russell Diagram

In [15]:
# plot canvas
fig = plt.figure(figsize=(10,10))
plt.xlim(14000, 3000)
plt.title("Hertzsprung-Russell Diagram", fontsize=20)
plt.xlabel('temp K',fontsize=20)
plt.ylabel('log_lum',fontsize=20)
sns.set_style("dark")

# plot data points
sns.scatterplot(data=df,
                x='temp',
                y='log_lum',
                hue=df.temp,
                size=df.radius,
                sizes=(100, 1000),
                palette="Spectral",
                legend=False) 

#plot cluster labels for each star class
plt.text(means.loc['dwarfs','temp'], means.loc['dwarfs','log_lum'], 'DWARFS', style='normal',color='red', fontsize=16,horizontalalignment='center',fontweight='bold')
plt.text(means.loc['giants','temp'], means.loc['giants','log_lum'], 'GIANTS', style='normal',color='red', fontsize=16,horizontalalignment='right',verticalalignment='bottom',fontweight='bold')
plt.text(means.loc['ms','temp'], means.loc['ms','log_lum'], 'MAIN SEQUENCE', style='normal',color='orange', fontsize=16,horizontalalignment='right',verticalalignment='top',rotation=-25,fontweight='bold')
plt.text(means.loc['supergiants','temp'], means.loc['supergiants','log_lum'], 'SUPERGIANTS', style='normal',color='red', fontsize=16,horizontalalignment='center',verticalalignment='top',fontweight='bold')
plt.text(means.loc['blue giant','temp'], means.loc['blue giant','log_lum'], 'BLUE GIANTS', style='normal',color='blue', fontsize=16,horizontalalignment='center',verticalalignment='top',fontweight='bold')

#show plot
plt.show()

Luminosity vs radius

In [17]:
# plot canvas
fig = plt.figure(figsize=(10,10))
#plt.xlim(14000, 3000)
plt.title("Radius vs luminosity", fontsize=20)
plt.xlabel('log_radius',fontsize=20)
plt.ylabel('log_lum',fontsize=20)
sns.set_style("dark")

# plot data points
sns.scatterplot(data=df,
                x='log_radius',
                y='log_lum',
                legend=False,
                hue=df.log_temp,
                size=df.log_radius,
                palette="Spectral",
                sizes=(1, 1000)
                ) 

#plot cluster labels for each star class
plt.text(means.loc['dwarfs','log_radius'], means.loc['dwarfs','log_lum'], 'DWARFS', style='normal',color='red', fontsize=16,horizontalalignment='center',fontweight='bold')
plt.text(means.loc['giants','log_radius'], means.loc['giants','log_lum'], 'GIANTS', style='normal',color='red', fontsize=16,horizontalalignment='right',verticalalignment='bottom',fontweight='bold')
plt.text(means.loc['ms','log_radius'], means.loc['ms','log_lum'], 'MAIN SEQUENCE', style='normal',color='orange', fontsize=16,horizontalalignment='right',verticalalignment='top',rotation=-25,fontweight='bold')
plt.text(means.loc['supergiants','log_radius'], means.loc['supergiants','log_lum'], 'SUPERGIANTS', style='normal',color='red', fontsize=16,horizontalalignment='center',verticalalignment='top',fontweight='bold')
plt.text(means.loc['blue giant','log_radius'], means.loc['blue giant','log_lum'], 'BLUE GIANTS', style='normal',color='blue', fontsize=16,horizontalalignment='center',verticalalignment='top',fontweight='bold')

#show plot
plt.show()

The plot shows the well known form of the Hertzsprung-Russell diagram, on the center, we can observe the main sequence, which contains the regular stars. The main sequence has a linear like behavior (lum-temp plot), we can also see some outlier clusters that contains the rare stars as dwarfs, giants, supergiants and blue giants. The dwarfs for example, have low luminosity for their temperature, giants, supergiants and blue giants have high luminosity for their related temperature. The plot point sizes are related to the star radius and the point colors with their temperature (blue hotter and red colder). We have also made a luminosity-radius plot, wich shows that the radius of the star does not explain the oulier behavior of those stars, instead of that, we see again the clusters for the dwarfs, giants, supergiants and blue giants

Animation

We will use the previous plot to make an animated plot. The matplotlib.animation sublibrary will be used for this task.

In [18]:
# import library
from matplotlib.animation import FuncAnimation
In [32]:
# define animation iteration function
# set canvas configuration
fig, ax = plt.subplots(figsize=(10,10))
ax.set(xlim=(14000, 3000),ylim=(-5, 7))
plt.title("Hertzsprung-Russell Diagram", fontsize=20)
plt.xlabel('temp K',fontsize=20)
plt.ylabel('log_lum',fontsize=20)
sns.set_style("dark")

def animate(i):
    #data slice
    dfi=df.loc[0:i,:]
    
    #make plot
    sns.scatterplot(data=dfi,x='temp',y='log_lum',hue=df.temp,size=df.radius,sizes=(100, 1000),palette="Spectral",legend=False) 
    
    #print cluster labels
    if any(dfi.type=="dwarfs"):
        plt.text(means.loc['dwarfs','temp'], means.loc['dwarfs','log_lum'], 'DWARFS', style='normal',color='red', fontsize=16,horizontalalignment='center',fontweight='bold')
    
    if any(dfi.type=="giants"):    
        plt.text(means.loc['giants','temp'], means.loc['giants','log_lum'], 'GIANTS', style='normal',color='red', fontsize=16,horizontalalignment='right',verticalalignment='bottom',fontweight='bold')
    
    if any(dfi.type=="ms"):
        plt.text(means.loc['ms','temp'], means.loc['ms','log_lum'], 'MAIN SEQUENCE', style='normal',color='orange', fontsize=16,horizontalalignment='right',verticalalignment='top',rotation=-25,fontweight='bold')
    
    if any(dfi.type=="supergiants"):
        plt.text(means.loc['supergiants','temp'], means.loc['supergiants','log_lum'], 'SUPERGIANTS', style='normal',color='red', fontsize=16,horizontalalignment='center',verticalalignment='top',fontweight='bold')
    
    if any(dfi.type=="blue giant"):
        plt.text(means.loc['blue giant','temp'], means.loc['blue giant','log_lum'], 'BLUE GIANTS', style='normal',color='blue', fontsize=16,horizontalalignment='center',verticalalignment='top',fontweight='bold')

#make animation 
anim = FuncAnimation(fig, animate, interval=100, frames=len(df)-1)

#save animation 
anim.save('Hertzsprung-Russell-Diagram.gif')
MovieWriter ffmpeg unavailable; using Pillow instead.

Final comments

We have shown the characteristics of the Hertzsprung-Russell Diagram and used the available data to reproduce it satifactorily, we have made data manipulation with pandas library, data plotting and animation with matplotlib library. The Hertzsprung-Russell Diagram shows the behavior of star's luminosity related to their temperature, which is, normaly almost linear. In contrast, we find groups of stars which show an outlier behavior, and as out luminosity-radius plot showed, can not be explained by the star size.