Mi nombre es Juan Carrillo. El objetivo de este notebook es resolver los ejercicios de la Clase No. 3
Ejercicio No. 1
El diagrama Hertzprung-Russel es un diagrama estadístico que permite clasificar las estrellas basadas en su temperatura y luminosidad. El próposito de este Notebook es re-crear dicho diagrama para una serie de datos dadas que son representativas a la forma normal del diagrama
En primera instancia se importan las librerías necesarias para la elaboración del proyecto. Estas corresponden a:
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.ticker import FuncFormatter
from matplotlib.animation import FuncAnimation
Ahora se debe de abrir las bases de datos provistas, lo cuál se hace a través de la función read_csv de pandas y se crea un DataFrame para cada base de datos
Dwarfs = pd.read_csv('data/dwarfs.csv')
MainSequence = pd.read_csv('data/ms.csv')
Giants = pd.read_csv('data/giants.txt',sep=' ')
Supergiants = pd.read_csv('data/supergiants.txt',sep=' ')
Con el fin de unificar los datos en un solo DataFrame fácil de usar se unifican los creados anteriormente usando la función concat de pandas
AllStars = pd.concat([MainSequence,Dwarfs,Giants,Supergiants])
Ahora viene se procede a generar la gráfica de los datos obtenidos anteriormente Como punto de partida se genera el template de la gráfica, esto incluye tamaño, ejes, escalas, titulos y otros, y se proceden a gráficar los puntos. En el siguiente código se explica cada función
#Se inicializa la función plt y se determina el tamaño de la figura
plt.figure(figsize=(15,10))
ax = plt.subplot()
#Se establecen los minimos y máximos de los ejes y se determinan como escala logaritimica, es importante notar que para
#el eje X se identifica el mayor valor, menor valor con el fin de que al graficar la escala sea decendente
plt.xlim(14000,3000)
plt.xscale('log')
plt.ylim(10**-5,10**9)
plt.yscale('log')
plt.xticks([3500,7000,14000])
#Se modifican los ticks del eje X con el fin de eliminar la notación cientifica
def log_10_product(x, pos):
return '%1i' % (x)
formatter = FuncFormatter(log_10_product)
ax.xaxis.set_major_formatter(formatter)
plt.setp(ax.get_xminorticklabels(), visible=False)
#Se añanaden los nombres de los ejes X, Y y el Titulo
plt.xlabel('Temperature (K)',fontsize=15)
plt.ylabel('Luminosity (Lsun)',fontsize=15)
plt.title('Hertzsprung-Russell Diagram',fontsize=20)
#Se añaden textos dentro de la gráfica que permiten identificar los tipos de estrella según su posición en el diagrama
plt.text(5000,10**8,'Red Supergiants',fontsize=15)
plt.text(5000,10**3,'Red Giants',fontsize=15)
plt.text(12500,10**8,'Blue Giants',fontsize=15)
plt.text(13000,10,'Main Sequence',fontsize=15)
plt.text(4800,10**-3,'Main Sequence',fontsize=15)
plt.text(9000,10**-2,'White Dwarfs',fontsize=15)
#Se añaden los puntos a la gráfica considerando que el valor x es temperatura, y luminosidad, el tamaño es dependiente
#de la variable radius dada, y para facilidad en la visualización se multiplica por 50, y el color es dependiente de la
#temperatura, de esta manera la función plt.scatter en su parametro c determina el color en una escala de colores determinada
#como RdYlBu que varía de Rojo a Amarillo a Azul según el valor de la temperatura en el punto dado, adicionalmente se añaden
#bordes grises a cada punto
plt.scatter(x = AllStars.temp, y = AllStars.lum,s=AllStars.radius*50,c = AllStars.temp,cmap='RdYlBu',edgecolors='grey',linewidth=1.5)
#En este caso las Enanas Blancas cumplen una excepción al color del punto anterior, puesto que su color no es dependiente
#de la temperatura, por lo que encima del gráfico anterior se plotea los mismos datos pero de color blanco
plt.scatter(x = Dwarfs.temp, y = Dwarfs.lum,s=Dwarfs.radius*50,color='white',edgecolors='grey',linewidth=1.5)
#finalmente se muestra la gráfica generada que corresponde al diagrama Hertzprung-Russel para los datos dados
plt.show()
Ejercicio No. 2
El próposito de este ejercicio es animar la generación de la gráfica anterior. Para ello daremos uso a la función FuncAnimation de Matplotlib:
#En primer lugar se establece template inicial donde se generará la gráfica. Este corresponde al mismo del punto
#anterior donde se modifica el tamaño, ejes, escalas etc
#es importante detallar que la gráfica se identifica con la variable f, la cuál será usada más adelante
f = plt.figure(figsize=(15,10))
ax = plt.subplot()
plt.xlim(14000,3000)
plt.xscale('log')
plt.ylim(10**-5,10**9)
plt.yscale('log')
plt.xticks([3500,7000,14000])
def log_10_product(x, pos):
return '%1i' % (x)
formatter = FuncFormatter(log_10_product)
ax.xaxis.set_major_formatter(formatter)
plt.setp(ax.get_xminorticklabels(), visible=False)
#Para este caso no se añade el texto en la gráfica representativo de cada tipo de estrella, pues se generará dentro
#de la animación
plt.xlabel('Temperature (K)',fontsize=15)
plt.ylabel('Luminosity (Lsun)',fontsize=15)
plt.title('Hertzsprung-Russell Diagram',fontsize=20)
#Una vez definido el template se procede a generarlo graficando un punto vacío con el fin de generar la gráfica sin
#graficar ningún punto
scat = plt.scatter(x = AllStars.temp.iloc[0], y = AllStars.lum.iloc[0],s=AllStars.radius.iloc[0],c = AllStars.temp.iloc[0],cmap='RdYlBu',edgecolors='grey',linewidth=1.5)
#se define la función animation, la cual determina los cambios que se generarán a los puntos en la gráfica según el valor
#de iteración i que corresponde al frame de la animación
def animation(i):
#Los primeros 90 valores corresponden la secuencia prinicial, debido a que la densidad de puntos de estos datos
#es mucho mayor en comparación a los otros se generarán 3 puntos por cada punto de iteración i
if i <= 30:
#al pasar por cada punto de iteración i se generan los puntos de graficación al tomar los puntos desde 0 hasta el punto 3i
#de la columna conteniendo dichos datos del Dataframe mediante la función iloc, y los anexa a una lista para poder ser graficados
#usando la función tolist()
x = AllStars.temp.iloc[:i*3].tolist()
y = AllStars.lum.iloc[:i*3].tolist()
size = AllStars.radius.iloc[:i*3].tolist()
c = AllStars.temp.iloc[:i*3].tolist()
#En este caso se cambia el valor del tamaño * 50 al igual que en el punto anterior pero esto se realiza dentro de una lista
#usando list comprehension
s = [a*50 for a in size]
else:
#De manera analoga para el resto de puntos itera por cada punto i dentro de la base de datos, a excepción que ahora va punto
#a punto para que la animación sea menos rápida
x = AllStars.temp.iloc[:60+i].tolist()
y = AllStars.lum.iloc[:60+i].tolist()
size = AllStars.radius.iloc[:60+i].tolist()
s = [a*50 for a in size]
c = AllStars.temp.iloc[:60+i].tolist()
#En este punto se grafican los puntos generados en las variables x,y,s según las iteraciones anteriores
scat = plt.scatter(x, y ,s,c,cmap='RdYlBu',edgecolors='grey',linewidth=1.5)
#Cuando se alcanza el valor i=30 se abrán graficado todos los puntos de la secuencia principal, por lo que se genera el
#texto en la gráfica de identificación 'Main Sequence'
if i>30:
plt.text(13000,10,'Main Sequence',fontsize=15)
plt.text(4800,10**-3,'Main Sequence',fontsize=15)
#La siguiente secuencia corresponde a las enanas blancas, como vimos el punto anterior ellas presentan una excepción
#a la regla de color, por lo que se grafican encima de los puntos anteriores correspondientes a las enanas blancas
#pero de color blanco
xd = Dwarfs.temp.iloc[:i-30].tolist()
yd = Dwarfs.lum.iloc[:i-30].tolist()
sized = Dwarfs.radius.iloc[:i-30].tolist()
sd = [a*50 for a in sized]
scat = plt.scatter(xd, yd ,sd,color='white',edgecolors='grey',linewidth=1.5)
#De manera analoga al texto de identificación de la secuencia principal se general los textos de las demas estrellas cuando
#la animación haya concluido la graficación de los puntos correspondiente a esa categoría
if i> 36:
plt.text(9000,10**-2,'White Dwarfs',fontsize=15)
if i >42:
plt.text(5000,10**3,'Red Giants',fontsize=15)
if i >44:
plt.text(5000,10**8,'Red Supergiants',fontsize=15)
if i >45:
plt.text(12500,10**8,'Blue Giants',fontsize=15)
#Finalmente la función devuelve los puntos graficados según el punto de iteración i
return scat,
#Para determinar cuantos puntos de iteración se tendrán se cuentan cuantos puntos habrán para finalizar la secuencia principal
#sumando el restante hasta completar todos los datos en la base de datos y se suman 20 iteraciones adicionales para dar
#tiempo a la animación de mostrar la figura final durante un par de segundos
N_points = int(90/3 + len(AllStars) - 90 + 20)
#Ahora se usa la función FuncAnimation, la cual tiene como imagen inicial la gráfica vacia f, la función de animación animation
#el numero de iteraciones determinado por N_points, el intervalo en ms entre cada iteración y finalmente la función
#blit la cual evita que se grafiquen los puntos graficados anteriormente a menos que hayan sufrido un cambio con el fin
#de disminuir el tiempo de procesamiento
anim= FuncAnimation(f,animation,frames=N_points,interval=200,blit=True)
#finalmente se guarda la animación generada en un archivo .gif y se cierra la figura estatica generada en el ultimo punto
#de iteración
anim.save('Hertzsprung-Russell Diagram.gif')
plt.close(f)
MovieWriter ffmpeg unavailable; using Pillow instead.
Una vez generado el archivo de animación en formato .gif se procede a anexarlo al notebook mediante el siguiente código usado en la siguiente celda Markdown: 'img src="Hertzsprung-Russell Diagram.gif"' encerrada en '<>' esto permite adicionar la animación generada en un punto local sin afectar la memoria y el peso total del notebook por si mismo