Usuario: vivasm.
Nombre: Mariana Vivas.
Institución: Universidad Central de Venezuela.
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 arbitrariasEl diagrama Hertzprung-Russell es una herramienta para estudiar la evolución estelar. Fue desarrollado independientemente a principios de 1900 por Ejnar Hertzsprung y Norris Russell.
En el diagrama se grafica la temperatura de las estrellas contra su luminosidad, o el color de las estrellas (o tipo espectral) contra su magnitud absoluta.
Dependiendo de su masa inicial, cada estrella pasa por etapas evolutivas específicas, dictadas por su estructura interna y cómo produce energía. Cada uno de estos estados corresponde a un cambio de temperatura y luminosidad que mueven la estrella a diferentes regiones del diagrama HR mientras evoluciona. De aquí el verdadero poder del diagrama: con él se puede conocer la estructura interna y el estado de evolución de una estrella, sólo determinando su posición en el diagrama.
Hay tres regiones principales (o estados de evolución) del diagrama HR:
Por ejemplo, el sol se encuentra en la secuencia principal, con luminosidad 1 y temperatura alrededor de 5,400 K.
Importamos las librerias a utilizar:
import os # Para el manejo de directorios
import pandas as pd # Para el manejo de la data
import matplotlib.pyplot as plt # Para graficar
Creamos una lista de los archivos que contienen los datos para ejercicio:
entries = os.listdir(r'/home/vivasm/ejercicios-clase-03-datos/data') # Nos da la lista de nombres de los archivos en data
entries
['giants.txt', 'supergiants.txt', 'ms.csv', '.ipynb_checkpoints', 'dwarfs.csv']
Eliminamos el archivo '.ipynb_checkpoints':
entries.remove('.ipynb_checkpoints')
entries
['giants.txt', 'supergiants.txt', 'ms.csv', 'dwarfs.csv']
Cargaremos la data en forma de dataframes:
lista = []
for entry in entries: # Loop en los archivos
# Como en los archivos .txt la data está separada por espacios en blanco, planteamos los dos casos:
if 'txt' in entry:
df=pd.read_csv(fr'/home/vivasm/ejercicios-clase-03-datos/data/{entry}', delim_whitespace=True)
else:
df=pd.read_csv(fr'/home/vivasm/ejercicios-clase-03-datos/data/{entry}')
# la columna tag nos va a servir para identificar a qué archivo pertenece la data.
df['tag'] = f'{entry}'
# agregamos todos los dataframes a una lista.
lista.append(df)
# creamos el masterfile concatenando todos lor archivos.
master = pd.concat(lista)
master
lum | temp | radius | tag | |
---|---|---|---|---|
0 | 304.228573 | 3654.601099 | 145.483474 | giants.txt |
1 | 58.884366 | 3808.609875 | 66.642938 | giants.txt |
2 | 9.246982 | 3991.751692 | 27.603430 | giants.txt |
3 | 58.505945 | 4164.818180 | 50.832968 | giants.txt |
4 | 32.033176 | 4425.773883 | 33.290931 | giants.txt |
... | ... | ... | ... | ... |
1 | 0.000128 | 5967.543450 | 4.583996 | dwarfs.csv |
2 | 0.000230 | 6674.161524 | 4.151078 | dwarfs.csv |
3 | 0.000269 | 7216.762974 | 3.491754 | dwarfs.csv |
4 | 0.000472 | 7795.184395 | 3.472736 | dwarfs.csv |
5 | 0.000613 | 8402.695283 | 3.077338 | dwarfs.csv |
106 rows × 4 columns
Como los archivos estan separados por tipo de estrella, en la columna 'tag' tendremos la etiqueta para el tipo de estrella de cada conjunto de datos:
master['tag'].unique() # Obtenemos los valores únicos en la columna 'tag'
array(['giants.txt', 'supergiants.txt', 'ms.csv', 'dwarfs.csv'], dtype=object)
Cambiaremos los nombres para utilizarlos más adelante:
# Eliminamos la extensión del nombre del tag
master['tag'] = master['tag'].replace(to_replace ='\..+', value = '', regex = True)
toreplace=['giants','supergiants','ms','dwarfs'] # Los nombres que vamos a cambiar
replaceval=['Gigantes','Supergigantes', 'Secuencia Principal', 'Enanas'] # Los nombres por los que los vamos a cambiar
# Utilizamos .replace() en la columna 'tag'
master['tag'] = master['tag'].replace(to_replace = toreplace, value = replaceval)
master['tag'].unique() # Visualizamos nuevamente los valores únicos
array(['Gigantes', 'Supergigantes', 'Secuencia Principal', 'Enanas'], dtype=object)
Calculamos los valores medios de luminosidad y temperatura, para colocar las etiquetas en el gráfico:
meanval = master.groupby('tag').mean() # Agrupamos por tag (por tipo de estrella) y calculamos la media
meanval = meanval.drop('radius', axis=1) # Eliminamos la columna del radio
meanval
lum | temp | |
---|---|---|
tag | ||
Enanas | 0.000304 | 6851.165387 |
Gigantes | 92.579808 | 4009.110946 |
Secuencia Principal | 27.658464 | 6834.153632 |
Supergigantes | 695379.680181 | 6340.653006 |
# Colocamos los valores medios de lum y temp, con su tag, en una lista de tuplas
listameanval=list(meanval.itertuples(index=True))
listameanval
[Pandas(Index='Enanas', lum=0.0003035131049290667, temp=6851.165387149475), Pandas(Index='Gigantes', lum=92.57980824531319, temp=4009.1109458664746), Pandas(Index='Secuencia Principal', lum=27.65846380844224, temp=6834.153632032207), Pandas(Index='Supergigantes', lum=695379.6801805029, temp=6340.653005916424)]
Con estos datos tenemos la posición de cada tag, lo que queda es agregarla al gráfico.
Graficamos:
# Extraemos del dataframe 'master' la data en la que estamos interesados
temp, lum = master['temp'], master['lum']
radius= master['radius']*20 # Multiplicamos por un factor para mejor visualización
# Creamos la figura definiendo el tamaño:
fig = plt.figure(figsize=(9, 6))
# Utilizamos 'scatter' para graficar
plt.scatter(
x=temp, # la temperatura en el eje x
y=lum, # la luminosidad en el eje y
s=radius, # el tamaño de los puntos de acuerdo al radio
c=temp, # el color de acuerdo a los datos de temperatura
cmap="RdYlBu", # mapa de color (https://matplotlib.org/3.1.0/tutorials/colors/colormaps.html para las distintas opciones)
edgecolors="gray") # color de los bordes de los puntos gris
# Ajustamos los ejes en escala logaritmica:
plt.xscale('log', base=2)
plt.yscale('log')
ax = plt.gca() # Colocamos en una variable el axis que estamos utilizando
ax.invert_xaxis() # Invertimos el eje x
# Eliminamos el eje de la derecha y de arriba
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
# Colocamos los ticks específicos para el eje x
ax.set_xticks([12000, 10000, 8000, 6000, 4000])
ax.set_xticklabels([12000, 10000, 8000, 6000, 4000])
# Colocamos los límites para la luminosidad (eje y)
plt.ylim([0.00001, 10000000])
# Definimos las etiquetas del diagrama
plt.xlabel('Temperatura (K)',fontsize=14)
plt.ylabel('Luminosidad (L$_{sun}$)', fontsize=14)
plt.title('Diagrama de Hertzprung-Russell', fontsize=20);
for tag, y_pos, x_pos in listameanval:
plt.text(x_pos, y_pos, fr"{tag}", fontsize=15) # Recursivo sobre cada tupla en la lista.
Otra manera de graficar es utilizando directamente el dataframe y sus etiquetas:
# Definimos el axis graficando directamente del dataframe
ax = master.plot.scatter(
x='temp', # temperatura en el eje x
y='lum', # luminosidad en el eje y
s=master['radius']*20, # el tamaño de los puntos dado por el radio, multiplicado por un factor para visualización
c='temp', # el color distribuido de acuerdo a la temperatura
cmap="RdYlBu", # el mapa de color a utilizar
edgecolors="gray", # el borde de los puntos
figsize=(10,6)) # el tamaño de la figura
ax.invert_xaxis() # Invertimos el eje x
# Colocamos ambos ejes logaritmicos
plt.xscale('log', base=2)
plt.yscale('log')
plt.ylim([0.00001, 10000000]) # Definimos los limites del eje y
# Colocamos las etiquetas
ax.set_title('Diagrama de Hertzprung-Russell', fontsize=20)
ax.set_ylabel('Luminosidad (L$_{sun}$)', fontsize=14)
# Ajustamos los ticks
ax.tick_params(
axis='x', # los cambios aplican al eje x
which='both', # ambos ticks, mayores y menores, se ven afectados
bottom=False, # eliminamos los ticks de abajo
top=False, # eliminamos los ticks de arriba
labelbottom=False) # eliminamos las etiquetas en el eje inferior
# Eliminamos el eje derecho y superior
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
# Colocamos los nombres de las estrellas de acuerdo a la lista de valores medios
for tag, y_pos, x_pos in listameanval: # Utilizando cada valor de la tupla
plt.text(x_pos, y_pos, fr"{tag}", fontsize=15) # Colocamos el texto
# Como graficamos directamente de pandas, tendremos el eje del grafico y el de la barra del mapa de color
f= plt.gcf() # Obtenemos los ejes
cax = f.get_axes()[1] # Obtenemos el eje de la barra de color
cax.set_ylabel('Temperatura (K)', fontsize=14); # Colocamos el titulo
Lo interesante de graficar utilizando pandas es que las opciones para filtrar información son muy amplias, y con solo cambiar algunas variables podemos obtener una infinidad de gráficos:
# Iteramos sobre cada tipo de estrella en la lista
for tag in list(master['tag'].unique()):
# Definimos el axis graficando directamente del dataframe
ax = master[master['tag']==tag].plot.scatter( # Filtramos las filas cuyo tag sea el que estamos considerando
x='temp', # temperatura en el eje x
y='lum', # luminosidad en el eje y
s= master[master['tag']==tag]['radius']*20, # el tamaño de los puntos dado por el radio, multiplicado por un factor para visualización
c='temp', # el color distribuido de acuerdo a la temperatura
cmap="RdYlBu", # el mapa de color a utilizar
edgecolors="gray", # el borde de los puntos
figsize=(10,6)) # el tamaño de la figura
ax.invert_xaxis() # Invertimos el eje x
# Colocamos ambos ejes logaritmicos
plt.xscale('log', base=2)
plt.yscale('log')
plt.ylim([0.00001, 10000000]) # Definimos los limites del eje y
plt.xlim([14000, 3200]) # Definimos los limites del eje x
# Colocamos las etiquetas
ax.set_title(fr'Diagrama de Hertzprung-Russell -- {tag}', fontsize=20)
ax.set_ylabel('Luminosidad (L$_{sun}$)', fontsize=14)
# Ajustamos los ticks
ax.tick_params(
axis='x', # los cambios aplican al eje x
which='both', # ambos ticks, mayores y menores, se ven afectados
bottom=False, # eliminamos los ticks de abajo
top=False, # eliminamos los ticks de arriba
labelbottom=False) # eliminamos las etiquetas en el eje inferior
# Eliminamos el eje derecho y superior
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
# Colocamos los nombres de las estrellas de acuerdo a la lista de valores medios
for _, y_pos, x_pos in listameanval: # utilizando cada valor en la tupla
if _==tag: # solo si la etiqueta es del diagrama que estamos graficando
plt.text(x_pos, y_pos, fr"{tag}", fontsize=15) # colocamos el texto
# Como graficamos directamente de pandas, tendremos el eje del grafico y el de la barra del mapa de color
f= plt.gcf() # Obtenemos los ejes
cax = f.get_axes()[1] # Obtenemos el eje de la barra de color
cax.set_ylabel('Temperatura (K)', fontsize=14); # Colocamos el titulo
import glob
os.environ["IMAGEIO_FFMPEG_EXE"] = "/usr/bin/ffmpeg" # Colocado porque da un error al correr la siguiente linea
import moviepy.editor as mpy
Primero creamos la función que grafica el gráfico que hicimos anteriormente:
def plot_data(tdata,ldata,rdata,fname):
# Creamos la figura definiendo el tamaño:
fig = plt.figure(figsize=(9, 6))
# Utilizamos 'scatter' para graficar
plt.scatter(
x=tdata, # la temperatura en el eje x
y=ldata, # la luminosidad en el eje y
s=rdata, # el tamaño de los puntos de acuerdo al radio
c=tdata, # el color de acuerdo a los datos de temperatura
cmap="RdYlBu", # mapa de color (https://matplotlib.org/3.1.0/tutorials/colors/colormaps.html para las distintas opciones)
edgecolors="gray") # color de los bordes de los puntos gris
# Ajustamos los ejes en escala logaritmica:
plt.xscale('log', base=2)
plt.yscale('log')
ax = plt.gca() # Colocamos en una variable el axis que estamos utilizando
ax.invert_xaxis() # Invertimos el eje x
# Eliminamos el eje de la derecha y de arriba
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
# Colocamos los límites para la luminosidad (eje y)
plt.ylim([0.00001, 10000000])
# y para la temperatura (eje x)
plt.xlim([13500, 3200])
# Colocamos los ticks específicos para el eje x
ax.set_xticks([12000, 10000, 8000, 6000, 4000])
ax.set_xticklabels([12000, 10000, 8000, 6000, 4000])
# Definimos las etiquetas del diagrama
plt.xlabel('Temperatura (K)',fontsize=14)
plt.ylabel('Luminosidad (L$_{sun}$)', fontsize=14)
plt.title('Diagrama de Hertzprung-Russell', fontsize=20);
plt.savefig(fname,dpi=150,bbox_inches='tight')
Vamos a hacer una imagen cada vez que agregamos un punto:
# Extraemos del dataframe 'master' la data en la que estamos interesados
temp, lum = master['temp'], master['lum']
radius= master['radius']*20
#Vamos a iterar sobre la data, creando una imagen con un punto más a medida que avanza el loop
for ii in range(len(temp)):
fname = 'HR_'+str(ii).zfill(5)+'.png' #Creamos el nombre del archivo automaticamente
plot_data(temp[:ii],lum[:ii],radius[:ii],fname) # Creamos un grafico,
# donde en cada iteracion graficamos los primeros ii elementos
plt.close()
Convertimos estas imagenes en un gif con moviepy:
#Colocamos el nombre de la animación
gif_name = 'HRanimation'
# Definimos los cuadros por segundo
fps = 20
# Creamos una lista ordenada con todos los png que creamos en el directorio
file_list = sorted(glob.glob('*.png'))
# Creamos una instancia de clip, utilizando ImageSequenceClip
clip = mpy.ImageSequenceClip(file_list, fps=fps)
# Guardamos la animación como un gif
clip.write_gif(gif_name+'.gif')
# Eliminamos los png creados anteriormente
dir_name = "/home/vivasm/ejercicios-clase-03-datos" # Definimos donde se encuentran los archivos
test = os.listdir(dir_name) # Creamos una lista de todo lo que hay en el directorio
for item in test: # Iteramos sobre esa lista
if item.endswith(".png"): # Eliminamos todos los items con extension png
os.remove(os.path.join(dir_name, item))
t: 0%| | 0/106 [00:00<?, ?it/s, now=None]
MoviePy - Building file HRanimation.gif with imageio.
La desventaja de utilizar este método es que se crean las imagenes en el directorio. En este caso, como los datos no son muy extensos, se puede hacer, pero a la hora de trabajar con más datos esto podría ser poco eficiente.