Investigue sobre el diagrama de Hertzsprung-Russell, una herramienta muy potente en astronomia, y describa un poco al respecto para darle contexto al resto de la tarea
El diagrama de Hertzsprung-Russell es un gráfico entre la luminosidad (o variables equivalentes) y la temperatura efectiva (o variables independientes) de un conjunto de estrellas. La información valiosa que este gráfico muestra es que la luminosidad y temperatura de las estrellas no están distribuidas aleatoreamente sino que se agrupan en ciertas regiones, las cuales se han identificado como diferentes fases de la vida de una estrella. Así pues, a lo largo de su vida, una estrella sigue un camino evolutivo sobre el diagrama (el camino preciso dependerá de cuánta masa de gas tenía la estrella cuando fue formada).
El objetivo es generar un diagrama HR lo más parecido al de esta referencia. No lucirá idéntico por que no se usarán exactamente los mismos datos, y las unidades pueden ser ligeramente distinta. La idea sí es dejar su figura lo más parecida a la de referencia en el estilo: colores, escalas en los ejes, tamaño de los marcadores, leyendas, textos en el gráfico, etc.

Los datos para crear la figura están en la carpeta data. Cada tabla contiene las informaciones sobre un tipo de estrellas según indican los nombres de archivo. La información viene en 3 columnas: luminosidad en luminosidades solares, Temperatura en Kelvin y Radio de la estrella en unidades arbitrarias
Primero cargo los datos
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import rc
import matplotlib.ticker
ms = np.loadtxt('data/ms.csv', delimiter =',', skiprows = 1, unpack = True)
giants = np.loadtxt('data/giants.txt', delimiter =' ', skiprows = 1, unpack = True)
supergiants = np.loadtxt('data/supergiants.txt', delimiter =' ', skiprows = 1, unpack = True)
dwarfs = np.loadtxt('data/dwarfs.csv', delimiter =',', skiprows = 1, unpack = True)
Algunas personalizaciones generales como el tamaño y el tipo de letra de los labels y ticks
rc('axes', linewidth = 1.3, labelweight = 'bold', labelsize = '18')
rc('font', weight = 'bold')
Ahora sí creo el gráfico
# creo el bastidor
fig, ax = plt.subplots(figsize=(14,12))
# personalización de los ejes
# escala logarítmica en ambos ejes
ax.set_xscale('log')
ax.set_yscale('log')
# elimino los ejes superior y derecho
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
# fijo el tamaño de los números de eje
ax.tick_params(axis='both', which='major', labelsize=12)
# especifico los ticks que aparecen
ax.set_xticks([5000,10000])
ax.set_xticks([], minor=True)
# elimino la notación científica del eje x
ax.get_xaxis().set_major_formatter(matplotlib.ticker.ScalarFormatter())
ax.get_xaxis().set_minor_formatter(matplotlib.ticker.NullFormatter())
# nombro los ejes
ax.set_xlabel('Temperature (K)')
ax.set_ylabel('Luminosity (L$_{sun}$)')
# invierto el eje x
ax.invert_xaxis()
# escala de color
# defino la escala de colores como los valores extremos de la intensidad
allTemps = np.concatenate([ms[1], giants[1], supergiants[1],dwarfs[1]], axis=0)
min_T, max_T = allTemps.min(), allTemps.max()
# grafico los datos, tomando la superficie de cada marcador proporcional a su radio
ax.scatter(ms[1],ms[0],s = 20*ms[2], c = ms[1], cmap = 'RdYlBu', vmin = min_T, vmax = max_T,
linewidths=1.5, edgecolor = 'grey')
ax.scatter(giants[1],giants[0],s = 20*giants[2], c = giants[1], cmap = 'RdYlBu', vmin = min_T, vmax = max_T,
linewidths=1.5, edgecolor = 'grey')
ax.scatter(supergiants[1], supergiants[0],s = 20*supergiants[2], c = supergiants[1], cmap = 'RdYlBu',
vmin = min_T, vmax = max_T, linewidths=1.5, edgecolor = 'grey')
ax.scatter(dwarfs[1], dwarfs[0],s = 20*dwarfs[2], c = 'white', linewidths=1.5, edgecolor = 'grey')
# añado etiquetas de cada conjunto de estrellas como texto
ax.text(5500,0.01,'Main Sequence', fontsize = 20, weight = 'bold')
ax.text(13000,6,'Main Sequence', fontsize = 20, weight = 'bold')
ax.text(4500,2,'Red Giants', fontsize = 20, weight = 'bold')
ax.text(5000,0.3e7,'Red Supergiants', fontsize = 20, weight = 'bold')
ax.text(11500,0.3e7,'Blue Giants', fontsize = 20, weight = 'bold')
ax.text(10000,0.002,'White Dwarfs', fontsize = 20, weight = 'bold')
plt.show()
Después de tener un diseño de base para el ejercicio No. 1, en este ejercicio se pide generar una animación, en la cual se reproduzca el miso gráfico de antes pero las estrellas vayan apareciendo progresivamente.
%matplotlib notebook
from matplotlib.animation import FuncAnimation
fig, ax = plt.subplots(figsize=(14,12))
# defino los extremos de luminosidad y temperatura
allTemps = np.concatenate([ms[1], giants[1], supergiants[1],dwarfs[1]], axis=0)
min_T, max_T = allTemps.min(), allTemps.max()
allLumi = np.concatenate([ms[0], giants[0], supergiants[0],dwarfs[0]], axis=0)
min_L, max_L = allLumi.min(), allLumi.max()
# personalización de los ejes
# escala logarítmica en ambos ejes
ax.set_xscale('log')
ax.set_yscale('log')
# elimino los ejes superior y derecho
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
# fijo el tamaño de los números de eje
ax.tick_params(axis='both', which='major', labelsize=12)
# especifico los ticks que aparecen
ax.set_xticks([5000,10000])
ax.set_xticks([], minor=True)
# elimino la notación científica del eje x
ax.get_xaxis().set_major_formatter(matplotlib.ticker.ScalarFormatter())
ax.get_xaxis().set_minor_formatter(matplotlib.ticker.NullFormatter())
# nombro los ejes
ax.set_xlabel('Temperature (K)')
ax.set_ylabel('Luminosity (L$_{sun}$)')
# invierto el eje x
ax.invert_xaxis()
# añado etiquetas de cada conjunto de estrellas como texto
ax.text(5500,0.01,'Main Sequence', fontsize = 20, weight = 'bold')
ax.text(13000,6,'Main Sequence', fontsize = 20, weight = 'bold')
ax.text(4500,2,'Red Giants', fontsize = 20, weight = 'bold')
ax.text(5000,0.3e7,'Red Supergiants', fontsize = 20, weight = 'bold')
ax.text(11500,0.3e7,'Blue Giants', fontsize = 20, weight = 'bold')
ax.text(10000,0.002,'White Dwarfs', fontsize = 20, weight = 'bold')
# uno todos los arreglos para poder animar
Lumis = np.concatenate((ms[0], giants[0], supergiants[0],dwarfs[0]))
Temps = np.concatenate((ms[1], giants[1], supergiants[1],dwarfs[1]))
Rads = np.concatenate((ms[2], giants[2], supergiants[2],dwarfs[2]))
#creo un sample de la figura y esta se va a sobre escribir
plt.figure(1)
scat = ax.scatter(Temps,Lumis,s = 20*Rads, c = Temps, cmap = 'RdYlBu',linewidths=1.5, edgecolor = 'grey',vmin = min_T, vmax = max_T)
# animation
def animate(i):
data = np.hstack((Temps[:i,np.newaxis], Lumis[:i, np.newaxis]))
scat.set_offsets(data)
return scat,
anim = FuncAnimation(fig, animate, frames=len(Temps)+1,
interval=200, blit=False, repeat=False)
anim.save('animation.gif')
MovieWriter ffmpeg unavailable; using Pillow instead.