grafico_3d_pareto.py 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  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. # Leer el archivo manualmente
  6. data = []
  7. with open('resultados1.txt', 'r', encoding='utf-8') as f:
  8. header = f.readline().strip().split('\t')
  9. for line in f:
  10. values = line.strip().split('\t')
  11. if len(values) >= 9: # Asegurar que hay suficientes columnas
  12. data.append(values)
  13. # Encontrar índices de columnas
  14. tf_idx = header.index('tf')
  15. tw_idx = header.index('tw')
  16. flecha_idx = header.index('Flecha_Media')
  17. # Convertir datos a números
  18. def convert_value(x):
  19. """Convierte string a float, manejando formato con coma decimal"""
  20. try:
  21. return float(x.replace(',', '.').strip())
  22. except:
  23. return np.nan
  24. tf_list = []
  25. tw_list = []
  26. flecha_list = []
  27. for row in data:
  28. tf_val = convert_value(row[tf_idx])
  29. tw_val = convert_value(row[tw_idx])
  30. flecha_val = convert_value(row[flecha_idx])
  31. if not (np.isnan(tf_val) or np.isnan(tw_val) or np.isnan(flecha_val)):
  32. tf_list.append(tf_val)
  33. tw_list.append(tw_val)
  34. flecha_list.append(flecha_val)
  35. tf = np.array(tf_list)
  36. tw = np.array(tw_list)
  37. flecha_media = np.array(flecha_list)
  38. # Función para calcular la frontera de Pareto (versión mejorada)
  39. def pareto_frontier(tf, tw, flecha):
  40. """
  41. Calcula los puntos que pertenecen a la frontera de Pareto.
  42. Queremos minimizar tf, tw y el valor absoluto de flecha (magn itud de deflexión).
  43. Un punto es Pareto si no hay otro punto que sea mejor en todos los criterios simultáneamente.
  44. """
  45. n = len(tf)
  46. is_pareto = np.ones(n, dtype=bool)
  47. # Usar valor absoluto de flecha para la comparación
  48. flecha_abs = np.abs(flecha)
  49. for i in range(n):
  50. for j in range(n):
  51. if i != j:
  52. # El punto j domina al punto i si es mejor (≤) en todos los criterios
  53. # y estrictamente mejor en al menos uno
  54. if (tf[j] <= tf[i] and tw[j] <= tw[i] and flecha_abs[j] <= flecha_abs[i]) and \
  55. (tf[j] < tf[i] or tw[j] < tw[i] or flecha_abs[j] < flecha_abs[i]):
  56. is_pareto[i] = False
  57. break
  58. return is_pareto
  59. # Calcular frontera de Pareto
  60. pareto_mask = pareto_frontier(tf, tw, flecha_media)
  61. pareto_tf = tf[pareto_mask]
  62. pareto_tw = tw[pareto_mask]
  63. pareto_flecha = flecha_media[pareto_mask]
  64. print(f"Total de puntos: {len(tf)}")
  65. print(f"Puntos en la frontera de Pareto: {len(pareto_tf)}")
  66. # Crear figura 3D
  67. fig = plt.figure(figsize=(14, 10))
  68. ax = fig.add_subplot(111, projection='3d')
  69. # Graficar todos los puntos
  70. scatter_all = ax.scatter(tf, tw, flecha_media, c='lightblue', marker='o', s=50, alpha=0.6, label='Todos los puntos')
  71. # Graficar la frontera de Pareto
  72. scatter_pareto = ax.scatter(pareto_tf, pareto_tw, pareto_flecha, c='red', marker='*', s=200, alpha=0.9, label='Frontera de Pareto')
  73. # Intentar graficar la superficie convexa de la frontera de Pareto
  74. if len(pareto_tf) >= 4:
  75. try:
  76. # Crear matriz de coordenadas para la frontera de Pareto
  77. points_pareto = np.column_stack((pareto_tf, pareto_tw, pareto_flecha))
  78. # Calcular la envolvente convexa (convex hull)
  79. hull = ConvexHull(points_pareto)
  80. # Graficar la superficie
  81. for simplex in hull.simplices:
  82. # Crear triángulos de la superficie
  83. triangle = points_pareto[simplex]
  84. # Graficar los bordes del triángulo
  85. for i in range(3):
  86. ax.plot(triangle[[i, (i+1)%3], 0],
  87. triangle[[i, (i+1)%3], 1],
  88. triangle[[i, (i+1)%3], 2], 'r-', alpha=0.3, linewidth=0.5)
  89. except Exception as e:
  90. print(f"No se pudo graficar la superficie convexa: {e}")
  91. # Etiquetas de ejes
  92. ax.set_xlabel('tf (espesor del ala)', fontsize=12, fontweight='bold')
  93. ax.set_ylabel('tw (espesor del alma)', fontsize=12, fontweight='bold')
  94. ax.set_zlabel('Flecha_Media (deflexión)', fontsize=12, fontweight='bold')
  95. ax.set_title('Nube de Puntos 3D y Frontera de Pareto\ntf vs tw vs Flecha_Media', fontsize=14, fontweight='bold')
  96. # Leyenda
  97. ax.legend(loc='upper right', fontsize=11)
  98. # Ajustar vista
  99. ax.view_init(elev=20, azim=45)
  100. plt.tight_layout()
  101. plt.savefig('grafico_3d_pareto.png', dpi=300, bbox_inches='tight')
  102. print("\nGráfico guardado como 'grafico_3d_pareto.png'")
  103. # Mostrar detalles de los puntos de Pareto
  104. print("\n" + "="*60)
  105. print("PUNTOS EN LA FRONTERA DE PARETO:")
  106. print("="*60)
  107. print(f"{'tf':<12} {'tw':<12} {'Flecha_Media':<15}")
  108. print("-"*60)
  109. for i in range(len(pareto_tf)):
  110. print(f"{pareto_tf[i]:<12.6f} {pareto_tw[i]:<12.6f} {pareto_flecha[i]:<15.6f}")
  111. plt.show()