solo25.py 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. import pandas as pd
  2. import matplotlib.pyplot as plt
  3. import numpy as np
  4. import warnings
  5. warnings.filterwarnings('ignore')
  6. # ── Leer datos ──────────────────────────────────────────────────────────────
  7. df_raw = pd.read_csv(
  8. 'resultados1.txt',
  9. sep=r'\s+',
  10. decimal=',',
  11. header=0
  12. )
  13. inputs = ['H', 'b', 'tf', 'tw', 'e', 'L']
  14. outputs = ['Flecha_Media', 'Peso']
  15. for col in inputs + outputs:
  16. df_raw[col] = pd.to_numeric(df_raw[col], errors='coerce')
  17. df_raw.dropna(subset=inputs + outputs, inplace=True)
  18. # ── FILTRO: Flecha_Media > -25 ───────────────────────────────────────────────
  19. df = df_raw[df_raw['Flecha_Media'] > -25].copy()
  20. print(f"Filas totales : {len(df_raw)}")
  21. print(f"Filas filtradas: {len(df)} (Flecha_Media > -25)")
  22. print(df[inputs + outputs].describe().to_string())
  23. # ── Paleta de colores ────────────────────────────────────────────────────────
  24. COLORS = {
  25. 'H': '#E63946',
  26. 'b': '#457B9D',
  27. 'tf': '#2A9D8F',
  28. 'tw': '#E9C46A',
  29. 'e': '#F4A261',
  30. 'L': '#A8DADC',
  31. }
  32. BG = '#0F1117'
  33. GRID = '#2A2D3A'
  34. TEXT = '#E8EAF6'
  35. plt.rcParams.update({
  36. 'figure.facecolor': BG,
  37. 'axes.facecolor': BG,
  38. 'axes.edgecolor': GRID,
  39. 'axes.labelcolor': TEXT,
  40. 'xtick.color': TEXT,
  41. 'ytick.color': TEXT,
  42. 'grid.color': GRID,
  43. 'text.color': TEXT,
  44. 'font.family': 'monospace',
  45. })
  46. labels = {
  47. 'H': 'H (altura)',
  48. 'b': 'b (ancho)',
  49. 'tf': 'tf (ala)',
  50. 'tw': 'tw (alma)',
  51. 'e': 'e (excentr.)',
  52. 'L': 'L (longitud)',
  53. }
  54. SUBTITLE = f'Filtro: Flecha_Media > -25 · {len(df)} filas de {len(df_raw)}'
  55. # ════════════════════════════════════════════════════════════════════════════
  56. # FIGURA 1 – Scatter: cada entrada vs Flecha_Media y Peso
  57. # ════════════════════════════════════════════════════════════════════════════
  58. fig1, axes = plt.subplots(
  59. 2, 6, figsize=(22, 8),
  60. facecolor=BG,
  61. gridspec_kw={'hspace': 0.45, 'wspace': 0.35}
  62. )
  63. fig1.suptitle(f'Entradas vs Salidas · Scatter\n{SUBTITLE}',
  64. fontsize=13, fontweight='bold', color=TEXT, y=1.02)
  65. for col_idx, inp in enumerate(inputs):
  66. for row_idx, out in enumerate(outputs):
  67. ax = axes[row_idx, col_idx]
  68. color = COLORS[inp]
  69. sample = df[[inp, out]].dropna().sample(min(2000, len(df)), random_state=42)
  70. ax.scatter(sample[inp], sample[out],
  71. s=6, alpha=0.35, color=color, linewidths=0)
  72. z = np.polyfit(sample[inp], sample[out], 1)
  73. p = np.poly1d(z)
  74. xs = np.linspace(sample[inp].min(), sample[inp].max(), 200)
  75. ax.plot(xs, p(xs), color='white', lw=1.2, alpha=0.7)
  76. if out == 'Flecha_Media':
  77. ax.axhline(-25, color='white', lw=1.2, linestyle='--', alpha=0.85, label='-25')
  78. ax.legend(fontsize=7, framealpha=0.2, labelcolor=TEXT)
  79. ax.set_xlabel(labels[inp], fontsize=8)
  80. ax.set_ylabel(out, fontsize=8)
  81. ax.grid(True, linestyle='--', alpha=0.3)
  82. ax.tick_params(labelsize=7)
  83. fig1.tight_layout()
  84. fig1.savefig('filtrado_scatter.png',
  85. dpi=150, bbox_inches='tight', facecolor=BG)
  86. print("✓ filtrado_scatter.png guardado")
  87. # ════════════════════════════════════════════════════════════════════════════
  88. # FIGURA 2 – Distribuciones
  89. # ════════════════════════════════════════════════════════════════════════════
  90. all_vars = inputs + outputs
  91. n = len(all_vars)
  92. fig2, axes2 = plt.subplots(2, 4, figsize=(18, 8), facecolor=BG,
  93. gridspec_kw={'hspace': 0.5, 'wspace': 0.35})
  94. fig2.suptitle(f'Distribución de variables\n{SUBTITLE}',
  95. fontsize=13, fontweight='bold', color=TEXT, y=1.02)
  96. axes2_flat = axes2.flatten()
  97. for i, var in enumerate(all_vars):
  98. ax = axes2_flat[i]
  99. clr = COLORS.get(var, '#90CAF9')
  100. data = df[var].dropna()
  101. ax.hist(data, bins=40, color=clr, alpha=0.85, edgecolor='none')
  102. ax.axvline(data.mean(), color='white', lw=1.4, linestyle='--', label=f'μ={data.mean():.3g}')
  103. ax.set_title(var, fontsize=10, fontweight='bold', color=clr)
  104. ax.set_ylabel('Frecuencia', fontsize=8)
  105. ax.grid(True, linestyle='--', alpha=0.3)
  106. ax.tick_params(labelsize=7)
  107. ax.legend(fontsize=7, framealpha=0.2, labelcolor=TEXT)
  108. for j in range(n, len(axes2_flat)):
  109. axes2_flat[j].set_visible(False)
  110. fig2.tight_layout()
  111. fig2.savefig('filtrado_distribuciones.png',
  112. dpi=150, bbox_inches='tight', facecolor=BG)
  113. print("✓ filtrado_distribuciones.png guardado")
  114. # ════════════════════════════════════════════════════════════════════════════
  115. # FIGURA 3 – Heatmap correlación
  116. # ════════════════════════════════════════════════════════════════════════════
  117. corr = df[inputs + outputs].corr()
  118. fig3, ax3 = plt.subplots(figsize=(9, 7), facecolor=BG)
  119. fig3.suptitle(f'Mapa de correlación\n{SUBTITLE}', fontsize=13, fontweight='bold', color=TEXT)
  120. cmap = plt.cm.RdYlGn
  121. im = ax3.imshow(corr.values, cmap=cmap, vmin=-1, vmax=1, aspect='auto')
  122. plt.colorbar(im, ax=ax3, fraction=0.046, pad=0.04).ax.tick_params(colors=TEXT)
  123. ticks = list(range(len(corr.columns)))
  124. ax3.set_xticks(ticks); ax3.set_yticks(ticks)
  125. ax3.set_xticklabels(corr.columns, rotation=45, ha='right', fontsize=9)
  126. ax3.set_yticklabels(corr.columns, fontsize=9)
  127. for i in range(len(corr)):
  128. for j in range(len(corr)):
  129. val = corr.values[i, j]
  130. color_txt = 'black' if abs(val) > 0.5 else TEXT
  131. ax3.text(j, i, f'{val:.2f}', ha='center', va='center',
  132. fontsize=8, color=color_txt, fontweight='bold')
  133. ax3.grid(False)
  134. fig3.tight_layout()
  135. fig3.savefig('filtrado_correlacion_heatmap.png',
  136. dpi=150, bbox_inches='tight', facecolor=BG)
  137. print("✓ filtrado_correlacion_heatmap.png guardado")
  138. # ════════════════════════════════════════════════════════════════════════════
  139. # FIGURA 4 – Boxplots de salidas por cuantiles de L
  140. # ════════════════════════════════════════════════════════════════════════════
  141. df['L_cat'] = pd.qcut(df['L'], q=5, labels=['L_Q1','L_Q2','L_Q3','L_Q4','L_Q5'])
  142. fig4, axes4 = plt.subplots(1, 2, figsize=(14, 6), facecolor=BG)
  143. fig4.suptitle(f'Distribución de salidas por cuantiles de L\n{SUBTITLE}',
  144. fontsize=13, fontweight='bold', color=TEXT)
  145. palette = ['#E63946','#F4A261','#E9C46A','#2A9D8F','#457B9D']
  146. for ax_idx, out in enumerate(outputs):
  147. ax = axes4[ax_idx]
  148. groups = [df.loc[df['L_cat'] == cat, out].dropna().values
  149. for cat in df['L_cat'].cat.categories]
  150. bp = ax.boxplot(groups, patch_artist=True, notch=False,
  151. medianprops=dict(color='white', lw=2),
  152. whiskerprops=dict(color=TEXT),
  153. capprops=dict(color=TEXT),
  154. flierprops=dict(marker='o', color=TEXT, alpha=0.2, markersize=2))
  155. for patch, clr in zip(bp['boxes'], palette):
  156. patch.set_facecolor(clr)
  157. patch.set_alpha(0.75)
  158. ax.set_xticklabels(df['L_cat'].cat.categories, rotation=20, fontsize=8)
  159. ax.set_title(out, fontsize=11, fontweight='bold', color=TEXT)
  160. ax.set_ylabel(out, fontsize=9)
  161. ax.grid(True, axis='y', linestyle='--', alpha=0.3)
  162. fig4.tight_layout()
  163. fig4.savefig('filtrado_boxplot_salidas_por_L.png',
  164. dpi=150, bbox_inches='tight', facecolor=BG)
  165. print("✓ filtrado_boxplot_salidas_por_L.png guardado")
  166. print("\n✅ Todos los gráficos filtrados generados correctamente.")