visualizacion_restriccion_detallada.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. import numpy as np
  2. import matplotlib.pyplot as plt
  3. from mpl_toolkits.mplot3d import Axes3D
  4. from scipy.spatial import ConvexHull
  5. import warnings
  6. warnings.filterwarnings('ignore')
  7. # Leer el archivo manualmente
  8. data = []
  9. with open('resultados1.txt', 'r', encoding='utf-8') as f:
  10. header = f.readline().strip().split('\t')
  11. for line in f:
  12. values = line.strip().split()
  13. if len(values) >= 15:
  14. data.append(values)
  15. # Convertir datos
  16. def convert_value(x):
  17. try:
  18. return float(x.replace(',', '.').strip())
  19. except:
  20. return np.nan
  21. tf = np.array([convert_value(row[2]) for row in data])
  22. tw = np.array([convert_value(row[3]) for row in data])
  23. flecha = np.array([convert_value(row[8]) for row in data])
  24. # Filtrar NaN
  25. valid = ~(np.isnan(tf) | np.isnan(tw) | np.isnan(flecha))
  26. tf = tf[valid]
  27. tw = tw[valid]
  28. flecha = flecha[valid]
  29. # RESTRICCIÓN DE DISEÑO
  30. LIMITE_FLECHA = -25.0
  31. # Separar válidos e inválidos
  32. valid_idx = flecha >= LIMITE_FLECHA
  33. invalid_idx = flecha < LIMITE_FLECHA
  34. tf_valid = tf[valid_idx]
  35. tw_valid = tw[valid_idx]
  36. flecha_valid = flecha[valid_idx]
  37. tf_invalid = tf[invalid_idx]
  38. tw_invalid = tw[invalid_idx]
  39. flecha_invalid = flecha[invalid_idx]
  40. print("="*80)
  41. print("VISUALIZACIÓN 3D CON PLANO DE RESTRICCIÓN DE DISEÑO")
  42. print("="*80)
  43. print(f"\nRestriction: Flecha_Media >= {LIMITE_FLECHA} mm")
  44. print(f"Valid points: {len(tf_valid)} ({100*len(tf_valid)/len(tf):.1f}%)")
  45. print(f"Invalid points: {len(tf_invalid)} ({100*len(tf_invalid)/len(tf):.1f}%)")
  46. # Crear figura con múltiples vistas
  47. fig = plt.figure(figsize=(20, 14))
  48. # Definir plano de restricción
  49. xx = np.linspace(tf.min(), tf.max(), 30)
  50. yy = np.linspace(tw.min(), tw.max(), 30)
  51. XX, YY = np.meshgrid(xx, yy)
  52. ZZ = np.full_like(XX, LIMITE_FLECHA)
  53. # Vista 1: Ángulo 45°
  54. ax1 = fig.add_subplot(2, 3, 1, projection='3d')
  55. ax1.plot_surface(XX, YY, ZZ, alpha=0.25, color='orange', label='Plano de restricción')
  56. ax1.plot_wireframe(XX, YY, ZZ, color='darkorange', alpha=0.4, linewidth=0.5)
  57. ax1.scatter(tf_invalid, tw_invalid, flecha_invalid, c='red', marker='x', s=80, alpha=0.4, label='Inválidos')
  58. ax1.scatter(tf_valid, tw_valid, flecha_valid, c='lightgreen', marker='o', s=60, alpha=0.6, edgecolors='darkgreen', linewidth=0.3, label='Válidos')
  59. ax1.set_xlabel('tf (mm)', fontweight='bold')
  60. ax1.set_ylabel('tw (mm)', fontweight='bold')
  61. ax1.set_zlabel('Flecha (mm)', fontweight='bold')
  62. ax1.set_title('Vista 45°', fontweight='bold', fontsize=11)
  63. ax1.view_init(elev=20, azim=45)
  64. ax1.legend(fontsize=9, loc='upper left')
  65. # Vista 2: Ángulo 135°
  66. ax2 = fig.add_subplot(2, 3, 2, projection='3d')
  67. ax2.plot_surface(XX, YY, ZZ, alpha=0.25, color='orange')
  68. ax2.plot_wireframe(XX, YY, ZZ, color='darkorange', alpha=0.4, linewidth=0.5)
  69. ax2.scatter(tf_invalid, tw_invalid, flecha_invalid, c='red', marker='x', s=80, alpha=0.4)
  70. ax2.scatter(tf_valid, tw_valid, flecha_valid, c='lightgreen', marker='o', s=60, alpha=0.6, edgecolors='darkgreen', linewidth=0.3)
  71. ax2.set_xlabel('tf (mm)', fontweight='bold')
  72. ax2.set_ylabel('tw (mm)', fontweight='bold')
  73. ax2.set_zlabel('Flecha (mm)', fontweight='bold')
  74. ax2.set_title('Vista 135°', fontweight='bold', fontsize=11)
  75. ax2.view_init(elev=20, azim=135)
  76. # Vista 3: Vista desde arriba (proyección 2D)
  77. ax3 = fig.add_subplot(2, 3, 3, projection='3d')
  78. ax3.plot_surface(XX, YY, ZZ, alpha=0.25, color='orange')
  79. ax3.plot_wireframe(XX, YY, ZZ, color='darkorange', alpha=0.4, linewidth=0.5)
  80. ax3.scatter(tf_invalid, tw_invalid, flecha_invalid, c='red', marker='x', s=80, alpha=0.4)
  81. ax3.scatter(tf_valid, tw_valid, flecha_valid, c='lightgreen', marker='o', s=60, alpha=0.6, edgecolors='darkgreen', linewidth=0.3)
  82. ax3.set_xlabel('tf (mm)', fontweight='bold')
  83. ax3.set_ylabel('tw (mm)', fontweight='bold')
  84. ax3.set_zlabel('Flecha (mm)', fontweight='bold')
  85. ax3.set_title('Vista Cenital (Desde arriba)', fontweight='bold', fontsize=11)
  86. ax3.view_init(elev=85, azim=45)
  87. # Vista 4: Proyección tf vs Flecha
  88. ax4 = fig.add_subplot(2, 3, 4)
  89. ax4.axhline(y=LIMITE_FLECHA, color='orange', linewidth=3, linestyle='--', label=f'Plano restricción (z={LIMITE_FLECHA})')
  90. ax4.axhspan(flecha_invalid.min() if len(flecha_invalid) > 0 else -100, LIMITE_FLECHA, alpha=0.2, color='red', label='Región inválida')
  91. ax4.axhspan(LIMITE_FLECHA, flecha_valid.max() if len(flecha_valid) > 0 else 0, alpha=0.2, color='green', label='Región válida')
  92. ax4.scatter(tf_invalid, flecha_invalid, c='red', marker='x', s=100, alpha=0.5, linewidth=2, label=f'Puntos inválidos ({len(tf_invalid)})')
  93. ax4.scatter(tf_valid, flecha_valid, c='lightgreen', marker='o', s=80, alpha=0.6, edgecolors='darkgreen', linewidth=0.5, label=f'Puntos válidos ({len(tf_valid)})')
  94. ax4.set_xlabel('tf - Espesor ala (mm)', fontweight='bold')
  95. ax4.set_ylabel('Flecha_Media (mm)', fontweight='bold')
  96. ax4.set_title('Proyección 2D: tf vs Flecha', fontweight='bold', fontsize=11)
  97. ax4.grid(True, alpha=0.3)
  98. ax4.legend(fontsize=9)
  99. ax4.set_xlim(tf.min()-0.01, tf.max()+0.01)
  100. # Vista 5: Proyección tw vs Flecha
  101. ax5 = fig.add_subplot(2, 3, 5)
  102. ax5.axhline(y=LIMITE_FLECHA, color='orange', linewidth=3, linestyle='--', label=f'Plano restricción (z={LIMITE_FLECHA})')
  103. ax5.axhspan(flecha_invalid.min() if len(flecha_invalid) > 0 else -100, LIMITE_FLECHA, alpha=0.2, color='red', label='Región inválida')
  104. ax5.axhspan(LIMITE_FLECHA, flecha_valid.max() if len(flecha_valid) > 0 else 0, alpha=0.2, color='green', label='Región válida')
  105. ax5.scatter(tw_invalid, flecha_invalid, c='red', marker='x', s=100, alpha=0.5, linewidth=2, label=f'Puntos inválidos ({len(tw_invalid)})')
  106. ax5.scatter(tw_valid, flecha_valid, c='lightgreen', marker='o', s=80, alpha=0.6, edgecolors='darkgreen', linewidth=0.5, label=f'Puntos válidos ({len(tw_valid)})')
  107. ax5.set_xlabel('tw - Espesor alma (mm)', fontweight='bold')
  108. ax5.set_ylabel('Flecha_Media (mm)', fontweight='bold')
  109. ax5.set_title('Proyección 2D: tw vs Flecha', fontweight='bold', fontsize=11)
  110. ax5.grid(True, alpha=0.3)
  111. ax5.legend(fontsize=9)
  112. ax5.set_xlim(tw.min()-0.01, tw.max()+0.01)
  113. # Vista 6: Proyección tf vs tw (plano horizontal)
  114. ax6 = fig.add_subplot(2, 3, 6)
  115. scatter_invalid_2d = ax6.scatter(tf_invalid, tw_invalid, c='red', marker='x', s=100, alpha=0.5, linewidth=2, label=f'Inválidos ({len(tf_invalid)})')
  116. scatter_valid_2d = ax6.scatter(tf_valid, tw_valid, c='lightgreen', marker='o', s=80, alpha=0.6, edgecolors='darkgreen', linewidth=0.5, label=f'Válidos ({len(tf_valid)})')
  117. ax6.set_xlabel('tf - Espesor ala (mm)', fontweight='bold')
  118. ax6.set_ylabel('tw - Espesor alma (mm)', fontweight='bold')
  119. ax6.set_title('Proyección 2D: tf vs tw', fontweight='bold', fontsize=11)
  120. ax6.grid(True, alpha=0.3)
  121. ax6.legend(fontsize=9)
  122. plt.suptitle(f'Análisis de Restricción de Diseño: Flecha_Media ≥ {LIMITE_FLECHA} mm',
  123. fontsize=14, fontweight='bold', y=0.995)
  124. plt.tight_layout(rect=[0, 0, 1, 0.99])
  125. plt.savefig('multiples_vistas_restriccion.png', dpi=300, bbox_inches='tight')
  126. print("\n✓ Visualización guardada como 'multiples_vistas_restriccion.png'")
  127. # Crear gráfico de comparación: válido vs inválido
  128. fig2, axes = plt.subplots(1, 3, figsize=(16, 5))
  129. # Histogramas de distribuciones
  130. axes[0].hist(flecha_invalid, bins=20, alpha=0.6, color='red', label='Inválidos', edgecolor='darkred')
  131. axes[0].hist(flecha_valid, bins=20, alpha=0.6, color='green', label='Válidos', edgecolor='darkgreen')
  132. axes[0].axvline(x=LIMITE_FLECHA, color='orange', linewidth=3, linestyle='--', label=f'Límite = {LIMITE_FLECHA} mm')
  133. axes[0].set_xlabel('Flecha_Media (mm)', fontweight='bold')
  134. axes[0].set_ylabel('Frecuencia', fontweight='bold')
  135. axes[0].set_title('Distribución de Deflexiones', fontweight='bold')
  136. axes[0].legend()
  137. axes[0].grid(True, alpha=0.3)
  138. # Comparación de ranges
  139. categories = ['tf (ala)', 'tw (alma)', 'Flecha']
  140. valid_min = [tf_valid.min(), tw_valid.min(), flecha_valid.min()]
  141. valid_max = [tf_valid.max(), tw_valid.max(), flecha_valid.max()]
  142. invalid_min = [tf_invalid.min(), tw_invalid.min(), flecha_invalid.min()]
  143. invalid_max = [tf_invalid.max(), tw_invalid.max(), flecha_invalid.max()]
  144. x = np.arange(len(categories))
  145. width = 0.2
  146. bars1 = axes[1].bar(x - width*1.5, valid_min, width, label='Válidos (mín)', color='lightgreen', edgecolor='darkgreen')
  147. bars2 = axes[1].bar(x - width/2, valid_max, width, label='Válidos (máx)', color='darkgreen', edgecolor='black')
  148. bars3 = axes[1].bar(x + width/2, invalid_min, width, label='Inválidos (mín)', color='lightcoral', edgecolor='darkred')
  149. bars4 = axes[1].bar(x + width*1.5, invalid_max, width, label='Inválidos (máx)', color='darkred', edgecolor='black')
  150. axes[1].set_ylabel('Valor', fontweight='bold')
  151. axes[1].set_title('Rango de Valores por Región', fontweight='bold')
  152. axes[1].set_xticks(x)
  153. axes[1].set_xticklabels(categories)
  154. axes[1].legend(fontsize=9)
  155. axes[1].grid(True, alpha=0.3, axis='y')
  156. # Estadísticas resumen
  157. axes[2].axis('off')
  158. stats_text = f"""RESUMEN DE RESTRICCIÓN DE DISEÑO
  159. Límite de Deflexión: Flecha_Media ≥ {LIMITE_FLECHA} mm
  160. PUNTOS VÁLIDOS (Flecha ≥ {LIMITE_FLECHA}):
  161. • Cantidad: {len(tf_valid)} puntos ({100*len(tf_valid)/len(tf):.1f}%)
  162. • tf range: [{tf_valid.min():.6f}, {tf_valid.max():.6f}] mm
  163. • tw range: [{tw_valid.min():.6f}, {tw_valid.max():.6f}] mm
  164. • Flecha range: [{flecha_valid.min():.2f}, {flecha_valid.max():.2f}] mm
  165. PUNTOS INVÁLIDOS (Flecha < {LIMITE_FLECHA}):
  166. • Cantidad: {len(tf_invalid)} puntos ({100*len(tf_invalid)/len(tf):.1f}%)
  167. • tf range: [{tf_invalid.min():.6f}, {tf_invalid.max():.6f}] mm
  168. • tw range: [{tw_invalid.min():.6f}, {tw_invalid.max():.6f}] mm
  169. • Flecha range: [{flecha_invalid.min():.2f}, {flecha_invalid.max():.2f}] mm
  170. TOTAL: {len(tf)} puntos
  171. """
  172. axes[2].text(0.1, 0.95, stats_text, transform=axes[2].transAxes, fontsize=10,
  173. verticalalignment='top', fontfamily='monospace',
  174. bbox=dict(boxstyle='round', facecolor='wheat', alpha=0.8))
  175. plt.suptitle('Comparación de Regiones: Válida vs Inválida', fontsize=14, fontweight='bold')
  176. plt.tight_layout()
  177. plt.savefig('comparacion_regiones.png', dpi=300, bbox_inches='tight')
  178. print("✓ Comparación guardada como 'comparacion_regiones.png'")
  179. print("\n" + "="*80)
  180. print("ARCHIVOS GENERADOS:")
  181. print("="*80)
  182. print(" 1. grafico_3d_pareto_con_restriccion.png - Vista 3D con plano de restricción")
  183. print(" 2. multiples_vistas_restriccion.png - 6 vistas diferentes del problema")
  184. print(" 3. comparacion_regiones.png - Análisis comparativo de regiones")
  185. print("="*80)
  186. plt.show()