253 lines
8.7 KiB
Python
253 lines
8.7 KiB
Python
#!/usr/bin/env python3
|
|
|
|
import json
|
|
import pandas as pd
|
|
import matplotlib.pyplot as plt
|
|
import seaborn as sns
|
|
from pathlib import Path
|
|
from datetime import datetime
|
|
|
|
# Configuración de estilo para los gráficos
|
|
plt.style.use('seaborn-v0_8-darkgrid')
|
|
sns.set_palette("husl")
|
|
|
|
def cargar_archivos_json(directorio='.'):
|
|
"""
|
|
Carga todos los archivos JSON del historial de Spotify
|
|
"""
|
|
archivos = Path(directorio).glob('Streaming_History_Audio_*.json')
|
|
todos_los_datos = []
|
|
|
|
for archivo in archivos:
|
|
print(f"Cargando {archivo.name}...")
|
|
with open(archivo, 'r', encoding='utf-8') as f:
|
|
datos = json.load(f)
|
|
todos_los_datos.extend(datos)
|
|
|
|
print(f"Total de reproducciones cargadas: {len(todos_los_datos)}")
|
|
return todos_los_datos
|
|
|
|
def procesar_datos(datos):
|
|
"""
|
|
Convierte los datos JSON en un DataFrame de pandas y procesa las fechas
|
|
"""
|
|
df = pd.DataFrame(datos)
|
|
|
|
# Convertir timestamp a datetime
|
|
df['ts'] = pd.to_datetime(df['ts'])
|
|
|
|
# Convertir milisegundos a minutos
|
|
df['minutos_reproducidos'] = df['ms_played'] / 60000
|
|
|
|
# Extraer año, mes, día
|
|
df['año'] = df['ts'].dt.year
|
|
df['mes'] = df['ts'].dt.month
|
|
df['año_mes'] = df['ts'].dt.to_period('M')
|
|
df['nombre_mes'] = df['ts'].dt.strftime('%B %Y')
|
|
|
|
# Filtrar solo canciones (no podcasts ni audiolibros)
|
|
df = df[df['master_metadata_track_name'].notna()]
|
|
|
|
return df
|
|
|
|
def minutos_por_mes(df):
|
|
"""
|
|
Calcula y grafica los minutos reproducidos por mes
|
|
"""
|
|
minutos_mes = df.groupby('año_mes')['minutos_reproducidos'].sum().reset_index()
|
|
minutos_mes['año_mes'] = minutos_mes['año_mes'].astype(str)
|
|
|
|
plt.figure(figsize=(15, 6))
|
|
plt.bar(minutos_mes['año_mes'], minutos_mes['minutos_reproducidos'], color='#1DB954')
|
|
plt.xlabel('Mes', fontsize=12)
|
|
plt.ylabel('Minutos Reproducidos', fontsize=12)
|
|
plt.title('Minutos Reproducidos por Mes', fontsize=16, fontweight='bold')
|
|
plt.xticks(rotation=45, ha='right')
|
|
plt.tight_layout()
|
|
plt.savefig('minutos_por_mes.png', dpi=300, bbox_inches='tight')
|
|
plt.close()
|
|
|
|
return minutos_mes
|
|
|
|
def top_artistas_mes(df, año, mes, top_n=10):
|
|
"""
|
|
Obtiene el top 10 de artistas de un mes específico
|
|
"""
|
|
df_mes = df[(df['año'] == año) & (df['mes'] == mes)]
|
|
|
|
if len(df_mes) == 0:
|
|
return None
|
|
|
|
top_artistas = df_mes.groupby('master_metadata_album_artist_name')['minutos_reproducidos'].sum().sort_values(ascending=False).head(top_n)
|
|
|
|
plt.figure(figsize=(12, 8))
|
|
top_artistas.plot(kind='barh', color='#1DB954')
|
|
plt.xlabel('Minutos Reproducidos', fontsize=12)
|
|
plt.ylabel('Artista', fontsize=12)
|
|
plt.title(f'Top {top_n} Artistas - {mes:02d}/{año}', fontsize=16, fontweight='bold')
|
|
plt.gca().invert_yaxis()
|
|
plt.tight_layout()
|
|
plt.savefig(f'top_artistas_{año}_{mes:02d}.png', dpi=300, bbox_inches='tight')
|
|
plt.close()
|
|
|
|
return top_artistas
|
|
|
|
def top_artistas_año(df, año, top_n=10):
|
|
"""
|
|
Obtiene el top 10 de artistas de un año específico
|
|
"""
|
|
df_año = df[df['año'] == año]
|
|
|
|
if len(df_año) == 0:
|
|
return None
|
|
|
|
top_artistas = df_año.groupby('master_metadata_album_artist_name')['minutos_reproducidos'].sum().sort_values(ascending=False).head(top_n)
|
|
|
|
plt.figure(figsize=(12, 8))
|
|
top_artistas.plot(kind='barh', color='#1ED760')
|
|
plt.xlabel('Minutos Reproducidos', fontsize=12)
|
|
plt.ylabel('Artista', fontsize=12)
|
|
plt.title(f'Top {top_n} Artistas - {año}', fontsize=16, fontweight='bold')
|
|
plt.gca().invert_yaxis()
|
|
plt.tight_layout()
|
|
plt.savefig(f'top_artistas_{año}.png', dpi=300, bbox_inches='tight')
|
|
plt.close()
|
|
|
|
return top_artistas
|
|
|
|
def top_canciones_mes(df, año, mes, top_n=10):
|
|
"""
|
|
Obtiene el top 10 de canciones de un mes específico
|
|
"""
|
|
df_mes = df[(df['año'] == año) & (df['mes'] == mes)]
|
|
|
|
if len(df_mes) == 0:
|
|
return None
|
|
|
|
df_mes['cancion_artista'] = df_mes['master_metadata_track_name'] + ' - ' + df_mes['master_metadata_album_artist_name']
|
|
top_canciones = df_mes.groupby('cancion_artista')['minutos_reproducidos'].sum().sort_values(ascending=False).head(top_n)
|
|
|
|
plt.figure(figsize=(12, 10))
|
|
top_canciones.plot(kind='barh', color='#1DB954')
|
|
plt.xlabel('Minutos Reproducidos', fontsize=12)
|
|
plt.ylabel('Canción', fontsize=12)
|
|
plt.title(f'Top {top_n} Canciones - {mes:02d}/{año}', fontsize=16, fontweight='bold')
|
|
plt.gca().invert_yaxis()
|
|
plt.tight_layout()
|
|
plt.savefig(f'top_canciones_{año}_{mes:02d}.png', dpi=300, bbox_inches='tight')
|
|
plt.close()
|
|
|
|
return top_canciones
|
|
|
|
def top_canciones_año(df, año, top_n=10):
|
|
"""
|
|
Obtiene el top 10 de canciones de un año específico
|
|
"""
|
|
df_año = df[df['año'] == año]
|
|
|
|
if len(df_año) == 0:
|
|
return None
|
|
|
|
df_año['cancion_artista'] = df_año['master_metadata_track_name'] + ' - ' + df_año['master_metadata_album_artist_name']
|
|
top_canciones = df_año.groupby('cancion_artista')['minutos_reproducidos'].sum().sort_values(ascending=False).head(top_n)
|
|
|
|
plt.figure(figsize=(12, 10))
|
|
top_canciones.plot(kind='barh', color='#1ED760')
|
|
plt.xlabel('Minutos Reproducidos', fontsize=12)
|
|
plt.ylabel('Canción', fontsize=12)
|
|
plt.title(f'Top {top_n} Canciones - {año}', fontsize=16, fontweight='bold')
|
|
plt.gca().invert_yaxis()
|
|
plt.tight_layout()
|
|
plt.savefig(f'top_canciones_{año}.png', dpi=300, bbox_inches='tight')
|
|
plt.close()
|
|
|
|
return top_canciones
|
|
|
|
def resumen_estadisticas(df):
|
|
"""
|
|
Muestra un resumen de estadísticas generales
|
|
"""
|
|
print("\n" + "="*60)
|
|
print("RESUMEN DE ESTADÍSTICAS")
|
|
print("="*60)
|
|
print(f"Total de reproducciones: {len(df):,}")
|
|
print(f"Total de minutos reproducidos: {df['minutos_reproducidos'].sum():,.2f}")
|
|
print(f"Total de horas reproducidas: {df['minutos_reproducidos'].sum()/60:,.2f}")
|
|
print(f"Artistas únicos: {df['master_metadata_album_artist_name'].nunique():,}")
|
|
print(f"Canciones únicas: {df['master_metadata_track_name'].nunique():,}")
|
|
print(f"Período: {df['ts'].min().date()} a {df['ts'].max().date()}")
|
|
print("="*60 + "\n")
|
|
|
|
def generar_todos_los_graficos(df):
|
|
"""
|
|
Genera todos los gráficos para cada año y cada mes disponible
|
|
"""
|
|
# Obtener años y meses únicos
|
|
años = sorted(df['año'].unique())
|
|
|
|
print("\n" + "="*60)
|
|
print("GENERANDO GRÁFICOS")
|
|
print("="*60)
|
|
|
|
# Generar gráficos por año
|
|
print("\n📊 Generando gráficos anuales...")
|
|
for año in años:
|
|
print(f" - Año {año}")
|
|
top_artistas_año(df, año)
|
|
top_canciones_año(df, año)
|
|
|
|
# Generar gráficos por mes
|
|
print("\n📊 Generando gráficos mensuales...")
|
|
for año in años:
|
|
meses_del_año = sorted(df[df['año'] == año]['mes'].unique())
|
|
for mes in meses_del_año:
|
|
print(f" - {año}-{mes:02d}")
|
|
top_artistas_mes(df, año, mes)
|
|
top_canciones_mes(df, año, mes)
|
|
|
|
print("\n✅ Todos los gráficos generados!")
|
|
|
|
# EJECUCIÓN PRINCIPAL
|
|
if __name__ == "__main__":
|
|
# 1. Cargar datos
|
|
datos = cargar_archivos_json()
|
|
|
|
# 2. Procesar datos
|
|
df = procesar_datos(datos)
|
|
|
|
# 3. Mostrar resumen
|
|
resumen_estadisticas(df)
|
|
|
|
# 4. Gráfico de minutos por mes
|
|
print("📊 Generando gráfico general de minutos por mes...")
|
|
minutos_mes = minutos_por_mes(df)
|
|
|
|
# 5. Guardar CSV de Año-Mes-Minutos
|
|
print("\n💾 Guardando CSV de minutos por mes...")
|
|
minutos_mes_csv = df.groupby(['año', 'mes'])['minutos_reproducidos'].sum().reset_index()
|
|
minutos_mes_csv.columns = ['Año', 'Mes', 'Minutos']
|
|
minutos_mes_csv = minutos_mes_csv.sort_values(['Año', 'Mes'])
|
|
minutos_mes_csv.to_csv('minutos_por_año_mes.csv', index=False, encoding='utf-8')
|
|
print("✅ CSV guardado: minutos_por_año_mes.csv")
|
|
|
|
# 6. Generar todos los gráficos
|
|
generar_todos_los_graficos(df)
|
|
|
|
# 7. Guardar datos procesados completos en CSV
|
|
print("\n💾 Guardando datos procesados completos en CSV...")
|
|
df.to_csv('historial_spotify_procesado.csv', index=False, encoding='utf-8')
|
|
print("✅ CSV guardado: historial_spotify_procesado.csv")
|
|
|
|
print("\n" + "="*60)
|
|
print("🎉 ANÁLISIS COMPLETADO")
|
|
print("="*60)
|
|
print("\nArchivos generados:")
|
|
print(" 📊 minutos_por_mes.png")
|
|
print(" 📊 top_artistas_[año].png (para cada año)")
|
|
print(" 📊 top_canciones_[año].png (para cada año)")
|
|
print(" 📊 top_artistas_[año]_[mes].png (para cada mes)")
|
|
print(" 📊 top_canciones_[año]_[mes].png (para cada mes)")
|
|
print(" 📄 minutos_por_año_mes.csv")
|
|
print(" 📄 historial_spotify_procesado.csv")
|
|
print("="*60 + "\n")
|